How to change the installed version of a nested global npm package? - npm

For one of the globally installed npm packages I use, one of the dependencies received a minor version upgrade that unfortunately introduces breaking changes. In the below output, amplify-codegen version 2.28.1 was installed. When executing the command previously, amplify-codegen 2.28.0 would be installed.
npm i -g #aws-amplify/cli#6.4.0
npm list -g amplify-codegen
└─┬ #aws-amplify/cli#6.4.0
├── amplify-codegen#2.28.1
├─┬ amplify-provider-awscloudformation#4.65.0
│ └── amplify-codegen#2.28.1 deduped
Here the problem is that, despite the update from 2.28.0 to 2.28.1 being a minor version update, it introduces changes that break our project. So we would like to revert the update, and ensure that when installing #aws-amplify/cli#6.4.0, the 2.28.0 version of amplify-codegen is installed.
For a locally installed package, this could be easily resolved with a yarn.lock or the "overrides" option in the package.json. However, for globally installed packages, I'm struggling to find a solution, as there's no equivalent of a yarn.lock or package.json for globally installed npm packages.

Related

How to remove optional peer dependency from NPM project?

I am participating in building a webapp that used to use node-sass. We migrated to sass in the meantime but we have still node-sass in our package-lock.json. I want to fix that.
In the beginning, we had something like this
$ npm ls node-sass
cookbook#0.9.13 /home/private/Documents/Projekte/nextcloud-apps/nextcloud-app-dev/volumes/custom_apps/cookbook
├── node-sass#7.0.1
└─┬ sass-loader#13.0.2
└── node-sass#7.0.1 deduped
OK, lets remove the dependency by calling npm uninstall node-sass. The result is
$ npm ls node-sass
cookbook#0.9.13 /home/private/Documents/Projekte/nextcloud-apps/nextcloud-app-dev/volumes/custom_apps/cookbook
└─┬ sass-loader#13.0.2
└── node-sass#7.0.1
I do not get the reason, why sass-loader is still depending on node-sass. OK, let's have a closer look:
$ npm why node-sass
node-sass#7.0.1 optional peer
node_modules/node-sass
peerOptional node-sass#"^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" from sass-loader#13.0.2
node_modules/sass-loader
sass-loader#"^13.0.2" from the root project
peer sass-loader#"^13.0.1" from #nextcloud/webpack-vue-config#5.3.0
node_modules/#nextcloud/webpack-vue-config
dev #nextcloud/webpack-vue-config#"^5.0.0" from the root project
Now I am a bit surprised. The package node-sass is only installed as a peer dependency. So, why is it installed at all? I thought the idea of peer dependencies is to allow for the root project to select the version in use.
Also, it is only optional. So, it should be able to remove it (eventually there might be a warning during removal but nothing serious).
I am not working on the #nextcloud/webpack-vue-config package. It is a mere dev dependency of the webapp. So, NPM should not install the node-sass as a dev dependency on any of my dependencies.
How can I remove the node-sass package from my project's package-lock.json? It is still anchored in the package-lock.json and thus installed on each build.
I could use the --no-optional CLI option of npm to skip over all optional dependencies. I do not want to do that. The "problem" with this is that the GitHub dependency checker will not consider the node-sass module as skipped and continue complaining. Also, other optional dependencies might be skipped as well, although we would like to have them.
I ran into this with node-sass and sass-loader the other day.
Easy solve for me was to remove #nextcloud/webpack-vue-config from my package.json, do an npm install then put it back and rerun npm install
that was enough to get the internals reset to make node-sass go away.

How to exclude a specific version of a package that a project dependency uses and override it with a different one?

I'm running into an issue with my npm mirror.
It appears to be lagging behind. Currently, my Jenkins build fails, because it does not see scheduler#^0.20.2, which was published about 20 hours ago.
Weirdly enough, npm ls scheduler returns empty, so I'm not sure what package is requesting it, but I need to, at least for now, somehow specify scheduler#^0.20.1 to be used in my project.
Is there a way to do this? I want to ensure that whichever package it is that depends on scheduler#^0.20.2 will have only scheduler#^0.20.1 available to it.
I just run
$ npm install scheduler#0.20.1
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN nm#1.0.0 No description
npm WARN nm#1.0.0 No repository field.
+ scheduler#0.20.1
added 4 packages from 3 contributors and audited 4 packages in 2.939s
found 0 vulnerabilities
then check
$ npm ls
nm#1.0.0 /home/daniil/
└─┬ scheduler#0.20.1
├─┬ loose-envify#1.4.0
│ └── js-tokens#4.0.0
└── object-assign#4.1.1
Editing package.json would probably have worked when you need force deep-lying module version:
{
"scripts": {
"preinstall": "npx npm-force-resolutions"
},
"resolutions": {
"scheduler": "^0.20.1"
},
}
I solved this way potential vulnerabilities in my repo

Why doesn't npm upgrade install my 0.0.1 dep with a dependency on '^0.0.0'?

So I've read the doc at npm upgrade#caret dependencies. But npm upgrade does not seem to work for me. It is possible this has something to do with github packages. The package that fails to update is a package in our internal github packages repo.
And here is my package.json
{
<snip>
"devDependencies": {
"#1uphealth/build-lifecycle-scripts": "^0.0.0",
"#types/jest": "^25.2.2",
"jest": "^26.0.1",
},
"dependencies": {}
}
But asking for an upgrade does nothing.
% npm ls --depth=0
#1uphealth/core-example-lib#0.0.0
├── #1uphealth/build-lifecycle-scripts#0.0.0
├── #types/jest#25.2.3
└── jest#26.1.0
% npm upgrade --only=dev
<nothing happens>
% npm upgrade --only=dev #1uphealth/build-lifecycle-scripts
<nothing happens>
But, an explicit install of the 0.0.1 version works fine...
% npm install '#1uphealth/build-lifecycle-scripts#^0.0.1'
+ #1uphealth/build-lifecycle-scripts#0.0.1
updated 1 package and audited 585 packages in 3.514s
<snip>
% npm ls --depth=0
#1uphealth/core-example-lib#0.0.0 /Users/marvin/git/internal/components/0.x/core-example-lib
├── #1uphealth/build-lifecycle-scripts#0.0.1
├── #types/jest#25.2.3
└── jest#26.1.0
Here is my .npmrc
#1uphealth:registry=https://npm.pkg.github.com/1uphealth
So should npm update be updating this install? Does this seem like something broken in github packages repository implementation? Or, am I doing something wrong?
OK. So reading more closely, the documentation at npm-semver for caret ranges explains this. I had read that page but thought that the basic rules about "major", "minor", "patch" were something that I just understood -- major versions are breaking chnages, minor versions are compatible additions to the API, and patch are fixes/changes that don't affect the API. But this sentence
Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple
explains that it is more subtle. The basic result is that for 0 major-versions, the minor version is considered a breaking change. So while ^1.0.0 will allow (be satisfied by) 1.1.0 and ^2.0.0 will allow 2.1.0, ^0.0.0 will actually not allow ANYTHING else, and '^0.1.0' will allow only ^0.1.[0-9]*.
Essentially (mostly) the minor version "becomes" the major version. So the rationale is that for 0 major versions, many releases will be breaking changes and this allows that to be done without forcing a 1.x release (which suggests a certain maturity of the component that may not be warranted.)

How do I find what npm package has a particular dependency?

My webpack project has a new error:
Browserslist: caniuse-lite is outdated. Please run next command npm update caniuse-lite browserslist
Which I haven't solved yet, but the underlying problem is: I don't have caniuse-lite in my package.json - so where is it?
btw: running that command makes no difference.
It's obviously a dependency or a dependency of a dependency, ad infinitum...
npmjs caniuse-lite lists 80 dependent packages.
Is there a way to search the dependency graph of packages to easily find what package in my package.json file is the parent that somewhere along the line depends on caniuse-lite?
You can easily check that by following way.
Checkout more here : https://docs.npmjs.com/cli/ls
npm ls contextify
app-name#0.0.1 /home/zorbash/some-project
└─┬ d3#3.3.6
└─┬ jsdom#0.5.7
└── contextify#0.1.15

npm: using 'npm uninstall' vs. just removing the folder

I wanted to try grunt-babel, so I opened up a terminal in my Home folder and did npm install --save-dev grunt-babel babel-preset-es2015 according to the plugin's instructions.
I was doing this too hastily, and realized I should probably have done this in my new project folder where I am dabbling with ES6 code. I had not even done npm init in that folder nor in the Home folder from where I executed the install command.
When I do npm uninstall grunt-babel, the preset files are removed but 91 folders of different dependencies remain in the node_modules folder.
Can I simply remove the folder instead of running npm uninstall 91 times?
This guy asked a similar question but none of the answers address his subquestion of just removing the folder: how to uninstall npm modules in node js?
npm uninstall <name> removes the module from node_modules, but not package.json.
npm uninstall <name> --save to also delete the dependency from package.json.
npm rm <package_name> removes the packages when uninstall not working
npm prune <name> (see docs) for extraneous packages and packages that are not listed on the parent package's dependencies list.
If you don't want to uninstall one by one run
rm -rf node_modules && npm cache clean && npm install
It's a good way for being sure the packages you uninstall are no more in the packages json.
Now in 2021 npm uninstall <name> will also removed it from package.json
UPDATED answer (2020):
These are all aliases to uninstall:
remove, rm, r, un, unlink
And today there is no need for --save flag since it is the default. The same goes for install BTW.
Use npm list as a tool to understand your changes. I usually use the time to make a capture file like:
npm list >1307
do some change
npm list >1309
so then:
cat 13??
or an editor lets me see what npm thinks it did.
For uninstall, only packages on the root all size of 'whole package' get removed. Other then that, the command is politely ignored...
For example:
├── safe-stable-stringify#1.1.0
├── semver#6.3.0
├─┬ tableify#1.1.0
│ └─┬ optimist#0.6.1
│ ├── minimist#0.0.8 deduped
│ └── wordwrap#0.0.3
safe-stable-stringify is a removal candidate, but wordwrap is not. Think about it, this is entirely reasonable !
npm uninstall pkgtoyank -save
updates packages.json by removing it from there as well.
npm is very well designed to say the least. I usually hugely avoid directly poking under it in ./node_modules I will copy things out from there to look at them, but why yank on a leash of a BIG CAT and get bit. it works; use it as its intended....