Skip to content

Conversation

@baymer
Copy link

@baymer baymer commented Sep 29, 2025

if use virtual-store outside of node_modules and node_modules outside of build dir, bin path can be broke

for example we have this hypothetical structure

~/Projects/app/node_modules -> ~/.cache/modules/app/node_modules

~/.cache/modules/app/node_modules/eslint -> ~/.cache/vstore/app/[email protected]/node_modules/eslint

~/.cache/modules/app/node_modules/.bin/eslint =>
$0 => node_modules/.bin/eslint
basedir => node_modules/.bin
...
node  "node_modules/.bin/../../../../vstore/app/[email protected]/node_modules/eslint/bin/eslint.js"

=> error, module not found

module not found, because path is incorrect
~/Projects/app/node_modules/.bin/../../../../vstore/app/[email protected]/node_modules/eslint/bin/eslint.js

with realpath it will fixed

realpath $0 => ~/.cache/modules/app/node_modules/.bin/eslint
basedir => ~/.cache/modules/app/node_modules/.bin
node ~/.cache/modules/app/node_modules/.bin/../../../../vstore/app/[email protected]/node_modules/eslint/bin/eslint.js

=> no errors

ps: we have node_modules outside of our build dir for some optimisation

if use virtual-store outside of node_modules and node_modules outside of build dir, bin path can be broke

for example we have this hypothetical  structure
```
~/Projects/app/node_modules -> ~/.cache/modules/app/node_modules

~/.cache/modules/app/node_modules/eslint -> ~/.cache/vstore/app/[email protected]/node_modules/eslint

~/.cache/modules/app/node_modules/.bin/eslint =>
$0 => node_modules/.bin/eslint
basedir => node_modules/.bin
...
node  "node_modules/.bin/../../../../vstore/app/[email protected]/node_modules/eslint/bin/eslint.js"

=> error, module not found
```

module not found, because path is incorrect
`~/Projects/app/node_modules/.bin/../../../../vstore/app/[email protected]/node_modules/eslint/bin/eslint.js`

with realpath it will fixed
```
realpath $0 => ~/.cache/modules/app/node_modules/.bin/eslint
basedir => ~/.cache/modules/app/node_modules/.bin
node ~/.cache/modules/app/node_modules/.bin/../../../../vstore/app/[email protected]/node_modules/eslint/bin/eslint.js

=> no errors
```


ps: we have node_modules outside of our build dir for some optimisation
@baymer baymer changed the title Use realpath for building path of bin-file fix: use realpath for building path of bin-file Sep 30, 2025
src/index.ts Outdated
let sh = `\
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")
basedir=$(dirname "$(realpath "$0" | sed -e 's,\\\\,/,g')")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the realpath command available on all supported systems?

can this be fixed in https://github.com/pnpm/pnpm/tree/main/pkg-manager/link-bins instead?

Copy link
Author

@baymer baymer Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, some system may have no realpath.
May be we can use something like this?

get_path() {
    if command -v realpath >/dev/null 2>&1; then
        realpath "$1"
    elif command -v readlink >/dev/null 2>&1; then
        # some systems has readlink, but doesn't have "-f" flag
        if readlink -f "$1" >/dev/null 2>&1; then
            readlink -f "$1"
        else
             readlink "$1"
        fi
    elif command -v perl >/dev/null 2>&1; then
        perl -e 'use Cwd "abs_path"; print abs_path(shift)' "$1"
    elif [[ $1 = /* ]]; then
        echo "$1"
    else 
        echo "$PWD/${1#./}"
    fi
}

basedir=$(dirname "$(get_path "$0" | sed -e 's,\\\\,/,g')")

or

basedir=$(dirname "$(echo "$0" | sed -e 's,\\\\,/,g')")

case \`uname\` in
    *CYGWIN*|*MINGW*|*MSYS*)
        if command -v cygpath > /dev/null 2>&1; then
            basedir=\`cygpath -w "$basedir"\`
        fi
    ;;
    *)
      if command -v realpath >/dev/null 2>&1; then
          basedir=`realpath "$basedir"`
      elif command -v readlink >/dev/null 2>&1; then
          # some systems has the readlink, but doesn't have "-f" flag
          if readlink -f "$basedir" >/dev/null 2>&1; then
               basedir=`readlink -f "$basedir"`
          else
               basedir=`readlink "$basedir"`
          fi
      elif command -v perl >/dev/null 2>&1; then
          basedir=`perl -e 'use Cwd "abs_path"; print abs_path(shift)' "$basedir"`
      elif [[ $basedir != /* ]]; then
          basedir="$PWD/${basedir#./}"
      fi
    ;;
esac

Copy link
Author

@baymer baymer Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be fixed in https://github.com/pnpm/pnpm/tree/main/pkg-manager/link-bins instead?

I think we can't, because it can broke portable resource (build+node_modules).
So we cannot calculate it in the compile time. We can calculate it only in the runtime.

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was made by jest --updateSnapshot command

@zkochan
Copy link
Member

zkochan commented Oct 9, 2025

You have updated only the sh command shim. What about cmd and powershell? Also, I don't feel I am competent enough in this area, so I'd wait for opinion from other contributors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants