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 相关文章推荐
JQuery 选择器 xpath 语法应用
May 13 Javascript
关于scrollLeft,scrollTop的浏览器兼容性测试
Mar 19 Javascript
ExtJS4如何给同一个formpanel不同的url
May 02 Javascript
JS上传图片前实现图片预览效果的方法
Mar 02 Javascript
JavaScript转换二进制编码为ASCII码的方法
Apr 16 Javascript
利用Mongoose让JSON数据直接插入或更新到MongoDB
May 03 Javascript
vuejs+element-ui+laravel5.4上传文件的示例代码
Aug 12 Javascript
Angularjs 1.3 中的$parse实例代码
Sep 14 Javascript
Javascript 实现 Excel 导入生成图表功能
Oct 22 Javascript
JavaScript 对引擎、运行时、调用堆栈的概述理解
Oct 22 Javascript
微信小程序实现页面分享onShareAppMessage
Aug 12 Javascript
JavaScript 判断数据类型的4种方法
Sep 11 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
cache_lite试用
2007/02/14 PHP
php中ob(Output Buffer 输出缓冲)函数使用方法
2007/07/21 PHP
实用函数5
2007/11/08 PHP
php Mysql日期和时间函数集合
2007/11/16 PHP
比较简单的百度网盘文件直链PHP代码
2013/03/24 PHP
php实现根据IP地址获取其所在省市的方法
2015/04/30 PHP
PHP join()函数用法与实例讲解
2019/03/11 PHP
基于jquery的内容循环滚动小模块(仿新浪微博未登录首页滚动微博显示)
2011/03/28 Javascript
Nodejs为什么选择javascript为载体语言
2015/01/13 NodeJs
jQuery中live()方法用法实例
2015/01/19 Javascript
NodeJS学习笔记之Connect中间件模块(二)
2015/01/27 NodeJs
js控制网页背景音乐播放与停止的方法
2015/02/06 Javascript
JS实现选择TextArea内文本的方法
2015/08/03 Javascript
jQuery实现标签页效果实战(4)
2017/02/08 Javascript
JS查找数组中重复元素的方法详解
2017/06/14 Javascript
Vue中引入样式文件的方法
2017/08/18 Javascript
web前端开发中常见的多列布局解决方案整理(一定要看)
2017/10/15 Javascript
JavaScript数组去重算法实例小结
2018/05/07 Javascript
浅谈webpack4 图片处理汇总
2018/09/12 Javascript
Vue动态面包屑功能的实现方法
2019/07/01 Javascript
Vue.js组件使用props传递数据的方法
2019/10/19 Javascript
基于node+vue实现简单的WebSocket聊天功能
2020/02/01 Javascript
vue自定义指令和动态路由实现权限控制
2020/08/28 Javascript
Python里disconnect UDP套接字的方法
2015/04/23 Python
python中hashlib模块用法示例
2017/10/30 Python
Python基础教程之异常详解
2019/01/10 Python
10 分钟快速入门 Python3的教程
2019/01/29 Python
python:批量统计xml中各类目标的数量案例
2020/03/10 Python
ETO男装官方网店:ETO Jeans
2019/02/28 全球购物
英国女性化妆品收纳和家具网站:Beautify
2019/12/07 全球购物
继承时候类的执行顺序问题,一般都是选择题,问你将会打印出什么?
2015/11/18 面试题
优秀幼教自荐信
2014/02/03 职场文书
小学音乐教学反思
2014/02/05 职场文书
redis requires ruby version2.2.2的解决方案
2021/07/15 Redis
TV动画「神渣☆爱豆」公开第一弹主视觉图
2022/03/21 日漫
nginx搭建NFS网络文件系统
2022/04/14 Servers