7

I have a project that I work on with two different laptops. Sometimes I add extra packages to my project, so I have to use npm install <package-name> (duh). When I do that, I git push up the new package.json and package-lock.json files, and when I switch computers I have to git pull those changes, then run npm install again to get that package onto the other computer.

I recently noticed and started caring that one laptop kept adding carets (^) to the beginning of every package version number. For example:

One computer set package version #s to look like this:

"regexpu-core": {
  "version": "1.0.0",
  "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
  "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
  "requires": {
    "regenerate": "1.4.0",
    "regjsgen": "0.2.0",
    "regjsparser": "0.1.5"
  }
},

The other set package version #s to look like this:

"regexpu-core": {
  "version": "1.0.0",
  "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
  "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
  "requires": {
    "regenerate": "^1.2.1",
    "regjsgen": "^0.2.0",
    "regjsparser": "^0.1.4"
  }
},

I understand that carets (^) mean the version is not 100% precise, but I'm trying to figure out WHY my different laptops create different formats for package versions! I checked this SO question which has some great explanations for the differences between ~ and ^, but I didn't find anything explaining why npm would sometimes add and sometimes remove carets (^) altogether. I also looked at this npm issue on Github which recommended looking at npm config settings, but both of my laptops have the same settings:

  • npm config get save = true (both computers)
  • npm config get save-prefix = ^ (both computers)
  • npm config get save-exact = false (both computers)

One laptop was running npm version 5.6.0, but I just updated it to 6.5.0. The other computer was running version 6.4.1, but I also updated it to 6.5.0. I tried running npm install in my project on both computers, but still I find that one computer always removes ^ and the other always adds ^.

Please let me know if there's something I'm missing. Thanks for any help!

Blundering Philosopher
  • 6,245
  • 2
  • 43
  • 59

1 Answers1

3

Edit: According to the discussion in issue #20434 this occurs by design using npm >=6.0.0.

Why does this happen? @rarkins elaborately explains the reasoning for why this happens (and it’s advantages) in this comment. For convenience his comment is quoted below (verbatim):

Let's say that you use pinned versions of dependencies 'aaa', 'bbb' and 'ccc'. Let's say they each depend on 'zzz' like so:

  • aaa depends on zzz@^1.0.0
  • bbb depends on zzz@^1.1.0
  • ccc depends on zzz@^1.0.1

i.e. all three of them depend on a range of zzz, and not an exact version.

And let's say that the latest version of zzz is 1.5.0.

Both before and after this change, it's pretty obvious that the resolved version of zzz should be 1.5.0, so the only difference is how the package-lock.json is structured and documents this sub-dependency.

Before, the lock file would show that all three of them depend on zzz@1.5.0, and the resolved version of z is 1.5.0.

Now, it documents the actual "original" dependency versions (e.g. ^1.0.0, ^1.1.0, etc) for each dependency, but still shows the resolved version of z as 1.5.0.

Then consider what happens when zzz@1.5.1 is released:

Before, the lock file would need to update from z@1.5.0 to z@1.5.1 in all four places.

Now, the lock file only needs to update the resolved version of z to 1.5.1 while the dependencies can keep the ^1.0.0, ^1.1.0, and ^1.0.1 because they haven't changed.

As I mentioned previously in the thread, you still get the exact same node_modules in both cases. The advantages of the new approach are:

  1. You get to see what the dependencies actually require (e.g. a range, and not an exact version). before, you could not tell if aaa actually required exactly zzz@1.5.0 or that it was instead zzz@^1.0.0.

  2. Instead of four lines changing in the lock file, you get only one. It's less churn, and it's more clear what's happened.

As an aside, yarn uses a similar concept with yarn.lock. e.g. here's an example where @sindresorhus/is is pinned, but it's sub-dependency symbol-observable is not:

"@sindresorhus/is@0.10.0":
 version "0.10.0"
 resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.10.0.tgz#f42dd6a9d12cd79fa6f53b27cf5bea3a30d2cafa"
 dependencies:
   symbol-observable "^1.2.0"

Original Answer:

After you git pull the revised package.json and package-lock.json onto computer two try deleting the node_modules directory before installing the packages again.

For example:

  1. Firstly cd to your project directory on computer 2.

  2. Delete the existing node_modules directory by running: rm -rf node_modules.

  3. Then run: npm install

Or you can chain the two aforementioned commands using the && operator:

rm -rf node_modules && npm install
RobC
  • 22,977
  • 20
  • 73
  • 80
  • 3
    This does not answer the question _why_ npm adds/remove the caret (^) from the versions in the lock file on `npm i` .. Too bad, because I run into the same issue and don't need the workaround, but I want to know _why_ this happens (and how it can be made consistent with/without node_modules dir) – Klaas van der Weij Jan 21 '20 at 12:48
  • 1
    @KlaasvanderWeij - I suggest either; asking a new SO question and provide a reference to this question, or ask npm directly via their Github repo. However, firstly read through the comments for issue [#20434](https://github.com/npm/npm/issues/20434). According to comments; [A](https://github.com/npm/npm/issues/20434#issuecomment-392346742) and [B](https://github.com/npm/npm/issues/20434#issuecomment-392421024), it occurs by design using npm `>=6.0.0`, i.e. it's intentional. Comment [C](https://github.com/npm/npm/issues/20434#issuecomment-402988364) provides further detail on why npm does this. – RobC Jan 22 '20 at 17:29
  • 1
    thanks for pointing out the GitHub issue and indeed comment C explains the _why_ of this elaborately – Klaas van der Weij Jan 24 '20 at 10:05