Install other package.json dependencies - npm

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

Related

package.json and package-lock.json does not reflect node_module's versions

I updated my Angular project with npm and for some reason package.json and package-lock.json was not updated accordingly. So the question is, do I have to update them manually, or is there a way to update these files according to the actual versions in node_modules?
I tried npm init but that gives me a very big package.json containing every package in node_modules. Therefore I would prefer something that updates each entry in package.json according to what is actually installed.
I had a similar problem, where not all of the needed modules in node_modules were "required" (directly or indirectly) by package.json, so every time I installed something using npm install, it also removed a whole bunch of modules.
My solution wasn't a very satisfactory one, but it did the trick:
Renamed my package-lock.json file and package.json files to keep them safe but out of the way.
Used npm init as you mentioned, to create a version of package.json that contained all of the modules in node_modules.
Moved that out of the way but kept it for reference.
Renamed node_modules to something else to keep it safe but out of the way.
Created a brand new package.json file, again using npm init, but which had no dependencies because there was now no node_modules directory.
Went through my source files finding every dependency require statement, and did an npm --save install package#version on each. I got the package name from the require and then found it in the complete package.json (from steps 2 and 3) and used the version number from that to ensure it matched what was there before. (I've got some legacy code with out-of-date modules, which is why I wanted specific versions.)
Now, my package.json file is minimal, but when I run npm install, everything is up to date.

What is the difference between "npm install" and "npm ci"?

I'm working with continuous integration and discovered the npm ci command.
I can't figure what the advantages are of using this command for my workflow.
Is it faster? Does it make the test harder, okay, and after?
From the official documentation for npm ci:
In short, the main differences between using npm install and npm ci are:
The project must have an existing package-lock.json or npm-shrinkwrap.json.
If dependencies in the package lock do not match those in package.json, npm ci will exit with an error, instead of updating the package lock.
npm ci can only install entire projects at a time: individual dependencies cannot be added with this command.
If a node_modules is already present, it will be automatically removed before npm ci begins its install.
It will never write to package.json or any of the package-locks: installs are essentially frozen.
Essentially,
npm install reads package.json to create a list of dependencies and uses package-lock.json to inform which versions of these dependencies to install. If a dependency is not in package-lock.json it will be added by npm install.
npm ci (also known as Clean Install) is meant to be used in automated environments — such as test platforms, continuous integration, and deployment — or, any situation where you want to make sure you're doing a clean install of your dependencies.
It installs dependencies directly from package-lock.json and uses package.json only to validate that there are no mismatched versions. If any dependencies are missing or have incompatible versions, it will throw an error.
Use npm install to add new dependencies, and to update dependencies on a project. Usually, you would use it during development after pulling changes that update the list of dependencies but it may be a good idea to use npm ci in this case.
Use npm ci if you need a deterministic, repeatable build. For example during continuous integration, automated jobs, etc. and when installing dependencies for the first time, instead of npm install.
npm install
Installs a package and all its dependencies.
Dependencies are driven by npm-shrinkwrap.json and package-lock.json (in that order).
without arguments: installs dependencies of a local module.
Can install global packages.
Will install any missing dependencies in node_modules.
It may write to package.json or package-lock.json.
When used with an argument (npm i packagename) it may write to package.json to add or update the dependency.
when used without arguments, (npm i) it may write to package-lock.json to lock down the version of some dependencies if they are not already in this file.
npm ci
Requires at least npm v5.7.1.
Requires package-lock.json or npm-shrinkwrap.json to be present.
Throws an error if dependencies from these two files don't match package.json.
Removes node_modules and install all dependencies at once.
It never writes to package.json or package-lock.json.
Algorithm
While npm ci generates the entire dependency tree from package-lock.json or npm-shrinkwrap.json, npm install updates the contents of node_modules using the following algorithm (source):
load the existing node_modules tree from disk
clone the tree
fetch the package.json and assorted metadata and add it to the clone
walk the clone and add any missing dependencies
dependencies will be added as close to the top as is possible
without breaking any other modules
compare the original tree with the cloned tree and make a list of
actions to take to convert one to the other
execute all of the actions, deepest first
kinds of actions are install, update, remove and move
npm ci will delete any existing node_modules folder and relies on the package-lock.json file to install the specific version of each package. It is significantly faster than npm install because it skips some features. Its clean state install is great for ci/cd pipelines and docker builds! You also use it to install everything all at once and not specific packages.
While everyone else has answered the technical differences none explain in what situations to use both.
You should use them in different situations.
npm install is great for development and in the CI when you want to cache the node_modules directory.
When to use this? You can do this if you are making a package for other people to use (you do NOT include node_modules in such a release). Regarding the caching, be careful, if you plan to support different versions of Node.js remember that node_modules might have to be reinstalled due to differences between the Node.js runtime requirements. If you wish to stick to one version, stick to the latest LTS.
npm ci should be used when you are to test and release a production application (a final product, not to be used by other packages) since it is important that you have the installation be as deterministic as possible, this install will take longer but will ultimately make your application more reliable (you do include node_modules in such a release). Stick with LTS version of Node.js.
npm i and npm ci both utilize the npm cache if it exists, this cache lives normally at ~/.npm.
Also, npm ci respects the package-lock.json file. Unlike npm install, which rewrites the file and always installs new versions.
Bonus: You could mix them depending on how complex you want to make it. On feature branches in git you could cache the node_modules to increase your teams productivity and on the merge request and master branches rely on npm ci for a deterministic outcome.
The documentation you linked had the summary:
In short, the main differences between using npm install and npm ci are:
The project must have an existing package-lock.json or npm-shrinkwrap.json.
If dependencies in the package lock do not match those in package.json, npm ci will exit with an error, instead of updating the package lock.
npm ci can only install entire projects at a time: individual dependencies cannot be added with this command.
If a node_modules is already present, it will be automatically removed before npm ci begins its install.
It will never write to package.json or any of the package-locks: installs are essentially frozen.
The commands are very similar in functionality however the difference is in the approach taken to install the dependencies specified in your package.json and package-lock.json files.
npm ci performs a clean install of all the dependencies of your app whereas npm install may skip some installations if they already exist on the system. A problem may arise if the version already installed on the system isn't the one your package.json intended to install i.e. the installed version is different from the 'required' version.
Other differences would be that npm ci never touches your package*.json files. It will stop installation and show an error if the dependency versions do not match in the package.json and package-lock.json files.
You can read a much better explanation from the official docs here.
Additionally, you may want to read about package locks here.
It is worth having in mind that light node docker images like alpine do not have Python installed which is a dependency of node-gyp which is used by npm ci.
I think it's a bit opinionated that in order to have npm ci working you need to install Python as dependency in your build.
More info here Docker and npm - gyp ERR! not ok
npm ci - install exactly what is listed in package-lock.json
npm install - without changing any versions in package.json, use package.json to create/update package-lock.json, then install exactly what is listed in package-lock.json
npm update - update package.json packages to latest versions, then use package.json to create/update package-lock.json, then install exactly what is listed in package-lock.json
Or said a different way, npm ci changes 0 package files, npm install changes 1 package file, and npm update changes 2 package files.
It does a clean install, use it in situations where you would delete node_modules and re-run npm i.
I have no idea why some people think it's short for "continuous integration". There is an npm install command that can be run as npm i and an npm clean-install command that can be run as npm ci.
npm install is the command used to install the dependencies listed in a project's package.json file, while npm ci is a command that installs dependencies from a package-lock.json or npm-shrinkwrap.json file. The npm ci command is typically used in continuous integration (CI) environments, where the package-lock.json or npm-shrinkwrap.json file is checked into version control and should not be modified. Because npm ci installs dependencies from a locked file, it is a faster and more reliable way to install dependencies than npm install, which could install different versions of dependencies based on the state of the package.json file.

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.

dependencies and devDependencies when using webpack

Does it make sense to put any modules into package.json dependencies when I use webpack?
When I want to develope a package, I use git clone <url> then npm install, then npm installs all dependencies and devDependencies from package.json file and it makes sense.
When I'm end-user and I just want to install some package into my node_modules to use it in my project, I run npm install package-name, then npm installs package-name with only its dependencies, and it makes sense too.
But does it make sense to put any modules into dependencies when I use webpack? The webpack will bundle all dependencies into eg. bundle.js, so, for me, there is no need to install dependencies then (while they're included into bundle.js file).
Let's assume that I put all neccessary modules into devDependencies (keep the dependencies object empty) for my project: my-project, bundle it with webpack and publish:
the developer-user will use git clone <url to my_project>, then run npm install, then npm will install devDependencies from package.json (and ommit empty dependencies object), then it is ready to develope.
the end-user will use npm install my-project, then npm will install my-project, do not install devDependencies (because this is for production) and do not install dependencies (because dependencies object in package.json remain empty). Putting anything into dependencies would double the dependencies: both the dependencies would be installed, and the same dependencies would be accessible in the bundle.js file.
Am I right?
You are correct that there may be no dependencies once it's been transpiled with webpack. However, some packages are multi-purpose and may be used in multiple ways, so in some circumstances dependencies may still be required.
If you look at the package.json specification, there are two possible entry points, 'main' and 'browser'. There is also the proposed 'module' entry point. It is currently under discussion about how to handle these in webpack and users seem to want webpack to prioritize them as module > browser > main, however browser is currently used by webpack first.
The idea behind prioritizing them in the order module > browser > main is presumably that browsers could use the pre-transpiled stuff directly in "browser", whereas another project calling require() or include() on your package would use non-transpiled code from the "module" entry. The "module" entry code could contain modern JavaScript with new features and the project/package requiring it could then transpile it to their own specifications, using "browserslist" for example.
I found this question because I was wondering the same thing...

How to shrinkwrap npm modules without local dependencies

I tried to maintain package.json with the list of node modules dependencies. when I call npm install it installs the node modules.and generates a folder for it in my app. I call the npm shrinkwrap. But this generates the dependency on the local node module
"dependencies": {
"async": {
"version": "0.2.5",
"from": "async#0.2.5",
"resolved": "https://registry.npmjs.org/async/-/async-0.2.5.tgz"
},
when I upload the app to the appfog server it can install from the npm-shrinkwrap.json. So Ideally I want to remove the node modules folder and just pass the shrinkwrap.json file. But it has this "from". I had in the past generated the shrinkwrap & it didn't have the "from" field in there.
How to generate without "from"/ can I just get a shrinkwrap file from package.json. so my app will be leaner. I can maintain all the node module globally.
Thanks
I'm a bit confused by your question.
Shrinkwrap does not install, package, upload or do anything to your dependencies.
All it does is scan your installed node_modules and record the versions (recursively) into a file. Invoking npm install after that file is defined becomes repeatable, which is a principle of software engineering.
"from" was introduced a few months back. The npm shrinkwrap command seems to set it to the URL from which a module was installed. This is probably for portability. npm install takes a module name, consults a registry (whose URL is configurable as an npm config setting) and installs it. I could take the same package.json and npm-shrinkwrap.json, put them on another machine and theoretically get a different result if that machine's npm config settings point it to a different registry. Therefore, embedding the resolved URL in the shrinkwrap file adds an additional level of repeatability to npm install
See the npm config man page for details of setting the registry parameters.
According to npm issue 3145 on github, the "from" setting is known to cause backwards-compatibility issues with pre-1.2.x npm systems. Upgrading is the only resolution.
https://github.com/isaacs/npm/issues/3145
I think that you are looking for shrinkpack: https://www.npmjs.com/package/shrinkpack
from the doc:
Shrinkpack complements the npm shrinkwrap command by maintaining a node_shrinkwrap directory in your project, containing the exact same tarballs that npm install downloads from https://registry.npmjs.org.
The rest of the npm install process is exactly the same. The only difference is that no network activity is necessary when installing and building your project. The node_shrinkwrap directory can be ignored in your editor (much like is done with the node_modules directory) but is instead checked into source control.