how can I force npm 3 to install nested dependencies? - module

I just upgraded to npm version 3 and noticed one of the biggest changes it made is that it enforces a flat dependency tree.
Your dependencies will now be installed maximally flat. Insofar as is possible, all of your dependencies, and their dependencies, and THEIR dependencies will be installed in your project's node_modules folder with no nesting. You'll only see modules nested underneath one another when two (or more) modules have conflicting dependencies.
So for example if package A is dependent on package B, when you npm install A you will get this file structure:
--- root/
|--- node_modules/
|--- A/
|--- B/
instead of the old file structure from version 2 or lower:
--- root/
|--- node_modules/
|--- A/
|--- node_modules/
|--- B/
The first (and I’m sure not the last) problem I ran into was this:
Package A isn’t aware of npm v3’s behavior and is dependent on package B. But A assumes the old (v2) file structure because it has node_modules/B in its code, instead of the proper ../node_modules/B. Now the code from A won’t compile because it’s looking for B/ in the wrong directory.
If I don’t feel like nagging the developer to fix the code and waiting for an update of A, I wonder if there’s a way I can set an option that will force npm to install A’s dependencies inside its own node_modules folder, the same way npm v2 would have done it.

Have you tried --legacy-bundling for npm install?
https://docs.npmjs.com/cli/install
The --legacy-bundling argument will cause npm to install the package such that versions of npm prior to 1.4, such as the one included with node 0.8, can install the package. This eliminates all automatic deduping.

This is what happens when I don’t get enough sleep. The obvious solution somehow escaped me.
$ cd node_modules/A/
$ npm install
$ cd ../../

I've just ran into this issue and found an alternative to fix this issue. Since Node.js comes with NPM, the only way that I could think of was to downgrade to Node.js 0.10 version, which comes with an older version on NPM, which will install dependencies in the old fashion way. To downgrade I used NVM and ran nvm use 0.10.0. You can switch back and forth between npm versions by following this trick. Hope it helps!

Related

NPM global install still creating a node_modules directory

In Ubuntu, I have a directory with my code /code which has my packages.json and such. My NPM prefix is /usr via npm prefix -g. I am trying to install packages globally so as to not create a node_modules directory in /code, but really as long as node_modules is not in /code, that will also work.
While in /code, I run npm install -g. I see a .staging directory created under my global prefix (eg, /usr/lib/node_modules/.staging) but then NPM takes another step and begins creating a /code/node_modules directory.
If I instead just run npm install -g <package> it correctly ends up in /usr/lib/node_modules/<package>. But I do not want to have to run npm install -g <package> for every package I need.
Why is NPM doing that and how can I make it stop doing that? At the very least, I would like the node_modules directory to NOT be in my /code directory (this is due to some environment constraints I can't change).
Globally installed packages are (almost always) not going to be used by your code. That's not how node or npm (conventionally) works. There isn't a shared global node_modules that programs all look in. (OK, there kinda is, but you don't want to use it if you can avoid it. Read on.) Having a local node_modules helps you avoid dependency hell. Global modules are for CLI tools that end up in your PATH and things like that.
You don't explain why you don't want a local node_modules for your project, so I will mention that if it is simply because it somehow bothers you, then please please please just get over it. You will be vastly happier. Type npm install and move on.
That said, for legacy reasons, your code in /code will look in /node_modules if there is no /code/node_modules. This is true for CommonJS modules that use require(). If you are using ESM modules via import, you may need to read the docs.
So, if you are using CommonJS/require(), you could have a directory structure like /project-name/code. You could have your index.js or whatever other code in the code subdirectory, while your package.json could be in project-name. Run npm install from /project-name and it will create a node_modules directory there rather than in the code subdirectory, and your Node.js files in code will find those modules.
If you don't like that, then for other options, you can review the relevant docs. At the time of this writing, those options include a NODE_PATH environment variable, $HOME/.node_modules, $HOME/.node_libraries, and $PREFIX/lib/node. However it all comes with this caveat that I implore you to abide by if you can:
It is strongly encouraged to place dependencies in the local node_modules folder. These will be loaded faster, and more reliably.

NPM - How to install transitive dependencies pointing to git URL?

I'm using transitive dependencies that point to git URLs (not on GitHub) and I've found that NPM skips over these dependencies when installing the direct parent dependency.
For example, let's say I have package A, which has a dependency B:
"B": "git+https://username:password#giturl.com/username/B"
Now in a new project, C, I install A.
npm i git+https://username:password#giturl.com/username/A
Now if I look at C's package.json and package-lock.json, I can't find B anywhere! Interestingly enough, if I then install B manually:
npm i git+https://username:password#giturl.com/username/B
then B shows up in C's package.json and package-lock.json, both as a transitive dependency for A and a direct dependency for C.
It's also worth mentioning that this behavior does not occur when using github.com, only when using custom git hosts.
Is there any way around this so I don't have to manually install all my transitive dependencies each time? I'd like NPM to behave like it does for github.com.
I found a workaround, although I'm bewildered as to why NPM decided to skip over these dependencies. I'm assuming it's a bug and have filed a report.
I added the --global-style flag to my npm install command, and NPM will now install my transitive dependencies, except now I don't get the benefits of deduping. --legacy-bundling (disables deduping) also seems to do the trick - which leads me to believe the problem lies in deduping.
The --global-style argument will cause npm to install the package into
your local node_modules folder with the same layout it uses with the
global node_modules folder. Only your direct dependencies will show in
node_modules and everything they depend on will be flattened in their
node_modules folders. This obviously will eliminate some deduping.

Install other package.json dependencies

Simple question : Is it possible, in a package.json, to reference another package.json, and install its dependencies ?
Thank you.
Yes, this is possible, and this is automatically done by npm install.
If you have pkg-a that depends on pkg-b, including pkg-a in your dependencies will install both pkg-a and pkg-b when running npm install. That is because dependencies are actually references to the package.json of other packages. NPM, upon running install, builds a dependency tree of all the packages that are indirectly required by your current project, and installs all of them in the node_modules directory, and keeps track of them all in package-lock.json.
Good question! but this is not possible as you cannot internally reference one json document from another (json is just a document format, it lacks any ability to process logic, import files etc), npm is configured to run using a single package.json file so your best best would be to put all your dependencies in a single package.json file or split your project into two directories with two separate package.json files, two npm installs etc, if for some reason you require your dependencies to be separate. You could then run your two node projects separately and connect via http if you wish.
The only way that you could come close to doing this would be to write an npm start script in the package.json that cds to another directory with a package.json and runs npm install, this would however only install the dependencies in the second directory node-modules/ folder

How to prevent nested node_modules inside node_modules

I've created my own npm package, let's call it XYZ, it has #material-ui dependency in it's package.json file.
When I install it in project A I have nested node_modules inside of XYZ folder(so it's A\node_modules\XYZ\node_modules\#material-ui), but when I install it in project B I don't have nested node_modules folder. Both project A and B has #material-ui in their package.json files with same versions.
How to force my XYZ package to use #material-ui from A\node_modules?
There are upside of having less nested folders and downside having more folders in node_modules folder directly and version control problems.
Use correct npm version
Correct yarn and npm (ie: npm v3) should not have such structure issue. It should always flatten the whole structure where possible and only have nested node_modules if the versions are incompatible with the one at top.
Check versions
So if you have it working properly on one project and not on another, its probably due to version. Check out if the #material-ui is same version on both. Maybe two different packages are conflicting with each other at some point.
Check how you are installing them
From your question, it says it's same version. However, you did not mention how you installed your package on both project. If you install with yarn link or npm link it should install dependencies properly as expected.
Check if you are using different packages
If you check the package, recently material-ui has been deprecated, and the notice says to upgrade to #material-ui/core instead. It might be some packages inside that folder is not same. Either way, it's like this whenever there is some dependency conflict. Check inside the #material-ui folder.
Flatten them manually (dangerous)
There are several packages to forcefully resolve this issue. They will go thru the nested node_modules folders and flatten them into single folder.
flatten-packages
Install with, npm install -g flatten-packages.
Run executable flatten-packages to rearrange all packages in node_modules folder in the project directory.
Flatten will delete older version of a package. You should take care of version breaking changes related errors.
You can use npm dedupe command to accomplish this.
You can put the command in postinstall script in package.json, and every time NPM installs package, the npm dedupe command will flatten all the duplicated packages in same version for you.
For more information, see https://docs.npmjs.com/cli/dedupe
npm postinstall script
I had the same issue in a React Native app with my NPM package.
The problem was that in project A the version of React Native used was (0.59.5) below the version used in my package (0.59.8).
Installing the package in a brand new project (B), of course was using the latest version of React Native in that moment, that was the same of my package (0.59.8).
I have another addition to the accepted answer:
Clear Local node_modules folder Cache
rm -rf node_modules
Handle with care: Sometimes migrating projects to new npm modules can cause weird cache issues inside a node_modules folder, especially those that have been around for a while, or happened to have newer versions of packages installed in sub-dependencies that differed from the installed version in root.
Once you remove direct dependencies via the package.json dependencies, the packages will be removed from the <root>/node_modules. This can cause a bug where the new modules are still nested under your dependency instead of being moved to root as expected.
So by wiping out your local node_modules, you can do a clean reinstall and let the flattening to its work.

How can I determine where an NPM's transitive dependency is coming from?

I'm trying to npm install a package, but it's failing to install due to a missing transitive dependency.
(I don't think the details are important, but we're proxying to an Nexus NPM registry, which didn't support scoped modules at the time. One of our dependency's dependencies is trying to pull down the #bahmutov/parse-github-repo-url module, and we get a 404.)
In my npm-debug.log I see the 404 from our registry:
404 - Path /#bahmutov/parse-github-repo-url not found in group repository</title>
But I can't tell which dependency is trying to pull it down.
Normally I'd run npm ls [package-name] but this doesn't work for a project with an empty node_modules folder, which is what's going on here.
We're using npm3, which has a flat dependency tree, so I can't just open up the partially-hydrated node_modules folder and see where things get laid down.
Is there a way to inspect a package.json file and determine the calculated dependency tree without relying on npm install to succeed?
npm-remote-ls looks like it might give you a reasonable answer!