In business development, there is little need to pay attention to the structure of node_modules after NPM install/ YARN is executed, but at some point, not knowing the installation rules for node_modules can make writing code very smooth and building difficult.

For example, if your project is created based on create-react-app, to avoid build problems, the react-scripts build will check the version of the specified packages and exit the build if the verification fails.

You don’t know what’s going on, and you still don’t know how to get out of it, even after following the console’s 1, 2, 3, 4, 5 cues for the umpteenth time.

You need to understand the installation rules of the NPM package.

Npm3 before

Before NPM 3, the way of dealing with dependency packages was simple — only the direct dependency packages of app were installed in the top node_modules, and the dependency packages of dependency packages were installed in their respective node_modules in the order of their dependencies.

Such a tree structure is simple, clear, and as expected, but it is unfriendly to large projects, wastes space, and creates nested hell.

npm3

After NPM 3, node_modules is no longer nested, but installed flat first, meaning nesting still exists, just much less.

The installation package

We created A new small project, App, and our App depends on A, A depends on B. The dependency tree formed in NPM3 would look like this:

A month has passed, and we need to add A C to App for function requirements. However, the B version that C relies on is different from the B version that A relies on. How to install NPM3?

$ npm install C –save

Npm3 will install B 2.0 on node_modules where C already has a 1.0 B.

After another month, functionality iteration required, App now needs to add a D package, and coincidentally, D also relies on B 2.0 implementation

$ npm install D –save

The following structure is obtained:

We then installed E in the same way and, impressively, E relies on B 2.0. Now, our node_modules structure looks like this:

Our package.json might have a fragment like this:

{A: "1.0", C: "1.0", D: "1.0", E: "1.0"}Copy the code

Update package

We can’t wait to try out new features. We find that A 2.0 relies on B 2.0. What does NPM3 do when we run the install A command?

  • To delete A 1.0
  • Install A 2.0
  • Leave B 1.0 because E 1.0 is still dependent
  • Install B 2.0 under A 2.0 because there is already A B 1.0 at the top level

Newcomers to the

One day, a new member of the team came, and the new member cloned the App on his computer and executed it

$ npm install

Does the node_modules tree on the rookie machine have the same structure as my old one? Not the same.

Remember our package.json fragment?

{A: "2.0", C: "1.0", D: "1.0", E: "1.0"}Copy the code

If node_modules does not exist locally, A will be installed first after the install command is executed, so B 2.0 will directly occupy the top level and feel the sensation of being alone at the top.

So the new person gets a dependency tree like this:

The new guy is fresh and stylish.

The old man continues to upgrade

Two months later, E 2.0 is released, and E 2.0 also relies on B 2.0. What will nPM3 update E do?

  • Delete the E 1.0
  • Install E 2.0
  • Delete B 1.0
  • Install B 2.0 in the top-level node_modules, because there is no version of B in the top-level now

It’s terrible, I want to get rid of all the duplicate packages, because I’m running out of computer space, and I can execute

$ npm dedupe

The result is a clean, flat dependency structure:

Of course, I could pretend to be a new person, delete node_modules and reinstall all the packages in the order declared in package.json.

If you use YARN in your project, Yarn Install automatically deduplicates.

The VIP in the NPM bag

Eventually, our App will need to rely directly on B 3.0.

So where will B 3.0 be installed?

The answer is: top-level node_modules.

The direct dependence on B 3.0 is like the landlord holding the key to the top floor, evicting B 2.0 from the prime position when he needs it, forcing them to live separately in a small room with a narrow view.

conclusion

When installing nPM3 packages, remember two rules: dependency path first, dependency order second. That is, the packages directly dependent on the project are installed in the top layer first, regardless of the order; For packages that are not directly dependent on the project, the package installed first takes the top position.