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

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.

Related

version in package-lock file of a dependency is being ignored

I am importing a dependency in my package.json. That dependency has it's own package-lock.json file in which a the versions of its own dependencies are written. However, when I do my npm install ... --save, the version of the dependency's dependency is not the right one, npm is picking up the latest version. It seems to be ignoring the lock file that belongs to the dependency.
So my dependency contains this in it's package.json file: "ccxt": "^1.52.41". And in it's package-lock.json there is ... "ccxt": { "version": "1.52.41"....
When I add this dependency to my project, the version of ccxt that gets installed (the version in my lock file) is 1.52.94.
What am I doing wrong?
Using npm v6.14.13
Ok, so the package-lock files that belong to your dependencies are ignored by npm. This is by "design" apparently. So at npm install time, you will essentially get a totally random bunch of dependencies installed and added to your package-lock file. From that point on those dependencies are fixed by your lock file until you manually update them using the npm command line.
This means that if you are unlucky and install at a 'bad' time, like I did, then you will pick up some completely untested code that could be broken and/or incompatible with its parent project or your project.

What is the correct use of package.lock.json file, when exactly it works

What is the exact use of package.lock.json file? I have read about it but it's confusing.
Let's say I do npm install so that it will create a package.lock.json file, and the next time when I do npm install, will it retain installation of the same packages as it was mentioned in the package.lock.json file?
Let's say I have a package version defined as "^1.0.0" in my package.json file and a new version becomes available in the npm registry. Will it update the package when I do npm install, or will it keep the same as what was there in the package.json?
Is there any easy way to update the package.json file with the exact no of package version without manually updating it one by one? I want to keep maintain the version of the package the same so that next time anybody does npm install, they should get exactly the same package. It's need for a release branch
Actually I need what was the original definition of package.lock.json file but I found inconsistency in its behavior.
I tried using NPM CI but it fails with error node_gyp needs python https://github.com/nodejs/node-gyp/issues/1977
What is the exact use of package.lock.json file?
Ans: The file is used to describe the exact tree that was generated initially, that is the version of the dependency that was used initially to install (NOTE: It will always be modified if package.json or node_modules are modified by npm)
source: https://docs.npmjs.com/configuring-npm/package-lock-json.html
Now coming to your specific questions :
Let's say I do npm install so that it will create a package.lock.json file, and the next time when I do npm install, will it retain installation of the same packages as it was mentioned in the package.lock.json file?
The simple answer here is: Yes
When you do npm install initially, you specify the package name. npm will create node_modules folder and package-lock.json file and the entry of the package with the version that was used to install will be added. next time when you do npm install, without specifying the package it will not update any of your package even with the caret (^) symbol because this time npm will look at the package-lock.json file (as it is present there) and it will install the same version that is specified in the (package-lock.json) file.
Let's say I have a package version defined as "^1.0.0" in my package.json file and a new version becomes available in the npm registry. Will it update the package when I do npm install, or will it keep the same as what was there in the package.json?
As explained in first question, it will not, if the package-lock.json is present in the directory. Updating of the package will only happen if package-lock.json file and node_modules folder are not present in the directory.
Is there any easy way to update the package.json file with the exact no of package version without manually updating it one by one? I want to keep maintain the version of the package the same so that next time anybody does npm install, they should get exactly the same package. It's need for a release branch
It is a good practice to use npm ci, but you can also use npm update, this will update the dependencies to its latest minor version, and your package.json as well as package-lock.json file will also be updated
For the production, its preferred way to use the same version of dependencies that was used initially. In this case it is better to have package-lock.json file, so in case of dockerizing application when you do npm install it will install the dependencies with versions that are used in package-lock.json

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.

What is the difference between npm-shrinkwrap.json and package-lock.json?

With the release of npm#5, it will now write a package-lock.json unless a npm-shrinkwrap.json already exists.
I installed npm#5 globally via:
npm install npm#5 -g
And now, if a npm-shrinkwrap.json is found during:
npm install
a warning will be printed:
npm WARN read-shrinkwrap This version of npm
is compatible with lockfileVersion#1,
but npm-shrinkwrap.json was generated for lockfileVersion#0.
I'll try to do my best with it!
So my take-away is that I should replace the shrinkwrap with the package-lock.json.
Yet why is there a new format for it? What can the package-lock.json do that the npm-shrinkwrap.json cannot?
The files have exactly the same content, but there are a handful of differences in how npm handles them, most of which are noted on the docs pages for package-lock.json and npm-shrinkwrap.json:
package-lock.json is never published to npm, whereas npm-shrinkwrap is by default
package-lock.json files that are not in the top-level package are ignored, but shrinkwrap files belonging to dependencies are respected
npm-shrinkwrap.json is backwards-compatible with npm versions 2, 3, and 4, whereas package-lock.json is only recognized by npm 5+
You can convert an existing package-lock.json to an npm-shrinkwrap.json by running npm shrinkwrap.
Thus:
If you are not publishing your package to npm, the choice between these two files is of little consequence. You may wish to use package-lock.json because it is the default and its name is clearer to npm beginners; alternatively, you may wish to use npm-shrinkwrap.json for backwards compatibility with npm 2-4 if it is difficult for you to ensure everyone on your development team is on npm 5+. (Note that npm 5 was released on 25th May 2017; backwards compatibility will become less and less important the further we get from that date, as most people will eventually upgrade.)
If you are publishing your package to npm, you have a choice between:
using a package-lock.json to record exactly which versions of dependencies you installed, but allowing people installing your package to use any version of the dependencies that is compatible with the version ranges dictated by your package.json, or
using an npm-shrinkwrap.json to guarantee that everyone who installs your package gets exactly the same version of all dependencies
The official view described in the docs is that option 1 should be used for libraries (presumably in order to reduce the amount of package duplication caused when lots of a package's dependencies all depend on slightly different versions of the same secondary dependency), but that option 2 might be reasonable for executables that are going to be installed globally.
Explanation from NPM Developer:
The idea is definitely for package-lock.json to be the Latest and
Greatest in shrinkwrap technology, and npm-shrinkwrap.json to be
reserved for those precious few folks out there who care very much
about their libraries having an exact node_modules -- and for people
who want CI using npm#>=2 to install a particular tree without having
to bump its npm version.
The new lockfile ("package-lock.json") shares basically all of the
same code, the exact same format as npm-shrinkwrap (you can rename
them between one another!). It's also something the community seems to
understand: "it has a lockfile" seems to click so much faster with
people. Finally, having a new file meant that we could have relatively
low-risk backwards-compat with shrinkwrap without having to do weird
things like allow-publication mentioned in the parent post.
I think the idea was to have --save and shrinkwrap happen by default but avoid any potential issues with a shrinkwrap happening where it wasn't wanted. So, they just gave it a new file name to avoid any conflicts. Someone from npm explained it more thoroughly here:
https://www.reddit.com/r/javascript/comments/6dgnnq/npm_v500_released_save_by_default_lockfile_better/di3mjuk/
The relevant quote:
npm publishes most files in your source directory by default, and
people have been publishing shrinkwraps for years. We didn't want to
break compatibility. With --save and shrinkwrap by default, there was
a great risk of it accidentally making it in and propagating through
the registry, and basically render our ability to update deps and
dedupe... null.
So we chose a new name. And we chose a new name kind of all of a
sudden. The new lockfile shares basically all of the same code, the
exact same format
package-lock.json versions are guaranteed with only npm ci (since npm install overwrites package-lock.json if there is a conflict with package.json).
npm-shrinkwrap.json versions are guaranteed with both npm ci and npm install.