├── .github └── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── LICENSE.md └── README.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | Proposed changes: 4 | 5 | * .. 6 | * .. 7 | 8 | Resolves # . 9 | 10 | ## Checklist 11 | 12 | * [ ] The changes only affect or contain one style guide rule or section. 13 | * [ ] The changes are in [style guide format](/CONTRIBUTING.md#format). 14 | * [ ] The new style guide section has an entry in the [Table of Contents](/README.md#table-of-contents) (only if changes introduce new section). 15 | * [ ] The changes can be merged into the target branch without conflicts. 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | For new additions or changes to the guide, create a branch and submit a Pull Request. 4 | Only add/change 1 style guide rule per Pull Request. 5 | The Pull Request serves as a place to discuss and refine the additions/changes. 6 | 7 | ## Format 8 | 9 | Use [Github Flavoured Markdown](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown). 10 | 11 | Use short and descriptive rule names as 2nd level heading: 12 | 13 | ```markdown 14 | ## Keep expressions simple 15 | ``` 16 | 17 | Optionally add an short summary for the rule. 18 | 19 | Describe **why** the rule exists. What purpose does it serve? 20 | 21 | ```markdown 22 | ### Why? 23 | 24 | With nvm you can have multiple different versions available and switch to the one that suits better your project. 25 | ``` 26 | 27 | Describe **how** (and how not) to apply the rule. 28 | 29 | ```markdown 30 | ### How? 31 | 32 | To install or update nvm, you can use the install script using cURL 33 | ``` 34 | 35 | When using code snippets: 36 | * use `` and `/* recommended */` or `` and `/* avoid */` at the start of the snippet to indicate if it's a good or bad practice. 37 | 38 | When in need refer to npm in lowercase. 39 | 40 | Add a [↑ back to Table of Contents](README.md#table-of-contents) link at the end of each rule, so the reader can easily navigate back: 41 | 42 | ```markdown 43 | [↑ back to Table of Contents](#table-of-contents) 44 | ``` 45 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # CC0 1.0 Universal 2 | 3 | ## Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | **1. Copyright and Related Rights.** A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | **2. Waiver.** To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | **3. Public License Fallback.** Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | **4. Limitations and Disclaimers.** 94 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 95 | surrendered, licensed or otherwise affected by this document. 96 | 97 | b. Affirmer offers the Work as-is and makes no representations or warranties 98 | of any kind concerning the Work, express, implied, statutory or otherwise, 99 | including without limitation warranties of title, merchantability, fitness 100 | for a particular purpose, non infringement, or the absence of latent or 101 | other defects, accuracy, or the present or absence of errors, whether or not 102 | discoverable, all to the greatest extent permissible under applicable law. 103 | 104 | c. Affirmer disclaims responsibility for clearing rights of other persons 105 | that may apply to the Work or any use thereof, including without limitation 106 | any person's Copyright and Related Rights in the Work. Further, Affirmer 107 | disclaims responsibility for obtaining any necessary consents, permissions 108 | or other rights required for any use of the Work. 109 | 110 | d. Affirmer understands and acknowledges that Creative Commons is not a 111 | party to this document and has no duty or obligation with respect to this 112 | CC0 or use of the Work. 113 | 114 | For more information, please see 115 | 116 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # npm Style Guide 2 | 3 | Opinionated ​*npm Style Guide*​ for teams by [De Voorhoede](https://twitter.com/devoorhoede). 4 | 5 | [![npm style guide](https://img.shields.io/badge/style%20guide-npm-5ed9c7.svg)](https://github.com/voorhoede/npm-style-guide) 6 | 7 | ## Purpose 8 | 9 | This guide provides a set of rules to better manage, test and build your [npm](https://npmjs.org) modules and project scripts. It should make them 10 | 11 | * easier for a new developer to pick up 12 | * reduce friction with different environment configurations 13 | * have a predictable api 14 | * easier to add new scripts 15 | 16 | ## Table of Contents 17 | 18 | * [Use nvm to manage node versions](#use-nvm-to-manage-node-versions) 19 | * [Configure your npm personal info](#configure-your-npm-personal-info) 20 | * [Use `save exact` option](#use-save-exact-option) 21 | * [Specify engines on `package.json`](#specify-engines-on-packagejson) 22 | * [Avoid installing modules globally](#avoid-installing-modules-globally) 23 | * [Use standard script names](#use-standard-script-names) 24 | * [Write atomic scripts](#write-atomic-scripts) 25 | * [Use npm modules for system tasks](#use-npm-modules-for-system-tasks) 26 | * [Avoid shorthand command flags](#avoid-shorthand-command-flags) 27 | * [Group related scripts by prefix](#group-related-scripts-by-prefix) 28 | * [Document your script API](#document-your-script-api) 29 | 30 | 31 | ## Use nvm to manage node versions 32 | 33 | ### Why? 34 | 35 | With [nvm](https://github.com/creationix/nvm) you can have multiple different versions available and switch to the one that suits better your project. 36 | 37 | ### How? 38 | 39 | To install or update nvm, you can use the install script using cURL: 40 | 41 | ```bash 42 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash 43 | ``` 44 | 45 | For Windows check [nvm for windows](https://github.com/coreybutler/nvm-windows). 46 | 47 | 48 | If everything goes well, you can now install a specific node version. 49 | 50 | ```bash 51 | nvm install stable 52 | nvm install vX.Y.Z 53 | nvm alias default stable 54 | ``` 55 | 56 | It’s also easy when updating a newer version, copying your existing global modules. 57 | 58 | ```bash 59 | nvm copy-packages 60 | ``` 61 | 62 | [↑ back to Table of Contents](#table-of-contents) 63 | 64 | 65 | ## Configure your npm personal info 66 | 67 | ### Why? 68 | 69 | When creating a new package `npm init` your defaults will be already included on the scaffolding. 70 | 71 | ### How? 72 | 73 | ```bash 74 | npm config set init-author-name "{name}" 75 | npm config set init-author-email "{email}" 76 | ``` 77 | 78 | Check [npm config](https://docs.npmjs.com/misc/config#init-module) docs, for more info. 79 | 80 | You can use `cat ~/.npmrc` to check your current definitions. 81 | 82 | [↑ back to Table of Contents](#table-of-contents) 83 | 84 | 85 | ## Use `save exact` option 86 | 87 | ### Why? 88 | 89 | By default, installing a package with the `--save` or `--save-dev` option, npm saves the package version with `^` prefix, meaning that will update minor versions if available. While this is a good idea as is, this makes it possible for different developers having different versions of the same package and making it harder to debug if there is inconsistency. Defining the `save-exact` option prevents this. More info [npm config](https://docs.npmjs.com/misc/config#save-exact) docs. 90 | 91 | ### How? 92 | 93 | ```bash 94 | npm config set save-exact 95 | ``` 96 | 97 | [↑ back to Table of Contents](#table-of-contents) 98 | 99 | 100 | ## Specify engines on `package.json` 101 | 102 | ### Why? 103 | 104 | Specifying engine versions for your module, warns the user if he is not using a supported version. This is specially important for ensuring npm@3 flat tree dependency on Windows, or ES2015 features that your scripts require on node. 105 | 106 | ### How? 107 | 108 | In `package.json`: 109 | ```javascript 110 | "engines" : { 111 | "node" : "5.10.0", 112 | "npm" : "3.8.5" 113 | } 114 | ``` 115 | 116 | Preventing the user from using your module is also possible with [check-pkg-engines](https://www.npmjs.com/package/check-pkg-engines). 117 | 118 | [↑ back to Table of Contents](#table-of-contents) 119 | 120 | 121 | ## Avoid installing modules globally 122 | 123 | NPM first tries globally installed modules before looking for local ones. Globally installed modules are shared between projects and might not match the required version for the project. 124 | 125 | ### Why? 126 | 127 | * Locally installed modules are custom and specific for the project. 128 | * Locally installed modules are directly accessible via [npm scripts](https://docs.npmjs.com/misc/scripts). 129 | 130 | ### How? 131 | 132 | ```bash 133 | # recommended: install locally 134 | npm install --save-dev grunt-cli grunt 135 | ``` 136 | and use in `package.json`: 137 | ```json 138 | "scripts": { 139 | "icons": "grunt grunticon" 140 | } 141 | ``` 142 | ```bash 143 | # avoid: don't install modules globally 144 | npm install -g grunt-cli grunt 145 | ``` 146 | 147 | [↑ back to Table of Contents](#table-of-contents) 148 | 149 | 150 | ## Use npm modules for system tasks 151 | 152 | ### Why? 153 | 154 | When you use system specific commands like `rm -rf` or `&&`, you are locking your tasks to your current operating system. If you want to make your scripts work everywhere think about Windows developers also. 155 | 156 | ### How? 157 | 158 | Use npm modules with node that mimic the same tasks but are system agnostic. Some examples: 159 | 160 | * create directory (`mkdir` / `mkdir -p`) -> [`mkdirp`](https://www.npmjs.com/package/mkdirp) 161 | * remove files and directories (`rm ...`) -> [`rimraf`](https://www.npmjs.com/package/rimraf) 162 | * copy files (`cp ...`) -> [`ncp`](https://www.npmjs.com/package/ncp) 163 | * run multiple scripts in sequence (`... && ...`) or in parallel (`... & ...`) -> [`npm-run-all`](https://www.npmjs.com/package/npm-run-all) 164 | * set environment variable (`ENV_VAR = ...`) -> [`cross-env`](https://www.npmjs.com/package/cross-env) 165 | 166 | [↑ back to Table of Contents](#table-of-contents) 167 | 168 | 169 | ## Avoid shorthand command flags 170 | 171 | npm and npm modules with a command-line interface support different options using fully written out and / or shorthand flags. For instance, instead of `npm install --save-dev` you can use the shorter `npm i -D`. For `npm test` you can use simply `npm t`. But `npm start` is not the same as `npm s`, as that's an alias for `npm search`. So while you can use these shorthands in your daily routine, you should avoid them in scripts and documentation shared with other developers. 172 | 173 | ### Why? 174 | 175 | * Shorthand flags can only be understood by developers who know the modules and options well. 176 | * Fully written out command options help in writing self documented scripts. 177 | * Fully written out command options make scripts more accessible to other developers. 178 | 179 | ### How? 180 | 181 | Always prefer fully written command flags over shorthand. Example using [uglifyjs](https://www.npmjs.com/package/uglify-js): 182 | 183 | ```bash 184 | # recommended 185 | uglify index.js --compress --mangle --reserved '$' --output index.min.js 186 | ``` 187 | 188 | ```bash 189 | # avoid 190 | uglifyjs index.js -c -m -r '$' -o index.min.js 191 | ``` 192 | 193 | [↑ back to Table of Contents](#table-of-contents) 194 | 195 | ## Use standard script names 196 | 197 | npm lets you define custom scripts. You can give these scripts any name you like, but you should stick to standard names when you can. 198 | 199 | ### Why? 200 | 201 | Using standard script names creates a predictable script API, which makes your project easier to use by other developers. When used consistently between projects a user doesn't even need to read the documentation or `package.json` to know which scripts are available. 202 | 203 | ### How? 204 | 205 | `npm start` and `npm test` are predefined aliases for custom scripts. In addition use of `build`, `deploy` and `watch` are widely spread within the developer community. You should use these script names as follows: 206 | 207 | * **`npm run build`** to create a distribution of your project (mostly for production). 208 | * **`npm run deploy`** to put your project on a host environment. 209 | * **`npm start`** (alias for `npm run start`) to start a web server (defaults to `node server.js`). 210 | * **`npm test`** (alias for `npm run test`) to run project's entire test suite. 211 | * **`npm run watch`** to run other scripts on files changes. 212 | 213 | In `package.json`: 214 | ```javascript 215 | /* recommended: standard script names */ 216 | { 217 | "scripts": { 218 | "build": "...", 219 | "deploy": "...", 220 | "start": "...", 221 | "test": "...", 222 | "watch": "..." 223 | } 224 | } 225 | 226 | /* avoid: */ 227 | { 228 | "scripts": { 229 | "bundle": "...", 230 | "upload": "...", 231 | "serve": "...", 232 | "check": "...", 233 | "watcher": "..." 234 | } 235 | } 236 | ``` 237 | 238 | [↑ back to Table of Contents](#table-of-contents) 239 | 240 | 241 | ## Write atomic scripts 242 | 243 | Each script should be only responsible for one action. 244 | 245 | ### Why? 246 | 247 | * Atomic scripts are easy to read and understand. 248 | * Atomic scripts are easy to reuse. 249 | 250 | ### How? 251 | 252 | Separate each step of the script to an individual script. For example a "generate icon" script can be split into atomic script like "clean directory", "optimize SVGs", "generate PNGs" and "generate data-uris for SVGs". 253 | 254 | [↑ back to Table of Contents](#table-of-contents) 255 | 256 | ## Group related scripts by prefix 257 | 258 | Bundle your scripts with a prefix so you can execute them all at once. 259 | 260 | ### Why? 261 | 262 | * Bundling helps keeping your scripts organized. 263 | * Tasks grouped by prefix can be easily executed with one command. 264 | * Your high-level script API remains unchanged when scripts are added, removed or renamed. 265 | 266 | ### How? 267 | 268 | In `package.json`: 269 | ```javascript 270 | /* recommended: group related scripts by prefix */ 271 | scripts: { 272 | "test": "npm run test:eslint && npm run test:unit && npm run test:e2e", 273 | "test:eslint": "eslint src/**/*.js", 274 | "test:unit": "tape --require dist/index.js src/**/*.test.js", 275 | "test:e2e": "karma start test/config.js" 276 | } 277 | 278 | /* avoid */ 279 | scripts: { 280 | "eslint": "eslint src/**/*.js", 281 | "tape": "tape --require dist/index.js src/**/*.test.js", 282 | "karma": "karma start test/config.js", 283 | } 284 | ``` 285 | 286 | Bundled scripts can be executed (in parallel or in sequence) using [npm-run-all](https://www.npmjs.com/package/npm-run-all): 287 | 288 | ```javascript 289 | /* recommended: use `npm-run-all` to run all bundled scripts */ 290 | scripts: { 291 | "test": "npm-run-all test:*", 292 | "test:eslint": "eslint src/**/*.js", 293 | "test:unit": "tape --require dist/index.js src/**/*.test.js", 294 | "test:e2e": "karma start test/config.js" 295 | } 296 | ``` 297 | 298 | [↑ back to Table of Contents](#table-of-contents) 299 | 300 | 301 | ## Document your script API 302 | 303 | ### Why? 304 | 305 | * Documentation provides developers with a high level overview to the script, without the need to go through all its code. This makes a module more accessible and easier to use. 306 | * Documentation formalises the API. 307 | 308 | ### How? 309 | 310 | Document your script API in the project's README.md or CONTRIBUTING.md as those are the first places contributors will look. 311 | Describe what each task does using a simple table: 312 | 313 | ```markdown 314 | `npm run ...` | Description 315 | ---|--- 316 | task | What it does as a plain human readable description. 317 | ``` 318 | 319 | An example: 320 | 321 | `npm run ...` | Description 322 | ---|--- 323 | `build` | Compile, bundle and minify all CSS and JS files.. 324 | `build:css` | Compile, autoprefix and minify all CSS files to `dist/index.css`. 325 | `build:js` | Compile, bundle and minify all JS files to `dist/index.js`. 326 | `start` | Starts a server on `http://localhost:3000`. 327 | `test` | Run all unit and end-to-end tests. 328 | 329 | [↑ back to Table of Contents](#table-of-contents) 330 | 331 | --- 332 | 333 | ## License 334 | 335 | [![CC0](http://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)](https://creativecommons.org/publicdomain/zero/1.0/) 336 | 337 | [De Voorhoede](https://twitter.com/devoorhoede) waives all rights to this work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. 338 | 339 | You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. 340 | --------------------------------------------------------------------------------