Nerv monorepo工程化实践:Lerna+Rollup+TypeScript包拆分、自动构建与发布流水线完整指南
【免费下载链接】nervA blazing fast React alternative, compatible with IE8 and React 16.项目地址: https://gitcode.com/NervJS/nerv
Nerv 是一个极速的 React 替代方案,兼容 IE8 与 React 16 生态。它的源码仓库是一个典型的Nerv monorepo工程:用 Lerna 管理 9 个 npm 包、Rollup 构建 TypeScript 源码、Azure Pipelines 自动跑构建与测试,最终通过lerna publish一键发布。本文带你完整拆解这套 Nerv 工程化流水线,新手也能看懂 monorepo 是怎么落地的。
为什么 Nerv 选择 Monorepo 架构 🏗️
Nerv 不只是"一个框架",而是一整套生态工具:核心渲染引擎、Redux 绑定、服务端渲染、测试工具、开发调试器……如果每个工具都单独建仓库,版本同步、代码共享、依赖对齐都会非常痛苦。
Monorepo(多包单仓库)的做法是:所有包放在同一个 Git 仓库里,共享一套构建、测试、发布配置。Nerv 仓库就是这样一个结构——根目录一份总配置,packages/目录下 9 个独立可发布的包:
| 包名 | 职责 |
|---|---|
| nervjs | 核心框架(虚拟 DOM、组件、事件、Hooks) |
| nerv-shared | 各包共享的常量与工具 |
| nerv-utils | 通用工具函数(next-tick、shallow-equal 等) |
| nerv-redux | Redux 状态管理绑定 |
| nerv-server | 服务端同构渲染 |
| nerv-create-class | 函数组件 + Hooks 的 class 化封装 |
| nerv-test-utils | 测试工具集 |
| nerv-devtools | 浏览器 DevTools 调试器支持 |
| nerv-is | 轻量类型判断工具 |
💡 拆分原则很清晰:核心包依赖共享包,周边工具包围绕核心包生长。比如 nervjs 的 package.json 里声明了对
nerv-shared和nerv-utils的依赖,而nerv-shared、nerv-utils则没有反向依赖,形成清晰的单向依赖链。
一键安装:Lerna 如何接管多包管理 🚀
在仓库根目录安装依赖后,一条命令就能拉起整个 monorepo:
git clone https://gitcode.com/NervJS/nerv cd nerv npm install # postinstall 会自动执行 lerna bootstrap背后的关键配置有两处:
- lerna.json:声明
packages/*为包目录,并锁定 monorepo 统一版本号1.5.7,同时约定发布时自动生成的 commit message 格式为chore(release): publish %s; - 根 package.json:通过
"postinstall": "lerna bootstrap"钩子,让npm install结束时自动完成所有子包的依赖安装与链接。
这套组合的好处是:新人克隆仓库后不需要理解任何包依赖关系,一条npm install即可得到可运行、可测试、可构建的完整工程。
Rollup 构建 TypeScript:一份源码产出三种格式
核心包 nervjs 的构建入口是 rollup.config.js,它体现了 Nerv"高性能小体积"的构建思路:
- 入口与插件链:以
src/index.ts为入口,依次经过rollup-plugin-typescript2(编译 TypeScript)、buble(ES6 降级)、babel+es3插件(ES3 降级,这是兼容 IE8 的关键); - 多格式输出:同一次构建同时产出 CJS 版本(
dist/index.js,供 Node/服务端用)、UMD 版本(dist/nerv.js,供浏览器<script>直接用)、ESM 版本(dist/index.esm.js,供 webpack 等打包工具 tree-shaking); - 生产压缩:额外的 production 配置追加
uglify(开启ie8: true保证语法兼容 IE8)与optimize-js插件,产出nerv.min.js; - 跨包引用:用
alias插件把nerv-shared、nerv-utils直接指向兄弟包的dist目录,实现 monorepo 内部的"源码级"依赖解析。
根目录的npm run build:esm/npm run build:umd则是通过lerna exec加环境变量TARGET来只构建单一格式,方便按需构建。
自动构建流水线:npm run build 的五个阶段
根 package.json 中一条build命令串起了完整链路:
- clean:
lerna exec -- rimraf dist,清空所有包的产物; - rollup 构建:
lerna exec -- rollup -c,在每个包目录下执行自己的 Rollup 配置; - 类型生成:
tsc将全仓 TypeScript 编译到lib/目录(配置见 tsconfig.json),再由 typing.js 调用dts-bundle把每个包的类型声明合并为单文件dist/index.d.ts——用户安装nervjs后能直接获得完整类型提示; - CI 环境修复:afterbuild.js 检测到 CI 环境时自动升级 karma 内的 socket.io,规避已知兼容问题;
- 体积度量:
gzip-size输出nerv.min.js的 Gzip 体积,作为每次构建的性能基线参考。
质量守门:提交前、推送前、CI 上的三道测试关卡 🔒
- precommit:
tslint --type-check全量类型检查 +lint-staged只对本次暂存文件跑 ESLint/TSLint 自动修复; - prepush:推送前强制跑
jest全量测试。测试由 jest.config.js 统一调度,通过moduleNameMapper把nervjs、nerv-utils等包名直接映射到packages/*/src源码目录——monorepo 里测试不需要先构建产物,速度更快也更贴近真实; - CI 流水线:azure-pipelines.yml 在每次推送 master 时自动执行:安装 Node 8 →
yarn装依赖 →npm run build→npm run test:coverage,生成覆盖率报告。
本地跑测试也很简单:
npm test # jest 全量 npm run test:coverage # 带覆盖率 npm run test:karma # 浏览器端(karma + jasmine)发布流水线:从 Conventional Commits 到 npm 📦
发布环节的配置体现了"自动化 + 可控"的平衡:
- 自动版本推导:
"release": "lerna publish --exact --conventional-commits"依据提交记录(feat:/fix:前缀)自动决定 semver 版本号,--exact保证所有包版本与lerna.json中的 monorepo 统一版本严格一致; - beta 通道:
release:beta使用--preid=beta --npm-tag=beta,让预发布版本走独立的 npm tag,不打扰稳定版用户; - 交互式发布器:release.js 提供 auto(semver 自动推导)/ beta / manual(手动指定精确版本号)三种模式,先执行
npm run build再发布,确保产物最新。
配合 lerna.json 中约定的发布 commit 格式,每次发布都会在 Git 历史中留下一条清晰的chore(release): publish 1.5.7记录,可追溯性极佳。
总结:Nerv monorepo 工程化的 5 个可抄作业要点 ✨
- 单一 lerna.json + workspaces:一个根配置管住所有包,版本统一、依赖自链接;
- 单向依赖拆分:core → shared/utils,避免包之间循环依赖;
- 多格式构建:一份 TypeScript 源码经 Rollup 产出 CJS / UMD / ESM + 压缩版,兼容 IE8 与现代打包器;
- 类型体验不降级:
dts-bundle合并.d.ts,让用户拿到的是"一个文件"的完整类型; - 测试与发布全自动化:precommit/prepush 本地守门 + CI 构建测试 + conventional-commits 自动发版。
如果你正在规划自己的前端框架或组件库 monorepo,Nerv 的这套 Lerna + Rollup + TypeScript + CI 组合,是一份经过 IE8 级别兼容性验证的成熟参考。
【免费下载链接】nervA blazing fast React alternative, compatible with IE8 and React 16.项目地址: https://gitcode.com/NervJS/nerv
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考