Configure npm's package-lock.json to prevent pruning a specific module - npm

So, at the risk of inciting knee jerk responses of "why would you ever want to do that?!?!"... Does anyone know of a config setting one could put into either package.json or the generated package-lock.json such that npm will ignore a given module when updating/pruning?
Basically I'd like to have some code inside the node_modules directory tree which npm ignores. This used to be trivial before auto-pruning. I can, of course, use --no-package-lock to prevent auto-pruning, but what I would actually like to do is allow normal pruning behavior except for specific module(s).

Related

Use different versions of the same package in dev or prod?

(not a native speaker, sorry if things don't seems clear)
We are devs for a clients and we work with others devs from another company. The other devs make us a package that we sometimes change this in it, then submit the changes in a pull request.
So we end up having a local version of the package and the official version. And so we want to use the local version in dev (where we might make little changes in the package to match what the client want), and the official in prod (where our changes and other devs changes are merges).
I will show an example that don't work but that can help understand the idea:
[...]
"dependencies"{
[...]
"package":"prod-package"
},
"devDependencies"{
[...]
"package":"local/version/of/package"
},
and so, we should have this:
npm build # use local/version/of/package
npm build --prod # use prod-package
I'm not really good with npm (in fact, beside npm install and npm remove, I basically know nothing), so I might ask something obvious, but I can't find the answer anywere.
Have you tried using npm-link to link to the local version of the package you are consuming? That way, you could still commit your changes to the package back to the vendor.
https://docs.npmjs.com/cli/v8/commands/npm-link
You would essentially run npm link in the checked-out-from-VCS (git?) package folder, then you switch back to your project where you are consuming that package and run npm link {name-of-npm-package}
This would allow you to develop on that version locally, make your changes (and they will show up on VCS for easy pull request management).

Permanent fix for lockfileVersion of npm-shrinkwrap to lockfileVersion#1, it automatically makes lockfileversion#2?

I am getting this when I am trying to push my code into github actions or building dockerimage.
shell: /usr/bin/bash -e {0}
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion#1, but package-lock.json was generated for lockfileVersion#2. I'll try to do my best with it!
I tried to implement this Link it works but again after some commit I am getting the same error and I have to repeat the same procedure again and again.
Any fix for that?
Look in your .gitignore if you have the lines :
package-lock.json
node_modules/
if not,then add them,
after that look in your Github repository and delete the package-lock.json file and the node_modules directory (if any)
Important Edit :
My bad, Kevin Martin is right the official documentation tell us to add it to the repository for CI/CD.
This file is intended to be committed into source repositories, and
serves various purposes:
Describe a single representation of a dependency tree such that
teammates, deployments, and continuous integration are guaranteed to
install exactly the same dependencies.
Provide a facility for users to "time-travel" to previous states of
node_modules without having to commit the directory itself.
To facilitate greater visibility of tree changes through readable
source control diffs.
And optimize the installation process by allowing npm to skip repeated
metadata resolutions for previously-installed packages.
But for my case (Azure Devops) i had a lot of trouble with it.

NPM lockfiles/shrinkwrap get random "dl" parameter tacked on to the "resolved" URL

Our company uses an Artifactory repository for storing internally-published packages and as a proxy for the NPM registry. Sometimes the resolved field in lockfiles/shrinkwrap files is as expected, containing URLs for our internal repository, but occasionally they show up as something like this (line break added for clarity):
https://our.repository.com/artifactory/api/npm/some-repo/lodash/-/lodash-3.10.1.tgz
?dl=https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz
Then, from pull request to pull requests, these dl parameters constantly oscillate to being present or removed depending on which developer does an npm install, leading to a lot of pull request & commit noise.
I'm guessing it's Artifactory that's adding this dl param, since I fail to see it in a code search in the npm code base.
Why does this happen? Can we disable this behavior? And is it safe to strip this parameter as a postshrinkwrap script workaround?
I think the root of your problem is likely caching.
NPM caches packages that have been downloaded, so they don't have to be downloaded again, and they can even be re-installed offline if necessary. It also caches the resolved value for later use. If a package of the same version has already been resolved and downloaded, it doesn't need to go and fetch it again and get the updated download/resolved URL.
You can manually clear this cache with the following command.
npm cache clean --force
Alternately, it could be that difference in how different versions of NPM calculate the resolved field are to blame (following the Location header or not). However I think caching is more-likely to blame.

When using Webpack to resolve directly to a sibling NPM project, how can I specify a resolve order wrt which node_modules to look at first?

I have two npm projects, project-a and project-b. They both publish and ought to be able to be directly depended upon by any npm project in my company. project-a depends on project-b. They both live as siblings in the same Git repo.
I want to directly import certain components from project-b into project-a. I'm very close -- by specifying a resolve.alias in project-a that looks like project-b: path.resolve(__dirname, '../project-b/entrypoint.js') I can pull in what entrypoint.js offers. However, when Webpack attempts to resolve what entrypoint imports, it looks first in project-b/node_modules. This is a problem for two reasons: we use React, so this pulls in multiple copies of React (project-a/node_modules/react and project-b/node_modules/react), which React users know will break the UI, and similarly it pulls in multiple copies of any shared dependency, of which there are many, leading to a considerable amount of otherwise benign bloat in the Webpack artifact of project-a.
My hunch is there must be a way to tell webpack to, when resolving imports in project-b, first look in project-a and failing that go ahead and look in project-b. This way it'll first look in project-a/node_modules for react whether the import statement is in project-a or project-b, leading to only project-a/node_modules copies of shared dependencies in project-a's artifact, while successfully allowing unique project-b dependencies / components to be resolved. I've played around a bunch with resolve.root, resolve.modulesDirectories, and resolve.fallback, but haven't been able to achieve what I want.
Any ideas?
I ran into a similar issue in my project, also with multiple copies of React being included in the bundle.
The solution is quite simple -- add this to your webpack (version 2) configuration under the resolve key:
modules: [path.resolve(__dirname, "node_modules"), "node_modules"]
This instructs webpack to resolve in node_modules within the build directory before resolving in node_modules in other directories. In your case, this should mean that the module is grabbed from project-a/node_modules instead of project-b/node_modules.
You can find more documentation here.

Why does `npm install` use the shrinkwrap's 'resolved' property

I am considering setting up a local npm mirror such as "npm_lazy" on my computer.
But it seems like npm install and npm shrinkwrap don't work well with local mirrors.
Let me explain. When there is an npm-shrinkwrap.json file, the npm install command always requests packages from the URL specified in the shrinkwrap file's "resolved" property. So, even if I have a local npm mirror running at http://localhost:12345/, and even if I configure npm to use that as its registry, it will not request any package modules from my local mirror (unless a "resolved" property in the shrinkwrap file happens to point to http://localhost:12345/).
Basically, npm install ignores npm's registry configuration and follows the shrinkwrap "resolved" property.
Is there a reason why npm install uses the "resolved" property instead of constructing it dynamically with the dependency package name and version? Why does npm-shrinkwrap.json have this field at all?
So back to my issue. I want to use npm_lazy as a local npm mirror. I could rewrite all the "resolved" URLS in npm-shrinkwrap.json to point to http://localhost:12345/. But then my shrinkwrap file is less portable — my coworkers would not be able to use unless their computers have the same npm_lazy server running.
I have considered redirecting all registry.npmjs.org traffic to localhost in order to create a transparent mirror. But it would be too hard -- it needs to supoprt HTTPS, and also, how would npm_lazy access the true domain? I would have to specify it by its IP address, which may change.
Has anyone else attempted to do the same thing -- to set up a local-computer NPM cache?
But, my main question is, why does npm use the "resolved" property? Thanks.
Shrinkwrap locks down the dependencies, attempting to guarantee the same 'build' (or dependencies) for everyone using that shrinkwrap file. It not only locks down the versions, but also the repository URL, for the same reason: changing any of these potentially changes the content of the package, thus losing any guarantee. Of course, if shrinkwrap were aware of the concept of a repository cache or proxy, it should certainly use yours, but apparently it isn't.
Normally you'd replace the repository URL in package.json (since this is a source file) and run npm shrinkwrap again to re-generate the npm-shrinkwrap.json file (since it is a generated file), and keep that on a local dev branch. But it is a hassle to keep configuration files separated.
So you could enter cache.repository.example.com as the repository hostname, and add a CNAME to DNS pointing to npmregistry. Anyone having npm_lazy installed locally could then safely override this DNS entry in their Hosts file to point to localhost.
However, there is a simpler solution to localize your checkout. Recently I answered a question with this little script to update package.json versions with values from npm-shrinkwrap.json, which can easily be adapted to update all resolved properties in npm-package.json to use your proxy, and which I will leave as an excercise ;-)
I prefer not to save resolved property into npm-package.json.
The utility shonkwrap do the trick. But it impacts everybody in the team: type shonkwrap instead of npm shrinkwrap. Or you can write similar code into your build script (e.g. gulpfile) to delete resolved property from existing npm-package.json.