Globally installing Node Modules is an anti-pattern and should not be encouraged. Here’s why, and what to do instead.
grunt
to gulp
, or from gulp
to broccoli
, or from gulp
to browserify
, or from gulp
to webpack
, or from webpack
to parcel
. Technology evolves and tastes change. Don’t make your users globally install every new dependency you want to try out. If you just update your devDependencies, they won’t even notice the changes and will not have to do any extra work to keep your project running locally.It’s actually surprisingly easy to get around this. We’ll be using gulp
in the following example, because it’s pretty popular and the type of thing I see being commonly recommended for global installs. But you can mentally replace it with any other Node Module if it makes you feel better.
devDependencies
add the module manually and the version number you know works for your project, (hopefully the latest version). The easy way to do this is:
npm install --save-dev gulp
package.json
, create an alias for whatever the global command you were going to have people run previously.
scripts: {
"build": "gulp build"
},
gulp
with instructions to just npm install
and then run your new NPM script.
BAD: To build this repo do
npm install -g gulp
and then rungulp build
.
GOOD: To build this repo donpm install
and thennpm run build
.
In npm 5.2.0+ it’s even easier now. We’ll be using gulp
in the following example, because it’s pretty popular and the type of thing I see being commonly recommended for global installs. But you can mentally replace it with any other Node Module if it makes you feel better.
devDependencies
add the module manually and the version number you know works for your project, (hopefully the latest version). The easy way to do this is:
npm install --save-dev gulp
gulp
with instructions to just npm install
and then run your new NPM script.
BAD: To build this repo do
npm install -g gulp
and then rungulp build
.
GOOD: To build this repo donpm install
and thennpx gulp build
.
This requires gulp
to be in the dependencies
or devDependencies
so it will be installed locally in the node_modules
. Then npx
can run the commands without needing to create items in the scripts
section of package.json
.
Note: Depending on your Node Version Manager, if you are on npm 5.2.0+ but don’t have access to npx
, then you will (ironically), need to globally install it, npm install -g npx
. However since this was meant to be globally installed anyway with npm, I think we can make an exception for it.
package.json
and know they can run the following commands and have the project running.
git clone [repo]
npm install
npm start
node_modules
directory.That’s it, here’s some bonus tips for sticking around:
You can see a listing of all of your global installs AND all of their dependencies with:
npm list -g
+-- npm@5.6.0
| +-- abbrev@1.1.1
| +-- ansi-regex@3.0.0
| +-- ansicolors@0.3.2
| +-- ansistyles@0.1.3
| +-- aproba@1.2.0
| +-- archy@1.0.0
| +-- bin-links@1.1.0
| | +-- bluebird@3.5.1 deduped
| | +-- cmd-shim@2.0.2 deduped
| | +-- fs-write-stream-atomic@1.0.10 deduped
| | +-- gentle-fs@2.0.1 deduped
| | +-- graceful-fs@4.1.11 deduped
| | `-- slide@1.1.6 deduped
| +-- bluebird@3.5.1
| +-- cacache@10.0.1
| | +-- bluebird@3.5.1 deduped
| | +-- chownr@1.0.1 deduped
...and so on for thousands of lines
But that is long, messy, and mostly stuff you don’t care about, so instead, you can limit it just to showing your globally installed modules WITHOUT all of their dependencies.
npm list -g --depth=0
+-- npm@5.6.0
+-- npx@10.2.0
`-- vue-cli@2.9.3
That’s a lot better, now you only see the packages you care about, but what if you are not sure what some of them are?
npm la -g --depth=0
+-- npm@5.6.0
| a package manager for JavaScript
| git+https://github.com/npm/npm.git
| https://docs.npmjs.com/
+-- npx@10.2.0
| execute npm package binaries
| git+https://github.com/zkat/npx.git
| https://github.com/zkat/npx#readme
`-- vue-cli@2.9.3
A simple CLI for scaffolding Vue.js projects.
git+https://github.com/vuejs/vue-cli.git
https://github.com/vuejs/vue-cli#readme
Cool, now you’ve got a detailed list of your globally installed packages.
npm uninstall -g name-of-the-package
npm install
So sometimes you can’t just tell a user to npm install
and npm start
. What if, for example, you have additional dependencies that need downloading from another service, like bower
?
bower
as a devDep, don’t globally install it (obviously).postinstall
, and assign it the command you want to run after npm install
finishes. Like so:
"scripts": {
"postinstall": "bower update"
},
(Note: Bower has been deprecated. Move your Bower dependencies over to NPM. If there is a Bower dep that is not on NPM, add an issue on their repo to request they port it over.)
npm install --save-dev pre-commit
package.json
add a section called pre-commit
and feed it an array of strings that match the aliased names of your NPM scripts:
"pre-commit": [ "lint", "sasslint" ]
git commit -m "Commit Title" -m "Commit Body"
or, if you’re lazy, git commit -m "Did stuff"
it will first run each of the NPM scripts in the pre-commit array, and if nothing throws an error, it will then do the commit.Here are the common names I expect for most projects:
npm start
- Starts the project, and auto-launches the app or browsernpm run serve
- Starts the project, but doesn’t auto-launch anythingnpm run dev
- If npm start
is for production use, then this is used for development usenpm run build
- Builds a package ready for deploymentnpm run bump
- Bumps the “patch” part of the version number (0.0.1 -> 0.0.2) in package.json
, the git tag, and pushesnpm run deploy
- Builds the package and then deploys it to a network location/server/hostnpm run test
- Runs some testing suite, typically unit testsnpm run e2e
- Runs some end-to-end testing suitenpm run lint
- Lints all of your JavaScript filesnpm run fix
- Lints your JS files and also attempts to auto fix any errorsnpm run sasslint
- Lints all of your Sass files.npm run sassfix
- Lints all Sass files and attempts to auto fix any errors