29

How I can skip installing optional dependencies from package-lock.json by npm ci?

RobC
  • 22,977
  • 20
  • 73
  • 80
art201214
  • 437
  • 1
  • 4
  • 10
  • 1
    Please solutions that are for `npm ci` and not `npm install` – Joe May 19 '20 at 18:08
  • Hi, sorry for bothering you, but have you finally found any solution? Except these "remove lock file, lol" of course :) – faiwer Mar 17 '21 at 12:55

5 Answers5

14

You can use npm ci --no-optional . If npm still installs the optional package. Then try after removing package.lock.json and run the command again.

Anshu Kumar
  • 807
  • 1
  • 8
  • 27
  • 3
    I need to use `npm ci` instead `npm install`, and shouldn't remove `package-lock.json`. And yes, I know about `npm install --no-optional`, but that's not really my case – art201214 Dec 29 '18 at 12:45
7

There was an error in NPM's implementation of npm ci --no-optional. It has been fixed in versions > 6.13.3 - maybe earlier versions as well, but I can only vouch for 6.13.4 and up.

oligofren
  • 20,744
  • 16
  • 93
  • 180
Maxime Gélinas
  • 2,202
  • 2
  • 18
  • 35
  • 2
    It's never too late <3 Thank you! – Jess Feb 14 '20 at 16:25
  • confirmed. CI was using npm 6.11.3 and --no-optional was not being respected. Upgraded to 6.13.4 and now it is. cheers all – James Render Feb 19 '20 at 11:20
  • Unfortunately it does not work for me. Is there a documentation anywhere that lists this flag for npm ci? On my machine I am having troubles with fsevents being installed on windows with npm ci (which does not work as it is Mac-OS specific) but not with npm i. Thus npm ci is not usable – rominator007 Apr 15 '20 at 08:16
  • @rominator007 Make shure you deleted package-lock.json first. I don't know any docs for that. I assume every `npm install` options work with `npm ci`. – Maxime Gélinas Apr 16 '20 at 17:26
  • 3
    @MaximeGélinas The whole point of using npm ci is to load the packages as of what is written to package-lock.json. At least that is documented https://docs.npmjs.com/cli/ci So sorry that is not a solution – rominator007 May 03 '20 at 03:02
  • @rominator007 Make sure package is marked as optional in package-lock.json. – Petr Peller Oct 08 '20 at 11:39
  • I am on npm 6.14.11, optional deps are marked as `"optional": true` in the package-lock.json but it still install them when running `npm ci --no-optional`. I found a quite recent threads on npm forum so I fear this is yet another bug that will never be closed - https://npm.community/t/workaround-for-npm-ci-no-optional-which-still-installs-optional-dependencies/8154/5 – keul Mar 02 '21 at 11:53
  • Confirm: `npm ci --no-optional` doesn't work. Maxime Gélinas removing `package-json.lock` doesn't make any sense with `npm ci` – faiwer Mar 17 '21 at 12:52
  • 1
    @faiwer Just to be clear, it should work without deleting `package-json.lock`, but if it don't then delete it **only once**, regenerate it and try again. Also, test it in a project with no dependency packages (e.g. `ms`, `uuid`) and you will see it works. Sometimes an optional dependency is a nested dependency of another package. – Maxime Gélinas Mar 17 '21 at 14:40
  • Do you mean regenerate it without optional dependencies? – faiwer Mar 17 '21 at 16:26
  • 1
    @faiwer No, `npm i` should do it. – Maxime Gélinas Mar 17 '21 at 18:07
  • 1
    I checked it out. I removed `package-lock.json`, ran `npm i` (it created a new `package-lock.json` file). Then when I ran `npm ci --no-optional` in the docker with these `package*.json` files my `optionalDependencies` weren't installed. So, you're right. It looks like it's NPM bug and to avoid it we need to make a refresh for `-lock` file sometimes. Thank you – faiwer Mar 19 '21 at 09:42
  • @MaximeGélinas I don't suppose you happen to remember the issue number for this? The last time I looked I could only find closed/wontfix for this problem. Turns out my workaround has been biting us badly. – Jason Jan 10 '22 at 20:14
4

I was facing this issue with CI workflow script and even "--no-optional" was not working

npm ci --no-optional

The above command only worked when I added the optional package as

"optionalDependencies": {
    "fsevents": "^2.3.2"
}

in the package.json file

2

In order to make npm ci --no-optional skip/ignore an optional pacakge, it's important to understand how npm intracts with package.json and pacakge-lock.json.

  1. npm install --no-optional (is only effective if pacakge-lock.json doesn't exists otherwise it would ignore --no-optional)*
  2. npm ci --no-optional is only effective if pakcage-lock.json was already created with npm install --no-optional**.

* This means if you want to make an already installed package an optional, you can would have to

  1. Add it "optionalDependencies": either manulally or through npm install pacakge-name --save-optional
  2. Delete the pacakge-lock.json.
  3. then run rm -rf node_modules/
  4. Lastly run npm install --no-optional
  5. Add this point npm ci --no-optional isn't suppose to install it.

** TIP: you could debug if a certian package is assigned as optional by running npm ls package-name

Note: This one the reason why its recommended to keep trak pacakge-lock.json with git repo of the project.

1

It's not a proper solution, rather an ugly one, but it helped me out. It looks like npm ci --no-optional doesn't work and probably never worked. But at the same time flag --production works. And if we afford mutating package.json (e.g. in a docker container) then...

So I wrote a simple script that:

  • reads package.json content
  • Object.assign(cfg.dependencies, cfg.devDependencies)
  • delete cfg.devDependencies
  • overwrites the initial package.json

So finally we have:

  • dependencies contains both normal & dev dependencies
  • devDependencies section is empty
  • optionalDependencies are intact

And when we run npm ci --production we got what we want - no optional dependencies (in my case cypress). Due to the fact that all these steps are performed inside of a docker container we can mutate package.json.

But I'm not sure that it'll help you too.

faiwer
  • 1,808
  • 1
  • 15
  • 17