问题
How can I know when to prompt user to run npm install if there are any unmet package.json dependencies?
I would like to do this, because if any require() fails, the user gets a poor error message:
module.js:340
throw err;
^
Error: Cannot find module 'nopt'
I've previously tried to just check for the existence of a node_modules directory, but this only works effectively for fresh git clones. I've also tried just requiring npm and running npm install as part of load, but that is very heavy weight.
I'm hoping there is a lighter weight library out there that just parses package.json and makes sure node_modules contents satisfy the requirements.
One idea was to use process.on('uncaughtException') to catch only module import errors, but looking to see if there is a "standard" solution first.
回答1:
Found this today. Not sure if your still need this.
https://www.npmjs.com/package/check-dependencies
npm install check-dependencies --save-dev
Install this package and save to your package.json.
require('check-dependencies')(config, callback);
config is the following object, which is then passed to the callback.
{
status: number, // 0 if successful, 1 otherwise
depsWereOk: boolean, // true if dependencies were already satisfied
log: array, // array of logged messages
error: array, // array of logged errors
}
回答2:
You can use yarn and do yarn check --verify-tree (you can continue using npm for everything else)
回答3:
If you use github, or at least host your project.json on github, you can use: https://david-dm.org/
replace your username and repo.
https://david-dm.org/username/repo.svg
Then you can see something like https://david-dm.org/bower/bower to identify the out of date packages.
回答4:
Not sure there is npm way to do it, but just found this seems helpful:
blog post: http://bahmutov.calepin.co/check-dependencies-in-grunt-by-default.html
project: https://github.com/bahmutov/deps-ok
回答5:
npm ls will report missing packages when run from the project folder.
npm-ls documentation
This might have issues if you're using git dependencies, though. (Thanks @gman).
回答6:
Another solution
function dependenciesNeedUpdating() {
const childProcess = require('child_process');
const result = JSON.parse(childProcess.execSync('npm install --dry-run --json').toString());
return result.added.length > 0 || result.updated.length > 0 || result.removed > 0;
}
Call it like this
if (dependenciesNeedUpdating()) {
console.error('dependencies need updating. Please run `npm install`');
process.exit(1);
}
If you want to install this as a dependency 🤣 its 5 lines are in an npm package here. It adds a ld-check-dependencies command (the 4 usage lines above) so you can use it directly in your npm scripts. Example:
"scripts": {
"build": "ld-check-dependencies && rollup ..."
},
Rationale:
I'm learning that dependencies are a huge liability and should be avoided any time there is a simpler solution.
For example here's is the ridiculous dependency tree for check-dependencies
└─┬ check-dependencies@1.1.0
├─┬ bower-config@1.4.3
│ ├── graceful-fs@4.2.4
│ ├── minimist@0.2.1 extraneous
│ ├── mout@1.2.2
│ ├─┬ osenv@0.1.5
│ │ ├── os-homedir@1.0.2
│ │ └── os-tmpdir@1.0.2
│ ├─┬ untildify@2.1.0
│ │ └── os-homedir@1.0.2 deduped
│ └── wordwrap@0.0.3
├─┬ chalk@2.4.2
│ ├─┬ ansi-styles@3.2.1
│ │ └─┬ color-convert@1.9.3
│ │ └── color-name@1.1.3
│ ├── escape-string-regexp@1.0.5
│ └─┬ supports-color@5.5.0
│ └── has-flag@3.0.0
├─┬ findup-sync@2.0.0
│ ├── detect-file@1.0.0
│ ├─┬ is-glob@3.1.0
│ │ └── is-extglob@2.1.1
│ ├─┬ micromatch@3.1.10
│ │ ├── arr-diff@4.0.0
│ │ ├── array-unique@0.3.2
│ │ ├─┬ braces@2.3.2
│ │ │ ├── arr-flatten@1.1.0
│ │ │ ├── array-unique@0.3.2 deduped
│ │ │ ├── extend-shallow@2.0.1 extraneous
│ │ │ ├─┬ fill-range@4.0.0
│ │ │ │ ├── extend-shallow@2.0.1 extraneous
│ │ │ │ ├─┬ is-number@3.0.0
│ │ │ │ │ └── kind-of@3.2.2 extraneous
│ │ │ │ ├── repeat-string@1.6.1
│ │ │ │ └─┬ to-regex-range@2.1.1
│ │ │ │ ├── is-number@3.0.0 deduped
│ │ │ │ └── repeat-string@1.6.1 deduped
│ │ │ ├── isobject@3.0.1
│ │ │ ├── repeat-element@1.1.3
│ │ │ ├── snapdragon@0.8.2 deduped
│ │ │ ├─┬ snapdragon-node@2.1.1
│ │ │ │ ├── define-property@1.0.0 extraneous
│ │ │ │ ├── isobject@3.0.1 deduped
│ │ │ │ └─┬ snapdragon-util@3.0.1
│ │ │ │ └── kind-of@3.2.2 extraneous
│ │ │ ├─┬ split-string@3.1.0
│ │ │ │ └── extend-shallow@3.0.2 deduped
│ │ │ └── to-regex@3.0.2 deduped
│ │ ├─┬ define-property@2.0.2
│ │ │ ├── is-descriptor@1.0.2 extraneous
│ │ │ └── isobject@3.0.1 deduped
│ │ ├─┬ extend-shallow@3.0.2
│ │ │ ├── assign-symbols@1.0.0
│ │ │ └── is-extendable@1.0.1 extraneous
│ │ ├─┬ extglob@2.0.4
│ │ │ ├── array-unique@0.3.2 deduped
│ │ │ ├── define-property@1.0.0 extraneous
│ │ │ ├─┬ expand-brackets@2.1.4
│ │ │ │ ├── debug@2.6.9 deduped
│ │ │ │ ├── define-property@0.2.5 extraneous
│ │ │ │ ├── extend-shallow@2.0.1 extraneous
│ │ │ │ ├── posix-character-classes@0.1.1
│ │ │ │ ├── regex-not@1.0.2 deduped
│ │ │ │ ├── snapdragon@0.8.2 deduped
│ │ │ │ └── to-regex@3.0.2 deduped
│ │ │ ├── extend-shallow@2.0.1 extraneous
│ │ │ ├── fragment-cache@0.2.1 deduped
│ │ │ ├── regex-not@1.0.2 deduped
│ │ │ ├── snapdragon@0.8.2 deduped
│ │ │ └── to-regex@3.0.2 deduped
│ │ ├─┬ fragment-cache@0.2.1
│ │ │ └── map-cache@0.2.2
│ │ ├── kind-of@6.0.3
│ │ ├─┬ nanomatch@1.2.13
│ │ │ ├── arr-diff@4.0.0 deduped
│ │ │ ├── array-unique@0.3.2 deduped
│ │ │ ├── define-property@2.0.2 deduped
│ │ │ ├── extend-shallow@3.0.2 deduped
│ │ │ ├── fragment-cache@0.2.1 deduped
│ │ │ ├── is-windows@1.0.2
│ │ │ ├── kind-of@6.0.3 deduped
│ │ │ ├── object.pick@1.3.0 deduped
│ │ │ ├── regex-not@1.0.2 deduped
│ │ │ ├── snapdragon@0.8.2 deduped
│ │ │ └── to-regex@3.0.2 deduped
│ │ ├─┬ object.pick@1.3.0
│ │ │ └── isobject@3.0.1 deduped
│ │ ├─┬ regex-not@1.0.2
│ │ │ ├── extend-shallow@3.0.2 deduped
│ │ │ └─┬ safe-regex@1.1.0
│ │ │ └── ret@0.1.15
│ │ ├─┬ snapdragon@0.8.2
│ │ │ ├─┬ base@0.11.2
│ │ │ │ ├─┬ cache-base@1.0.1
│ │ │ │ │ ├─┬ collection-visit@1.0.0
│ │ │ │ │ │ ├─┬ map-visit@1.0.0
│ │ │ │ │ │ │ └── object-visit@1.0.1 deduped
│ │ │ │ │ │ └─┬ object-visit@1.0.1
│ │ │ │ │ │ └── isobject@3.0.1 deduped
│ │ │ │ │ ├── component-emitter@1.3.0 deduped
│ │ │ │ │ ├── get-value@2.0.6
│ │ │ │ │ ├─┬ has-value@1.0.0
│ │ │ │ │ │ ├── get-value@2.0.6 deduped
│ │ │ │ │ │ ├─┬ has-values@1.0.0
│ │ │ │ │ │ │ ├── is-number@3.0.0 deduped
│ │ │ │ │ │ │ └── kind-of@4.0.0 extraneous
│ │ │ │ │ │ └── isobject@3.0.1 deduped
│ │ │ │ │ ├── isobject@3.0.1 deduped
│ │ │ │ │ ├─┬ set-value@2.0.1
│ │ │ │ │ │ ├── extend-shallow@2.0.1 extraneous
│ │ │ │ │ │ ├── is-extendable@0.1.1
│ │ │ │ │ │ ├─┬ is-plain-object@2.0.4
│ │ │ │ │ │ │ └── isobject@3.0.1 deduped
│ │ │ │ │ │ └── split-string@3.1.0 deduped
│ │ │ │ │ ├─┬ to-object-path@0.3.0
│ │ │ │ │ │ └── kind-of@3.2.2 extraneous
│ │ │ │ │ ├─┬ union-value@1.0.1
│ │ │ │ │ │ ├── arr-union@3.1.0 deduped
│ │ │ │ │ │ ├── get-value@2.0.6 deduped
│ │ │ │ │ │ ├── is-extendable@0.1.1 deduped
│ │ │ │ │ │ └── set-value@2.0.1 deduped
│ │ │ │ │ └─┬ unset-value@1.0.0
│ │ │ │ │ ├── has-value@0.3.1 extraneous
│ │ │ │ │ └── isobject@3.0.1 deduped
│ │ │ │ ├─┬ class-utils@0.3.6
│ │ │ │ │ ├── arr-union@3.1.0
│ │ │ │ │ ├── define-property@0.2.5 extraneous
│ │ │ │ │ ├── isobject@3.0.1 deduped
│ │ │ │ │ └─┬ static-extend@0.1.2
│ │ │ │ │ ├── define-property@0.2.5 extraneous
│ │ │ │ │ └─┬ object-copy@0.1.0
│ │ │ │ │ ├── copy-descriptor@0.1.1
│ │ │ │ │ ├── define-property@0.2.5 extraneous
│ │ │ │ │ └── kind-of@3.2.2 extraneous
│ │ │ │ ├── component-emitter@1.3.0
│ │ │ │ ├── define-property@1.0.0 extraneous
│ │ │ │ ├── isobject@3.0.1 deduped
│ │ │ │ ├─┬ mixin-deep@1.3.2
│ │ │ │ │ ├── for-in@1.0.2
│ │ │ │ │ └── is-extendable@1.0.1 extraneous
│ │ │ │ └── pascalcase@0.1.1
│ │ │ ├─┬ debug@2.6.9
│ │ │ │ └── ms@2.0.0
│ │ │ ├── define-property@0.2.5 extraneous
│ │ │ ├── extend-shallow@2.0.1 extraneous
│ │ │ ├── map-cache@0.2.2 deduped
│ │ │ ├── source-map@0.5.7
│ │ │ ├─┬ source-map-resolve@0.5.3
│ │ │ │ ├── atob@2.1.2
│ │ │ │ ├── decode-uri-component@0.2.0
│ │ │ │ ├── resolve-url@0.2.1
│ │ │ │ ├── source-map-url@0.4.0
│ │ │ │ └── urix@0.1.0
│ │ │ └── use@3.1.1
│ │ └─┬ to-regex@3.0.2
│ │ ├── define-property@2.0.2 deduped
│ │ ├── extend-shallow@3.0.2 deduped
│ │ ├── regex-not@1.0.2 deduped
│ │ └── safe-regex@1.1.0 deduped
│ └─┬ resolve-dir@1.0.1
│ ├─┬ expand-tilde@2.0.2
│ │ └─┬ homedir-polyfill@1.0.3
│ │ └── parse-passwd@1.0.0
│ └─┬ global-modules@1.0.0
│ ├─┬ global-prefix@1.0.2
│ │ ├── expand-tilde@2.0.2 deduped
│ │ ├── homedir-polyfill@1.0.3 deduped
│ │ ├── ini@1.3.5
│ │ ├── is-windows@1.0.2 deduped
│ │ └─┬ which@1.3.1
│ │ └── isexe@2.0.0
│ ├── is-windows@1.0.2 deduped
│ └── resolve-dir@1.0.1 deduped
├── lodash.camelcase@4.3.0
├── minimist@1.2.5
└── semver@5.7.1
788 js files and 48000 lines of code.
Everyone one of those dependencies is another chance for you to be told something is broke, deprecated, there's a new vulnerability, etc. Basically by using something with so many dependencies you're adding to your workload when you could instead be spending time shipping, dancing, playing with your kids, whatever. You thought you were saving time by using a dependency but if it's got so many dependencies than you're not saving time if you compare to a lower or simple no dependency option because you will be forever dealing with the issues of those dependencies.
Here's the dependency tree for deps-ok which is much more reasonable.
└─┬ deps-ok@1.4.1
├── check-more-types@2.24.0
├─┬ debug@3.1.0
│ └── ms@2.0.0
├── lazy-ass@1.6.0
├── lodash@4.17.10
├── minimist@1.2.0
├─┬ q@2.0.3
│ ├── asap@2.0.6
│ ├── pop-iterate@1.0.1
│ └── weak-map@1.0.5
├── quote@0.4.0
└── semver@5.5.0
But it still manages to demonstrate the problem with dependencies
❯ npm audit
=== npm audit security report ===
┌──────────────────────────────────────────────────────────────────────────────┐
│ Manual Review │
│ Some vulnerabilities require your attention to resolve │
│ │
│ Visit https://go.npm.me/audit-guide for additional guidance │
└──────────────────────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High │ Prototype Pollution │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in │ >=4.17.11 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ deps-ok │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ deps-ok > lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/782 │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High │ Prototype Pollution │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in │ >=4.17.12 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ deps-ok │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ deps-ok > lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/1065 │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low │ Prototype Pollution │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in │ >=4.17.19 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ deps-ok │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ deps-ok > lodash │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/1523 │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low │ Prototype Pollution │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package │ minimist │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in │ >=0.2.1 <1.0.0 || >=1.2.3 │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ deps-ok │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path │ deps-ok > minimist │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info │ https://npmjs.com/advisories/1179 │
└───────────────┴──────────────────────────────────────────────────────────────┘
found 4 vulnerabilities (2 low, 2 high) in 13 scanned packages
4 vulnerabilities require manual review. See the full report for details.
Now of course maybe you don't care about those vulnerabilities because this script is only used during building but now you have a new problem that any real vulnerabilities will be buried in these ones you don't care about.
I have no idea how robust or comprehensive the solution above is. The good thing is it relies on npm so whatever npm install is going to do it's doing that exact thing.
来源:https://stackoverflow.com/questions/22915698/how-to-easily-verify-correct-npm-dependencies-installed