npm install creates incorrect package-lock.json if package-lock.json is present

cli
priority:medium
triaged

(Colin Doig) #1

What I Wanted to Do

“npm-bug-c” should not be added into the dependency tree under “npm-bug-b” the second time I run “npm install”.

What Happened Instead

“npm-bug-c” was added into the dependency tree under “npm-bug-b”

Reproduction Steps

git clone https://github.com/captain-igloo/npm-bug-a
cd npm-bug-a
npm install

At this point the correct package-lock.json has been created. A has two dependencies, B and C.

{
  "name": "npm-bug-a",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "npm-bug-b": {
      "version": "git+https://github.com/captain-igloo/npm-bug-b.git#4f5ae00054fedf960d3d58ca9a681e363eb764e0",
      "from": "git+https://github.com/captain-igloo/npm-bug-b.git",
      "requires": {
        "npm-bug-c": "git+https://github.com/captain-igloo/npm-bug-c.git#7fac39f7c8043a839375066d7efa400b6a20a2e5"
      }
    },
    "npm-bug-c": {
      "version": "git+https://github.com/captain-igloo/npm-bug-c.git#7fac39f7c8043a839375066d7efa400b6a20a2e5",
      "from": "git+https://github.com/captain-igloo/npm-bug-c.git"
    }
  }
}

rm -rf node_modules
npm install

Now package-lock.json is wrong, C has been added as a dependency of B, so it appears twice in the tree (the same version).

{
  "name": "npm-bug-a",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "npm-bug-b": {
      "version": "git+https://github.com/captain-igloo/npm-bug-b.git#4f5ae00054fedf960d3d58ca9a681e363eb764e0",
      "from": "git+https://github.com/captain-igloo/npm-bug-b.git",
      "dependencies": {
        "npm-bug-c": {
          "version": "git+https://github.com/captain-igloo/npm-bug-c.git#7fac39f7c8043a839375066d7efa400b6a20a2e5",
          "from": "git+https://github.com/captain-igloo/npm-bug-c.git#7fac39f7c8043a839375066d7efa400b6a20a2e5"
        }
      }
    },
    "npm-bug-c": {
      "version": "git+https://github.com/captain-igloo/npm-bug-c.git#7fac39f7c8043a839375066d7efa400b6a20a2e5",
      "from": "git+https://github.com/captain-igloo/npm-bug-c.git"
    }
  }
}

Details

Say you have a project A that depends on B and C. B and C are git repositories. Additionally B depends on C. The initial npm install produces the correct package-lock.json; C appears once in the dependency tree at the top level. But if you then remove node_modules and run “npm install” again, the package-lock.json produced is wrong. C now appears twice in the dependency tree, once at the top level and once under B.

Platform Info

$ npm --versions
{ npm: '6.2.0',
  ares: '1.14.0',
  cldr: '33.1',
  http_parser: '2.8.0',
  icu: '62.1',
  modules: '64',
  napi: '3',
  nghttp2: '1.32.0',
  node: '10.8.0',
  openssl: '1.1.0h',
  tz: '2018e',
  unicode: '11.0',
  uv: '1.22.0',
  v8: '6.7.288.49-node.19',
  zlib: '1.2.11' }
$ node -p process.platform
linux

(Sunya Dickman) #3

This seems to be similar, or the same as the behaviour I have observed (using npm 6.4.1). As with your example I had a single sub-dependency to a package that I installed via a git url.

  • On initial npm install I had expected behaviour where the tree is flattened and dependency A is listed alongside the its dependency:
{
  "name": "test-package-lock",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "npmtest-dep": {
      "version": "git+https://github.com/simonneaves/npmtest-dep.git#907bee8c789e831b65a0259deb14b625f789be05",
      "from": "git+https://github.com/simonneaves/npmtest-dep.git",
      "requires": {
        "npmtest-subdep": "github:simonneaves/npmtest-subdep#e2685263cd567007ebb079bd2c72088e8915ad46"
      }
    },
    "npmtest-subdep": {
      "version": "github:simonneaves/npmtest-subdep#e2685263cd567007ebb079bd2c72088e8915ad46",
      "from": "github:simonneaves/npmtest-subdep"
    }
  }
}

I then updated the package of the subdependency a major version.

If I delete package-lock.json and run npm install this is reproduced perfectly. Nevertheless if I delete node_modules (and not package-lock), the first time I run any npm install command, the tree is no flattened, but the correct version of the sub-dependency is correctly installed and listed in package-lock.json:

{
  "name": "test-package-lock",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "npmtest-dep": {
      "version": "git+https://github.com/simonneaves/npmtest-dep.git#907bee8c789e831b65a0259deb14b625f789be05",
      "from": "git+https://github.com/simonneaves/npmtest-dep.git",
      "dependencies": {
        "npmtest-subdep": {
          "version": "github:simonneaves/npmtest-subdep#e2685263cd567007ebb079bd2c72088e8915ad46",
          "from": "github:simonneaves/npmtest-subdep#e2685263cd567007ebb079bd2c72088e8915ad46"
        }
      }
    }
  }
}

However the second time any npm install command is run (i.e installing another package) the tree is flattened and the sub-dependency is updated, ignoring the hash in package-lock.json.

This seems to be 2 bugs, the first install behaves like earlier versions of npm, not flattening the tree (but correctly(?) installing the version in package-lock), while the second install flattens the tree but ignores the version in package-lock