What is monorepo
Simply put, a Git repository manages all the code in a scope
Why monorepo
- Source transparency
- Cascading publishing (e.g. Babel)
- Code reuse
- Configuration reuse (hoist to superlayer, subproject inheritance)
- Mandatory communication (e.g., public libraries only provide the latest version, library developers and users are more closely connected)
- .
rush
Rush official documentation
Simply put, rush provides the ability to manage large warehouses such as monorepo
Rush also supports low-level package management using PNPM, addressing issues like Phantom Dependency and NPM Doppelgangers
Basic use of rush
rush init
Initialize the project as rush management
Rush update (executed in the rush.json directory or any of its subdirectories)
- Common update/config
- Check package.json for all projects and compare the common Shrinkwrap file with the repository to see if it is valid, and update the shrinkwrap file if it has expired
- All dependencies are installed into common/temp/node_modules
- Finally, Rush creates a node_modules directory for each project and creates a Symlinks soft chain to common/temp/node_modules
Rush Update may update the lockfile, and Rush Install will install by lockfile
Rush Update — Purge (Force reinstallation of dependencies instead of cache-based)
What are shrinkwrap files (e.g. Package-lock. json)
Resolve the dependency installation uncertainty by keeping a complete dependency installation plan in a large file managed by Git
rush add
Install dependencies
Rush add -p webpack --dev // -p specifies the package to install, which installs webpack as a subproject dev dependencyCopy the code
rushx
Equivalent to NPM run
Rush build (executed in the rush.json directory or any of its subdirectories)
Rush Build will execute builds in all project NPM scripts
PNPM fundamentals
Dependency files are uniformly promoted to the top level, using soft-linked dependency trees in node_modules in subprojects (see rush Update for dependency installation details above)
The correct dependency tree structure (as opposed to flat dependencies) ensures that dependencies are used safely (e.g., the libraries introduced in the project must be dependencies declared in package.json)
At the same time, the soft chain to the upper layer of the unified management of dependencies, can prevent the repeated installation of dependencies
Phantom dependency
Simply put, this means that the code can be loaded into dependent libraries that are not declared in package.json
For example, A depends on B and C, and BOTH B and C depend on D
Then NPM will rely on flattening to repeat D, that is, after installation, B, C, D are in the outermost layer of NODE_modules of A
D can now be directly relied on in A, even though D is not included in A’s package.json declaration
Specific problems with shadow dependency
- Incompatible versions
Let’s say our code depends on A and specifies it as ^3, and A depends on B
When our code is imported directly into B, the exact version of B will be unknown, because the version of B is completely controlled by the developer of A
Assuming that A has A patch upgrade, it still conforms to our specified version range. However, if THE version of B in A is specified as the upgrade version of the main version, it may lead to the incompatibility of B introduced in our code
- Depend on the lost
Suppose we are the developers of the library Lib, which has A dev dependency called A, and A depends on B
When we use B in our code and publish it, the dev dependency of lib will not be installed when the user installs lib, that is, the dev dependency of LIB will not be installed
At this point, our library has an exception due to the inability to introduce B
At the same time, due to the flat dependency, the user may implicitly install B when installing other libraries, so our library can still work normally without the dependency declaration of B
NPM doppelgangers
The four dependencies are A, B, C, and D. A and B depend on E@1, and C and D depend on E@2
The possible situation is that
- If E@1 is installed flat, E@2 is installed in node_modules for both C and D
- If E@2 is installed flat first, E@1 is installed in node_modules of both A and B
impact
- Repeated installation dependencies (affecting installation speed and disk space)
- Affect package volume (duplicate packages will be entered)
- May break the singleton pattern inside the tripartite library (there may be some logic in E that depends on singletons, while duplicate E dependencies may introduce separate instances)
- Ts Type Conflict
- .
Inter-project dependencies
< span style = “box-sizing: inherit! Important;
If the subproject APP depends on the subproject libs, it is in the package.json of the app
"dependencies": {
"libs": "workspace:*"
}
Copy the code
Build product dependency
Pre build libs
Rush build-t. // -t. Build all dependencies of the current subproject (excluding itself)Copy the code
Libs’ package.json has main pointing to the product entry
{
"main": "./dist/main.js"
}
Copy the code
When app introduces LIBS, it should be consistent with common tripartite library
Source code dependencies (two ways)
- The main field in package.json of libs specifies the package entry, which is directly imported by APP
The libs package. The json
{
"main": "./src/index.js"
}
Copy the code
The introduction of app
import * as libs from 'libs'
Copy the code
- I’m going to use the relative path
import * as libs from '.. /.. /libs/src'Copy the code