directory
- background
- Monorepo management
- Monorepo advantage
- Monorepo disadvantage
- Lerna
- Install Lerna globally
- Initialize the project
- Create a Package
- Open the Workspace
- LernaScript
- CreateReactApp architecture
- packages/create-react-app
- The preparatory work
- Create package. Json
- Install dependencies
- Copy the template
- See the effect
- packages/cra-template
- packages/cra-template–typescript
- packages/react-scripts
- react-scripts build
- react-scripts start
- The react – scripts subtotal
- packages/react-dev-utils
- PnpWebpackPlugin
- ModuleScopePlugin
- InterpolateHtmlPlugin
- WatchMissingNodeModulesPlugin
- conclusion
background
The article was first published@careteen/create-react-app, please indicate the source.
Create React App is an officially supported scaffolding for creating Single-page React applications. It provides a modern configuration setting with zero configuration.
React is used in some projects in my daily work. Besides, I need to understand the implementation principle of scaffolding.
Before the template project scaffolding @careteen/ CLI, the implementation is relatively primitive. Lerna is used for subsequent reconstruction.
Let’s do some preparatory knowledge to understand.
Monorepo management
If you already know monorepo and lerna, you can move directly to the CreateReactApp architecture
Monorepo is a way to manage project code by managing multiple modules/packages in a project repository (REPO). Unlike the common practice of building a REPO for each module.
The Babel Packages directory holds multiple packages.
Monorepo advantage
The main benefit of Monorepo is unified workflow and code sharing.
For example, when I look at the source code for babel-CLI, which references other libraries, if instead of using Monorepo management, I create a new repository for @babel/core, I need to open another repository. It’s much easier to read someone else’s code if you view it directly in the current repository, or even modify it for local debugging.
import { buildExternalHelpers } from "@babel/core";
Copy the code
Most open source libraries currently use Monorepo for management, such as React, VUE-next, create-React -app.
Monorepo disadvantage
- It’s huge.
babel
All the relevant code is stored in the warehouse,clone
It also takes time to get there. - Not suitable for corporate projects. Each line of business repository code is basically independent, and if stacked together, the cost of understanding and maintaining it can be considerable.
Lerna
If you already know monorepo and lerna, you can move directly to the CreateReactApp architecture
Lerna is the Babel team’s best practice for Monorepo. NPM is a tool to manage multiple NPM modules, optimize the maintenance of multiple packages workflow, solve the problem of multiple packages depend on each other, and release the need to manually maintain multiple packages.
Go to Lerna to see the official documentation. Here’s a quick primer.
Install Lerna globally
$ npm i -g lerna
Copy the code
Initialize the project
$ mkdir lerna-example && cd The $_
$ lerna init
Copy the code
Generate project structure
| -- lerna. Json | -- package. Json ` - packages # temporarily as an empty folderCopy the code
Json file specifying the Packages working directory as all directories under Packages /*
{
"packages": [
"packages/*"]."version": "0.0.0"
}
Copy the code
Create a Package
#Hit the car.
$ lerna create create-react-app
$ lerna create react-scripts
$ lerna create cra-template
Copy the code
Three subprojects are generated under the Packages/directory
Open the Workspace
The default is NPM, and each subpackage has its own node_modules.
Added the following configuration to start workspace. The goal is to have the top layer manage node_modules uniformly and the subpackage does not.
// package.json
{
"private": true."workspaces": [
"packages/*"],}Copy the code
// lerna.json
{
"useWorkspaces": true."npmClient": "yarn"
}
Copy the code
Lerna Script
Head to Lerna to see the detailed use of each command
- lerna add
- lerna bootstrap
- lerna list
- lerna link
- lerna publish
lerna add
#grammar
$ lerna add <package>[@version] [--dev] [--exact] [--peer]
Copy the code
#The sample
#Install 'chalk' for all children 'package'
$ lerna add chalk
#Install 'commander' for 'create-react-app'
$ lerna add commander --scope=create-react-app
#If the installation fails, check for spelling errors or to see if subpackages have namespaces
$ lerna list
#Since my package has a namespace, I need to prefix it
$ lerna add commander --scope=@careteen/create-react-app
Copy the code
If you want to add uniform dependencies for all subpackages in the root directory, and only in the root directory package.josn, you can use YARN
yarn add chalk --ignore-workspace-root-check
Copy the code
You can also install dependencies for a subpackage in the root directory
#Subpackages have namespaces to add
yarn workspace create-react-app add commander
Copy the code
lerna bootstrap
The default value is NPM I. If yarn is specified, it is equivalent to YARN install
lerna list
List all packages
$ lerna list
Copy the code
Print the result
Info CLI using local version of lerna lerna notice CLI v3.22.1 @careteen/cra-template @careteen/create-react-app @careteen/react-scripts lerna success found 3 packagesCopy the code
lerna link
Establish a soft chain, equivalent to an NPM link
lerna publish
$ lerna publish Publish packages that have changed since the last release
$ lerna publish from-git Explicitly publish the package marked in the current commit
$ lerna publish from-package # explicitly publish packages that do not have the latest version in the registry
Copy the code
The first release reported an error
- why
Error: LerNA ERR! E402 You must sign up for private packages for lerna #1821
- The solution
Ensure that all local changes are git push and the NPM registry is set to registry.npmjs.org/ and you have logged in.
- Due to the
npm
Limit, need to be in firstpackage.json
Do the following Settings
"publishConfig": {
"access": "public"
},
Copy the code
- Then go to each sub-package through first
npm publish
Publish a
$ cd packages/create-react-app && npm publish --access=public
Copy the code
- Modify the code until the next release
lerna publish
, the following logs can be obtained
$ lerna publish# Select this option and press Enter Minor (0.1.0) Major (1.0.0) Prepatch (0.0.1-alpha.0) Preminor (0.1.0-alpha.0) Premajor (1.0.0-alpha.0) Custom Prerelease Custom Version? Select a new version (currently 0.0.0) Patch (0.0.1) Changes: -@careteen /cra-template: 0.0.1 => careteen/create-react-app: 0.0.1 => careteen/react-scripts: 0.0.1 => 0.0.1? Are you sure you want to publish these packages? (ynH) # Enter y and press Enter Successfully published: # Release success - @careteen/[email protected] - @careteen/[email protected] - @careteen/[email protected] Lerna success published 3 packagesCopy the code
If this process fails again and an error is reported, lerna ERR! Fatal: TAG ‘v0.0.1’ already exists. You need to remove the local and remote tags before publishing.
#Deleting a Local TagGit v0.0.1 tag - d#Deleting a Remote TagGit push origin: refs/tags/v0.0.1#redistribution
lerna publish
Copy the code
CreateReactApp architecture
packages/create-react-app
The preparatory work
Add the following configuration in the package.json file in the project root directory
"scripts": {
"create": "node ./packages/create-react-app/index.js"
}
Copy the code
Then add the following configuration in Packages /create-react-app/package.json
"main": "./index.js"."bin": {
"careteen-cra": "./index.js"
},
Copy the code
New packages/create-react-app/index.js file
#! /user/bin/env node
const { init } = require('./createReactApp')
init()
Copy the code
New packages/create-react-app/ createreactapp.js file
const chalk = require('chalk')
const { Command } = require('commander')
const packageJson = require('./package.json')
const init = async() = > {let appName;
new Command(packageJson.name)
.version(packageJson.version)
.arguments('<project-directory>')
.usage(`${chalk.green('<project-directory>')} [options]`)
.action(projectName= > {
appName = projectName
})
.parse(process.argv)
console.log(appName, process.argv)
}
module.exports = {
init,
}
Copy the code
Run in the project root directory
#Viewing the Package Version
npm run create -- --version
#Print out the ` myProject `
npm run create -- myProject
Copy the code
It prints myProject, [‘/Users/apple/NVM/versions/node/v14.8.0 / bin/node ‘, ‘/Users/apple/Desktop/create-react-app/packages/create-react-app/index.js’, ‘myProject’ ]
Create package. Json
Add dependencies first
#Cross-spawn starts child processes across platforms
#Fs - Extra FS
yarn add cross-spawn fs-extra --ignore-workspace-root-check
Copy the code
Create the myProject directory in your current working environment, and then create a package.json file to write part of the configuration
const fse = require('fs-extra')
const init = async() = > {// ...
await createApp(appName)
}
const createApp = async (appName) => {
const root = path.resolve(appName)
fse.ensureDirSync(appName)
console.log(`Creating a new React app in ${chalk.green(root)}. `)
const packageJson = {
name: appName,
version: '0.1.0 from'.private: true,
}
fse.writeFileSync(
path.join(root, 'package.json'),
JSON.stringify(packageJson, null.2))const originalDirectory = process.cwd()
console.log('originalDirectory: ', originalDirectory)
console.log('root: ', root)
}
Copy the code
Install dependencies
Then change the working directory to the newly created myProject directory and make sure that subsequent installations of this directory rely on react, react-dom, react-scripts, and crA-template
const createApp = async (appName) => {
// ...
process.chdir(root)
await run(root, appName, originalDirectory)
}
const run = async (root, appName, originalDirectory) => {
const scriptName = 'react-scripts'
const templateName = 'cra-template'
const allDependencies = ['react'.'react-dom', scriptName, templateName]
console.log(
`Installing ${chalk.cyan('react')}.${chalk.cyan(
'react-dom'
)}, and ${chalk.cyan(scriptName)}The ${` with ${chalk.cyan(templateName)}`
}. `)}Copy the code
At this point we haven’t written the react-scripts and crA-template packages, so we’ll use the existing ones.
@careteen/react-scripts, @careteen/cra-template
lerna add react-scripts cra-template --scope=@careteen/create-react-app
Copy the code
Start the child process to install dependencies with cross-spawn
const run = async (root, appName, originalDirectory) => {
// ...
await install(root, allDependencies)
}
const install = async (root, allDependencies) => {
return new Promise((resolve) = > {
const command = 'yarnpkg'
const args = ['add'.'--exact'. allDependencies,'--cwd', root]
const child = spawn(command, args, {
stdio: 'inherit',
})
child.on('close', resolve)
})
}
Copy the code
Copy the template
The core is to run react-scripts/scripts/init.js to copy templates.
const run = async (root, appName, originalDirectory) => {
// ...
await install(root, allDependencies)
const data = [root, appName, true, originalDirectory, templateName]
const source = ` var init = require('react-scripts/scripts/init.js'); init.apply(null, JSON.parse(process.argv[1])); `
await executeNodeScript(
{
cwd: process.cwd(),
},
data,
source,
)
console.log('Done.')
process.exit(0)}const executeNodeScript = async ({ cwd }, data, source) => {
return new Promise((resolve) = > {
const child = spawn(
process.execPath,
['-e', source, The '-'.JSON.stringify(data)],
{
cwd,
stdio: 'inherit',
}
)
child.on('close', resolve)
})
}
Copy the code
Spawn (process.execPath, args, {CWD}) is similar to using node -e ‘console.log(1 + 1)’ directly in terminal.
See the effect
Run the following script
npm run create -- myProject
Copy the code
It can be seen in the current project root directorymyProject
Directory structure.
At this point, the core functionality of create-React-app ‘ ‘package has been implemented. Cra – Tempalte and React-scripts will be dissected below.
packages/cra-tempalte
Cra – Tempalte can be copied from cra- Tempalte to start a simple React single-page application.
If you are interested in the React principle, check out the Fiber architecture.
packages/cra-tempalte–typescript
As above, it is not the focus of this article.
packages/react-scripts
Install dependencies
#'LERna' WARN No packages foundwhere webpack can be added.`
lerna add webpack webpack-dev-server babel-loader babel-preset-react-app html-webpack-plugin open --scope=@careteen/react-scripts
#Therefore, install yarn
yarn workspace @careteen/react-scripts add webpack webpack-dev-server babel-loader babel-preset-react-app html-webpack-plugin open
Copy the code
For the package. The json configuration
"bin": {
"careteen-react-scripts": "./bin/react-scripts.js"
},
"scripts": {
"start": "node ./bin/react-scripts.js start"."build": "node ./bin/react-scripts.js build"
},
Copy the code
Create the bin/react-scripts.js file
#! /usr/bin/env node
const spawn = require('cross-spawn')
const args = process.argv.slice(2)
const script = args[0]
spawn.sync(
process.execPath,
[require.resolve('.. /scripts/' + script)],
{ stdio: 'inherit'})Copy the code
react-scripts build
Those interested in the webpack principle can go to @careteen/webpack for a simple implementation.
Creating scripts/build.js does two things
- Copy the template project
public
Directory for all static resources tobuild
directory - Configured to
production
Environment, usewebpack(config).run()
Compile the package
process.env.NODE_ENV = 'production'
const chalk = require('chalk')
const fs = require('fs-extra')
const webpack = require('webpack')
const configFactory = require('.. /config/webpack.config')
const paths = require('.. /config/paths')
const config = configFactory('production')
fs.emptyDirSync(paths.appBuild)
copyPublicFolder()
build()
function build() {
const compiler = webpack(config)
compiler.run((err, stats) = > {
console.log(err)
console.log(chalk.green('Compiled successfully.\n'))})}function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
filter: file= >file ! == paths.appHtml, }) }Copy the code
Configure the config/webpack.config.js file
const paths = require('./paths')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = function (webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development'
const isEnvProduction = webpackEnv === 'production'
return {
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development'.output: {
path: paths.appBuild
},
module: {
rules: [{
test: /\.(js|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
presets: [[require.resolve('babel-preset-react-app']}},]},plugins: [
new HtmlWebpackPlugin({
inject: true.template: paths.appHtml
})
]
}
}
Copy the code
Configure the config/paths.js file
const path = require('path')
const appDirectory = process.cwd()
const resolveApp = relativePath= > path.resolve(appDirectory, relativePath)
module.exports = {
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveApp('src/index.js'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public')}Copy the code
After NPM run build, you can view all files generated after compilation and packaging in the build directory
react-scripts start
Create scripts/start.js file and start the service with the help of webpack
process.env.NODE_ENV = 'development'
const configFactory = require('.. /config/webpack.config')
const createDevServerConfig = require('.. /config/webpackDevServer.config')
const WebpackDevServer = require('webpack-dev-server')
const DEFAULT_PORT = parseInt(process.env.PORT, 10) | |3000
const HOST = process.env.HOST || '0.0.0.0'
const config = configFactory('development')
const webpack = require('webpack')
const chalk = require('chalk')
const compiler = createCompiler({
config,
webpack
})
const serverConfig = createDevServerConfig()
const devServer = new WebpackDevServer(compiler, serverConfig)
devServer.listen(DEFAULT_PORT, HOST, err= > {
if (err) {
return console.log(err)
}
console.log(chalk.cyan('Starting the development server... \n'))})function createCompiler({ config, webpack }) {
let compiler = webpack(config)
return compiler
}
Copy the code
Create config \ webpackDevServer. Config. Js file to provide a local service Settings
Those interested in the webpack hot update principle can go to @careteen/ webpack-hMR for a simple implementation.
module.exports = function () {
return {
hot: true}}Copy the code
After NPM run start, you can open it at http://localhost:8080/ to view the result
The react – scripts subtotal
The above two implementations are not as complete as the source code considers. I’ll look at some of the more ingenious third-party libraries and Webpack-plugins used in the source code.
packages/react-dev-utils
Under this sub package to store a lot of webpack plugin auxiliary to react – scripts/config/webpack config. Js file. Search the plugins field in the file to see.
Here are some plugins that I found useful
- PnpWebpackPlugin. Provides a more efficient module lookup mechanism, in an attempt to replace
node_modules
. - ModuleScopePlugin. Prevents users from importing files from outside SRC /(or node_modules/).
- InterpolateHtmlPlugin. make
<link rel="icon" href="%PUBLIC_URL%/favicon.ico">
You can use variables in%PUBLIC_URL%
. - WatchMissingNodeModulesPlugin. Enables new dependencies to be installed without the need to restart the project.
return {
// ...
resolve: {
plugins: [
// Added support for Plug'n'Play installations, improved installation speed, added protection against forgotten dependencies, etc.
PnpWebpackPlugin,
// Prevent users from importing files from outside SRC /(or node_modules/).
// This often causes confusion because we only use Babel to process files in SRC /.
// To solve this problem, we prevent you from importing files from SRC / -- if you like,
// Link these files to node_modules/ and let module parsing begin.
// Make sure the source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc, [
paths.appPackageJson,
reactRefreshOverlayEntry,
]),
],
},
plugins: [
// ...
// Make some environment variables available in index.html.
// Public URL in index as %PUBLIC_URL%. HTML, such as:
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
// Unless you specify "homepage" it will be an empty string
// In the package. In this case, it will be the pathname of the URL.
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
// If you need a missing module and install it with 'NPM install', you still need to restart the development server for WebPack to find it. This plugin makes discovery automatic, so you don't have to reboot.
/ / see https://github.com/facebook/create-react-app/issues/186
isEnvDevelopment &&
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
]
}
Copy the code
PnpWebpackPlugin
Added support for Plug’n’Play installations, improved installation speed, and added protection against forgotten dependencies, among other things. Try to replace node_modules.
Let’s look at the mechanics of using node_modules mode
- Resolves the version range of a dependent package to a specific version number
- Download the version dependent
tar
Reporting a local offline mirror - Decompress dependencies from offline images to the local cache
- Copies dependencies from the cache to the current directory
node_modules
directory
PnP works as an alternative to step 4 above
PnP use
The examples are stored in plugins-example/PnpWebpackPlugin
Create-react-app has integrated SUPPORT for PnP. Simply add the — use-pNP parameter when creating the project.
create-react-app myProject --use-pnp
Copy the code
Enable — PNP in an existing project that can use YARN
yarn --pnp
yarn add uuid
Copy the code
At the same time, PNP is automatically configured to enable in package.json. Node_modules is not generated, instead of.pnp.js.
{
"installConfig": {
"pnp": true}}Copy the code
Since node_modules is no longer available in PnP enabled projects, all dependent references must be handled by resolver in.pnp
{
// You also need to configure the usage script
"scripts": {
"build": "node uuid.js"}}Copy the code
Run the script to view the effect
yarn run build
#Or use node
yarn node uuid.js
Copy the code
ModuleScopePlugin
Prevents users from importing files from outside SRC /(or node_modules/). This often leads to confusion because we only use Babel for files in SRC /. To fix this, we prevent you from importing files from SRC / — link those files to node_modules/ if you like, and let module parsing begin. Make sure the source files are compiled, as they will not be processed in any way.
Create-react-app does not internally reference a directory other than SRC. Which falls outside of the project SRC/directory. Relative imports outside of SRC/are not supported.
The usual solution is to use react-app-rewired and customize-cra solutions.
So let’s see how this is done.
Sample in the plugins – example/ModuleScopePlugin
The implementation steps are mainly
- Set out toresolver.hooks.fileThe parser reads the file
request
At the right time. - The parsed file path if yes
node_modules
The release. - Parse the file path if it contains pass-arguments using this plug-in
appSrc
The release. - Parse the file path and
src
dopath.relative
If the result is../
At the beginning, it is believed thatsrc
Out of the path, you get a throw error.
const chalk = require('chalk');
const path = require('path');
const os = require('os');
class ModuleScopePlugin {
constructor(appSrc, allowedFiles = []) {
this.appSrcs = Array.isArray(appSrc) ? appSrc : [appSrc];
this.allowedFiles = new Set(allowedFiles);
}
apply(resolver) {
const { appSrcs } = this;
resolver.hooks.file.tapAsync(
'ModuleScopePlugin'.(request, contextResolver, callback) = > {
// Unknown issuer, probably webpack internals
if(! request.context.issuer) {return callback();
}
if (
// If this resolves to a node_module, we don't care what happens next
request.descriptionFileRoot.indexOf('/node_modules/')! = = -1 ||
request.descriptionFileRoot.indexOf('\\node_modules\\')! = = -1 ||
// Make sure this request was manual! request.__innerRequest_request ) {return callback();
}
// Resolve the issuer from our appSrc and make sure it's one of our files
// Maybe an indexOf === 0 would be better?
if (
appSrcs.every(appSrc= > {
const relative = path.relative(appSrc, request.context.issuer);
// If it's not in one of our app src or a subdirectory, not our request!
return relative.startsWith('.. / ') || relative.startsWith('.. \ \ '); {}))return callback();
}
const requestFullPath = path.resolve(
path.dirname(request.context.issuer),
request.__innerRequest_request
);
if (this.allowedFiles.has(requestFullPath)) {
return callback();
}
// Find path from src to the requested file
// Error if in a parent directory of all given appSrcs
if (
appSrcs.every(appSrc= > {
const requestRelative = path.relative(appSrc, requestFullPath);
return (
requestRelative.startsWith('.. / ') ||
requestRelative.startsWith('.. \ \ ')); {}))const scopeError = new Error(
`You attempted to import ${chalk.cyan( request.__innerRequest_request )} which falls outside of the project ${chalk.cyan(
'src/'
)} directory. ` +
`Relative imports outside of ${chalk.cyan(
'src/'
)} are not supported.` +
os.EOL +
`You can either move it inside ${chalk.cyan(
'src/'
)}, or add a symlink to it from project's ${chalk.cyan(
'node_modules/'
)}. `
);
Object.defineProperty(scopeError, '__module_scope_plugin', {
value: true.writable: false.enumerable: false}); callback(scopeError, request); }else{ callback(); }}); }}Copy the code
InterpolateHtmlPlugin
Make some environment variables available in index.html. Public URL exists in the index as %PUBLIC_URL%. HTML, such as:
Unless you specify “homepage”, it’s going to be an empty string in the package. In this case, it will be the pathname of the URL.
Sample in the plugins – example/InterpolateHtmlPlugin
Implementation approach is mainly to HTML – webpack – the plugin/afterTemplateExecution template execution after the regular replacement of the generated HTML files.
const escapeStringRegexp = require('escape-string-regexp');
class InterpolateHtmlPlugin {
constructor(htmlWebpackPlugin, replacements) {
this.htmlWebpackPlugin = htmlWebpackPlugin;
this.replacements = replacements;
}
apply(compiler) {
compiler.hooks.compilation.tap('InterpolateHtmlPlugin'.compilation= > {
this.htmlWebpackPlugin
.getHooks(compilation)
.afterTemplateExecution.tap('InterpolateHtmlPlugin'.data= > {
// Run HTML through a series of user-specified string replacements.
Object.keys(this.replacements).forEach(key= > {
const value = this.replacements[key];
data.html = data.html.replace(
new RegExp(The '%' + escapeStringRegexp(key) + The '%'.'g'), value ); }); }); }); }}Copy the code
WatchMissingNodeModulesPlugin
If you need a missing module and then install it with ‘NPM install’, you still need to restart the development server for WebPack to find it. This plugin makes discovery automatic, so you don’t have to reboot. See github.com/facebook/cr…
Sample in the plugins – example/WatchMissingNodeModulesPlugin
This is done by reinstalling missingDependencies and contextDependencies. Add from compilation before generating resources to the Output directory.
class WatchMissingNodeModulesPlugin {
constructor(nodeModulesPath) {
this.nodeModulesPath = nodeModulesPath;
}
apply(compiler) {
compiler.hooks.emit.tap('WatchMissingNodeModulesPlugin'.compilation= > {
var missingDeps = Array.from(compilation.missingDependencies);
var nodeModulesPath = this.nodeModulesPath;
// If any missing files are expected to appear in node_modules...
if (missingDeps.some(file= > file.includes(nodeModulesPath))) {
/ /... tell webpack to watch node_modules recursively until they appear.compilation.contextDependencies.add(nodeModulesPath); }}); }}Copy the code
conclusion
useMultiple warehouse
Advantages of management
- Each module has a high degree of freedom in management, and can choose its own building tools, dependency management, unit testing and other supporting facilities
- The volume of each module warehouse is generally not too large
Disadvantages of using multiple warehouse management
- Scattered warehouses are hard to find, and even harder when there are many, and branch management is chaotic
- Version update is tedious. If the public module version changes, all modules need to be updated depending on it
CHANGELOG
Combing the abnormal, unable to automatically associate the changes of each module, basically rely on word of mouth
usemonorepo
Shortcomings of management
- Unified build tools, build tools put forward higher requirements, to be able to build a variety of related modules
- The warehouse will get bigger
Advantages of using Monorepo management
- A warehouse maintains multiple modules without having to hunt around for warehouses
- Convenient version management and dependency management, reference between modules, debugging are very convenient, with the corresponding tools, can be a command done
- Convenient unified generation
CHANGELOG
, in conjunction with the submission specification, can be generated automatically at release timeCHANGELOG
, with the aid ofLeran-changelog