Monorepo是一种项目管理方式,将多个项目的代码集中到一个仓库中,能更好的处理发版的依赖关系、提高代码的复用。 yarn/npm 的workspaces本身就是支持monorepo的,对于重复的依赖,monorepo会将依赖提升到根目录,避免重复安装,在代码开发阶段monorepo的模块之间可以实时引用代码,提升开发效率。
yarn workspace 的常用命令
yarn workspaces info // 查看monorepo的配置信息, 其中包含模块之间的依赖关系
yarn add package_name -W // 安装依赖到monorepo的根目录
yarn remove package_name -W // 移除根目录以依赖
yarn workspace package_name add package_name // 安装依赖到指定模块
yarn workspace package_name build // 编译指定模块
yarn workspace package_name test // 运行指定模块的测试用例
从上面的命令可以看出yarn workspace的好处是不用切换项目的目录,在根目录就能执行子项目的命令
yarn workspace pages add package_name // 安装依赖到pages模块
yarn workspace pages statr // 运行项目
当然你仍然可以切换到子项目的目录执行命令,如:
cd packages/pages
yarn add package_name
基于yarn workspace 的monorepo
项目结构如下:
|--node_modules
|--packages
| |--components
| | |--node_modules
| | |--public
| | | |--index.html
| | |--src
| | | |--index.jsx
| | | |--button.jsx
| | | |--input.jsx
| | |--package.json
| | |--webpack.config.js
| |--pages
| | |--node_modules
| | |--public
| | | |--index.html
| | |--src
| | | |--index.jsx
| | | |--app.jsx
| | |--package.json
| | |--webpack.config.js
|--package.json
|--.gitignore
|--README.md
一、 初始化
yarn init -y 创建package.json文件
{
"name": "demo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": ["packages/*"]
}
二、创建子模块
2.1.创建目录
创建packages/pages、packages/components模块,它都是react项目,pages是业务页面,components是公共组件库,pages依赖components。这里的react项目是手动创建的,也可以通过cra去创建。
2.2 依赖安装
由于两个模块都是react项目,它们的依赖也完全相同,所以这里直接安装到monorepo的根目录共享依赖。
yarn add react react-dom webpack weback-dev-server @babel/core @babel/preset-env @babel/preset-react
babel-loader --dev -W
之后在两个模块的目录下分别安装依赖:
yarn add react react-dom webpack webpack-cli webpack-dev-server @babel/core @babel/preset-env @babel/preset-react babel-loader --dev
2.3 配置webpack 处理jsx文件
pages和components都需要webpack配置,这里以pages为例,配置webpack.config.js文件。
// pages/webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.jsx$/,
use: {
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ["@babel/preset-env", "@babel/preset-react"]
}
},
}
]
},
resolve: {
extensions: ['.jsx', '.js']
},
mode: 'development',
devServer: {
static: {
directory: path.join(__dirname, 'public'),
watch: true
},
open: true,
port: 3000,
hot: true
}
}
三、components模块的代码
// components/src/button.jsx
import React, { Component } from 'react'
export default class Button extends Component {
render() {
return (
<div>{this.props.children}</div>
)
}
}
// components/src/index.jsx
export { default as Button } from "./Button";
export { default as Input } from "./Input";
四、在pages模块中使用components模块的组件
yarn workspaces pages add components
实际上是通过npm link的方式将两个模块关联起来,这样就可以直接在pages模块中使用components模块的组件,components模块的更新也会同步到pages模块中。
在pages模块中使用components模块的组件
// pages/src/app.jsx
import React, { Component } from 'react'
import { Button} from 'components/src/index'
export default class App extends Component {
render() {
return (
<Button>add</Button>
)
}
}
yarn workspace pages start运行项目
五、npm发版
cd packages/components
npm version patch // 发布一个小版本
npm publish // 发布到npm仓库
yarn workspace的发版和npm的发版基本一致,为了简化发版流程,可以使用lerna管理monorepo,lerna可以自动化执行版本的发布和自动化生成CHANGELOG。