11

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.

SE_net4 the downvoter
  • 21,043
  • 11
  • 69
  • 107
Francisc
  • 66,160
  • 57
  • 172
  • 264
  • According to the specifications, `npm update --save-dev` will indeed update your packages (and write the new versions in package.json). It just won't update certain cases in order to respect [semversioning](https://docs.npmjs.com/misc/semver). – SE_net4 the downvoter Oct 26 '15 at 10:50
  • It won't update anything if versions are fixed. It only does so if you use a semver range. – Francisc Oct 26 '15 at 11:03
  • So I noticed. I'm afraid you are really better off manually modifying the version range, or installing each package with a new version. Those versions ought to be fixed for a reason. I'll see what else can be advised. – SE_net4 the downvoter Oct 26 '15 at 11:06
  • Manually modifying works, but it's stupid to not be able to do it from the command line since that's how they were created. Fixed versions are updated after being tested with new versions. – Francisc Oct 26 '15 at 12:46
  • actually, installing a package with `npm install --save` will do "^«latest»" by default. – SE_net4 the downvoter Oct 26 '15 at 13:00
  • That doesn't update existing packages though. – Francisc Oct 26 '15 at 13:22

3 Answers3

27

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:

  1. Run npm install in the package root to install the current versions of all dependencies.
  2. Validate that the package works as expected with these versions.
  3. 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:

  1. Run npm install in the package root to install the current versions of all dependencies.
  2. 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.
  3. Validate that the package works as expected with the new dependencies.
  4. 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
SE_net4 the downvoter
  • 21,043
  • 11
  • 69
  • 107
  • Fixed versions for dependencies is something else. They are fixed because I wanted them so. After testing newer versions, I want to update them via command line as were created. – Francisc Oct 26 '15 at 12:48
  • 1
    So you wish to keep hold of a tested list of version-tagged dependencies while still allowing npm to update them. I'll update the answer soon enough, but for the moment, see if [shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap) works for you. – SE_net4 the downvoter Oct 26 '15 at 13:20
  • No, I wish to update the fixed version to the latest one, also fixed, via command line. I'll add the expected output in the package.json file to the question so it's completely clear. – Francisc Oct 26 '15 at 13:22
  • @Francisc It was already clear in the first place. Please see my update. – SE_net4 the downvoter Oct 26 '15 at 14:22
  • Unfortunately, locking the project manually allows you to prevent misdesigned packages that do not respect semver to enter your build. This is why we use npm-check-updates to upgrade the dependencies when we are able to test them. – Yennefer Jan 14 '20 at 17:58
  • I agree that exact version matching may be useful in such a case, @Yennefer. On the other hand, we don't need to disregard semver entirely in assisting dependency updates, and package locks serve better for reproducible testing. – SE_net4 the downvoter Jan 14 '20 at 19:36
  • @E_net9 is disappointed I agree with you. Sometimes we take an extreme path simply for the fear of losing control. – Yennefer Jan 14 '20 at 20:06
2

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.

Christophe
  • 958
  • 10
  • 20
1

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

  • 1
    I don't want to save an exact version, I want to save a range just as install would (given save-exact isn't set to true in `.npmrc`). Another problem with this approach would be verbosity, it just takes to long to type every package name. – Francisc Nov 27 '15 at 18:48
  • The example you gave in the question shows an exact version being saved in the package.json. Removing `--save-exact` will save a range. Agreed that specifying all packages is verbose. If all you want is to update everything and set a range the only way I know of to achieve that is with an npm tool such as [npm-check-updates](https://www.npmjs.com/package/npm-check-updates). – Elijah El-Haddad Nov 30 '15 at 19:53
  • They were saved using `--save-exact`. I'm wondering if there's a way via npm to override that in package.json. I'll take a look at the link you posted. – Francisc Dec 02 '15 at 14:50
  • Being able to automatically override a dependency's fixed version simply breaks the purpose of using a fixed version in the first place. – SE_net4 the downvoter Dec 03 '15 at 15:35