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 相关文章推荐
javascript 日历提醒系统( 兼容所有浏览器 )
Apr 07 Javascript
Javascript 检测、添加、移除样式(className)函数代码
Sep 08 Javascript
原生js实现查找/添加/删除/指定元素的class
Apr 12 Javascript
在JS中操作时间之getUTCMilliseconds()方法的使用
Jun 10 Javascript
Node.js中防止错误导致的进程阻塞的方法
Aug 11 Javascript
浅析Javascript ES6新增值比较函数Object.is
Aug 24 Javascript
JS不完全国际化&本地化手册 之 理论篇
Sep 27 Javascript
react开发教程之React 组件之间的通信方式
Aug 12 Javascript
JS设计模式之状态模式概念与用法分析
Feb 05 Javascript
Angular Excel 导入与导出的实现代码
Apr 17 Javascript
基于Vue+ElementUI的省市区地址选择通用组件
Nov 20 Javascript
vue实现网络图片瀑布流 + 下拉刷新 + 上拉加载更多(步骤详解)
Jan 14 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 地址栏信息的获取代码
2009/01/07 PHP
PHP添加Xdebug扩展的方法
2014/02/12 PHP
PHP获取当前完整URL地址的函数
2014/12/21 PHP
php实现mysql数据库分表分段备份
2015/06/18 PHP
十个PHP高级应用技巧果断收藏
2015/09/25 PHP
php获得客户端浏览器名称及版本的方法(基于ECShop函数)
2015/12/23 PHP
Ubuntu VPS中wordpress网站打开时提示”建立数据库连接错误”的解决办法
2016/11/03 PHP
Laravel框架实现多个视图共享相同数据的方法详解
2019/07/09 PHP
获取Javscript执行函数名称的方法
2006/12/22 Javascript
推荐5 个常用的JavaScript调试技巧
2015/01/08 Javascript
node.js操作mysql(增删改查)
2015/07/24 Javascript
Angularjs 动态改变title标题(兼容ios)
2016/12/29 Javascript
js cookie实现记住密码功能
2017/01/17 Javascript
详解Weex基于Vue2.0开发模板搭建
2017/03/20 Javascript
微信小程序中post方法与get方法的封装
2017/09/26 Javascript
JS模拟实现哈希表及应用详解
2018/05/04 Javascript
详解小程序循环require之坑
2019/03/08 Javascript
vue微信分享插件使用方法详解
2020/02/18 Javascript
JavaScript中变量提升和函数提升的详解
2020/08/07 Javascript
Python自定义scrapy中间模块避免重复采集的方法
2015/04/07 Python
Python中的字符串类型基本知识学习教程
2016/02/04 Python
python 异常处理总结
2016/10/18 Python
Python面向对象之继承代码详解
2018/01/29 Python
Python实现的绘制三维双螺旋线图形功能示例
2018/06/23 Python
Python企业编码生成系统之主程序模块设计详解
2019/07/26 Python
django将网络中的图片,保存成model中的ImageField的实例
2019/08/07 Python
python实现的自动发送消息功能详解
2019/08/15 Python
使用Django清空数据库并重新生成
2020/04/03 Python
TripAdvisor越南:全球领先的旅游网站
2017/09/21 全球购物
波兰香水和化妆品购物网站:Notino.pl
2017/11/07 全球购物
任课老师推荐信范文
2013/11/24 职场文书
会计专业应届生求职信
2013/11/24 职场文书
村委会贫困证明范文
2014/09/21 职场文书
2016高三毕业赠言寄语
2015/12/04 职场文书
Python制作动态字符画的源码
2021/08/04 Python
Python Pandas 删除列操作
2022/03/16 Python