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

前言

前段时间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   

monorepo demo 链接

总结

本文介绍了vue3.0中monorepo管理模式的实现,通过yarn workspace和lerna两者相结合,达到了在一个repo 中高效便捷地管理多个package的目的。

在我们日常工作中可能没有开发白鹭引擎,vue这类大型框架的需求,但是这不代表我们用不到该模式,下面我总结了几种适合monorepo管理模式的场景:

  1. 大型框架,依赖自身开发的多个独立底层模块支撑;
  2. 后台项目,技术栈统一的多个后台系统,每个系统作为独立的package单独开发,优化开发和打包时间,同时共用的组件和js方法可以作为一个package;
  3. ui组件库,各个组件之间独立实现按需加载,例如饿了么的移动端组件库mint-ui;
  4. sdk,接入同一sdk的不同渠道代码统一管理;
  5. ...

参考资料

框架开发中的基础设施搭建
Vue 3 源码导读
基于lerna和yarn workspace的monorepo工作流

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

(0)

相关推荐

  • Vue3.0数据响应式原理详解

    基于Vue3.0发布在GitHub上的第一版源码(2019.10.05)整理 预备知识 ES6 Proxy,整个响应式系统的基础. 新的composition-API的基本使用,目前还没有中文文档,可以先通过这个仓库(composition-api-rfc)了解,里面也有对应的在线文档. 先把Vue3.0跑起来 先把vue-next仓库的代码clone下来,安装依赖然后构建一下,vue的package下的dist目录下找到构建的脚本,引入脚本即可. 下面一个简单计数器的DEMO: <!DOCTY

  • 浅谈Vue3.0之前你必须知道的TypeScript实战技巧

    很多人对TypeScript的使用还停留在基本操作上,其实TypeScript的特性非常强大,我们利用好这些特性可以有效地提高代码质量.加速开发效率,今天就介绍9个非常实用的TypeScript技巧或者特性. 注释的妙用 我们可以通过 /** */ 来注释TypeScript的类型,当我们在使用相关类型的时候就会有注释的提示,这个技巧在多人协作开发的时候十分有用,我们绝大部分情况下不用去花时间翻文档或者跳页去看注释. 巧用类型推导 TypeScript 能根据一些简单的规则推断(检查)变量的类型

  • 你了解vue3.0响应式数据怎么实现吗

    从 Proxy 说起 什么是Proxy proxy翻译过来的意思就是"代理",ES6对Proxy的定位就是target对象(原对象)的基础上通过handler增加一层"拦截",返回一个新的代理对象,之后所有在Proxy中被拦截的属性,都可以定制化一些新的流程在上面,先看一个最简单的例子 const target = {}; // 要被代理的原对象 // 用于描述代理过程的handler const handler = { get: function (target,

  • vue3.0中的双向数据绑定方法及优缺点

    熟悉vue的人都知道在vue2.x之前都是使用object.defineProperty来实现双向数据绑定的 而在vue3.0中这个方法被取代了 1. 为什么要替换Object.defineProperty 替换不是因为不好,是因为有更好的方法使用效率更高 Object.defineProperty的缺点: 1. 在Vue中,Object.defineProperty无法监控到数组下标的变化, 导致直接通过数组的下标给数组设置值,不能实时响应. push() pop() shift() unsh

  • 详解Vue3.0 前的 TypeScript 最佳入门实践

    前言 我个人对更严格类型限制没有积极的看法,毕竟各类转类型的骚写法写习惯了. 然鹅最近的一个项目中,是 TypeScript + Vue ,毛计喇,学之...-真香! 注意此篇标题的"前",本文旨在讲Ts混入框架的使用,不讲Class API 1. 使用官方脚手架构建 npm install -g @vue/cli # OR yarn global add @vue/cli 新的 Vue CLI 工具允许开发者 使用 TypeScript 集成环境 创建新项目. 只需运行 vue cr

  • Vue3.0结合bootstrap创建多页面应用

    本人主要做c#winform应用,刚接触vue,发现用vue做单页面应用的比较多,多页面的资料很少,特别是用vue3.0版本做多页面的资料,更少,所以自己整理一下,结合bootstrap和jquery,也可以给有需要的同行做个参考. 1.首先用 vue --version 命令查一下安装的vue-cli版本,要3.x版本,我原先装的是2.9.6版本的 2.卸载vue-cli,执行命令:cnpm uninstall -g vue-clinpm uninstall -g vue-cli ,执行完就好

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

    前言 前段时间9月21日参加了在成都举办的第五届FEDAY, 印象比较深刻的是白鹭引擎首席架构师@王泽分享的<框架开发中的基础设施搭建>,提到了在下一代白鹭引擎中使用到monorepo模式,以用来管理多个模块,协调各个模块之间的依赖更新. 正好在国庆期间10月5日尤大公开了vue3.0已完成的源码,也是采用了monorepo管理模式,看来monorepo确实有其独到的优势,再加上以前在项目中遇到过相关的痛点,所以深入地了解了一下这种模式,本文将基于vue3.0讨论如何通过monorepo模式来

  • 快速掌握Vue3.0中如何上手Vuex状态管理

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.Vuex 也集成到 Vue 的官方调试工具 devtools,提供了诸如零配置的 time-travel 调试.状态快照导入导出等高级调试功能. 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的.确实是如此--如果您的应用够简单,您最好不要使用 Vuex.一个简单的 store 模式就足够您所需了.但是,如果您需要构建一个中大型

  • vue3.0中setup使用(两种用法)

    一.setup函数的特性以及作用 可以确定的是 Vue3.0 是兼容 Vue2.x 版本的 也就是说我们再日常工作中 可以在 Vue3 中使用 Vue2.x 的相关语法 但是当你真正开始使用 Vue3 写项目时 你会发现他比 Vue2.x 方便的多 Vue3 的一大特性函数 ---- setup 1.setup函数是处于 生命周期函数 beforeCreate 和 Created 两个钩子函数之间的函数 也就说在 setup函数中是无法 使用 data 和 methods 中的数据和方法的 2.

  • vue3.0中友好使用antdv示例详解

    前言 随着我们vue3.0的出现,我们的ui组件库也有了一些变化,像我们的旧版的element-ui已经不能在vue3.0中使用了,如果要使用element的话需要使用最新版的element-plus,由于发现它并不太好用,因此我选择了Ant Design Vue. 如果我们以前经常使用antd的话,我们使用起来这个上手会非常方便. 在vue3.0中引入我们的antdv 1.首先使用我们的vue/cli创建vue3.0项目并使用less 2. 在vue3.0中使用的话我们需要安装 ant-des

  • vue3.0中使用element的完整步骤

    前言: 在vue3.0中使用element框架,因为element是支持vue2.0的,他推出的支持vue3.0的版本叫 element-plus 官网入口:点我进入 一.个人遇到的问题与解决办法: 遇到的问题: 我直接用cnpm  i element-plus -S 装的版本,不知道为啥,一直报错 图1,版本型号 图2 ,我的代码中使用图3 解决办法: 我把package.json中的element-plus的版本更换成    下面这句话,解决了问题(是否为最新版本问题,还在求证中) "ele

  • Vue3.0中Ref与Reactive的区别示例详析

    目录 Ref与Reactive Ref Reactive Ref与Reactive的区别 shallowRef 与shallowReactive toRaw ---只修改数据不渲染页面 markRaw --- 不追踪数据 toRef --- 跟数据源关联 不修改UI toRefs ---设置多个toRef属性值 customRef ---自定义一个ref ref 捆绑页面的标签 总结 Ref与Reactive Ref Ref 用来创建基础类型的响应式数据,模板默认调用value显示数据.方法中修

  • 如何在vue3.0+中使用tinymce及实现多图上传文件上传公式编辑功能

    相关文档 本文部分内容借鉴: https://www.cnblogs.com/zhongchao666/p/11142537.html tinymce中文文档: http://tinymce.ax-z.cn/ 安装tinymce 1.安装相关依赖 yarn add tinymce || npm install tinymce -S yarn add @tinymce/tinymce-vue || npm install @tinymce/tinymce-vue -S 2.汉化编辑器前往此地址下载

  • vue3.0中的watch侦听器实例详解

    目录 前言 侦听器和计算属性的区别 vue3如何使用watch呢? 基本使用 监听多个响应式数据 侦听reactive定义的响应式数据 监听reactive定义的响应式数据的某一个属性 配置选项用法 总结 前言 虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器.这就是为什么 Vue 通过watch选项提供了一个更通用的方法,来响应数据的变化.当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的. 侦听器和计算属性的区别 计算属性里不可以做异步操作,侦听器可以做异步操作

  • vue3.0中使用element UI表单遍历校验问题解决

    问题 在使用vue3.0写项目的时候遇到一个需要遍历的表单,可以增加删除表单对象 不考虑校验问题的话,就是简单的数组包form对象.涉及校验的时候,按照以往的写法就是绑定ref值,然后调用组件的validate方法[form表单中配置rule规则]. 解决方法就是将数组内嵌在一个对象中,对象的结构跟我们定义的form对象结构一致 //我们需要遍历的form对象数组 const arr = [ { name:'', sex:'', age:'', },{ name:'', sex:'', age:

随机推荐