头图

The Angular application generated by ng new app comes with 11 dependencies:

Customer Storefront with library installed using Schematics:

Create a new empty folder locally and execute the command line in it: npm i @spartacus/storefront

There is only one node_modules folder, which contains many js files and TypeScript .d.ts files:

In the package.json of @Spartacus/storefront, there is still only one tslib dependency:

But peerDependencies contains a lot of dependencies defined in the Spartacus project source code package.json:

 "peerDependencies": {
    "@angular/common": "^12.0.5",
    "@angular/core": "^12.0.5",
    "@angular/forms": "^12.0.5",
    "@angular/platform-browser": "^12.0.5",
    "@angular/router": "^12.0.5",
    "@angular/service-worker": "^12.0.5",
    "@ng-bootstrap/ng-bootstrap": "^10.0.0",
    "@ng-select/ng-select": "^7.0.1",
    "@ngrx/effects": "^12.1.0",
    "@ngrx/router-store": "^12.1.0",
    "@ngrx/store": "^12.1.0",
    "@spartacus/core": "4.3.1",
    "ngx-infinite-scroll": "^8.0.0",
    "rxjs": "^6.6.0"
  },

npm handles sub-dependencies nicely: if my package depends on request version 2 and other libraries, but other libraries depend on request version 1, the resulting dependency graph looks like this:

This is usually great: now some-other-library has its own v1 copy of requests, and it can use it without interfering with my v2 copy of the package.

However, there is one use case that fails: plugins. A plugin package is designed to work with another host package, even if it doesn't always use the host package directly. There are already many examples of this pattern in the Node.js package ecosystem:

  • Grunt plugins
  • Chai plugins
  • LevelUP plugins
  • Express middleware
  • Winston transports

Essentially, plugins are designed to work with host packages. But more importantly, they are designed to work with a specific version of the host package. For example, versions 1.x and 2.x of my chai-as-promised plugin are for chai version 0.5, and version 3.x is for chai 1.x. Another example is grunt. Version 0.3.1 of grunt-contrib-stylus works with grunt 0.4.0rc4, but breaks when used with grunt 0.4.0rc5 due to the removed API.

Assuming that the plugin explicitly declares the version number of the host package, even for plugins that do have this direct dependency, possibly due to the utility API provided by the host package, specifying the dependency in the plugin's package.json will result in a dependency The tree contains multiple copies of the host package. For example, suppose winston-mail 0.2.3 has winston: 0.5.x specified in its dependencies, since this is the latest version against which it was tested.

As an application developer, using the latest version 0.6 of winston, put these in package.json:

Once run npm install , two different versions of winston are produced:

The solution to this problem is peerDependencies .

peerDependencies are very simple to use. When writing a plugin, please determine the version of the host package of peerDependencies and add it to package.json:

 {
  "name": "chai-as-promised",
  "peerDependencies": {
    "chai": "1.x"
  }
}

Now, when chai-as-promised is installed, the chai package will be installed with it.

If you later try to install another Chai plugin that only works with 0.x versions of Chai, you will get an error.


注销
1k 声望1.6k 粉丝

invalid