Vue3.0中的monorepo管理模式的实现


Posted in Javascript onOctober 14, 2019

前言

前段时间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. 安装依赖

如果需要重新安装依赖,切记在删除项目根路径的node_modules前进行git提交保存,因为monorepo模式是以软链接的形式来实现内部 package 引用的,直接删除整个node_modules的同时会把所有package的文件删掉,难以恢复!

建议永不进行删除整个node_modules的操作,可以进入node_modules全选后再取消勾选内部package软链接再删除。

// 给所有 package 安装依赖,在对于的目录生成 node_modules,并在 node_modules 中为内部package生成软链接
$ lerna bootstrap
// 默认会使用 npm 安装,但是本项目使用 yarn,可以指定使用 yarn
$ lerna bootstrap --npm-client=yarn   // 或者在 lerna.json 配置 {"npmClient": "yarn"}
// 上述安装方式如果不同package之间安装了同一个npm包,会造成重复安装,增加安装时间和项目体积
// 可以利用 node_modules 向上查找的特性,将所有依赖安装到项目根路径的 node_modules 中,lerna 加上 --hosit即可
$ lerna bootstrap --hosit
// 使用lerna bootstrap --npm-client=yarn --hoist
// 会有冲突,报错--hoist is not supported with --npm-client=yarn, use yarn workspaces instead
------------------------------------------------
$ yarn // 推荐!! 用 yarn workspace 特性替代 lerna bootstrap

3. 清除pacakge中多余的node_modules

// 在 6.2 安装依赖时,部分npm包会给当前的package目录安装 node_modules
// 同时根路径中的 node_modules 也会安装项目
$ lerna clean

4. 查看所有pacakge

// package.json 中设置了 "private": true 的 package 不会展示
$ lerna ls

5. 查看有改动的pacakge

// package.json 中设置了 "private": true 的 package 不会展示
// 在 Independent mode 下只有改动过的 package 才会被发布
// vue3.0 采用的是 Fixed/Locked mode (default),每次都会发布所有 package,package 版本跟随项目的版本走
$ lerna changed

6. 推送到git和发布到npm(重要)

// 根据当前的 lerna 模式(Fixed/Locked mode (default) 或者 Independent mode)来进行整包发布或者有改动的 package 单独发布
// 每次发布会自动更新相关package的版本号,并且会更新引用该package的其他package依赖
$ lerna publish

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
ExtJS自定义主题(theme)样式详解
Nov 18 Javascript
javascript判断两个IP地址是否在同一个网段的实现思路
Dec 13 Javascript
javascript实现列表切换效果
May 02 Javascript
Svg.js实例教程及使用手册详解(一)
May 16 Javascript
JS中Json数据的处理和解析JSON数据的方法详解
Jun 29 Javascript
详解vue-router 2.0 常用基础知识点之导航钩子
May 10 Javascript
node.js中http模块和url模块的简单介绍
Oct 06 Javascript
为输入框加入数字js校验代码分享
Nov 02 Javascript
vue源码学习之Object.defineProperty对象属性监听
May 30 Javascript
vue修改对象的属性值后页面不重新渲染的实例
Aug 09 Javascript
vue组件开发之用户无限添加自定义填写表单的方法
Aug 28 Javascript
Vue 表情包输入组件的实现代码
Jan 21 Javascript
Vue3 源码导读(推荐)
Oct 14 #Javascript
基于JS实现父组件的请求服务过程解析
Oct 14 #Javascript
JavaScript this在函数中的指向及实例详解
Oct 14 #Javascript
vue循环数组改变点击文字的颜色
Oct 14 #Javascript
基于纯JS实现多张图片的懒加载Lazy过程解析
Oct 14 #Javascript
VUE+node(express)实现前后端分离
Oct 13 #Javascript
javascript sort()对数组中的元素进行排序详解
Oct 13 #Javascript
You might like
用Php实现链结人气统计
2006/10/09 PHP
php中cookie的作用域
2008/03/27 PHP
Zend Framework教程之Zend_Helpers动作助手ViewRenderer用法详解
2016/07/20 PHP
替换php字符串中的单引号为双引号的方法
2017/02/16 PHP
YII框架批量插入数据的方法
2017/03/18 PHP
HTML复选框和单选框 checkbox和radio事件介绍
2012/12/12 Javascript
javascript操纵OGNL标签示例代码
2014/06/16 Javascript
js实现的捐赠管理完整实例
2015/01/20 Javascript
深入理解JavaScript系列(21):S.O.L.I.D五大原则之接口隔离原则ISP详解
2015/03/05 Javascript
通用无限极下拉菜单的实现代码
2016/05/31 Javascript
JavaScript提升性能的常用技巧总结【经典】
2016/06/20 Javascript
javascript中异常处理案例(推荐)
2016/10/03 Javascript
Express之get,pos请求参数的获取
2017/05/02 Javascript
jQuery plugin animsition使用小结
2017/09/14 jQuery
vue 中滚动条始终定位在底部的方法
2018/09/03 Javascript
VUE脚手架具体使用方法
2019/05/20 Javascript
浅谈Vue为什么不能检测数组变动
2019/10/14 Javascript
vue使用recorder.js实现录音功能
2019/11/22 Javascript
vue v-for 点击当前行,获取当前行数据及event当前事件对象的操作
2020/09/10 Javascript
Python IDLE入门简介
2017/12/08 Python
python3解析库lxml的安装与基本使用
2018/06/27 Python
pandas.DataFrame删除/选取含有特定数值的行或列实例
2018/11/07 Python
一百行python代码将图片转成字符画
2021/02/19 Python
在matplotlib的图中设置中文标签的方法
2018/12/13 Python
python多线程实现代码(模拟银行服务操作流程)
2020/01/13 Python
CSS3——齿轮转动关键代码
2013/05/02 HTML / CSS
世界著名的顶级牛排:Omaha Steak(奥马哈牛排)
2016/09/20 全球购物
Banana Republic英国官网:香蕉共和国,GAP集团旗下偏贵族风
2018/04/24 全球购物
为什么group by 和order by会使查询变慢
2014/05/16 面试题
采购部岗位职责
2013/11/24 职场文书
应届本科生推荐信范文
2013/12/25 职场文书
旷课检讨书3000字
2014/02/04 职场文书
公务员平时考核实施方案
2014/03/11 职场文书
毕业设计指导教师评语
2014/12/30 职场文书
JavaScript的function函数详细介绍
2021/11/20 Javascript
python画条形图的具体代码
2022/04/20 Python