Monorepos介绍
Monorepos简单点来说就是一个项目下有好几个独立的子模块,这些子模块可以单独运行、打包、发布,但是这些子模块又在同一个git仓库下管理,而且这些子模块可能存在相互的依赖关系。
用这种方式管理项目的好处就是既方便统一管理这些子模块,又可以最大程度上降低模块间的耦合。
目前很多大型项目都采用的这种管理方式,比如Babel、React、Vue等等。
去github上看一下create-react-app
的目录结构
可以看到packages
文件夹下面有很多个子模块,如create-react-app
、react-dev-utils
、react-scripts
...,这些模块全都可以独立的发布到npm
上
同时它们又在同一个git仓库里维护,所以create-react-app
是一个典型的采用monorepos方式管理的项目。
创建前的准备
创建一个monorepos
项目需要用到lerna
这个多包管理工具,以及Yarn
的wrokspaces
特性,所以先要把这两个工具全局安装一下,安装方式这里就不多做介绍了。
然后创建一个项目文件夹,名字随意,我这里取名叫lerna-test
开始创建
初始化
在lerna-test
下执行如下命令
lerna init
成功之后目录结构如下
修改配置
-
修改lerna.json
添加
npmClient
配置如下{ "packages": ["packages/*"], "npmClient": "yarn", "version": "0.0.0" }
-
修改package.json
添加
workspaces
配置如下{ "name": "root", "private": true, "workspaces": [ "packages/*" ], "devDependencies": { "lerna": "^3.20.2" } }
初始化子模块
为了方便说明,我这里用lerna
初始化了一个普通项目,以及用create-react-app
初始化了一个react
项目
首先进入到/packages
文件夹下,分别创建如下两个子项目
-
创建普通项目
lerna create aaawu
aaawu
这个项目名字可以随意取 -
创建react项目
yarn create react-app test-react
test-react
这个项目名字可以随意取
两个子项目都创建好,目录结构应该是这样的
添加依赖关系
正常的Monorepos项目里,各模块之间很有可能存在相互的依赖关系,接下来我们假设test-ract
需要依赖aaawu
。
打开/packages/test-react/package.json
,在dependencies
下手动添加一行依赖
"aaawu": "^0.1.0"
0.1.0
这个版本号对应了/packages/aaawu/package.json
的version
此时命令行执行如下命令,查看各个模块的依赖关系
yarn workspaces info
结果如下
yarn workspaces v1.12.1
{
"aaawu": {
"location": "packages/aaawu",
"workspaceDependencies": [],
"mismatchedWorkspaceDependencies": []
},
"test-react": {
"location": "packages/test-react",
"workspaceDependencies": [
"aaawu"
],
"mismatchedWorkspaceDependencies": []
}
}
已经可以看到依赖添加成功了。
建立关联
现在test-react
和aaawu
的依赖关系有了,怎么才能让test-react
项目里能import
到aaawu
里的代码呢?
和普通的yarn add ×××
不同,本地开发的时候我们需要的是引用本地的aaawu
,而不是线上npm
里的项目。
这个时候yarn
的workspaces
就起到作用了,它会自动管理/package.json
里workspaces
字段指定包下的所有依赖。由于我们之前配置的是
"workspaces": [
"packages/*"
]
所以,packages
文件下所有子包的依赖关系,它都直接解决了。
命令行执行
yarn
test-react
和aaawu
需要的所有依赖包都被统一安装到根目录下的node_modules
里(除了因版本冲突无法统一的包)。因版本冲突无法统一的包,还是会安装在各个模块下的node_modules
里。
此时查看根目录下node_modules
看到aaawu
和其他的不太一样,旁边有个箭头。这个确实和从线上下载下来的包不同,它其实指向的是本地/packages/aaawu
,它是一个镜像,也就是说/packages/aaawu
里的代码改动这边也会一起改变。
运行项目
依赖都安装完了,接下来就可以直接运行项目了
切换到/packages/test-ract
目录下,直接
npm start
test-react
会正常跑起来
修改代码
我们想要在test-react
项目里试一下能不能import
进aaawu
中的方法。直接在原有代码的基础上做最小的改动,小试牛刀一下
- 修改
/packages/aaawu/lib/aaawu.js
"use strict";
module.exports = aaawu;
function aaawu() {
// TODO
return "this is aaawu";
}
- 修改
/packages/test-react/src/App.js
import React from "react";
import logo from "./logo.svg";
import A from "aaawu";
import "./App.css";
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
{A()}
</a>
</header>
</div>
);
}
export default App;
此时不用刷新页面,便能看到页面上已经正确显示出内容了
以上,子模块存在相互依赖关系的monorepos项目,创建成功,并能成功运行