Vue3.0 中的 monorepo 管理模式

前言

前段時間9月21日參加了在成都舉辦的第五屆FEDAY, 印象比較深入的是白鷺引擎首席架構師@王澤分享的《框架開發中的基礎設施搭建》,提到了在下一代白鷺引擎中使用到monorepo模式,以用來管理多個模塊,協調各個模塊之間的依賴更新。vue

正好在國慶期間10月5日尤大公開了vue3.0已完成的源碼,也是採用了monorepo管理模式,看來monorepo確實有其獨到的優點,再加上之前在項目中遇到過相關的痛點,因此深刻地瞭解了一下這種模式,本文將基於vue3.0討論如何經過monorepo模式來管理代碼的。node

什麼是 monorepo?

monorepo是一種將多個package放在一個repo中的代碼管理模式,摒棄了傳統的多個package多個repo的模式。
目前 Babel, React, Angular, Ember, Meteor, Jest等許多開源項目都使用該種模式來管理代碼。react

解決的問題

  1. 多個repo難以管理,編輯器須要打開多個項目;
  2. 某個模塊升級,依賴改模塊的其餘模塊須要手動升級,容易疏漏;
  3. 公用的npm包重複安裝,佔據大量硬盤容量,好比打包工具webpack會在每一個項目中安裝一次;
  4. 對新人友好,一句命令便可完成全部模塊的依賴安裝,且整個項目模塊不用到各個倉庫去找;

帶來的問題

  1. 全部package代碼集中在一個項目,單個項目體積較大;
  2. 全部package代碼對全部人可見,沒法作權限管理;

如何實現 monorepo?

目前業界最佳實踐是採用yarn workspace + lerna 來實現,vue3.0也是採用二者結合的方式來實現。webpack

yarn workspace能夠實如今一個項目中實現多個模塊的依賴新增和共用,而lerna的功能則更完善,不只能夠管理多個模塊,還有清除模塊node_modules,發佈模塊到npm,自動更新模塊間版本依賴,並支持全量發佈和根據改動單獨發佈等功能。git

yarn官方推薦用yarn來處理依賴安裝,用lerna來處理依賴更新和發佈問題。github

下面開始基於monorepo模式來搭建一個仿vue3.0的項目web

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種安裝形式typescript

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.0npm

lerna介紹

A tool for managing JavaScript projects with multiple packages.json

一個在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.0monorepo管理模式的實現,經過yarn workspacelerna二者相結合,達到了在一個repo 中高效便捷地管理多個package的目的。

在咱們平常工做中可能沒有開發白鷺引擎vue這類大型框架的需求,可是這不表明咱們用不到該模式,下面我總結了幾種適合monorepo管理模式的場景:

  1. 大型框架,依賴自身開發的多個獨立底層模塊支撐;
  2. 後臺項目,技術棧統一的多個後臺系統,每一個系統做爲獨立的package單獨開發,優化開發和打包時間,同時共用的組件和js方法能夠做爲一個package
  3. ui組件庫,各個組件之間獨立實現按需加載,例如餓了麼的移動端組件庫mint-ui
  4. sdk,接入同一sdk的不一樣渠道代碼統一管理;
  5. ...

參考資料

框架開發中的基礎設施搭建
Vue 3 源碼導讀
基於lerna和yarn workspace的monorepo工做流

相關文章
相關標籤/搜索