npm - Semver versioning - Updating a package with a caret "^" - npm

I have a npm package in my package.json file
"clean-webpack-plugin": "^0.1.18"
Now when I hover over the package I can see that there is a newer version
"clean-webpack-plugin": "^0.1.19"
Now, as I understood, I could for example do npm update to update all packages obeying the semver rules or just the package npm update clean-webpack-plugin.
So the caret ^ symbol should mean, that you could possibly update the packge to version 0.9.9 if available, right?
npm update has no effect, that's why I ask.

I'm quite certain that npm will have updated the application files for clean-webpack-plugin from version 0.1.18 to version 0.1.19 after you run: npm update clean-webpack-plugin as described in your question.
However, npm will not have updated the entry in your package.json as theoretically it's not actually necessary to do so. Why?.. because version "^0.1.18" is specified in package.json. I.e. The version is specified with the caret ^ symbol.
Let's say your were to publish your project with ^0.1.18 specified in package.json then any subsequent user running npm install will actually get version 0.1.19 anyway (caveat: as the version history for clean-webpack-plugin currently stands in the npm repository at the time of writing this).
So, in short I'm quite sure that version 0.1.19 has been installed on your system, it simply hasn't changed the version specified in package.json. It's not actually necessary to do so and the rules of semver and the use of the caret symbol are still being respected.
So the caret ^ symbol should mean, that you could possibly update the package to version 0.9.9 if available, right?
The caret in "^0.1.18" is saying to npm I WILL accept any updates to the most recent MINOR version but I WILL NOT accept a MAJOR update. I.e. ^0.1.18 means any updates in the range >=0.1.18 <1.0.0 (PATCH updates within that range are allowed too).
Verifying whether it has been updated:
To verify whether version 0.1.19 has actually been installed you can cd to your project directory and run:
npm ls clean-webpack-plugin
You should see the following logged to your console:
...
└── clean-webpack-plugin#0.1.19
But I want package.json to show "^0.1.19" after running npm update:
When you initially run npm update clean-webpack-plugin you could have:
Appended the --save-dev argument (applicable if it was listed in your devDependencies section of package.json).
Or, appended the --save argument (applicable if it was listed in your dependencies section of package.json).
Appending either --save-dev or --save as appropriate to npm update clean-webpack-plugin would have update the entry in package.json. This is further explained in the Recording Updates with --save section of the npm documentation.
By doing this, you can think of it as re-specifying the initial >= part of the range of updates you'll accept.
Note
Running npm update clean-webpack-plugin with the additional --save or --save-dev argument will not have any affect if npm ls clean-webpack-plugin reports:
...
└── clean-webpack-plugin#0.1.19
There would be nothing to update, so I'd just manually specify "^0.1.19" in package.json.

Related

Package.json pasting a package name in bad?

What happens differently when you go into your package.json and paste a package name in and do npm i vs. doing it the real npm i package-name?
package.json:
"dep": 1.0.0
vs
npm i dep --save
We have a build error and learned can bypass it by pasting. I know it isn't kosher but I really want to know why and what consequences that causes?
npm install dep doesn't add the dependency to the package.json file.
You have to add --save or --save-dev to add it to the package.json file.
Besides that, npm install will always serve you the latest build (in most cases the version tagged as latest (see npm docs)), unless you specify a specific version.
If you want your lock file to update, you have to delete the file before running npm install to generate a lock file with the dependency included (for more info check out this GitHub issue)
In conclussion it shouldn't make much of a difference if you manually add the dependency to package.json file and install it with npm install, unless the latest version of your dependency is broken.

How Does npm --save Decide Which Version and SemVer Options?

If I type the following into my computer
$ echo '{}' > package.json
$ npm install pug --save
and then look at my package.json, I'll see that npm added a dependency for me.
#File: package.json
{
"dependencies": {
"pug": "^2.0.0-rc.1"
}
}
Sweet! However -- how does npm decide to grab version 2.0.0-rc.1? And how does npm decide to use the ^ SemVer version modifier?
As a user of npm can I configure or tell it to use a different SemVer modifier and/or download a different version? (both a specific version and/or something like "latest stable")
As an npm package maintainer, can I specify that npm's default behavior should be something other than "grab the latest version and slap a ^ on there"?
npm takes the latest tag publicly available and ^ is the default, you can use save-prefix to change it locally.
To a get specific version use #version after package name i.e. npm install pug#0.1.0.
Something like composer's minimum-stability doesn't exist in npm world.
As a maintainer, you can't do anything, except keeping SemVer and writeing good code :)
But at all package.json is just a JSON, you can simply modify them, without using any CLI commands and define whatever you need.

How do I force npm to reinstall a single package, even if the version number is the same?

In my Node.js project, I have a dependency on another local project. Oftentimes, I need to make a small change to the dependency and see how it affects my main project. In order to do this, I have to reinstall my dependency using npm.
I can use npm update to try to update my dependency, but this seems like it will only work if the version number has changed on the dependency. I don't want to have to change the version number on my dependency every time I change a line of code or two to make an experimental change in development.
I can rm -rf node_modules/; npm install to ensure that I get the latest versions of all of my dependencies. Downloading all of my non-local dependencies takes several minutes, breaking up my train of thought.
Is there a way to force npm to reinstall a single dependency, even if that dependency's version number hasn't changed?
When you run npm install, it will install any missing dependencies, so you can combine it with an uninstall like this:
npm uninstall some_module; npm install
With npm 5, uninstalled modules are removed from the package.json, so you should use:
npm uninstall some_module; npm install some_module
On npm v 6.14:
npm install module_name --force --no-save
You get a message stating:
npm WARN using --force I sure hope you know what you are doing.
And then it proceeds to uninstall and reinstall the package.
Note: if you don't specify the --no-save option, npm updates the package version on package.json to the highest version that is compatible with the existing SemVer rule.
If you do not want npm to update the package's version on package.json, keep the --no-save option.
Not the best answer, but just for information, you can run
npm ci
It is the same as npm install, but it will remove the existing node_modules folder, if any, and do a fresh install for all packages. This is useful if the files in node_modules have been changed for some reason and you want to revert them to their original state.

What do the --save flags do with npm install

I see instructions to install a package with either
npm install <package_name>
or
npm install <package_name> --save
or
npm install <package_name> --save-dev
What is the difference between these options?
Updated, 2019:
Since this question was asked there was a change to npm, such that --save has become the default option, so you do not need to use --save to update the dependencies.
Original Answer:
npm install <package_name> --save installs the package and updates the dependencies in your package.json.
npm install <package_name> --no-save installs the package but does not update the dependencies as listed in your package.json.
npm install <package_name> ---save-dev updates the devDependencies in your package. These are only used for local testing and development.
You can read more at https://docs.npmjs.com/getting-started/using-a-package.json.
npm install takes 3 exclusive, optional flags which save or update the package version in your main package.json:
-S, --save: Package will appear in your dependencies.
-D, --save-dev: Package will appear in your devDependencies.
-O, --save-optional: Package will appear in your optionalDependencies.
When using any of the above options to save dependencies to your package.json, there is an additional, optional flag:
-E, --save-exact: Saved dependencies will be configured with an exact version rather than using npm's default semver range operator.
Further, if you have an npm-shrinkwrap.json then it will be updated as well.
<scope> is optional. The package will be downloaded from the registry associated with the specified scope. If no registry is associated with the given scope the default registry is assumed. See npm-scope.
Note: if you do not include the #-symbol on your scope name, npm will interpret this as a GitHub repository instead, see below. Scopes names must also be followed by a slash.
Examples:
npm install sax --save
npm install githubname/reponame
npm install #myorg/privatepackage
npm install node-tap --save-dev
npm install dtrace-provider --save-optional
npm install readable-stream --save --save-exact
Note: If there is a file or folder named <name> in the current working directory, then it will try to install that, and only try to fetch the package by name if it is not valid.
(from official docs) https://docs.npmjs.com/cli/install
The --save flag no longer serves a purpose.
Previously, as the other answers noted, the --save flag would update the dependencies in the project's package.json file, but npm install now includes this functionality by default.
At this point if you want to prevent npm install from saving dependencies, you have to use the --no-save flag.
Thanks to Coruscate5 for mentioning this in their comment.
More info in the npm-install documentation:
npm install saves any specified packages into dependencies by default. Additionally, you can control where and how they get saved with some additional flags:
-P, --save-prod: Package will appear in your dependencies. This is the default unless -D or -O are present.
-D, --save-dev: Package will appear in your devDependencies.
-O, --save-optional: Package will appear in your optionalDependencies.
--no-save: Prevents saving to dependencies.
When using any of the above options to save dependencies to your package.json, there are two additional, optional flags:
-E, --save-exact: Saved dependencies will be configured with an exact version rather than using npm’s default semver range operator.
-B, --save-bundle: Saved dependencies will also be added to your bundleDependencies list.

Update npm package with fixed dependency from command line

I have an npm package with a fixed version that has an update.
Example package.json extract:
devDependencies: {
"someFixedVersionPackage": "1.0.0", //1.1.0 is latest
"anotherFixedVersionPackage": "2.3.2", //2.3.4 is latest
}
Does an npm command exist which installs the latest version of that package and updates the package.json, preferably all packages at once?
To be clear, I want the package.json snippet above to be updated to this, in addition to the packages themselves being updated:
devDependencies: {
"someFixedVersionPackage": "1.1.0", //latest
"anotherFixedVersionPackage": "2.3.4", //latest
}
Thank you.
Why doesn't npm update work here?
As per the documentation on npm update:
This command will update all the packages listed to the latest version (specified by the tag config), respecting semver.
It will also install missing packages. As with all commands that install packages, the --dev flag will cause devDependencies to be processed as well.
Since your packages are defined with a fixed version, the update sub-command will not update those to respect semantic versioning. Therefore, it will only automatically update your packages if you specify a greater version range for each package. Note that it is actually typical in an npm project to specify a loose range version; one that is meant to avoid breaking changes but still leaves room for improvements and fixes.
Still, why shouldn't I fix dependency versions in my package.json?
But they are fixed because I wanted them so. After testing newer versions, I want to update them via command line as were created.
Having a list of dependencies with a fixed version does not mean that the dependencies installed will always be the same, because the dependencies of your dependencies will most likely also be defined with a version range. In order to keep track of a list of tested version-tagged dependencies, npm provides another mechanism: package locks.
Before version 5 of npm, you can create a "npm-shrinkwrap.json" file with the shrinkwrap command:
npm shrinkwrap
This command locks down the versions of a package's dependencies so that you can control exactly which versions of each dependency will be used when your package is installed.
Since npm 5, a "package-lock.json" is automatically generated when an npm operation modifies the "node_modules" tree or "package.json".
Rather than modifying package.json, either one of these package locks will override the default behaviour of npm install, installing dependencies with the versions specified by the lock, right when they were created or manually updated. With that out of the way, your dependencies can now be expanded without the risk of dependents installing untested package versions.
Shrinkwraps are used for publishing packages. To shrinkwrap a package:
Run npm install in the package root to install the current versions of all dependencies.
Validate that the package works as expected with these versions.
Run npm shrinkwrap, add npm-shrinkwrap.json to git, and publish your package.
At this point, dependency versions can be loosened in your package.json (this will hopefully be done only once every major dependency update), so that later on they can be updated at will with npm update:
"devDependencies": {
"someFixedVersionPackage": "^1.0.0",
"anotherFixedVersionPackage": "^2.3.2",
}
The package-lock.json file can be used instead of a shrinkwrap, and is more suitable for reproducing a development environment. It should also be committed to the repository.
So how do I update my dependencies?
Calling npm update will do what's mentioned above: update dependencies while respecting semantic versioning. To add or upgrade a dependency in a package:
Run npm install in the package root to install the current versions of all dependencies.
Add or update dependencies. npm install --save each new or updated package individually to update the package.json, as well as the existing package locks ("package-lock.json" and "npm-shrinkwrap.json"). Note that they must be explicitly named in order to be installed: running npm install with no arguments will merely reproduce the locked dependencies.
Validate that the package works as expected with the new dependencies.
Commit the new package locks.
Moreover, here are a few tips for a smooth transition from a project with fixed dependencies:
If you haven't done so, expand the version range by adding a tilde (~) before the version specifier, or a caret (^). npm update will then attempt to install all patch revisions and minor revisions, respectively (major version 0 is a corner-case, see the documentation). For instance, "^1.0.0" can now be updated to "^1.1.0", and "~2.3.2" can be updated to "~2.3.4". Adding the --save or --save-dev flags will also update the "package.json" with the installed version (while keeping the previous range specifiers).
Run npm outdated to check which packages are outdated. Entries in red will be updated automatically with npm update. Other entries will require a manual intervention.
For packages with major version bumps, install that package with a version specification (e.g. npm install browserify#11.2.0 --save-dev). Further issues that may arise with the update will have to be handled manually. It usually helps to read the news feed or the release history on that package to further understand what has changed from previous versions.
This is not simple enough, is there another way to do this?
Before continuing, it is always worth mentioning that packages have a SemVer-compliant version definition for a reason. One should avoid blindly installing the latest version of every single package. Although such a full update can be done and tools are available for that, some caution is advised. For instance, you would not want to install React 15 if the remaining React components and libraries are not compatible with react#15.x.x. See also npm's blog post: Why use SemVer?
I'll take my chances. What other tools are there?
To name a few:
npm-check-updates will do what was initially asked in the question: install and update the versions of all dependencies, regardless of the given range constraint. This would be the least recommended tool for the job, however.
updtr will update dependencies one by one and roll back to the previous version if the project's tests fail, which may save time in projects with good test coverage.
npm-check provides an interactive command-line interface, which allows you to easily select which packages to update.
Is this any different with npm 5?
Since major version 5, npm will automatically create a "package-lock.json", which will fill the role of specifying the dependency tree when a shrinkwrap does not exist. A more detailed description can be found in the package-locks documentation. In general, npm-shrinkwrap.json is meant to be used when publishing, whereas package-lock.json is to be used in development. This is why you should also commit "package-lock.json" to the repository.
What about with Yarn?
Yarn, an npm-compatible dependency manager, creates a lock file automatically on use, which behaves similarly to the npm shrinkwrap. Calling yarn upgrade «package» will update one dependency to the version in the latest tag, regardless of the version range recorded in the package.json or the lock file. Using yarn upgrade-interactive also allows you to selectively upgrade packages to the latest version, not unlike npm-check.
$ yarn outdated
yarn outdated v0.16.1
Package Current Wanted Latest
babel-eslint 7.0.0 7.0.0 7.1.0
chai 3.0.0 3.0.0 3.5.0
Done in 0.84s.
$ yarn upgrade babel-eslint chai
yarn upgrade v0.16.1
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 2 new dependencies.
├─ babel-eslint#7.1.0
└─ chai#3.5.0
Running the following command will do what you want:
npm install someFixedVersionPackage#latest anotherFixedVersionPackage#latest --save-dev --save-exact
Breakdown:
npm install someFixedVersionPackage#latest will install the latest version of the package
The --save-dev flag will cause it to update the version in your package.json's devDependencies
The --save-exact flag will cause it to save a fixed version instead of a semver range operator
Link to the npm install docs
I've been looking for an easy way to update npm dependencies for a long time. Then I found this tool: https://github.com/dylang/npm-check
It shows you which dependencies are out of date in a nice ui and allows you to update them. It even tells you which ones are likely to break due to major changes and warns you of unused dependencies.