The body of the

Is NPM different from YARN? After writing a small composition, a little surprised everyone’s desire for knowledge degree; It also reveals that you still don’t understand a lot of things. Here we will continue to make a specific update based on the previous questions.

First of all, I might write in a long-winded manner, or I might have been rejected so many times recently that I had to pick up my pen again to make up for everyone’s previous enthusiasm.

Why lockFiles? Do you want to submit lockfiles to the warehouse?

As we already know, NPM adds package-lock.json files starting with V5. So what does package-lock.json do? Locking the dependent setup structure ensures that on any machine we run NPM install we get exactly the same node_modules setup result.

I actually have a question here, right? Why can’t a single package.json determine a unique dependency tree?

  • The first is that different versions of NPM installation may depend on different policies and algorithms
  • npm installBased on thepackage.jsonIn thesemver-range versionUpdate dependencies, some of which may have been released in new versions since the last installation.

Therefore, ensuring complete and accurate restoration of project dependencies is where lockFiles come in.

First, we need to understand the mechanism of package-lock.json. Here’s an example:

"@ Babel/core" : {" version ":" 7.2.0 ", "integrity" : "sha1 - pN04FJAZmOkzQPAIbphn/voWOto =", "dev" : true, "requires" : {"@babel/code-frame": "^7.0.0", //... }, "dependencies" : {" @ Babel/generator ": {" version" : "7.2.0", "resolved" : "Http://www.npm.com/@babel%2fgenerator/-/generator-7.2.0.tgz" and "integrity", "sha1-6 voch6awhz1k74jmpuvmgbc7oww =", "dev" : True, "requires" : {" @ Babel/types ":" ^ 7.2.0 ", "jsesc" : "^ 2.5.1", "lodash" : "^ 4.17.10", "the source - the map" : "^0.5.0", "trim-right": "^1.0.1"}}, //... }}, / /... }Copy the code

Json dependency a package-lock.json dependency consists of the following components:

  • Version: indicates the Version number of the dependent package
  • Resolved: Resolved package installation source
  • Intergrity: Hash value indicating integrity
  • Dev: indicates whether the module is a development dependency of a top-level module or a transitive dependency
  • Requires: Requires all dependencies required by the package, corresponding to the dependencies in the package.json package
  • Dependencices Package for node_modeles (exists only in special cases)

In fact, not all child dependencies have a dependencies property. They only have dependencies that conflict with those currently installed in node_modules in the root directory. This may involve dependency management for nested cases, so let’s find some information.

As for whether we should submit lockfiles to the warehouse? This depends on the positioning of our specific projects.

  • If you are developing an application, my understanding is that the package-lock.json file is submitted to the code repository. This ensures that project members, o&M deployment members, or CI systems will get exactly the same dependent installation content on different nodes after NPM install is executed

  • If your goal is to develop a library for external use, you need to be careful because library files are typically dependent on other projects. Without using package-lock.json, you can reuse packages already loaded by the main project, reducing dependency duplication and volume

  • If we develop a library that relies on a module with an exact version number, we may have the same dependency downloaded by different versions when we commit lockfiles to the repository. If we, as library developers, actually use a specific version-dependent requirement, it is a better choice to define peerDependencies.

So, one of the things I personally recommend is to commit package-lock.json to the repository without ignore. But when NPM publish is executed, when a library is published, it should be ignored and should not be published.

Of course, I have learned that the processing of lockfiles may require a more fine-grained understanding, and I would recommend you to combine the above understanding.

  1. The way to lock versions used earlier in NPM was to use npm-shrinkwrap. Json, which is different from package-lock.json we mentioned earlier: NPM packages are published with nPM-shrinkwrap. Json by default, so libraries and components need to be careful.

  2. The use of package-lock.json was a new feature in NPM V5.x and stabilized after NPM V5.6. Between 5.0-5.6, The package-lock.json processing logic has been updated several times.

  3. In NPM V5.0.x, NPM will download from package-lock.json regardless of the contents of your package.json file.

  4. NPM install ignores package-lock.json file downloaded from NPM v5.1.0 to NPM v5.4.2, and will download the latest package and update package-lock.json.

  5. After NPM 5.4.2, we will continue to detail the analysis:

    • If in our actual development of the project, onlypackage.jsonA file,npm installAfter that, one will be generated from itpackage-lock.jsonfile
    • If it exists in the projectpackage.jsonpackage-lock.jsonFile, at the same timepackage.jsonsemver-rangeVersion andpackage-lock.jsonEven if a new version is available,npm installOr will it be based onpackage-lock.jsonDownload the
    • If it exists in the projectpackage.jsonpackage-lock.jsonFile, at the same timepackage.jsonsemver-rangeVersion andpackage-lock.jsonIncompatible with the Chinese version,npm installthepackage-lock.jsonUpdate to compatiblepackage.jsonVersion.
    • ifpackage-lock.jsonnpm-shrinkwrap.jsonExists in the root directory of the project,package-lock.jsonWill be ignored.

For the above process analysis, I made a process flow chart analysis in the previous article, you can combine the above to make a more detailed understanding

So, moving on to the next question, whether we are using NPM or YARN, we may install package dependencies into different dependency modules. Have you ever wondered why you do this? What does this have to do with our future development and release?

Why do you have xxxDependencies?

Instead, NPM designs the following dependency type declarations:

  • Dependencies
  • DevDependencies Develops dependencies
  • PeerDependencies Dependencies of the same version
  • BundledDependencies Bundle dependencies
  • OptionalDependencies Optional Dependency

They have different functions and declarative meanings. Let’s give a specific introduction:

Dependencies represent project dependencies, which become part of the code in your online production environment. When associated with the NPM package, the module under Dependencies is also downloaded as a dependency.

DevDependencies means development dependencies, which are not automatically downloaded. DevDependencies are usually useful in the development phase or only in the development environment. For example, we use Webpack, preprocessor Babel-Loader, SCSS-Loader, test tool E2E, etc., which are quite auxiliary toolkits and do not need to be used in the production environment.

One thing I need to mention here is that dependencies in devDependencies are not packaged together. In fact, whether or not a dependency is packaged depends entirely on whether or not the module is introduced in your project.

If you already install peerDependencies, you should install my dependencies as well. Here’s a quick example: We need to develop a React UI component library based on React. It will need a host environment to run it. The host environment also needs the specified React version to be used with it, so we need to configure it in package.json:

"PeerDependencies ": {"React": "^17.0.0"}Copy the code

BundledDependencies is related to the NPM pack packing command. Suppose we have the following configuration in package.json:

{" name ":" test ", "version" : "1.0.0", "dependencies" : {" dep ":" ^ hundreds ",... }, "devDependencies": { ... "BundledDependencies ": ["bundledDependencies", "bundledDependencies", "bundledDependencies", "bundledDependencies", "bundledDependencies"Copy the code

When we execute NPM pack, we will generate a test-1.0.0. TGZ package, in this package also contains bundleD1 and bundleD2 installation packages. When you actually use this package

BundleD1 and bundleD2 will also be installed when NPM installs test-1.0.0. TGZ.

The dependencies specified in bundledDependencies must be declared in Dependencies and devDependencies, otherwise the NPM pack phase will fail.

OptionalDependencies are optionalDependencies. If you install a dependency and it fails, it does not affect the installation process. It is rarely used, and I do not recommend it, as it may add uncertainty and complexity to the project.

By now, are you familiar with the implications of dependency declarations in the NPM specification? Next I’d like to talk about versioning specifications and take a look at the behavior of resolving versions that depend on library locks.

Versioning specification – depends on library lock versioning behavior resolution

First of all, NPM follows the SemVer version specification, as for the specific content of the link for you to learn the semantic version I will not go to the verbose. We will focus on one detail: the behavior of dependent library lock versions —-.

Vue officially reads:

When a new version of each VUE package is released, a corresponding version of vue-template-Compiler is also released. The version of the compiler must be synchronized with the base VUE package so that vue-Loader generates run-time compatible code. This means that every time you upgrade the VUE package in your project, you should also upgrade the VUe-template-Compiler.

With that in mind, what we as library developers need to consider is: how do we ensure mandatory minimum version requirements between dependencies?

In create-react-app’s core react-script, it uses the verifyPackageTree method. A series of comparisons and constrains on dependencies in business projects. We can take a look at the source code:

function verifyPackageTree() { const depsToCheck = [ 'babel-eslint', 'babel-jest', 'babel-loader', 'eslint', 'jest', 'webpack', 'webpack-dev-server', ]; const getSemverRegex = () => /\bv? (? :0|[1-9]\d*)\.(? :0|[1-9]\d*)\.(? :0|[1-9]\d*)(? :-[\da-z-]+(? :\.[\da-z-]+)*)? (? :\+[\da-z-]+(? :\.[\da-z-]+)*)? \b/gi; const ownPackageJson = require('.. /.. /package.json'); const expectedVersionsByDep = {}; depsToCheck.forEach(dep => { const expectedVersion = ownPackageJson.dependencies[dep]; if (! expectedVersion) { throw new Error('This dependency list is outdated, fix it.'); } if (! getSemverRegex().test(expectedVersion)) { throw new Error( `The ${dep} package should be pinned, instead got version ${expectedVersion}.` ); } expectedVersionsByDep[dep] = expectedVersion; }); let currentDir = __dirname; while (true) { const previousDir = currentDir; currentDir = path.resolve(currentDir, '.. '); if (currentDir === previousDir) { // We've reached the root. break; } const maybeNodeModules = path.resolve(currentDir, 'node_modules'); if (! fs.existsSync(maybeNodeModules)) { continue; } depsToCheck.forEach(dep => { const maybeDep = path.resolve(maybeNodeModules, dep); if (! fs.existsSync(maybeDep)) { return; } const maybeDepPackageJson = path.resolve(maybeDep, 'package.json'); if (! fs.existsSync(maybeDepPackageJson)) { return; } const depPackageJson = JSON.parse( fs.readFileSync(maybeDepPackageJson, 'utf8') ); const expectedVersion = expectedVersionsByDep[dep]; if (! semver.satisfies(depPackageJson.version, expectedVersion)) { console.error(//...) ; process.exit(1); }}); }}Copy the code

In fact, when WE look at this piece of code, Creation-react-app retrieves all core dependencies in the project, including babel-esLint, babel-jest, babel-loader, esLint, jest, webpack, and webpack-dev-server Does create-React-app comply with the version requirements that depend on these core modules? The create-react-app build will exit if it does not meet the dependency requirements.

So why does create-React-app do this?

Some definitive version of the above dependencies is needed to ensure that create-React-app source-related functionality is stable

Do not know you for such a kind of processing way can have some thoughts?

So I’d like to share some of my own suggestions for NPM practices, so that the big guys can discuss whether or not this is possible

Probably the best practical advice

Below I will give specific practical suggestions for your reference:

  1. Priority should be given to using official, stable and supported versions of NPM to ensure the most basic progressiveness and stability of NPM

  2. When our project was first set up, we used NPM install to install the dependencies and commit package.json and package-lock.json, without submitting the node_moduled directory.

  3. When we were new to the project, when we were checkout/ Clone, we performed an NPM install to install the dependencies.

  4. When we have a requirement to upgrade dependencies:

    • When upgrading minor versions, rely on NPM update
    • To upgrade a larger version, rely on ** NPM install@ **
    • There is also a way to directly change the version number in ** package.json** and run NPM install to upgrade the version
    • Json and **package-lock.json ** files are submitted after we confirm that there is no problem with the new version of the local upgrade.
  5. The need for degraded dependencies: we need to submit new package.json and package-lock.json files after we run the NPM install@ command and verify that there are no problems.

  6. When deleting some dependencies:

    • When we execute the NPM uninstall command, we need to verify and submit the new package.json and package-lock.json files.
    • Or a little more violent, direct operationpackage.jsonTo delete the dependency, runnpm installCommand, need to validate, submit a newpackage.jsonpackage-lock.jsonFile.
  7. When you commit the updated package.json and package-lock.json to the repository, you need to notify your team members to ensure that when other team members pull the code, the updated dependencies will have a more friendly development environment for continuous development work.

  8. At no time should we modify package-lock.json, it is an IQ tax.

  9. If you have a package-lock.json conflict or problem, my recommendation is to delete the local package-lock.json file and go to the remote package.json and package-lock.json files that do not conflict. Then run the NPM install command.

Here I want to say goodbye to everyone, I hope you have a happy weekend, if there is any opportunity to recommend me can leave a message, thank you big guy.