什么是monorepo?
单仓库是一种软件开发方法,其中一个仓库包含多个项目。这些项目可以是任何东西,从单个应用程序到可重用的组件或者实用程序函数。在monorepo中,这些包通常被称为本地包。
monorepo有哪些好处
- 更容易跨团队标准化代码
- 支持更好的可见性和跨团队合作
- 简化了文件组织和代码依赖关系管理
如何使用npm构建Typescript Monorepo
可以通过以下命令获取github仓库中示例代码:
git clone https://github.com/vvangwenkun/monorepo.git
准备
为了使用npm构建Typescript Monorepo,你需要安装以下工具:
- Node.js >= 14
- NPM >= 7
- Typescript
初始化目录结构
你的monorepo目录结构应如下所示:
创建根目录package.json文件
{
"name": "monorepo",
"version": "1.0.0",
"description": "a monorepo in typescript",
"main": "index.js",
"scripts": {
"build": "npx tsc --build --verbose"
},
"author": "aric.vvang@gmail.com",
"license": "ISC",
"private": true,
"workspaces": [
"packages/*"
],
"devDependencies": {
"typescript": "^5.5.3"
}
}
其中,workspaces属性必须设置,npm才允许你在根目录中定义多个包。
添加一个本地包
在packages目录中创建util文件夹:
- 使用以下命令初始化util包的package.json文件
npm init --scope @monorepo --workspace ./packages/util -y
确保package.json包含以下内容:
{
"name": "@monorepo/util",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"scripts": {
"build": "npx tsc --build --verbose"
},
"author": "aric.vvang@gmail.com",
"license": "ISC",
"dependencies": {
"dayjs": "^1.11.12"
}
}
- 初始化tsconfig.json文件
{
"compilerOptions": {
"target": "ESNext",
"module": "CommonJS",
"moduleResolution": "Node",
"declaration": true,
"strict": true,
"incremental": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"rootDir": "src",
"outDir": "dist",
"composite": true
}
}
必须将composite选项设置为true,你才能在monorepo的其他部分引用这个项目。
验证本地包是否正常工作
npm run build --workspace ./packages/util
编译成功后,你的目录应该如下所示:
初始化根目录tsconfig.json文件
{
"compilerOptions": {
"incremental": true,
"target": "ESNext",
"module": "CommonJS",
"declaration": true,
"strict": true,
"moduleResolution": "Node",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"rootDir": "src",
"outDir": "dist"
},
"references": [
{
"path": "./packages/util"
}
]
}
在references属性中列出本地包目录。如果你需要新增一个名为ui本地包,则references应该如下所示:
{
"references": [
{
"path": "./packages/util"
},
{
"path": "./packages/ui"
}
]
}
在根目录下执行npm run build
编译成功后,你的目录应该如下所示:
在本地包中使用其他本地包
在 @monorepo/ui 包中引用 @monorepo/util 包,你需要在根目录中执行:
npm i @monorepo/util --workspace ./packages/ui
该命令会将 @monorepo/util 包设置为 @monorepo/ui 包的依赖:
{
"name": "@monorepo/ui",
"dependencies": {
"@monorepo/util": "^1.0.0"
}
}
添加外部npm包到本地包
比如在 @monorepo/util 包中引用dayjs包:
npm i dayjs --workspace ./packages/util
在根目录中添加所有本地依赖包
npm i @monorepo/ui @monorepo/util
注意
在本例中,因为ui包依赖于util包,所以在配置根目录中tsconfig.json中的references属性时,需要注意包的列出顺序,先列出被依赖包(util),如:
{
"references": [
{
"path": "./packages/util"
},
{
"path": "./packages/ui"
}
]
}
否则,编译时会出现error: