当你想要搭建一个Monorepo时,相信你已经调研过很多技术选型,之前我也使用过yarn
+workspace
+lerna
+dumi
开发过一套组件库,后续有时间把这套工具也抽一个模版。
因为pnpm
本身支持workspace
并且lerna
已经停止维护,因此决定使用新的工具从新搭建一套Monorepo模版,那么这套工具就是:
pnpm
—包管理器turborepo
—外壳changesets
—版本号管理、changelog管理dumi
—文档预览其他的规范代码的工具如
:—commitizen
、eslint
、lint-staged
、commitlint
、husky
等你可能对Turborepo不太了解,他的官方解释是高性能的JavaScript和TypeScript代码库构建系统,他在这只是作为一个壳子用来提升开发及打包效率,不用了解太多。
我现在这里的turbo的version是
1.10.12
,如果你很晚看见这篇文章,可能版本有了很大不同。
git remote add origin https://github.com/Atw-Lee/monorepo-template.git
不要划走:Monorepo可以用来管理多应用工程(app目录下的各种工程),所有工程依赖相同的UI,而Turborepo初始化的项目也是这么干的。但是,我需要的是搭建一个我的UI组件库,这是与它不同的地方,app下我只需要一个文档预览工程(dumi),因此,我需要调整它的目录结构
package.json
文件"preinstall": "npx only-allow pnpm"
只允许使用pnpm包管理器pnpm i -Dw eslint@latest @changesets/cli commitizen cz-conventional-changelog @commitlint/cli @commitlint/config-conventional husky lint-staged stylelint father
dumi
项目git init
.fatherrc.ts
文件(不需要在这打包组件).gitignore
文件增加docs-dist
(该目录为dumi的build产物)package.json
文件:
docs:build
build:dumi build
(打包直接是该文档工程打包,不打包组件)module
、types
、files
配置(用不着)eslint
包我不准备使用它默认的eslint,因为我用不到nextjs
相关的内容,我选择使用Tencent的eslint-config-alloy
pnpm i eslint-config-alloy
安装alloyeslint-plugin-react
(后续补充,不是最新的出错了)tsconfig
包package.json
的private属性(为了后续可以正常发版)nextjs.js
文件(不需要next的ts配置)ui
包turbo
目录(用不着)package.json
文件删除generate
脚本(用不着)package.json
文件删除eslint
依赖(外边已经有了)package.json
文件新增脚本"build": "father build"
(打包组件,app里的docs不需要了,因为UI组件包的开发在这里)package.json
文件修改main属性"main": "./src/index",
package.json
文件修改types属性"main": "./src/index",
tsconfig.json
文件{
"extends": "tsconfig/react-library.json",
"include": ["src"],
"exclude": ["lib", "dist", "es", "node_modules"]
}
.fatherrc.ts
文件import { defineConfig } from "father";
export default defineConfig({
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
esm: { output: "es" },
cjs: { output: "lib" },
});
.gitignore
文件增加lib及es
(该目录为ui通过father打包产物,具体名称还是根据上一步的配置来).gitignore
文件删除next相关的(用不到)module.exports = {
root: true,
extends: ["custom"],
};
registry=你公司的私有源,开发的UI组件库发布到这
(在这直接定义注册地址就比较方便了)package.json
文件增加"commit": "cz"
脚本package.json
文件增加config
属性 "config": {
"commitizen": {
"path": "node_modules/cz-conventional-changelog"
}
}
commitlint.config.js
文件module.exports = { extends: ["@commitlint/config-conventional"] };
package.json
文件增加"postinstall": "husky install"
pnpm i
生成.husky
文件,初始化husky。完成后可删除postinstall
属性npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
生成commit-msg的hookpackage.json
文件增加commitlint
及lint-staged
属性 "commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"lint-staged": {
"*.{md,json}": [
"prettier --write --no-error-on-unmatched-pattern"
],
"*.{css,less}": [
"stylelint --fix",
"prettier --write"
],
"*.{js,jsx}": [
"eslint --fix",
"prettier --write"
],
"*.{ts,tsx}": [
"eslint --fix",
"prettier --parser=typescript --write"
]
},
npx husky add .husky/pre-commit "npx --no-install lint-staged"
lint-staged
属性pnpm dev
:页面正常打开dumi运行的应用package.json
增加ui
的依赖"ui": "workspace:*"
ui包
中的button
组件他俩不需要打包,都是些配置项
上文我们已经设置好了father
打包的配置文件,直接执行pnpm build
生成了对应的lib和es
文件夹,docs也跟着打包了,这里是turborepo的操作逻辑,我们不用关心它
package.json
中新增files属性package.json
的main、types
属性也要做一个修改,之前是./src
"main": "./lib/index",
"types": "./lib/index",
"files": [
"es",
"lib",
"dist"
],
接下来就需要把我们的包发布到我们的私有源上了,当然开源也没有问题
我们现在有三个包,分别是
eslint、typescript、ui
。
我们的包肯定不能叫这个名字,那我们给他们改下名字,加上组织的前缀,我这里以@you-org
为例
pnpm changeset init
生成.changeset
文件pnpm changeset
选择要发布的包changeset version
增加版本号pnpm -r publish --tag alpha0.1.0
发布版本收获:从0开始搭建了一个多包(Monorepo)的UI组件模版,了解了一个简单开源UI工程应该具有的工具及搭建步骤。
不足之处在于:
rollup
可能会更好,但是因为额外的学习成本,还是使用了dumi
上自带的father
ui
包,应该在添加一个utils
包,这样才更加具有Monorepo的特性tsconfig
和eslint
包不确定是否有必要单独提成一个包,如果项目很复杂的话,eslint和tsconfig需要灵活配置的话,可能会更有用吧package.json
文件,后续也会做这方面的工作参考文章