└── Readme.md /Readme.md: -------------------------------------------------------------------------------- 1 | # NPM Tips and Tricks 2 | This information was generated from the egghead.io 3 | video series [How to Use npm Scripts as Your Build Tool](https://egghead.io/courses/how-to-use-npm-scripts-as-your-build-tool?utm_source=drip&utm_medium=email&utm_campaign=npm-build-tool) 4 | by Elijah Manor. See that for a better description and more information. Thanks go to egghead.io and Elijah since this document 5 | would not exist without their work. 6 | 7 | While the idea of the video series is to use npm for managing your build process, it also contains 8 | a lot of npm tips and tricks that can be useful in general. Which is why I pulled out some of the key concepts here. 9 | 10 | You can click on the section titles to go to the original video lessons for each topic. 11 | 12 | You can also find more information about these npm commands and features in the npm documentation. 13 | + [NPM Documentation](https://docs.npmjs.com/) 14 | + [Using a package.json file](https://docs.npmjs.com/getting-started/using-a-package.json) 15 | + [npm-config](https://docs.npmjs.com/misc/config) 16 | + [npm-scripts](https://docs.npmjs.com/misc/scripts) 17 | 18 | At the bottom of this document is a list of the various npm packages used in the examples. 19 | 20 | ## [Create a basic package.json file](https://egghead.io/lessons/tools-create-a-basic-package-json-file) 21 | * **npm init** (prompts for package info) 22 | * **npm init --force** (no prompts, use default) 23 | * **npm init --yes** (same as --force) 24 | * **npm init -f** (same as --force) 25 | * **npm init -y** (same as --yes) 26 | 27 | MIT license, permissive, few restrictions 28 | 29 | * **npm run** (list all scripts) 30 | * **npm test** (runs the test script) 31 | * **npm t** (runs the test script) 32 | 33 | ## [Run the basic npm scripts](https://egghead.io/lessons/tools-run-the-basic-npm-scripts) 34 | npm knows about the "test" and "start" scripts. To run them: 35 | **npm test** or **npm t** 36 | **npm start** 37 | 38 | typical start script: "node index.js" 39 | 40 | ## [Create a custom npm script](https://egghead.io/lessons/tools-create-a-custom-npm-script) 41 | "eslint" : "eslint --cache --fix ./" 42 | --cache don't relint files that haven't changed 43 | --fix autofix some rules with simple solutions 44 | 45 | **npm run env** -- list NPM provided environment variables 46 | **npm run-script eslint** (to run the eslint script) 47 | **npm run eslint** (same as run-script) 48 | 49 | ## [Run npm scripts in series](https://egghead.io/lessons/tools-run-npm-scripts-in-series) 50 | Use **&&** between commands to run them in series. 51 | 52 | If any command fails, the rest of the line is aborted. 53 | 54 | ```json 55 | scripts: { 56 | "lint" : "npm run eslint && npm run stylelint", 57 | "eslint": "eslint --cache --fix ./", 58 | "stylelint": "stylelint '**/*.scss' --syntax scss" 59 | } 60 | ``` 61 | 62 | ## [Run npm scripts in parallel](https://egghead.io/lessons/tools-run-npm-scripts-in-parallel) 63 | Use **&** between commands to run them in parallel. 64 | Use **wait** to allow a long running process to be terminated with CTRL-C. 65 | 66 | ```json 67 | scripts: { 68 | "lint" : "npm run eslint & npm run stylelint", 69 | "eslint": "eslint --cache --fix ./", 70 | "stylelint": "stylelint '**/*.scss' --syntax scss", 71 | "watch" : "npm run lint & gulp watch & wait" 72 | } 73 | ``` 74 | 75 | ## [Use a shorthand syntax for running multiple npm scripts with npm-run-all](https://egghead.io/lessons/tools-use-a-shorthand-syntax-for-running-multiple-npm-scripts-with-npm-run-all) 76 | npm i npm-run-all -D 77 | By default scripts will run in series, add --parallel switch to run in parallel. 78 | You don't need **wait** when using npm-run-all. 79 | 80 | ```json 81 | scripts: { 82 | "lint" : "npm-run-all --parallel eslint stylelint", 83 | "eslint": "eslint --cache --fix ./", 84 | "stylelint" "stylelint '**/*.scss' --syntax scss" 85 | } 86 | ``` 87 | ## [Run a set of similar npm scripts with a wildcard](https://egghead.io/lessons/tools-run-a-set-of-similar-npm-scripts-with-a-wildcard) 88 | npm supports a wildcard when running scripts. 89 | Name scripts with a common prefix, **"lint:"** in the example below. 90 | Use **"\*"** to match one level, or **"\*\*"** to match multiple levels. 91 | 92 | ```json 93 | scripts: { 94 | "lint" : "npm-run-all lint:**", 95 | "lint:js": "eslint --cache --fix ./", 96 | "lint:css": "stylelint '**/*.scss' --syntax scss", 97 | "lint:css:fix": "stylefmt -R src/" 98 | } 99 | 100 | ``` 101 | ## [Use pre and post npm script lifecycle hooks](https://egghead.io/lessons/tools-use-pre-and-post-npm-script-lifecycle-hooks) 102 | ```json 103 | scripts: { 104 | "pretest": "npm run lint", 105 | "test": "some command to run tests", 106 | "lint" : "npm-run-all lint:**", 107 | "lint:js": "eslint --cache --fix ./", 108 | "lint:css": "stylelint '**/*.scss' --syntax scss", 109 | "lint:css:fix": "stylefmt -R src/" 110 | } 111 | ``` 112 | 113 | In the example below: 114 | The **"cover"** script runs tests under the nyc app to collect test coverage data. 115 | The **"postcover"** script clean up the output generated by nyc. 116 | The **"cover:open"** script opens the coverage report in a browser. 117 | 118 | ```json 119 | scripts: { 120 | "pretest": "npm run lint", 121 | "test": "some command to run tests", 122 | "cover": "nyc npm t", 123 | "postcover": "rm -rf .nyc_output", 124 | "cover:open": "open coverage/index.html", 125 | "lint" : "npm-run-all lint:**", 126 | "lint:js": "eslint --cache --fix ./", 127 | "lint:css": "stylelint '**/*.scss' --syntax scss" , 128 | "lint:css:fix": "stylefmt -R src/" 129 | } 130 | ``` 131 | 132 | 133 | ## [Pass arguments to npm scripts](https://egghead.io/lessons/tools-pass-arguments-to-npm-scripts) 134 | Use **--** to pass additional arguments to an npm script. 135 | 136 | Say you wanted two versions of some task, perhaps you want a lint script that only lints and a second script to lint and fix. 137 | 138 | ```json 139 | scripts: { 140 | "lint:js": "eslint --cache ./", 141 | "lint:js:fix": "eslint --cache --fix ./" 142 | } 143 | ``` 144 | 145 | The issue above that there is now duplicate config for the two commands. 146 | 147 | Instead of doing that, the second script can just call the first, passing in the additional flag. 148 | Note you need the additional **--** to tell npm that what follows is the addional flags to be appended to the command. 149 | 150 | ```json 151 | scripts: { 152 | "lint:js": "eslint --cache ./", 153 | "lint:js:fix": "npm run lint:js -- --fix" 154 | } 155 | ``` 156 | 157 | ## [Pipe data from one npm script to another](https://egghead.io/lessons/tools-pipe-data-from-one-npm-script-to-another) 158 | Use the | character to send the output of one program as the input to another program. 159 | Use the > character to redirect console output to some file. 160 | 161 | ```json 162 | scripts: { 163 | "prebuild": "rm -rf public/", 164 | "build": "npm-run-all build:*", 165 | "build:html": "pug --obj data.json src/index.pug --out public/", 166 | "build:css": "node-sass src/index.scss | postcss -c .postcssrc.json | cssmin > public/index.min.css", 167 | "build:js": "mustache data.json src/index.mustache.js | uglifyjs > public/index.min.js", 168 | } 169 | ``` 170 | ## [Run npm scripts when files change with onchange](https://egghead.io/lessons/tools-run-npm-scripts-when-files-change-with-onchange) 171 | Some applications support a --watch flag to look for file changes, but what about those applciations that don't have watch support built in? 172 | 173 | Use onchange. 174 | 175 | ```json 176 | scripts: { 177 | "test": "script to run tests", 178 | "watch": "npm-run-all --parallel watch:*", 179 | "watch:test": "npm t -- -watch", 180 | "watch:lint": "onchange '**/*.js' '**/*.sass -- npm run lint", 181 | "lint" : "npm-run-all lint:**", 182 | "lint:js": "eslint --cache --fix ./", 183 | "lint:css": "stylelint '**/*.scss' --syntax scss" , 184 | "lint:css:fix": "stylefmt -R src/" 185 | } 186 | ``` 187 | 188 | ## [Use package variables in npm scripts](https://egghead.io/lessons/tools-use-package-json-variables-in-npm-scripts) 189 | npm exposes the properties defined in the package.json file as enviornment variables you can use in npm scripts. Things like "name", "version". 190 | 191 | **npm run env** -- list all the npm environment variables. package properties begin with **"npm_package_"** 192 | 193 | The example below uses the "version" in the package.json file to put the output to a version specific folder in public. 194 | Note: These examples use Linux format for using env variables. 195 | 196 | ```json 197 | scripts: { 198 | "prebuild": "rm -rf public/$npm_package_version/", 199 | "build": "npm-run-all build:*", 200 | "build:html": "pug --obj data.json src/index.pug --out public/$npm_package_version/", 201 | "build:css": "node-sass src/index.scss | postcss -c .postcssrc.json | cssmin > public/index.min.css", 202 | "build:js": "mustache data.json src/index.mustache.js | uglifyjs > public/$npm_package_version/index.min.js", 203 | } 204 | ``` 205 | 206 | ## [Use custom config settings in npm scripts](https://egghead.io/lessons/tools-use-custom-config-settings-in-your-npm-scripts) 207 | 208 | package.json can have a "config" section. You can use these config settings in your npm scripts. 209 | Config settings are exposed as enviornment variables with an "npm_package_config_" prefix. 210 | 211 | npm run env 212 | 213 | ```json 214 | config: { 215 | "port": 1337 216 | }, 217 | scripts: { 218 | "poststart" : "npm-run-all buld server", 219 | "build" : "command to do the build, see examples above", 220 | "server" : "npm-run-all server:*", 221 | "server:start": "http-server public/$npm_package_version -p $npm_package_config_port", 222 | "server:launch": "open http://localhost:$npm_package_config_port/index.html", 223 | } 224 | ``` 225 | 226 | You can also override the default config values in the package.json file from the command line. 227 | 228 | **npm config set key value** -- override default config setting in package.json. 229 | **npm config list** -- list current config settings 230 | **npm config delete key** -- remove override and go back to default config setting. 231 | 232 | See [npm-config](https://docs.npmjs.com/cli/config) for more npm config commands for getting and setting config properties. 233 | 234 | ## [Run npm scripts with git hooks](https://egghead.io/lessons/tools-run-npm-scripts-with-git-hooks) 235 | The npm husky package allows you to create npm scripts that are run before git commands. 236 | 237 | **npm install husky -D** 238 | 239 | ```json 240 | scripts: { 241 | "precommit" : "npm run test", 242 | "prepush": "npm run test" 243 | } 244 | ``` 245 | 246 | Now, when you run your git commit command: 247 | 248 | git commit -am "commit message" 249 | 250 | husksy will run your tests first and only allow the commit to go through if the tests pass. You can add a --no-verify flag to the commit command to bypass the tests during the commit. 251 | 252 | If you don't want to run the tests before every local commit, use the prepush script instead. That runs the tests prior to the push to the remote. 253 | 254 | ## [Change the level of console output when running npm scripts](https://egghead.io/lessons/tools-change-the-level-of-console-output-when-running-npm-scripts) 255 | Ref: [npm-config](https://docs.npmjs.com/misc/config) 256 | 257 | When running npm scripts you can pass in additional command line arguments to control the level of output. 258 | 259 | npm start --loglevel silent 260 | npm start -silent 261 | npm start -s 262 | 263 | Log Levels are: 264 | + --loglevel silent, -silent, -s 265 | + --loglevel warn, -quiet, -q 266 | + --loglevel info, -d 267 | + --loglevel verbose, -verbose, -dd 268 | + --loglevel silly, -ddd (can be useful for debugging npm scripts) 269 | 270 | ## [Make npm scripts cross-environment friendly](https://egghead.io/lessons/tools-make-npm-scripts-cross-environment-friendly) 271 | Need to run your npm scripts in different environment? 272 | 273 | ### Set an enviornment variable 274 | If you need to set an environment variable in your npm script, the following 275 | only works on Mac and Linux... 276 | 277 | ```json 278 | scripts: { 279 | "test" : "BABEL_ENV=test mocha spec/ --require babel-register", 280 | } 281 | ``` 282 | and this only works on windows... 283 | 284 | ```json 285 | scripts: { 286 | "test" : "set BABEL_ENV=test && mocha spec/ --require babel-register", 287 | } 288 | ``` 289 | 290 | Use **cross-env** to set environment variables in a platform independent manor. 291 | npm install cross-env -d 292 | 293 | This now works on Mac, Linux and Windows... 294 | ```json 295 | scripts: { 296 | "test" : "cross-env BABEL_ENV=test mocha spec/ --require babel-register", 297 | } 298 | ``` 299 | 300 | ### Delete Files 301 | If you need to delete files in your npm script, the following 302 | only works on Mac and Linux... 303 | 304 | ```json 305 | scripts: { 306 | "postcover" : "rm -rf .nyc_output", 307 | } 308 | ``` 309 | Use **rimraf** to delete files in a platform independent manor. 310 | npm install rimraf -d 311 | 312 | This now works on Mac, Linux and Windows... 313 | ```json 314 | scripts: { 315 | "postcover" : "rimraf .nyc_output", 316 | } 317 | ``` 318 | 319 | ### Open Files 320 | If you need to open files, like an index.html file, in your npm script, the following 321 | only works on Mac and Linux... 322 | 323 | ```json 324 | scripts: { 325 | "cover:open" : "open coverage/index.html", 326 | } 327 | ``` 328 | Use **opn-cli** to open files in a platform independent manor. 329 | npm install opn-cli -d 330 | 331 | This now works on Mac, Linux and Windows... 332 | ```json 333 | scripts: { 334 | "cover:open" : "opn coverage/index.html", 335 | } 336 | ``` 337 | 338 | ### Include quotes in script commands 339 | If you need to include quotes in a script command,open files, Linux and Mac will 340 | accept single quotes... 341 | 342 | ```json 343 | scripts: { 344 | "lint:css": "stylelint '**/*.scss' --syntax scss" , 345 | } 346 | ``` 347 | 348 | But on Windows you need to use double quotes and since we are 349 | already in a string, we need to escape them. This will 350 | also work on Linux and Mac. 351 | 352 | ```json 353 | scripts: { 354 | "lint:css": "stylelint \"**/*.scss\" --syntax scss" , 355 | } 356 | ``` 357 | 358 | ### Reference an environment variable 359 | If you need to reference an environment variable in an npm script... 360 | 361 | On Mac/Linux, use $ to reference an environment variable. 362 | ```json 363 | scripts: { 364 | "prebuild": "rimraf public/$npm_package_version/", 365 | } 366 | ``` 367 | 368 | On Windows, use % (before and after) to reference an environment variable. 369 | ```json 370 | scripts: { 371 | "prebuild": "rimraf public/%npm_package_version%/", 372 | } 373 | ``` 374 | 375 | Use **cross-var** to reference an environment variable in a platform independent manor. 376 | npm install cross-var -d 377 | 378 | ```json 379 | scripts: { 380 | "prebuild": "cross-var public/$npm_package_version/", 381 | } 382 | ``` 383 | 384 | Note: cross-var doesn't work across pipes or output redirects. 385 | In that case you need to pass cross-var one big string. 386 | 387 | ```json 388 | scripts: { 389 | "build:css": "cross-var \"node-sass src/index.scss | postcss -c .postcssrc.json | cssmin > public/$npm_package_version/index.min.css\"", 390 | } 391 | ``` 392 | 393 | ## [List available npm scripts and support tab completion](https://egghead.io/lessons/tools-list-available-npm-scripts-and-support-tab-completion) 394 | npm run -- list available scripts 395 | 396 | [npm completion](https://docs.npmjs.com/cli/completion) can enable tab completion. See link for Windows. 397 | 398 | Another option is to install the **ntl** (node task list) command... 399 | npm install ntl -g 400 | 401 | ## [Add comments to your npm scripts](https://egghead.io/lessons/tools-add-comments-to-your-npm-scripts) 402 | 403 | Use script name of "//", npm will ignore this script. You can have 404 | more than one of these. However, "npm run" will only list the last comment. 405 | 406 | ```json 407 | scripts: { 408 | "//": "Helpful comment here!!", 409 | "start": "node index.js", 410 | "//": "Another helpful comment here!!", 411 | } 412 | ``` 413 | See the [video](https://egghead.io/lessons/tools-add-comments-to-your-npm-scripts) for more options. (None looked particularly appealing to me.) 414 | 415 | ## [Pull out npm scripts to another file with p-s](https://egghead.io/lessons/tools-pull-out-npm-scripts-into-another-file-with-p-s) 416 | See video link. 417 | 418 | ## [Create a bash script to replace a complex npm script](https://egghead.io/lessons/tools-create-a-bash-script-to-replace-a-complex-npm-script) 419 | See video link. 420 | 421 | ## [Create a node script to replace a complex npm script](https://egghead.io/lessons/tools-create-a-node-script-to-replace-a-complex-npm-script) 422 | See video link. 423 | 424 | ## npm modules: 425 | These are the npm modules referenced in the lessons. 426 | **npm install {moduleName} -D** 427 | > -D add to devDependencies 428 | 429 | 430 | + **[eslint](https://www.npmjs.com/package/eslint)** - lint js file, similar to jslint, jshint 431 | + **[stylelint](https://www.npmjs.com/package/stylelint)** - CSS style linter 432 | + **[npm-run-all](https://www.npmjs.com/package/npm-run-all)** - Runs multiple npm scripts in series or parallel 433 | + **[stylefmt](https://github.com/morishitter/stylefmt)** - Automatically formats CSS files 434 | + **[nyc](https://www.npmjs.com/package/nyc)** - Generate test coverage reports (Babel, Istanbul ???) 435 | + **[pug-cli](https://www.npmjs.com/package/pug-cli)** - Command line interface for Pug, a clean, whitespace-sensitive template language for writing HTML 436 | + **[node-sass](https://www.npmjs.com/package/node-sass)** - SASS to CSS compiler 437 | + **[postcss-cli](https://www.npmjs.com/package/postcss-cli)** - Command line interface for postcss 438 | + **[cssmin](https://www.npmjs.com/package/cssmin)** - CSS minifier 439 | + **[mustache](https://www.npmjs.com/package/mustache)** - 440 | + **[uglify-js](https://www.npmjs.com/package/uglify-js)** - Javascript minifier 441 | + **[onchange](https://www.npmjs.com/package/onchange)** - Use glob patterns to watch file sets and run an npm script when anything is added, changed or deleted. 442 | + **[http-server](https://www.npmjs.com/package/http-server)** - A simple zero-configuration command-line http server for serving up static files. 443 | + **[husky](https://www.npmjs.com/package/husky)** - Integrates git hooks with npm scripts 444 | + **[cross-env](https://www.npmjs.com/package/cross-env)** - Run commands that set environment variables across platforms 445 | + **[rimraf](https://www.npmjs.com/package/rimraf)** - Deleted files across platforms 446 | + **[opn-cli](https://www.npmjs.com/package/opn-cli)** - Open files across platforms 447 | + **[cross-var](https://www.npmjs.com/package/cross-var)** - Reference environment variables across platform 448 | + **[ntl](https://www.npmjs.com/package/ntl)** - Node task list command line app. 449 | + **[p-s](https://www.npmjs.com/package/p-s)** - All the benefits of npm scripts without the cost of a bloated package.json and limits of json 450 | --------------------------------------------------------------------------------