├── .gitignore ├── test ├── fixtures │ ├── init │ │ ├── .gitignore │ │ ├── expected.json │ │ └── package.json │ ├── simple │ │ ├── expected.json │ │ ├── npm-shrinkwrap.json │ │ └── package.json │ ├── tarball │ │ ├── expected.json │ │ ├── npm-shrinkwrap.json │ │ └── package.json │ ├── 1.x │ │ └── git │ │ │ ├── package.json │ │ │ └── npm-shrinkwrap.json │ ├── 2.x │ │ └── git │ │ │ ├── package.json │ │ │ └── npm-shrinkwrap.json │ └── 3.x │ │ └── git │ │ ├── package.json │ │ └── npm-shrinkwrap.json └── run.sh ├── bin └── shrinkwarp ├── .travis.yml ├── lib ├── sort.js ├── args.js ├── visit.js └── index.js ├── package.json ├── npm-shrinkwrap.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /test/fixtures/init/.gitignore: -------------------------------------------------------------------------------- 1 | npm-shrinkwrap.json 2 | -------------------------------------------------------------------------------- /bin/shrinkwarp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('../lib')(process.argv); 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "4" 5 | before_install: 6 | - "npm i -g npm@^3.10.7" 7 | -------------------------------------------------------------------------------- /test/fixtures/init/expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "init", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "async": { 6 | "version": "1.4.2" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/simple/expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "async": { 6 | "version": "1.4.2" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/simple/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "async": { 6 | "version": "1.4.2" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/fixtures/tarball/expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tarball", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "async": { 6 | "version": "1.4.2", 7 | "resolved": "https://github.com/caolan/async/archive/v1.4.2.tar.gz" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/tarball/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tarball", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "async": { 6 | "version": "1.4.2", 7 | "resolved": "https://github.com/caolan/async/archive/v1.4.2.tar.gz" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/1.x/git/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git", 3 | "version": "1.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "abbrev": "^1.0.7", 7 | "async": "github:caolan/async#v1.4.2", 8 | "nopt": "^3.0.6", 9 | "pinkie-promise": "^2.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/2.x/git/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git", 3 | "version": "1.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "abbrev": "^1.0.7", 7 | "async": "github:caolan/async#v1.4.2", 8 | "nopt": "^3.0.6", 9 | "pinkie-promise": "^2.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/3.x/git/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git", 3 | "version": "1.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "abbrev": "^1.0.7", 7 | "async": "github:caolan/async#v1.4.2", 8 | "nopt": "^3.0.6", 9 | "pinkie-promise": "^2.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/fixtures/init/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "init", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "postshrinkwrap": "shrinkwarp" 7 | }, 8 | "devDependencies": { 9 | "shrinkwarp": "../../.." 10 | }, 11 | "dependencies": { 12 | "async": "1.4.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/simple/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "postshrinkwrap": "shrinkwarp" 7 | }, 8 | "devDependencies": { 9 | "shrinkwarp": "../../.." 10 | }, 11 | "dependencies": { 12 | "async": "1.4.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/tarball/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tarball", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "postshrinkwrap": "shrinkwarp" 7 | }, 8 | "devDependencies": { 9 | "shrinkwarp": "../../.." 10 | }, 11 | "dependencies": { 12 | "async": "https://github.com/caolan/async/archive/v1.4.2.tar.gz" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/sort.js: -------------------------------------------------------------------------------- 1 | module.exports = depsOnly; 2 | 3 | function depsOnly(a, b) { 4 | if (a === 'name' || 5 | a === 'version') { 6 | return -1; 7 | } 8 | if (a === 'dependencies' || 9 | b === 'dependencies') { 10 | // dependencies should always sort last 11 | return (a === 'dependencies') ? 1 : -1; 12 | } 13 | return a.localeCompare(b); 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/3.x/git/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "abbrev": { 6 | "version": "1.0.7" 7 | }, 8 | "async": { 9 | "version": "1.4.2", 10 | "from": "caolan/async#v1.4.2", 11 | "resolved": "git://github.com/caolan/async.git#92f78aebad222d60c13e4299c0e723f2fe2d6611" 12 | }, 13 | "nopt": { 14 | "version": "3.0.6" 15 | }, 16 | "pinkie": { 17 | "version": "2.0.1" 18 | }, 19 | "pinkie-promise": { 20 | "version": "2.0.0" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/fixtures/2.x/git/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "abbrev": { 6 | "version": "1.0.7" 7 | }, 8 | "async": { 9 | "version": "1.4.2", 10 | "from": "caolan/async#v1.4.2", 11 | "resolved": "git://github.com/caolan/async.git#92f78aebad222d60c13e4299c0e723f2fe2d6611" 12 | }, 13 | "nopt": { 14 | "version": "3.0.6" 15 | }, 16 | "pinkie-promise": { 17 | "version": "2.0.0", 18 | "dependencies": { 19 | "pinkie": { 20 | "version": "2.0.1" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/fixtures/1.x/git/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "git", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "abbrev": { 6 | "version": "1.0.7" 7 | }, 8 | "async": { 9 | "version": "1.4.2", 10 | "from": "async@git://github.com/caolan/async.git#92f78aebad222d60c13e4299c0e723f2fe2d6611", 11 | "resolved": "git://github.com/caolan/async.git#92f78aebad222d60c13e4299c0e723f2fe2d6611" 12 | }, 13 | "nopt": { 14 | "version": "3.0.6" 15 | }, 16 | "pinkie-promise": { 17 | "version": "2.0.0", 18 | "dependencies": { 19 | "pinkie": { 20 | "version": "2.0.1" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/args.js: -------------------------------------------------------------------------------- 1 | var debug = require('debug')('shrinkwarp:args'); 2 | var nopt = require('nopt'); 3 | 4 | module.exports = parseArgs; 5 | 6 | function parseArgs(argv) { 7 | debug('received argv', argv); 8 | 9 | var parsed = nopt({ 10 | 'ignore': [String, Array] 11 | }, null, argv); 12 | 13 | // back-compat for unguarded --dev 14 | if (parsed.argv.remain.length === 0 && parsed.dev) { 15 | parsed.argv.remain.push('--dev'); 16 | debug('propagated unguarded --dev') 17 | } 18 | 19 | // create lookup map if modules ignored 20 | parsed.ignoreModules = {}; 21 | if (parsed.ignore && parsed.ignore.length) { 22 | parsed.ignore.forEach(function (module) { 23 | parsed.ignoreModules[module] = true; 24 | }); 25 | debug('found ignored modules', parsed.ignore); 26 | } 27 | 28 | debug('parsed', parsed); 29 | return parsed; 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shrinkwarp", 3 | "version": "2.0.0", 4 | "description": "deterministic npm shrinkwrap", 5 | "repository": { 6 | "type": "git", 7 | "url": "git@github.com:evocateur/shrinkwarp.git" 8 | }, 9 | "bin": "bin/shrinkwarp", 10 | "files": [ 11 | "npm-shrinkwrap.json", 12 | "bin", 13 | "lib" 14 | ], 15 | "keywords": [ 16 | "shinkwrap" 17 | ], 18 | "author": "Daniel Stockman", 19 | "license": "BSD-3-Clause", 20 | "scripts": { 21 | "prepublish": "not-in-install && npm test || in-install", 22 | "pretest": "eslint bin lib", 23 | "test": "DEBUG=shrinkwarp:* ./test/run.sh" 24 | }, 25 | "engines": { 26 | "npm": ">=3.10.7", 27 | "node": ">=4" 28 | }, 29 | "eslintConfig": { 30 | "env": { 31 | "node": true 32 | }, 33 | "extends": [ 34 | "eslint:recommended" 35 | ], 36 | "root": true 37 | }, 38 | "dependencies": { 39 | "debug": "^2.2.0", 40 | "load-json-file": "^2.0.0", 41 | "nopt": "^3.0.6", 42 | "npm-package-arg": "^4.1.0", 43 | "path-exists": "^2.1.0", 44 | "pkg-dir": "^1.0.0", 45 | "traverse": "^0.6.6", 46 | "write-json-file": "^2.0.0" 47 | }, 48 | "devDependencies": { 49 | "eslint": "^2.13.1", 50 | "in-publish": "^2.0.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/visit.js: -------------------------------------------------------------------------------- 1 | var debug = require('debug')('shrinkwarp:visit'); 2 | var npa = require('npm-package-arg'); 3 | 4 | module.exports = cleanDeps; 5 | 6 | function cleanDeps(tree, ignored) { 7 | return tree.forEach(visitor); 8 | 9 | function visitor(node) { 10 | if (this.parent && 11 | this.parent.key === 'dependencies') { 12 | debug(this.key); 13 | 14 | if (ignored[this.key]) { 15 | debug('ignoring module'); 16 | this.remove(true); 17 | if (this.parent.keys.length === 1) { 18 | debug('removing empty dependencies block'); 19 | this.parent.remove(); 20 | } 21 | return; 22 | } 23 | 24 | debug(node); 25 | if (!node.from) { 26 | debug('already clean'); 27 | return; 28 | } 29 | 30 | // https://github.com/npm/npm-package-arg#result-object 31 | var parsed = npa(node.from); 32 | debug(parsed); 33 | 34 | if (parsed.type === 'git' || parsed.type === 'hosted') { 35 | // just leave them alone, they're too weird 36 | debug('ignored type "%s" from "%s"', parsed.type, node.from); 37 | } else if (parsed.type === 'remote') { 38 | // tarball does not need 'from' if it is identical to 'resolved' 39 | if (parsed.rawSpec === node.resolved) { 40 | debug('deleting redundant node.from'); 41 | delete node.from; 42 | } 43 | } else { 44 | // remove 'from' and 'resolved' with any other type of dependency 45 | delete node.from; 46 | delete node.resolved; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shrinkwarp", 3 | "version": "2.0.0", 4 | "dependencies": { 5 | "abbrev": { 6 | "version": "1.0.9" 7 | }, 8 | "debug": { 9 | "version": "2.2.0" 10 | }, 11 | "error-ex": { 12 | "version": "1.3.0" 13 | }, 14 | "find-up": { 15 | "version": "1.1.2" 16 | }, 17 | "graceful-fs": { 18 | "version": "4.1.4" 19 | }, 20 | "hosted-git-info": { 21 | "version": "2.1.5" 22 | }, 23 | "imurmurhash": { 24 | "version": "0.1.4" 25 | }, 26 | "is-arrayish": { 27 | "version": "0.2.1" 28 | }, 29 | "is-plain-obj": { 30 | "version": "1.1.0" 31 | }, 32 | "load-json-file": { 33 | "version": "2.0.0" 34 | }, 35 | "minimist": { 36 | "version": "0.0.8" 37 | }, 38 | "mkdirp": { 39 | "version": "0.5.1" 40 | }, 41 | "ms": { 42 | "version": "0.7.1" 43 | }, 44 | "nopt": { 45 | "version": "3.0.6" 46 | }, 47 | "npm-package-arg": { 48 | "version": "4.2.0" 49 | }, 50 | "parse-json": { 51 | "version": "2.2.0" 52 | }, 53 | "path-exists": { 54 | "version": "2.1.0" 55 | }, 56 | "pify": { 57 | "version": "2.3.0" 58 | }, 59 | "pinkie": { 60 | "version": "2.0.4" 61 | }, 62 | "pinkie-promise": { 63 | "version": "2.0.1" 64 | }, 65 | "pkg-dir": { 66 | "version": "1.0.0" 67 | }, 68 | "semver": { 69 | "version": "5.2.0" 70 | }, 71 | "slide": { 72 | "version": "1.1.6" 73 | }, 74 | "sort-keys": { 75 | "version": "1.1.2" 76 | }, 77 | "strip-bom": { 78 | "version": "3.0.0" 79 | }, 80 | "traverse": { 81 | "version": "0.6.6" 82 | }, 83 | "write-file-atomic": { 84 | "version": "1.1.4" 85 | }, 86 | "write-json-file": { 87 | "version": "2.0.0" 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var debug = require('debug')('shrinkwarp:cli'); 2 | var path = require('path'); 3 | 4 | var spawnSync = require('child_process').spawnSync; 5 | var traverse = require('traverse'); 6 | 7 | var load = require('load-json-file'); 8 | var write = require('write-json-file'); 9 | var pkgDir = require('pkg-dir'); 10 | var exists = require('path-exists'); 11 | 12 | var parseArgs = require('./args'); 13 | var cleanDeps = require('./visit'); 14 | var depsOnly = require('./sort'); 15 | 16 | module.exports = main; 17 | 18 | function getShrinkwrapFile() { 19 | var rootDir = pkgDir.sync(); 20 | if (rootDir === null) { 21 | console.error('no package.json found'); // eslint-disable-line no-console 22 | process.exit(1); 23 | } 24 | 25 | var filePath = path.join(rootDir, 'npm-shrinkwrap.json'); 26 | return exists.sync(filePath) ? filePath : null; 27 | } 28 | 29 | function main(argv) { 30 | debug('starting in %s', process.cwd()); 31 | 32 | var parsed = parseArgs(argv); 33 | var ignored = parsed.ignoreModules; 34 | 35 | var shrinkwrapFile = getShrinkwrapFile(); 36 | if (shrinkwrapFile === null || parsed.force) { 37 | debug('no existing npm-shrinkwrap.json found, generating...'); 38 | var args = [ 39 | 'shrinkwrap', 40 | '--ignore-scripts', 41 | '--loglevel=error' 42 | ].concat(parsed.argv.remain); 43 | 44 | debug('executing `npm %s`', args.join(' ')); 45 | var result = spawnSync('npm', args, {stdio: 'inherit'}); 46 | 47 | if (result.status) { 48 | debug('execution returned non-zero status %d', result.status); 49 | process.exit(result.status); 50 | } 51 | 52 | debug('finding npm-shrinkwrap.json after initial run'); 53 | shrinkwrapFile = getShrinkwrapFile(); 54 | } 55 | 56 | debug('cleaning dependency tree'); 57 | var tree = traverse(load.sync(shrinkwrapFile)); 58 | var data = cleanDeps(tree, ignored); 59 | 60 | debug('rewriting clean shrinkwrap'); 61 | write.sync(shrinkwrapFile, data, { 62 | sortKeys: depsOnly, 63 | indent: 2 64 | }); 65 | 66 | debug('finished'); 67 | } 68 | -------------------------------------------------------------------------------- /test/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CDPATH="" # nuked to avoid wonkiness 4 | ROOTDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." > /dev/null && pwd)" 5 | TEST_FIXTURES="${ROOTDIR}/test/fixtures" 6 | EXIT_STATUS="0" 7 | 8 | echo "node @ $(node --version)" 9 | 10 | NPM_VERSION=$(npm --version) 11 | echo "npm @ ${NPM_VERSION}" 12 | 13 | NPM_FIXTURE="${TEST_FIXTURES}/${NPM_VERSION%%.*}.x" 14 | echo "npm version-specific fixtures dir: ${NPM_FIXTURE}" 15 | echo 16 | 17 | SHRINKWARP_BIN="${ROOTDIR}/bin/shrinkwarp" 18 | NPM_SHRINKWRAP="npm shrinkwrap" 19 | 20 | # clean install 21 | # re-rerun, no changes 22 | # then install new git dep 23 | # then upgrade new git dep 24 | 25 | clean_run() { 26 | echo "Testing command '$1' in directory '$2'" 27 | # clean_run COMMAND IN_DIR 28 | pushd "$2" && \ 29 | git clean -fdx . && \ 30 | git checkout . && \ 31 | npm i . && \ 32 | $1 && \ 33 | git diff --no-ext-diff --exit-code npm-shrinkwrap.json expected.json 34 | 35 | EXIT_STATUS="$?" 36 | if [ "$EXIT_STATUS" -ne "0" ]; then 37 | exit $EXIT_STATUS 38 | fi 39 | } 40 | 41 | manual_diffs() { 42 | pushd "$1" && \ 43 | git clean -fdx && \ 44 | git checkout . && \ 45 | npm i . && \ 46 | $SHRINKWARP_BIN && \ 47 | git diff --no-ext-diff --quiet npm-shrinkwrap.json && \ 48 | npm i -S substack/js-traverse#0.6.5 && \ 49 | $SHRINKWARP_BIN && \ 50 | git diff --no-ext-diff npm-shrinkwrap.json && \ 51 | npm i -S substack/js-traverse#0.6.6 && \ 52 | $SHRINKWARP_BIN && \ 53 | git diff --no-ext-diff npm-shrinkwrap.json && \ 54 | npm rm -S traverse && 55 | git checkout npm-shrinkwrap.json 56 | # git diff --no-ext-diff --exit-code npm-shrinkwrap.json 57 | } 58 | 59 | if [ "$1" = "manual" ]; then 60 | manual_diffs "${NPM_FIXTURE}/git" 61 | else 62 | clean_run "$SHRINKWARP_BIN" "${TEST_FIXTURES}/simple" && \ 63 | clean_run "$NPM_SHRINKWRAP" "${TEST_FIXTURES}/simple" && \ 64 | clean_run "$NPM_SHRINKWRAP" "${TEST_FIXTURES}/tarball" && \ 65 | clean_run "$NPM_SHRINKWRAP" "${TEST_FIXTURES}/init" && \ 66 | clean_run "$SHRINKWARP_BIN" "${TEST_FIXTURES}/init" && \ 67 | echo "IGNORING GIT FOR NOW" 68 | # clean_run $NPM_SHRINKWRAP "${NPM_FIXTURE}/git" 69 | fi 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shrinkwarp 2 | 3 | [![Build Status](https://travis-ci.org/evocateur/shrinkwarp.svg?branch=master)](https://travis-ci.org/evocateur/shrinkwarp) 4 | 5 | A script that makes updating `npm-shrinkwrap.json` more deterministic, 6 | which helps avoid the madness of the stock `npm shrinkwrap` experience. 7 | 8 | * `shrinkwarp` removes `from` and `resolved` attributes for all dependencies 9 | * except for... 10 | - `git` dependencies, which retain both attributes 11 | - tarball (`.tgz`, `.tar.gz`, etc) dependencies, which retain `resolved` 12 | 13 | **NOTE:** This currently only works with `npm@2`, 14 | due to [this issue](https://github.com/npm/npm/issues/10502) affecting `npm@3`. 15 | 16 | This package is a fork of [shonkwrap](https://github.com/skybet/shonkwrap), 17 | which provides a great experience for `npm` 3.x users. 18 | 19 | # Install 20 | 21 | **WARNING:** Version 2 of this package is intended for `npm` v3.10.7 and above. 22 | If you are still using `npm@2`, 23 | you can continue using version [1.x][] of this package. 24 | 25 | ```sh 26 | npm install --save-dev shrinkwarp 27 | ``` 28 | 29 | Add a `postshrinkwrap` lifecycle script to your `package.json` scripts hash: 30 | 31 | ```json 32 | "scripts": { 33 | "postshrinkwrap": "shrinkwarp" 34 | } 35 | ``` 36 | 37 | **WARNING** on npm v3.10.8 and below (eg node 6.9.1) you'll need to use: 38 | 39 | ```json 40 | "scripts": { 41 | "postshrinkwrap": "cd $(npm prefix) && $(npm bin)/shrinkwarp" 42 | } 43 | ``` 44 | 45 | # Usage 46 | 47 | With the lifecycle script configured, 48 | just use `npm shrinkwrap` normally. 49 | With recent versions of `npm` 3.x, 50 | it will auto-shrinkwrap when passing the `--save`/`-S` flag to `npm install`. 51 | 52 | ```sh 53 | npm i -S foo-module 54 | npm test 55 | git commit -am "add foo-module" 56 | ``` 57 | 58 | However, installing a dev dependency (with `--save-dev`/`-D`) 59 | will still require a separate call to `npm shrinkwrap --dev`. 60 | 61 | ```sh 62 | npm i -D foo-dev-module 63 | npm shrinkwrap --dev 64 | npm test 65 | git commit -am "add foo-dev-module" 66 | ``` 67 | 68 | ## Options 69 | 70 | ### `--ignore ` 71 | 72 | In some cases, you just don't want an optional module shrinkwrapped. 73 | Often, it is due to platform-specific extensions that break builds when run on an incompatible platform. 74 | `npm` does fine with allowing optional dependencies to fail on incompatible platforms, 75 | but it falls down *hard* when those same dependencies are part of the shrinkwrap. 76 | 77 | This option will avoid all that pain. 78 | Please use sparingly, 79 | as it is a global block list. 80 | 81 | ```json 82 | "scripts": { 83 | "postshrinkwrap": "shrinkwarp --ignore fsevents" 84 | } 85 | ``` 86 | 87 | To ignore multiple modules, 88 | pass multiple flags: 89 | 90 | ```sh 91 | shrinkwarp --ignore fsevents --ignore otherthing 92 | ``` 93 | 94 | ```json 95 | "scripts": { 96 | "postshrinkwrap": "shrinkwarp --ignore fsevents --ignore otherthing" 97 | } 98 | ``` 99 | 100 | [1.x]: https://github.com/evocateur/shrinkwarp/tree/v1.2.0#install 101 | --------------------------------------------------------------------------------