What is a lernaJs
LernaJs is a multi-package management tool developed by the Babel team. Because Babel contains many sub-packages, which used to be stored in multiple repositories, it is difficult to manage, especially when there is a call to the system package, which is difficult to publish. So in order to manage packages better and faster,Babel introduced lernaJs, which uses monorepo concepts. Now React,Babel,Angular, and Jest all use this tool to manage packages.
Lerna official website: lerna.js.org/ Lerna Warehouse: github.com/lerna/lerna…
What is a monorepo?
Monorepo is compared to multi-package. Multi-package is the creation of multiple repositories, one for each package. Monorepo creates a repository where multiple packages are managed, which has two benefits:
- The communication between various packages is more convenient. For multi-package, if one of the packages in the system is modified, the version needs to be issued separately, and other packages referencing this package need to be issued. With Lerna you can automatically manage the release of these packages, which is very convenient
- Some common configurations, such as ESLint, Babel,rollup, etc., manage these development configurations uniformly
How to set up the environment
Install and initialize the LERNA project
Install lernajs
npm install lerna -g
Copy the code
Initialize the lernaJs project
lerna init
Copy the code
After execution, a MonorePO managed by Lerna is automatically generated. Its file structure is as follows:
Package. json // Lerna JS configuration fileCopy the code
Add child package
After the environment is initialized, you need to add a subpackage first. The command to add a subpackage is as follows:
lerna create <pkgName>
Copy the code
After executing this command, the package will ask the same questions about the package name, version and so on as NPM init. After filling in these questions, the package will automatically create a subpackage. The default directory structure for subpackages is as follows:
<packName> __tests__ // Test file lib // The entry file for the package is in the package.json readme.md directory by defaultCopy the code
How do I add dependencies to subpackages
The command to add a dependency is:
Lerna add <moduleName> --scope = <pkgName> --scope = <pkgName2> // Add pkgName1 to pkgName2. Cross-references within packages copy pkgName1 to pkgName2Copy the code
All subpackages update dependencies
lerna bootstrap
Copy the code
How to package
Since only pure JS files need to be packaged, I chose rollup here, and the configuration idea of WebPack is the same. Let’s talk about what we want to achieve.
- The SRC /index.js file for each subpackage is the entry file for the source code
- Lib /index.js for each subpackage is the packaged file and the entry point to which the package is referenced
- The configuration of each subpackage is basically the same, such as with Babel transformation, which compresses the code
- NPM run Build packName Packs the specified package
- NPM run dev packName Develops the specified package
Start by creating a script directory in the root directory that contains configuration files for development and packaging. Then create a build.js file under script to configure rollup. In build.js, the rollup javascript API is used. Rollup configurations can be found on the rollup website at www.rollupjs.org
Execute the following command to install the necessary packages:
npm i rollup rollup-plugin-babel rollup-plugin-commonjs rollup-plugin-terser --save-dev
Copy the code
The main code for build.js is as follows:
const rollup = require('rollup'); Rollup const terser =require('rollup-plugin-terser').terser // plugin for compressed code const commonjs = require('rollup-plugin-commonjs'Const Babel = require(const Babel = require(const Babel = require(const Babel = require('rollup-plugin-babel'Argv [2] const args = process.argv[2] const projectPath = `./packages/${args}Const inputOptions = {input: 'const inputOptions = {input:'${projectPath}/ SRC /index.js', plugins: [Babel ({// Babel file Settings, babel.config.js file Settings, runtimeHelpers:true,
exclude: 'node_modules/**'}), commonjs(), terser() ] }; // Const outputOptions = {file: '${projectPath}/lib/index.js`,
format: 'esm', // The output mode is es6 mode name: '${args}'// output a reference name called package}; asyncfunction build() { // create a bundle const bundle = await rollup.rollup(inputOptions); // inputOptions is placed here console.log(bundle.watchfiles); // an array of file names this bundle depends on await bundle.write(outputOptions); } build();Copy the code
After editing the file, add commands under scripts of package.json to execute the build file
"scripts": {
"build": "node script/build.js",}Copy the code
How to test
The test uses Facebook’s JEST framework, and has the following requirements for the test:
- NPM Run test packName Runs all tests under this subpackage
- NPM run test packName testFileName Because each subpackage contains multiple test files, this command is used to run the test files in the subpackage
As with rollup configuration above, jest’s javascript API is required. Add the test.js file under script
Const rawArgs = process.argv[2] // Get the package name consttestFile = process.argv[3]|| ' '// get test filename const path = require('path')
let rootDir = path.resolve(__dirname, '.. / ')
rootDir = rootDir + '\\packages\\'Const jestArgs = [const jestArgs = [const jestArgs = ['--runInBand'.'--rootDir', rootDir, // Incoming package pathtestFile? `${testFile}.spec.js`:' 'Console. log(' \n===> RUNNING: jest${jestArgs.join(' ')}`)
require('jest'). The run (jestArgs) / / executionCopy the code
Then add the following script to package.json:
"scripts": {
"test": "node script/test.js"
}
Copy the code
Add ESLint and CommitLint
Adding ESLint and COMMITLint is easier here, but because of the Monorepo structure, it is good to do the ESLint and COMMITLint configuration once, and all subpackages will use this configuration.
How to publish
The order issued was
lerna publish
Copy the code
You can set rules for version numbers in lerna.json
// lerna.json
"version": "0.0.3"// If it is a number, all subpackages are of this version. Set to 'independent' to manage the version of each package independentlyCopy the code
Lernajs compares package changes and automatically publishes the subpackages that need to be published.
Automatically adds CHANGELOG
Add the following Settings to lerna.json:
// lerna.json
"command": {
"publish": {
"conventionalCommits": true}}Copy the code
This will automatically add CHANGELOG at release time
conclusion
This allows us to implement the structure of a multi-package Monorepo, each of which can be developed, packaged, and tested by command. The configuration of ESLint, Babel, and Jest is the same for all subpackages. You can easily issue a command, update a command and add dependencies.
Final file structure
docs
|---README.md
packages
|---packageOne
|---packageTwo
.
.
.
script
|---build.js
|---test.js
.commitlintrc.js
.eslintignore
.eslintrc
.gitignore
babel.config.js
lerna.json
package.json
Copy the code
Using the command
Commands about packages
Create a new package:
lerna creat <packname>
Copy the code
release
lerna publish
Copy the code
All packages update node_modules
lerna bootstrap
Copy the code
Add package B to package A
lerna add pack-B --scope = pack-A
Copy the code
Commands about development
Build one of the packages:
npm run build <packname>
Copy the code
Test one of the packages
npm run test <packname>
Copy the code
Develop one of the packages
npm run dev <packname>
Copy the code