最近在工作中看到了项目中使用了pnpm
的workspace
来搭建monorepo
,于是就自己想搭建一个试一试
monorepo 简介
monorepo
是指将一个项目中的模块划分为本地的包的形式进行管理,后面在主工程中使用的时候,就像npm
包那样,安装并引入依赖,就可以使用其他的模块(本地的包)了
pnpm workspace 结构搭建
先来讲讲pnpm workspace
的结构:
在不使用monorepo
的情况下,subPkg1
和subPkg2
都应该是mainProject
文件夹下的子模块,但在使用了monorepo
后,可以将这些模块每个独立出来成为一个本地工作区的包,可以像npm
包那样install
和import
来使用
- pacakges // pacakges 文件夹就是 workspace 下的包
- subPkg1 // 子包1
- package.json
- subPkg2 // 子包2
- package.json
- mainProject // 主工程
- package.json
- pnpm-workspace.yaml // 工作区配置文件,pnpm workspace 的根目录必须包含这个文件
- package.json
搭建步骤
创建一个文件夹,执行pnpm init
初始化项目,然后创建pnpm-workspace.yaml
文件,添加如下内容:
// 声明包目录
packages:
- 'packages/*'
然后创建packages
文件夹,并在packages
下创建docs
文件夹,然后在docs
文件夹内初始化项目:
pnpm init
随后在docs
下的package.json
中,你可以将name
字段改为你喜欢的名字,最好要语义化一点,辨识度高一点,我改成了@mono/docs
,然后main
字段可以根据你的包的入口文件修改即可
然后我们在packages
下用vite
创建一个react
的主工程,我们最后的目的就是要在这个react
主工程中使用packages
下的其他子包
在主工程中安装其他子包的依赖
进入到主工程,执行pnpm
安装命令,注意这里安装的包名是你的子包的package.json
的name
字段值:
pnpm add @mono/docs
随后我们就可以看到主工程的package.json
的依赖项:
"dependencies": {
"@mono/docs": "workspace:^", // 这里的 workspace 就表示这个包是从本地工作区安装的
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
然后子包必须给主工程提供它要用到的的东西,于是我们在子包的入口文件导出即可,一般都是创建一个index.js
作为入口文件:
// 随便导出点东西测试一下,在主工程内就像 npm 包那样安装导入使用就好了
export const docs = "docs"
使用 typescript 编写项目
现在基本上是个项目都会用ts
来编写了,所以仅有上面的js
是不够的;在主工程中使用ts
非常快捷,直接用vite
创建一个react-ts
模板的项目即可,但我们还要给子包配置ts
的依赖,并且要进行编译,然后主工程安装子包,使用子包编译后的代码,并且还要有类型提示,我们先来理一理整个思路
npm 包是怎样工作的
当你安装了一个用ts
编写的包时,它会把源码和ts
编译后的目录一起安装到你的node_modules
下,然后你是跟据这个包的package.json
的name
字段来找到它的入口文件,然后引入使用
有的包编译后的产物会包含.d.ts
类型声明文件,这就是你在你的项目下引入后会有类型提示的原因
了解 ts 编译
使用ts
编写的项目,编译后会生成js
文件,你也可以选择为这些js
文件生成类型声明文件;ts
的编译配置集中在tsconfig.json
这个文件中,详情可以参考: https://aka.ms/tsconfig
搭建 ts 编译结构
我们先安装ts
的依赖:
npm install typescript
然后使用tsc
来初始化ts
项目,生成tsconfig.json
文件:
npx tsc --init
配置好tsconfig.json
的编译配置后,我们就可以在这些子包中编写一些复用的代码了,例如工具函数,请求api
等
然后就是项目的编译,我们还是用tsc
来进行编译,我们在子包的package.json
添加如下脚本:
"build": "npx tsc",
随后我们执行npm run build
,即可将编译好的ts
代码输出到指定的目录