How to npm prune and avoid the removal of a file: dependency? - node.js

I have a local npm package (a node.js/electron add-on) that we install via the file.
npm i --save my_package-1.0.0-beta.1.tgz
The package.json file lands up looking like this;
{
...
"dependencies": {
"my_package": "file:my_package-1.0.0-beta.1.tgz",
...
},
}
The module is used in the code, extensively.
When I run npm prune, the package is removed from node_modules. How can I configure or use npm prune to not remove this package?
Some notes from the comments;
Ultimately this is part of a workflow from dev to "test" builds for local device deployments and testing. On the build server, this issue doesn't really pop up since we only install for production and package from there (i.e. with no prune).
This dependency is part of the production dependencies, the solution must maintain that fact.

During a recent update to the environment, this was retested. It was found that npm now (as of npm#4.2.0 installed with node v 7.10.0 and npm#4.6.1, "latest") does seem to preserve the file: dependency. In addition the --production flag works as expected as well.
It is not known exactly when this begin to work or was supported, but it may be circa npm#4.1.0; in particular the rewrite to use the updated prune plumbing.
To update npm to the latest version;
npm install npm#latest -g

Related

Is there any way to fix package-lock.json lockfileVersion so npm uses a specific format?

If two different developers are using different versions of node (12/15) & npm (6/7) in a project that was originally created using a package-lock.json "lockfileVersion": 1, when the developer using npm 7x installs new packages it seems that the package-lock.json is re-created using "lockfileVersion": 2.
This seems to cause issues for the developer using npm v6, as it tries to work with the lockfileVersion 2, but it ends up producing new diffs.
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion#1, but package-lock.json was generated for lockfileVersion#2. I'll try to do my best with it!
Is there any way to specify to newer versions of npm to only use "lockfileVersion": 1? Or do we just have to get all devs on the same version of npm?
Is there any way to specify to newer versions of npm to only use "lockfileVersion": 1? Or do we just have to get all devs on the same version of npm?
I will advise you to pin the Node/NPM version and align it across your environments (development, staging, and production).
you can leverage nvm for managing Node version by adding to your project .nvmrc file (don't forget to store it in your source control).
for instance, .nvmrc will look like:
$ cat .nvmrc
14.15.0
then, you can use nvm install && nvm use to use the pinned version of Node.
NPM also supports engines:
You can specify the version of node that your stuff works on:
{ "engines" : { "node" : ">=0.10.3 <0.12" } }
And, like with dependencies, if you don't specify the version (or if you specify "*" as the version), then any version of Node will do.
If you specify an "engines" field, then npm will require that "node" be somewhere on that list. If "engines" is omitted, then npm will just assume that it works on Node.
You can also use the "engines" field to specify which versions of npm are capable of properly installing your program. For example:
{ "engines" : { "npm" : "~1.0.20" } }
Unless the user has set the engine-strict config flag, this field is advisory only and will only produce warnings when your package is installed as a dependency.
When utilizing the engines field and make npm fail when the version constraints are unmet, set engine-strict=true (since it is false by default) in .npmrc file or as an npm_config_engine_strict=true environment variable
If set to true, then npm will stubbornly refuse to install (or even consider installing) any package that claims to not be compatible with the current Node.js version.
This can be overridden by setting the --force flag.
Another approach is to use a Docker container as a runtime environment for development and execution, which implies that you neither need to install Node, nor NPM. e.g.
$ mkdir my-project
$ cd my-project
$ docker run --rm -it -v $PWD:/app --entrypoint /bin/bash --workdir /app node:14.15.0
root#4da6ee3c2ac0:/app# npm init -y
Wrote to /app/package.json:
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
root#4da6ee3c2ac0:/app# npm install
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN app#1.0.0 No description
npm WARN app#1.0.0 No repository field.
up to date in 1.694s
found 0 vulnerabilities
root#4da6ee3c2ac0:/app# exit
exit
$ ls -x1
package-lock.json
package.json
As you can see, with neither Node, nor NPM:
Created a new directory for a fresh project
Spun up a Node Docker container, which comes with Node and NPM
Created a new project (npm init -y)
Exited the Docker container
Listed the files within the working directory, where the container was spun
Since the docker run command above is long, you might wish to leverage docker-compose for a more streamlined workflow.
npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion#1, but package-lock.json was generated for lockfileVersion#2. I'll try to do my best with it!
to overcome this issue, running the command
npm i -g npm#latest
globally and running the command
npm i npm#latest
in the project file helped me resolve the issue.
As far as I can see the npm docs say that npm v6 will work with version 2 lockfiles in spite of the warning, so you don't need to do any of the things suggested in the accepted answer and can safely ignore the warning message.
In the npm 7 release notes they said:
One change to take note of is the new lockfile format, which is
backwards compatible with npm 6 users. The lockfile v2 unlocks the
ability to do deterministic and reproducible builds to produce a
package tree.
In the npm docs it says (my emphasis):
lockfileVersion
An integer version, starting at 1 with the version number of this
document whose semantics were used when generating this
package-lock.json.
Note that the file format changed significantly in npm v7 to track
information that would have otherwise required looking in node_modules
or the npm registry. Lockfiles generated by npm v7 will contain
lockfileVersion: 2.
No version provided: an "ancient" shrinkwrap file from a version of npm prior to npm v5.
1: The lockfile version used by npm v5 and v6.
2: The lockfile version used by npm v7, which is backwards compatible to v1 lockfiles.
3: The lockfile version used by npm v7, without backwards compatibility affordances. This is used for the hidden lockfile at
node_modules/.package-lock.json, and will likely be used in a future
version of npm, once support for npm v6 is no longer relevant.
This is why they can automatically upgrade lockfiles from v1 to v2, which you mention, without breaking anything.
As of version 8.1.0 there is a flag --lockfile-version in npm with which you can override the default lock file version:
npm i --lockfile-version 3
Here is the link to the original PR.
I encountered the same problem today. I am working on a project with a developer having a different version of npm (>7) and i ran into the same issue. I simply upgraded my npm version to the latest version which was being used by the other developer as mentioned above.
Following are the steps to upgrade your npm (for windows):
First, ensure that you can execute scripts on your system by running the following command from an elevated PowerShell. To run PowerShell as Administrator, click Start, search for PowerShell, right-click PowerShell and select Run as Administrator.
Next execute following commands:
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force
Then, to install and use this upgrader tool, run the following command (also from an elevated PowerShell or cmd.exe). Note: This tool requires at least Node v8
npm install --global --production npm-windows-upgrade
npm-windows-upgrade
Want to just install the latest version? Sure:
npm-windows-upgrade --npm-version latest
Now you can select the version which you want to install from the command line.
https://github.com/felixrieseberg/npm-windows-upgrade
The above link is the tool which I've used. This tool is both for Linux/Windows. I hope it will help.
There is a much more simpler solution than using nvm:
npx npm#6.14.17 i --save
With this you can generate a new lockfile with version 1, use the latest node js version and you don't need to change anything on your machine.
lockfile construction depends on the npm version. v7+ will create lockfile 2, below will create lockfile v1.
Lockfile v2 is backwards compatible so people running npm < v6 will be ok to use it, but i am looking at a circleci build failure on my second screen which suggests some of the npm packages we use are not compatible with lockfile v2... i.e. old npm packages may not be as well maintained and compatible with lockfile v2.
Hence probably the best course of action is to dockerise and isolate your env.
This is why docker was invented! Get your project running in a docker container, then have a makefile command to build your project, maybe something like
.PHONY: up
up:
$(MAKE) down
docker-compose up -d
$(MAKE) logs
With a compose file to setup your project, and then rely on make <insert command> to run / build your project. One command could be make shell to enter a shell environment where all your devs have the same npm / node versions. npm i -g npm#latest is not an answer as that just installs npm on wherever it is run, so new devs will still have to run that command unless its part of the build.
Try to remove package-lock.json and run npm install again.

Update local file dependency with npm

I have a project with a local file dependency in my package.json like this:
"dependencies": {
"dep_1": "file:../../dep_1"
}
}
When I do npm install it is installed into node_modules. But if I make changes to dep_1 how do I update the module version in node_modules?
I tried doing npm update but nothing happens.
If you are using a relatively new version of npm (I used version 2.14.2) you can bump the version number in package.json and npm update dep_1 should work. Otherwise how can npm know that something needs to be updated?
Note: This will only work if the version is higher than what has previously been installed. You will have to clean the cache to reset this behaviour.
However, you can forceably (and lazily) update local modules by simply running npm install again. e.g.
npm install dep_1
It should be fast since its on your local computer and you don't have to play around with version numbers.
For more detail see the discussion about this issue on the official npm repository page: https://github.com/npm/npm/issues/7426

What is the difference between --save and --save-dev?

What is the difference between:
npm install [package_name]
and:
npm install [package_name] --save
and:
npm install [package_name] --save-dev
What does this mean? And what is really the effect of --save and -dev keywords?
The difference between --save and --save-dev may not be immediately noticeable if you have tried them both on your own projects. So here are a few examples...
Let's say you were building an app that used the moment package to parse and display dates. Your app is a scheduler so it really needs this package to run, as in: cannot run without it. In this case you would use
npm install moment --save
This would create a new value in your package.json
"dependencies": {
...
"moment": "^2.17.1"
}
When you are developing, it really helps to use tools such as test suites and may need jasmine-core and karma. In this case you would use
npm install jasmine-core --save-dev
npm install karma --save-dev
This would also create a new value in your package.json
"devDependencies": {
...
"jasmine-core": "^2.5.2",
"karma": "^1.4.1",
}
You do not need the test suite to run the app in its normal state, so it is a --save-dev type dependency, nothing more. You can see how if you do not understand what is really happening, it is a bit hard to imagine.
Taken directly from NPM docs docs#dependencies
Dependencies
Dependencies are specified in a simple object that maps a package name
to a version range. The version range is a string that has one or
more space-separated descriptors. Dependencies can also be identified
with a tarball or git URL.
Please do not put test harnesses or transpilers in your dependencies
object. See devDependencies, below.
Even in the docs, it asks you to use --save-dev for modules such as test harnesses.
--save-dev is used to save the package for development purpose.
Example: unit tests, minification..
--save is used to save the
package required for the application to run.
By default, NPM simply installs a package under node_modules. When you're trying to install dependencies for your app/module, you would need to first install them, and then add them to the dependencies section of your package.json.
--save-dev adds the third-party package to the package's development dependencies. It won't be installed when someone runs npm install directly to install your package. It's typically only installed if someone clones your source repository first and then runs npm install in it.
--save adds the third-party package to the package's dependencies. It will be installed together with the package whenever someone runs npm install package.
Dev dependencies are those dependencies that are only needed for developing the package. That can include test runners, compilers, packagers, etc.
Both types of dependencies are stored in the package's package.json file. --save adds to dependencies, --save-dev adds to devDependencies
npm install documentation can be referred here.
--
Please note that --save is now the default option, since NPM 5. Therefore, it is not explicitly needed anymore. It is possible to run npm install without the --save to achieve the same result.
Let me give you an example,
You are a developer of a very SERIOUS npm library which uses different testing libraries to test the package.
Users download your library and want to use it in their code. Do they need to download your testing libraries as well? Maybe you use jest for testing and they use mocha. Do you want them to install jest as well? Just To run your library?
No. right? That's why they are in devDependencies.
When someone does, npm i yourPackage only the libraries required to RUN your library will be installed. Other libraries you used to bundle your code with or testing and mocking will not be installed because you put them in devDependencies. Pretty neat right?
So, Why do the developers need to expose the devDependancies?
Let's say your package is an open-source package and 100s of people are sending pull requests to your package. Then how they will test the package? They will git clone your repo and when they would do an npm i the dependencies as well as devDependencies.
Because they are not using your package. They are developing the package further, thus, in order to test your package they need to pass the existing test cases as well write new. So, they need to use your devDependencies which contain all the testing/building/mocking libraries that YOU used.
A perfect example of this is:
$ npm install typescript --save-dev
In this case, you'd want to have Typescript (a javascript-parseable coding language) available for development, but once the app is deployed, it is no longer necessary, as all of the code has been transpiled to javascript. As such, it would make no sense to include it in the published app. Indeed, it would only take up space and increase download times.
As suggested by #andreas-hultgren in this answer and according to the npm docs:
If someone is planning on downloading and using your module in their program, then they probably don't want or need to download and build the external test or documentation framework that you use.
However, for webapp development, Yeoman (a scaffolding tool that installs a peer-reviewed, pre-written package.json file amongst other things) places all packages in devDependencies and nothing in dependencies, so it appears that the use of --save-dev is a safe bet in webapp development, at least.
--save-dev saves semver spec into "devDependencies" array in your package descriptor file, --save saves it into "dependencies" instead.
--save-dev is used for modules used in development of the application,not require while running it in production environment
--save is used to add it in package.json and it is required for running of the application.
Example: express,body-parser,lodash,helmet,mysql all these are used while running the application use --save to put in dependencies while mocha,istanbul,chai,sonarqube-scanner all are used during development ,so put those in dev-dependencies .
npm link or npm install will also install the dev-dependency modules along with dependency modules in your project folder
Read Complete And Forget --save-dev Headache
Simplest answer is that --save-dev is useful when you are creating packages for other developers and want to host your package at NPM Registry like lodash, mongoose, express etc. When you are building or writing a Node Server there is no difference between --save and --save-dev because your Node Server implementation is private to you and you will never publish it on NPM.
How NPM Install Works
Whenever we install a new package using npm like npm install express then NPM installs that package to our system and put it into node_modules folder, now NPM will analyze the package.json file of newly installed package i.e express in this case, after analyzing NPM will install all those packages which were mentioned in dependencies section of package.json file of express package. After installing those packages on which express was dependent NPM again analyze the package.json file of all newly installed packages and again install the packages for them, this cycle goes on until all packages are available into node_modules folder to function properly. You can check package dependencies by running npm list in terminal where terminal should point location of your project directory.
How --save-dev Is Related To Above Explained Stuff
Suppose you want to create a new package like express, now while development of this new package you probably want to write some unit testing code and test the package with any other available testing package let's assume mocha in this case. Now you know mocha is only required to test the package not required to use the package. In this case you should install mocha using --save-dev flag, otherwise NPM will install it whenever a developer install your package using NPM. So if we want a dependency not installed when someone install our package from NPM we must install that package using --save-dev in development phase.
Last Thing
Do not mix --save-dev with collaboration development, if someone cloned your package code from a source version control system like github then NPM will surely install all devDependencies i.e package installed using --save-dev also.
Clear answers are already provided. But it's worth mentioning how devDependencies affects installing packages:
By default, npm install will install all modules listed as dependencies in package.json . With the --production flag (or when the NODE_ENV environment variable is set to production ), npm will not install modules listed in devDependencies .
See: https://docs.npmjs.com/cli/install
When you install an npm package using npm install <package-name>, you are installing it as a dependency.
The package is automatically listed in the package.json file, under the dependencies list (as of npm 5: before you had to manually specify --save).
ex. npm install lodash
After pressing enter check your package.json file.
"dependencies": {
"lodash": "4.x",
},
When you add the -D flag, or --save-dev, you are installing it as a development dependency, which adds it to the devDependencies list.
ex. npm install --save-dev lite-server
After pressing enter check your package.json file
"devDependencies": {
"lite-server": "^2.6.1"
},
Development dependencies are intended as development-only packages, that are unneeded in production. For example testing packages, webpack, or Babel.
When you go in production, if you type npm install and the folder contains a package.json file, they are installed, as npm assumes this is a development deploy.
You need to set the --production flag (npm install --production) to avoid installing those development dependencies.
All explanations here are great, but lacking a very important thing: How do you install production dependencies only? (without the development dependencies).
We separate dependencies from devDependencies by using --save or --save-dev.
To install all we use:
npm i
To install only production packages we should use:
npm i --only=production
You generally don't want to bloat production package with things that you only intend to use for Development purposes.
Use --save-dev (or -D) option to separate packages such as Unit Test frameworks (jest, jasmine, mocha, chai, etc.)
Any other packages that your app needs for Production, should be installed using --save (or -S).
npm install --save lodash //prod dependency
npm install -S moment // " "
npm install -S opentracing // " "
npm install -D jest //dev only dependency
npm install --save-dev typescript //dev only dependency
If you open the package.json file then you will see these entries listed under two different sections:
"dependencies": {
"lodash": "4.x",
"moment": "2.x",
"opentracing": "^0.14.1"
},
"devDependencies": {
"jest": "22.x",
"typescript": "^2.8.3"
},
--save-dev (only used in the development, not in production)
--save (production dependencies)
--global or -g (used globally i.e can be used anywhere in our local system)
People use npm on production to do wicked cool stuff, Node.js is an example of this, so you don't want all your dev tools being run.
If you are using gulp (or similar) to create build files to put on your server then it doesn't really matter.
Basically We Write
npm install package_name
But specially for Testing Purpose we don't need to run some package while Application is Running in Normal State so that Node introduce good way to solve this problem. Whenever we write
npm install package_name --save-dev
at that time this package is only installed for development purpose.
I want to add some of my ideas as
I think all differences will appear when someone uses your codes instead of using by yourself
For example, you write an HTTP library called node's request
In your library,
you used lodash to handle string and object, without lodash, your codes cannot run
If someone uses your HTTP library as a part of his code. Your codes will be compiled with his.
your codes need lodash, So you need to put in dependencies to compile
If you write a project like monaco-editor, which is a web editor,
you have bundled all your codes and your product env library using webpack, when build completed, only have a monaco-min.js
So someone doesn't care whether --save or --save-dependencies, only he needs is monaco-min.js
Summary:
If someone wants to compile your codes (use as a library),
put lodash which used by your codes into dependencies
If someone want to add more feature to your codes, he needs unit test and compiler, put these into dev-dependencies
as --save is default option for npm, so I use
npm i package
and for --save-dev, I use
npm i package -D
default option will install package as project dependency where as -D is for development dependencies like testing, lint etc. and install package for development process
you can find all the flags here https://docs.npmjs.com/cli/v8/commands/npm-install

How can I automatically link local npm package?

I'm buidling two private npm packages that depends on each other.
Say that I have :
project
/my-commons
package.json :
{
name : "my-commons",
version : "0.0.1"
...
}
/my-server
package.json :
{
dependencies : {
"my-commons" : "0.0.1"
}
}
I can use 'npm link' to install the 'commons' package. So anyone willing to
start working on server has to do :
checkout project
cd my-server
npm link ../my-commons
npm install
And a symlink to ../my-commons is added in /my-server/node_modules, and everything's fine.
Is there however a way to tell npm that 'my-commons' package will always be in that folder out there, so that you could just do :
checkout project
cd my-server
npm install
Or am I missing something obvious here ?
Thanks
Maybe.
But first: If my-commons is needed by my-server then it is most likely a good idea to keep it in my-server/node_modules even if that is redundant. In most cases it's best keep a module's dependencies isolated from the rest of your application.
In that scenario, npm link can be used during development, when you're working on my-commons and want to use the changes in my-server without having to npm publish my-commons.
In production you will not want to use npm link, because dependent modules will lose control over which version of the linked module they end up with. If my-server depends on my-commons 0.1.0, but you npm linked your 1.0.1-pre-release version of the my-commons module all hell might break loose.
However, since version 1.2.10 (shipping with node 0.8.19) NPM supports peer dependencies.
Peer dependencies allow you to specify that my-server requires that my-commons be installed "besides" my-server. This does not enable you to require("my-commons") inside my-server but could be useful if my-server is a plugin for my-commons.
For more information: http://blog.nodejs.org/2013/02/07/peer-dependencies/
And finally, since you said that you are developing private packages: If installing the packages is what is causing trouble for you, because you can't publish your packages to the public NPM registry, have a look at alternative ways to specify dependencies (git-, http-URLs, TGZ files): https://docs.npmjs.com/files/package.json#dependencies

How do you prevent install of "devDependencies" NPM modules for Node.js (package.json)?

I have this in my package.json file (shortened version):
{
"name": "a-module",
"version": "0.0.1",
"dependencies": {
"coffee-script": ">= 1.1.3"
},
"devDependencies": {
"stylus": ">= 0.17.0"
}
}
I am using NPM version 1.1.1 on Mac 10.6.8.
When I run the following command from the project root, it installs both the dependencies and devDependencies:
npm install
I was under the impression that this command installed the devDependencies:
npm install --dev
How do I make it so npm install only installs dependencies (so production environment only gets those modules), while something like npm install --dev installs both dependencies and devDependencies?
The npm install command will install the devDependencies along other dependencies when run inside a package directory, in a development environment (the default).
In version 8.x and above use --omit=dev flag to install only regular dependencies:
npm install --omit=dev
This will install only dependencies, and not devDependencies, regardless of the value of the NODE_ENV environment variable.
If you use 6.x or an earlier version, you need to use the --only=prod flag instead.
Note:
Before v3.3.0 of npm (2015-08-13), the option was called --production, i.e.
npm install --production
You may also need --no-optional flag.
I run into that problem too! npm install is somewhat confusing and web posts keep bringing in the -d/--dev flags as if there is an explicit 'development' install mode.
npm install will install both "dependencies" and "devDependencies"
npm install --production will only install "dependencies"
npm install --dev will only install "devDependencies"
The new option is:
npm install --only=prod
If you want to install only devDependencies:
npm install --only=dev
If you have already installed all your dependencies, and you want to avoid having to download your production packages from NPM again, you can simply type:
npm prune --production
This will remove your dev dependencies from your node_modules folder, which is helpful if you're trying to automate a two step process like
Webpack my project, using dev dependencies
Build a Docker image using only production modules
Running npm prune in between will save you from having to reinstall everything!
If you read this POST in 2016, please achieve what you want by using
--only={prod[uction]|dev[elopment]}
argument will cause either only devDependencies or only non-devDependencies to be installed regardless of the NODE_ENV.
from: https://docs.npmjs.com/cli/install
When using "npm install" the modules are loaded and available throughout your application regardless of if they are "devDependencies" or "dependencies". Sum of this idea: everything which your package.json defines as a dependency (any type) gets installed to node_modules.
The purpose for the difference between dependencies/devDependencies/optionalDependencies is what consumers of your code can do w/ npm to install these resources.
Per the documentation: https://npmjs.org/doc/json.html...
If someone is planning on downloading and using your module in their
program, then they probably don't want or need to download and build
the external test or documentation framework that you use.
In this case, it's best to list these additional items in a
devDependencies hash.
These things will be installed whenever the --dev configuration flag
is set. This flag is set automatically when doing npm link or when
doing npm install from the root of a package, and can be managed like
any other npm configuration param. See config(1) for more on the
topic.
However, to resolve this question, if you want to ONLY install the "dependencies" using npm, the following command is:
npm install --production
This can be confirmed by looking at the Git commit which added this filter (along with some other filters [listed below] to provide this functionality).
Alternative filters which can be used by npm:
--save => updates dependencies entries in the {{{json}}} file
--force => force fetching remote entries if they exist on disk
--force-latest => force latest version on conflict
--production => do NOT install project devDependencies
--no-color => do not print colors
#dmarr try using npm install --production
npm will install dev dependencies when installing from inside a package (if there is a package.json in the current directory). If it is from another location (npm registry, git repo, different location on the filesystem) it only installs the dependencies.
I suggest to use npm ci. If you want to install only production-needed packages (as you wrote - without devDependencies) then:
npm ci --only=production
or
NODE_ENV=production npm ci
If you prefer oldschool npm install then:
npm install --production
or
NODE_ENV=production npm install
Here is good answer why you should use npm ci.
It's worth mentioning that you can use the NODE_ENV environment variable to achieve the same result. Particularly useful if you're containerizing your Node application (e.g. Docker).
NODE_ENV=production npm install
The above code will install all your dependencies but the dev ones (i.e. devDependencies).
if you need to use environment variables in your Dockerfile more information can be found here.
Environment variables are easy to overwrite whenever needed (e.g. if you want to run your test suite say on Travis CI). If that were the case you could do something like this:
docker run -v $(pwd):/usr/src/app --rm -it -e NODE_ENV=production node:8 npm install
NPM Documentation here
production
Default: false
Type: Boolean
Set to true to run in "production" mode.
devDependencies are not installed at the topmost level when running local npm install without any arguments.
Set the NODE_ENV="production" for lifecycle scripts.
Happy containerization =)
npm install --production --no-optional
It installs only deps from dependencies and will ignore optionalDependencies and devDependencies
Use npm install packageName --save this will add package in dependencies, if you use npm install packageName --save-dev then it devDependencies.
npm install packageName --save-dev should be used for adding packages for development purpose. Like adding TDD packages (Chai, mocha, etc). Which are used in development and not in production.
I have found that, when trying to install dev dependencies for a package that contains a node addon, you cannot avoid building the addon when running npm install --dev even if you just want to install the devDependencies. So, I had to go around npm's back:
node -e 'console.log( Object.keys( require( "./package.json" ).devDependencies ) );' | \
sed -e "s/^[^']*'//" -e "s/'.*$//" | \
xargs npm install
Or, better (and more succinctly) yet,
node -e 'Object.keys( require( "./package.json" ).devDependencies )
.map( function( item ){ console.log( item ) } );' | xargs npm install
I ran into a problem in the docker node:current-slim (running npm 7.0.9) where npm install appeared to ignore --production, --only=prod and --only=production. I found two work-arounds:
use ci instead (RUN npm ci --only=production) which requires an up-to-date package-lock.json
before npm install, brutally edit the package.json with:
RUN node -e 'const fs = require("fs"); const pkg = JSON.parse(fs.readFileSync("./package.json", "utf-8")); delete pkg.devDependencies; fs.writeFileSync("./package.json", JSON.stringify(pkg), "utf-8");'
This won't edit your working package.json, just the one copied to the docker container.
Of course, this shouldn't be necessary, but if it is (as it was for me), there's your hack.
Need to add to chosen answer: As of now, npm install in a package directory (containing package.json) will install devDependencies, whereas npm install -g will not install them.
npm install --production is the right way of installing node modules which are required for production. Check the documentation for more details
Now there is a problem, if you have package-lock.json with npm 5+. You have to remove it before use of npm install --production.

Resources