You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] npx doesn't work when in child workspace #2826
If I run npx <binary> of a binary installed by a child's package.json, it doesn't find the binary as npm v7 now install the binaries under the parent node_modules.
Expected Behavior:
This used to work, as there was no workspaces concept before and therefore all the projects were linking binaries to their node_modules.
Steps To Reproduce:
Should be simple.
Environment:
Suggestion
I think this should not be fixed by npx itself, but instead, npm should create symlinks under the children's node_modules/.bin at least for the packages referenced in the children's package.json.
Make npx look up for node_modules/.bin folder up to the root folder /
Create a symbolic link of the root's bin folder: website/node_modules/.bin -> ../node_modules/.bin
Create a symbolic link of the modules defined in the child workspace: website/node_modules/.bin/docusaurus -> ../node_modules/.bin/docusaurus(seems to be the best approach to me)
Install the bins only to where they belong, instead of installing docusaurus on the node_modules, install to website/node_modules. Seems reasonable, but it would be too bad as I would lose the ability to run npx docusaurus from the root folder
What if there are two child projects which has docusaurus as dependencies? Would be good if npm would be smart enough to download it once (if the version constraints match of course), instead of downloading it twice in each repo.
That's why I think the third option would be better than the fourth.
In a monorepo, I would like to have semantic-release defined in the root project, so it would be available for all the child projects, even the binary because I would need to run npx semantic-release in all the child projects.
The only solution which would match this requirement would be 1 and 2. But now I thought in a new one which builds on 4:
Install the bins only to the project they belong, instead of installing child's binaries on the root's node_modules/.bin, install to child's node_modules/.bin. Exceptionally for the bins defined in the root project, install the bins into root's node_modules/.bin and create symbolic links of all the binaries from the root project to all the child projects (unless they collide, of course).
Now, this is the one which makes more sense to me.
I'm not sure if there was something that was fixed between your original post and now but this is working as intended when I test with npm@7.10.0, I have the following structure (with @ruyadorno/create-index being a dep of my workspace a):
it works as intended when I cd ./a && npm exec @ruyadorno/create-index
This is what both package.json files look like:
diff --git a/a/package.json b/a/package.json
new file mode 100644
index 0000000..c845857
--- a/a/package.json+++ b/a/package.json+{+ "name": "a",+ "version": "1.0.0",+ "dependencies": {+ "@ruyadorno/create-index": "^1.0.0"+ }+}diff --git a/package.json b/package.json
new file mode 100644
index 0000000..23dd3e2
--- a/package.json+++ b/package.json+{+ "name": "test-npx-workspaces",+ "workspaces": [+ "a"+ ]+}
I'll sync up internally with @darcyclarke again to see if he can still reproduce it but would appreciate if you can give it a try again @felipecrs, vlw!
@ruyadorno I'm sorry, but did you note that npx docusaurus in the root workspace works? And it's not only about docusaurus, it also happens with typedoc, which follows the rule you pointed:
> gitpod /workspace/megatar/website $ npx typedoc --versionNeed to install the following packages: typedocOk to proceed? (y)
> gitpod /workspace/megatar/website $ cd ..
> gitpod /workspace/megatar $ npx typedoc --versionInfo: Loaded plugin /workspace/megatar/node_modules/typedoc-plugin-markdownInfo: Loaded plugin /workspace/megatar/node_modules/typedoc-plugin-merge-modulesTypeDoc 0.20.32Using TypeScript 4.2.4 from /workspace/megatar/node_modules/typescript/lib
So, the issue remains valid.
Reacted by Ruy Adorno and Sebastian Fredriksson Bernholtz
@felipecrs you're right! I totally got confused by the name of the packages there, now I realize the actual package that install the docusaurus name you're using is @docusaurus/core that is inside your website workspace 🤦 I'm really sorry for the confusion.
I believe I'm on the right track now and I think this issue should be solved by looking up as you suggested in your #1 option in libnpmexec since that's the behavior of @npmcli/run-script which is used to actually run these (the final solution might differ but I'll open a PR to discuss it with the rest of the team). Thanks again!
@ljharb I'm carefully avoiding that topic here since I believe it's going to be better addressed as part of the upcoming workspaces-revamp RFC we have been alluding to in the last OpenRFC meetings 😉
That said, I'm not excluding the possibility the solution to the problem surfaced by this issue might have to pass through that major overhaul. For now I'm exploring the possibility of fixing this by simply reusing the lookup algo from run-script (which btw might not be so simple) either way I'll keep you posted 😊 Thanks!
@felipecrs I also forgot to mention that alternatively you can also use npm exec workspaces support (I don't remember exactly when we shipped this feature, might have been after you originally opened the issue), from the root level:
$ npm exec -w website -- docusaurus
so you can also use that while you wait for the fix 😊
Activity
ljharb commentedon Mar 4, 2021
I don't think this is something that was ever truly reliable. If you're expecting to run a local binary, it should be a direct dep/devDep.
If anything, it's a bug that bins are created at all for transitive deps.
felipecrs commentedon Mar 5, 2021
This can be replicated:
package.jsonin the root, and another in the website subfolder.docusaurusis set as dependency in the website folder.docusaurusis NOT set as dependency in the root projectnpm installautomatically in the root project, but feel free togit clean -fdxand runnpm installby yourselfcd website; npx docusaurus --versiondocusaurusis not inwebsite/node_modules/.binbut innode_modules/.bin(from the root folder).ljharb commentedon Mar 5, 2021
Ah, in the context of workspaces, i see what you mean. The bins should surely not be hoisted to the parent, even if the module itself is.
darcyclarke commentedon Apr 9, 2021
Can replicate & we're discussing internally how to fix this bug
felipecrs commentedon Apr 9, 2021
I have some ideas:
npxlook up fornode_modules/.binfolder up to the root folder/website/node_modules/.bin -> ../node_modules/.binwebsite/node_modules/.bin/docusaurus -> ../node_modules/.bin/docusaurus(seems to be the best approach to me)binsonly to where they belong, instead of installingdocusauruson thenode_modules, install towebsite/node_modules. Seems reasonable, but it would be too bad as I would lose the ability to runnpx docusaurusfrom the root folderljharb commentedon Apr 9, 2021
The last option makes the most sense to me; if you wanted to run a bin from the root it'd be in the root's package.json.
felipecrs commentedon Apr 9, 2021
What if there are two child projects which has
docusaurusas dependencies? Would be good if npm would be smart enough to download it once (if the version constraints match of course), instead of downloading it twice in each repo.That's why I think the third option would be better than the fourth.
ljharb commentedon Apr 9, 2021
Hoisting the dependency itself would make sense - but not the bin.
felipecrs commentedon Apr 9, 2021
In a monorepo, I would like to have
semantic-releasedefined in the root project, so it would be available for all the child projects, even the binary because I would need to runnpx semantic-releasein all the child projects.The only solution which would match this requirement would be 1 and 2. But now I thought in a new one which builds on 4:
binsonly to the project they belong, instead of installing child's binaries on the root'snode_modules/.bin, install to child'snode_modules/.bin. Exceptionally for thebinsdefined in the root project, install thebinsinto root'snode_modules/.binand create symbolic links of all the binaries from the root project to all the child projects (unless they collide, of course).Now, this is the one which makes more sense to me.
6 remaining items
ruyadorno commentedon Apr 21, 2021
That's the current behavior today: https://github.com/npm/run-script/blob/2a2f1b637ffa2463a82df477e17ea4e146682f5b/lib/set-path.js#L19
I'm not sure if there was something that was fixed between your original post and now but this is working as intended when I test with npm@7.10.0, I have the following structure (with
@ruyadorno/create-indexbeing a dep of my workspacea):it works as intended when I
cd ./a && npm exec @ruyadorno/create-indexThis is what both
package.jsonfiles look like:I'll sync up internally with @darcyclarke again to see if he can still reproduce it but would appreciate if you can give it a try again @felipecrs, vlw!
felipecrs commentedon Apr 22, 2021
The issue can still be replicated with the steps I suggested:
If that would be the case, the example above would have worked. Perhaps such logic only applies to
npm runand notnpx?ruyadorno commentedon Apr 26, 2021
felipecrs commentedon Apr 26, 2021
@ruyadorno I'm sorry, but did you note that
npx docusaurusin the root workspace works? And it's not only aboutdocusaurus, it also happens withtypedoc, which follows the rule you pointed:So, the issue remains valid.
ruyadorno commentedon Apr 27, 2021
@felipecrs you're right! I totally got confused by the name of the packages there, now I realize the actual package that install the
docusaurusname you're using is@docusaurus/corethat is inside yourwebsiteworkspace 🤦 I'm really sorry for the confusion.I believe I'm on the right track now and I think this issue should be solved by looking up as you suggested in your
#1option inlibnpmexecsince that's the behavior of@npmcli/run-scriptwhich is used to actually run these (the final solution might differ but I'll open a PR to discuss it with the rest of the team). Thanks again!ljharb commentedon Apr 27, 2021
@ruyadorno #2826 (comment)
ruyadorno commentedon Apr 27, 2021
@ljharb I'm carefully avoiding that topic here since I believe it's going to be better addressed as part of the upcoming workspaces-revamp RFC we have been alluding to in the last OpenRFC meetings 😉
That said, I'm not excluding the possibility the solution to the problem surfaced by this issue might have to pass through that major overhaul. For now I'm exploring the possibility of fixing this by simply reusing the lookup algo from run-script (which btw might not be so simple) either way I'll keep you posted 😊 Thanks!
ljharb commentedon Apr 27, 2021
Thanks, as long as it's not ignored :-)
feat: add walk up dir lookup to satisfy local bins
ruyadorno commentedon Apr 28, 2021
@felipecrs I also forgot to mention that alternatively you can also use
npm execworkspaces support (I don't remember exactly when we shipped this feature, might have been after you originally opened the issue), from the root level:$ npm exec -w website -- docusaurusso you can also use that while you wait for the fix 😊
felipecrs commentedon Apr 28, 2021
Thank you @ruyadorno. Very nice feature.
feat: add walk up dir lookup to satisfy local bins