preface

As a front-end developer, the importance of NPM as a package management tool is obvious. The advantages are not stated, but some of the disadvantages are complained about more by users: slow speed, version control. The following focuses on NPM version hardening issues, namely lock files.

NPM semantic versioning

For NPM, information about dependencies is given in package.json in Dependencies, which uses Semver’s specification for semantic versioning. The general criteria are as follows:

  • The software version consists of three characters, such as X.Y.Z
  • The version is strictly incremental, here: 16.2.0 -> 16.3.0 -> 16.3.1
  • Alpha, RC, and other prior releases are available for major releases
  • Modified versions such as alpha and RC can be followed by the number of times and meta information

Version format:

Publishers should focus on the rules of version formatting

Major version. Minor version. Revision numberCopy the code

The increment rules for different version numbers are as follows:

  • Major: When you make incompatible API changes,
  • Minor: When you make a backward-compatible Feature addition, which can be interpreted as a Feature version,
  • Patch: When you make a backward-compatible issue fix, it can be understood as a Bug fix version.

The dependent versions in package.json are required to follow the above rules. This ensures that the user leads to the desired version.

Version control character

For the consumer, the control character in front of the version is of concern to determine whether the reference dependency is the same as expected. NPM supports a variety of symbols. The following symbols are supported:

< span style = "box-sizing: border-box; color: RGB (0, 0, 0); line-height: 21px; font-size: 14px! Important; word-break: inherit! Important;" "> = 1.0.2 < 2.1.2", / / clearer Left closed right away "baz" : "> 1.0.2 < = 2.3.4", / / the left on the right off "boo" : "2.0.1", / / version "qux" : "< 1.0.0 | | > = 2.3.1 < 2.4.5 | | > = 2.5.2 < 3.0.0", / / expression is clear "asd" : "http://asdf.com/asdf.tar.gz" / / specified download address instead of version, the "til" : ^ "1.2.3" / / the same major version number, no less than 1.2.3 namely 1. X.y > = 2 x > y = 3, "elf" : "~ 1.2.3" / / the same major version and the version number The 1.2 x x > = 2, "two" : "2 x" / / this is image, x > = 0 2.0.0 above, namely "THR" : "3.3 x" / / same as above x > = 0 3.3.0 above, namely "lat" : / / the latest version of the "latest", "dyl" : "file:.. }}Copy the code

According to the notes above, you should be able to see what the different symbols mean. Here is an article that vividly illustrates the range of different symbols. If you are interested, you can read it in detail

NPM install uses ^ by default

The purpose of this is to accept updates to the specified version, such as optimizations of dependent packages and minor version updates.

The problem

Different environments have different dependencies

As you can see from the above, semantic versions are non-binding and require developers to follow the specification. Common situations are as follows:

After the completion of the test environment, the launch problem is caused by a dependent version released incompatible or buggy version before the launch, just before the release of the new version.

Hence the need for the following hardened version, or locked version.

The cured version ensures the same dependence for different environments or times of installation. Whether they should all be cured is discussed below.

Cured version mode

Fixed-line version, available in the following three ways:

npm-shrinkwrap.json

Json is similar to package-lock.json. The difference is that the NPM package can be published when it is released.

The recommended use is for applications that are deployed through the publishing process on the repository, that is, not libraries or utility classes. For example, emons and command line tools that want to be installed or relied on globally are strongly discouraged from publishing this file sitting down, as it would prevent the end user from controlling the update of the delivered dependencies.

Package-lock. json will be ignored if both package-lock.json and NPM-shrinkwrap.

That is, this approach will lock version dependent distribution through NPM, so libraries or components need to be careful.

Usage:

Dev dependencies are not included by default
npm shrinkwrap
// Count dev-dependencies
npm shrinkwrap--dev 
Copy the code

package-lock.json

In contrast to NPM-ShrinkWrap, it is not published to NPM and applies to applications, that is, our projects that are not utility classes.

Npm5 dependencies will add this file by default, but with so many iterations, different versions of NPM will implement package-lock.json differently. It’s iterative and evolving

1, NPM 5.0.x, no matter how package.json changes, NPM I will download according to the lock file.

After 5.1.0, NPM install will ignore the lock file to download the latest NPM package

If package.json is changed and the package.json file is different from lock file, then NPM will download the latest package according to the version number and semantic meaning in package and update it to Lock when executing NPM I. If the two are in the same state, then NPM I is downloaded according to lock, regardless of whether the actual package version is new. The segment content reference self-knowledge by users, please turn to https://www.zhihu.com/question/264560841 for details

This brings up the problem that different environments have different versions of NPM, and dependencies may still be different for the same project…

Nonflat dependence

Npmlock does not completely flatten the management of different versions of the same NPM package: all package dependencies are listed in order, the first occurrence of the package name will be promoted to the top layer, and subsequent repeats will be promoted to the node_modules of the dependent package, such as the following example: the first dependency, promoted to the top layer

Loader-utils dependencies are declared on the top layer at version 1.0.4
  "loader-utils": {
      "version": "1.0.4"."resolved": "http://r.npm.sankuai.com/loader-utils/download/loader-utils-1.0.4.tgz"."integrity": "sha1-E/Vhl/FSOjBYkSSLTHJEVAhIQmw="."requires": {
        "big.js": "^ 3.1.3"."emojis-list": "^ 2.0.0." "."json5": "^ 0.5.0"}}}Copy the code

For top-level dependencies that meet the requirements,

"sass-loader": {
      "version": "7.1.0"."resolved": "http://r.npm.sankuai.com/sass-loader/download/sass-loader-7.1.0.tgz"."integrity": "sha1-Fv1ROMuLQkv4p1lSihly1yqtBp0="."dev": true."requires": {
         // ^1.0.1 Top-level dependencies meet requirements
        "loader-utils": "^" 1.0.1}}Copy the code

For some dependencies that are not met, the corresponding version will be installed under the corresponding folder based on the dependencies. For example, less – loader

"less-loader": {
      "version": "4.1.0."."resolved": "http://r.npm.sankuai.com/less-loader/download/less-loader-4.1.0.tgz"."requires": {
        // 1.0.4 does not meet ^1.1.0
        "loader-utils": "^ 1.1.0." ",},"dependencies": {
        "loader-utils": {
          "version": "1.2.3"."resolved": "http://r.npm.sankuai.com/loader-utils/download/loader-utils-1.2.3.tgz"."integrity": "sha1-H/XcaRHJ8KBiUxpMBLYJQGEIwsc="."dev": true."requires": {
            "big.js": "^ 5.2.2." "."emojis-list": "^ 2.0.0." "."json5": "^" 1.0.1}}}}Copy the code

Package-lock. json vs. NPM-shrinkwrap. Json

  • Package-lock. json is not published to NPM, while nPm-shrinkwrap is published by default
  • Non-top-level package-lock.json files are ignored, while shrinkwrap files in the same state are kept.
  • Npm-shrinkwrap. Json is supported in NPM 2,3, and 4. Package-lock. json was introduced in NPM5
  • Npm-shrinkwrap. Json takes precedence over package-lock.json

yarn.lcok

After all, YARN is designed for the disadvantages of NPM, so it has version control. By default, yarn.lock file is generated, which is determined by package name and version.

Yarn – lock syntax

Yarn uses its own format, which is syntax-like YAML (Yarn 2.0 will use standard YAML). The line starting with # is a comment.

The first line records the name of the package and its semantic version (defined by package.json).

Everything that follows is indented to indicate that this is the information for the package.

The Version field records the exact version of the package.

The Resolved field records the URL of the package. Additionally, the value in the hash is shasum. Yarn records the shasum from package versions of [: version]. Dist. Shasum (manual access registry.npmjs.org/:package will get a JSON, parsing the JSON available)

Dependencies records the dependencies of a package. Perhaps package dependencies and dependencies are not documented here. As follows:

pkg-dir@^1.0. 0:
  version "1.0.0"
  resolved "http://r.npm.sankuai.com/pkg-dir/download/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
  integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q=
  dependencies:
    find-up "^ 1.0.0"

pkg-dir@^2.0. 0:
  version "2.0.0"
  resolved "http://r.npm.sankuai.com/pkg-dir/download/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
  integrity sha19 -tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
  dependencies:
    find-up "^ 2.1.0." "

pkg-dir@^3.0. 0:
  version "3.0.0"
  resolved "http://r.npm.sankuai.com/pkg-dir/download/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
  integrity sha1-J0kCDyOe2ZCIGx9xIQ1R62UjvqM=
  dependencies:
    find-up "^ 3.0.0"
Copy the code

Yarn, however, describes the dependencies between packages only in flatten format and relies on its current implementation to create a directory structure. This means that if its internal algorithms change, so does its structure.

As you improve, you will find that there are many packages that you do not rely on directly, but they all appear at the top level in yarn.lock. This is ascension, and it has two meanings:

  • Recording dependency Dependencies As mentioned above, dependency dependencies are not recorded directly under the dependency information — they are promoted to simplify the whole yarn.lock process, which makes installing dependencies easier because you don’t have to nest layer by layer to find dependency information.

  • Dependency version conflicts are inevitable, of course, sometimes not version conflicts, but just different version records in semantic version formats. For example, ^5.0.0 and 5.x.x do not contradict each other in many cases, so information can be merged. Such as:

chalk@^2.0. 0, chalk@^2.01.:
  version "2.3.2"
  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65"
  dependencies:
    ansi-styles "^ 3.2.1." "
    escape-string-regexp "^ 1.0.5." "
    supports-color "^ 5.3.0." "
Copy the code

Note that yarn.lock records ^2.0.0 and ^2.0.1, while adding the dependency on chalk, the latest version that conforms to the semantic version is 2.3.2 (version field). This version is for ^2.0.0 and ^2.0.1, So the information can be merged.

Yran. lock is still recommended for curing, NPM lock in different versions of the difference is a headache.

Whether the version should be locked

This debate is very normal, and we had this discussion when we started using it. You can take a look at our scenario and discuss:

1. All the projects in the group rely on a toolkit developed by themselves

2. The utility class relies on some third-party open source packages

Scenario 1: After the upgrade of a well-known package, the support of a certain function was removed, which was depended on by A, resulting in problems for all projects launched after this period of time.

Scenario 2: A finds a bug and fixes it in a unified manner. Each business item does not need to modify it by itself.

Combined with the specific analysis, for self-maintenance or confirmed projects can not lock the version. For third parties that need to lock the version, ensure that it is currently available. For later bug fixes, do not upgrade by yourself. For minor version upgrades such as Bugfix, lock the version again after verification.

.gitignore whether lock files should be ignored

Package-lock. json should not be written to.gitignore. If you use lock, you should commit package-lock.json to the repO. For example, Vue adopts this strategy. If you don’t use lock, you should add a.npmrc file with package-lock=false and submit it to the REPO. For example, ESLint adopts this policy.

Which brings us back to the question of whether the version should be locked. Locking dependent versions is definitely not an option for libraries. Otherwise, as long as the application uses more than two dependencies, there is a chance that there is absolutely no compatible version. This simply throws the problem at the end application, but does not solve the problem. The ultimate application of locking is also open to consideration.

The problem is that the reliability of the source code is not guaranteed, and there is no problem with semantics itself. But the bug is fine, so the business items are locked

conclusion

Refer to the article

Docs.npmjs.com/files/packa…

Juejin. Cn/post / 684490… Stackoverflow.com/questions/4…

I also give my opinion on whether and how to cure the version, because the level is limited. I hope it can help students in need.