前段时间9月21日参加了在成都举办的第五届FEDAY, 印象比较深刻的是白鹭引擎首席架构师@王泽分享的《框架开发中的基础设施搭建》 ,提到了在下一代白鹭引擎中使用到monorepo模式,以用来管理多个模块,协调各个模块之间的依赖更新。
正好在国庆期间10月5日尤大公开了vue3.0已完成的源码,也是采用了monorepo管理模式,看来monorepo确实有其独到的优势,再加上以前在项目中遇到过相关的痛点,所以深入地了解了一下这种模式,本文将基于vue3.0讨论如何通过monorepo模式来管理代码的。
什么是 monorepo?
monorepo是一种将多个package放在一个repo中的代码管理模式,摒弃了传统的多个package多个repo的模式。
目前 Babel, React, Angular, Ember, Meteor, Jest等许多开源项目都使用该种模式来管理代码。
解决的问题
多个repo难以管理,编辑器需要打开多个项目;
某个模块升级,依赖改模块的其他模块需要手动升级,容易疏漏;
公用的npm包重复安装,占据大量硬盘容量,比如打包工具webpack会在每个项目中安装一次;
对新人友好,一句命令即可完成所有模块的依赖安装,且整个项目模块不用到各个仓库去找;
带来的问题
所有package代码集中在一个项目,单个项目体积较大;
所有package代码对所有人可见,无法做权限管理;
如何实现 monorepo?
目前业界最佳实践是采用yarn workspace + lerna 来实现,vue3.0也是采用两者结合的方式来实现。
yarn workspace可以实现在一个项目中实现多个模块的依赖新增和共用,而lerna的功能则更完善,不仅可以管理多个模块,还有清除模块node_modules,发布模块到npm,自动更新模块间版本依赖,并支持全量发布和根据改动单独发布等功能。
yarn官方推荐用yarn来处理依赖安装,用lerna来处理依赖更新和发布问题。
下面开始基于monorepo模式来搭建一个仿vue3.0的项目
1. 全局安装 yarn 和 lerna
$ npm i -g yarn lerna
2. 初始化项目
$ mkdir vue-next && cd vue-next $ lerna init // 此时项目结构 vue-next |-packages |-lerna.json |-package.json
3. 添加yarn workspace配置
// vue-next/package.json "private": true, // 项目根目录下的private必须设置成true,否则workspace不会被启用 "workspaces": [ // 指定需要管理的模块 "packages/*" ],
4. 添加模块内容
// 此时项目结构 vue-next |-packages // packages下的所有包结构类似,下面仅展示了compiler-core包的目录结构 |-compiler-core // 与平台无关的编译器 |-__tests__ // 测试用例 |-src // 源文件 |-index.js // 根文件 |-package.json // 包配置 |-compiler-dom // 与浏览器相关的编译器 |-reactivity // 数据响应式系统 |-runtime-core // 与平台无关的runtime |-runtime-dom // 与浏览器相关的runtime |-runtime-test // 为了测试的轻量级runtime |-server-renderer // 服务端渲染 |-shared // 内部帮助方法 |-template-explorer // 预览模版转化成render函数的工具 |-vue // 用于构建完整的vue版本 |-lerna.json |-package.json
5. 安装相关依赖
项目中一般只会用到以下3种安装形式
5.1 给根项目安装依赖(一般是公用的开发工具)
// yarn 使用 workspace 模式安装 npm 包时必须加 -W 参数 $ yarn add -W -D rollup typescript jest prettier ...
5.2 给package安装外部npm包
// @vue/compiler-core 是取 vue-next/packages/compiler-core/package.json 的 name 字段 $ yarn workspace @vue/compiler-core add acorn estree-walker source-map $ yarn workspace @vue/template-explorer add monaco-editor
5.3 给package安装内部npm包
// @vue/compiler-core 是取 vue-next/packages/compiler-core/package.json 的 name 字段 $ yarn workspace @vue/compiler-dom add @vue/compiler-core@3.0.0-alpha.1 // 一定要指定正确的版本号,不然会到npm查找包 $ yarn workspace @vue/runtime-core add @vue/reactivity@3.0.0-alpha.1 $ yarn workspace @vue/runtime-dom add @vue/runtime-core@3.0.0-alpha.1 $ yarn workspace @vue/runtime-test add @vue/runtime-core@3.0.0-alpha.1 $ yarn workspace vue add @vue/compiler-dom@3.0.0-alpha.1 @vue/runtime-dom@3.0.0-alpha.1 // 可同时安装多个
至此已经完成了项目的基础搭建(打包等工程化内容略过,本文主要介绍monorepo相关),似乎主要是yarn在工作,lerna没有没有派上用场,下面来介绍lerna在哪些地方可以赋能vue3.0。
lerna介绍
A tool for managing JavaScript projects with multiple packages.
一个在js项目中用来管理多个package的工具。
主要是便于开发者更加高效简便地管理package本身,依赖,发布。
1. 初始化项目
// 生成基本项目结构和 lerna 配置 $ lerna init
2. 安装依赖