5

基于 Lerna 的 monorepo 实现跨项目组件共享

 1 year ago
source link: https://jelly.jd.com/article/6419a07bdecc790068411058
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
在开发中,我们可能会遇到多个项目有相同或高度相似的业务场景页面,这里我们可能会进行复制粘贴已有的组件,但是,这种解决方案并不值得提倡,那么本文我们探索一种比较优雅的解决方案。

最近有个项目,有着多个代码库,其中有插件、业务组件等相互依赖,在开发过程中,面临着来回切项目、包版本控制、不好调试等问题,这里来探索一种新的开发管理方式来解决上述痛点,即基于lerna的monorepo实现方式

二、Lerna

A tool for managing JavaScript projects with multiple packages.

Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.

Lerna 是一个管理多个 npm 模块的工具,是 Babel 自己用来维护自己的 Monorepo 并开源出来的一个项目。优化维护多包的工作流,解决多包互相依赖且需要手动维护多包发版问题,其优点如下:

  • 扁平:同一仓库下,统一管理维护多个 package
  • 集中:在根目录的 node_modules/ 文件夹下维护所有的 package 的三方依赖
  • 简化:根据文件变动统一执行命令,按需发包,自动升级版本并回写仓库、打 tag
  • 高效:有互相依赖的项目可直接关联,避免开发人员在多仓库之间切换

Lerna 已被很多项目使用,如:React、Vue、Angular、Ember,Jest等,接下来我们将从0到1构建一个基于 Lerna 的 Monorepo 项目,并实现跨项目组件共享

三、项目构建

第一步:初始化项目结构

a. 安装 Lerna

npm install lerna -g
// 或者
yarn global add lerna

b. 新建目录并初始化

mkdir monorepo-demo
cd monorepo-demo
lerna init --independent

Lerna 初始化的时候,追加了一个 --independent 参数,其含义是使用独立模式

在 Lerna 中,有两种模式:

  1. 固定模式: 所有 package 版本号保持一致,每次更新发包都是全量的
  2. 独立模式: 每个 package 版本号各自独立,互不影响,每次更新按需发包

c. 新建子项目

lerna create common
npm init vue@latest

common:共享业务组件

a项目:projectA

b项目:projectB

11d36b920f7b79f2.png

第二步:安装依赖包&清理依赖包

多个项目有相同依赖时,会在对应的 package 安装相同的包,出现重复安装问题,于是,我们使用 --hoist 把每个package里的依赖包提到工程根目录,来避免重复安装问题

lerna bootstrap --hoist 

再执行 lerna clean 来清除子项目里的包

learn clean 
11d36b920f7b79f2.png

每次命令都需要输入 --hoist 比较麻烦,这里推荐在 lerna.json 里配置

{
"command": {
"bootstrap": {
"hoist": true
}
}
}

这里依赖包提升,如果遇到同一个包不同的版本,会提升用的最多的版本,这样会出问题,所以,我们用 yarn workspace 来提升相同版本的包,不同版本的包还在各自的目录,不做提升

// 顶层package.json
{
"workspaces": [
"packages/*"
]
}

//lerna.json
{
"npmClient": "yarn",
"useWorkspaces": true
}

c. 启动项目

每次启动都要去到对应的项目里执行命令,比较麻烦,这里我们可以在工程在外层 package.json 增加对应项目的启动命令,这样就不用切换目录来启动项目了

"scripts": {
"start:aSite": "lerna --scope @mono-repo-demo/projecta run dev",
"start:bSite": "lerna --scope @mono-repo-demo/projectb run dev"
}

通过 yarn start:aSite 即可启动 a 项目

11d36b920f7b79f2.png
11d36b920f7b79f2.png

d. 创建公共组件

// common/QtCard.vue
<template>
这是个公共组件
</template>

引入公共组件

lerna add @mono-repo-demo/common --scope @mono-repo-demo/projecta  
11d36b920f7b79f2.png

a 项目引入

// projecta/App.vue
import QtCard from '@mono-repo-demo/common/components/QtCard.vue'
<qt-card></qt-card>
11d36b920f7b79f2.png

通过 learn public 命令发布,实际上也是 npm 发包,所以需要 npm login 登录一下 npm

11d36b920f7b79f2.png
11d36b920f7b79f2.png

至此,我们已经实现了最基本的 基于 Learn 的 monorepo 管理发布项目及包,还有很多东西值得我们去探索,比如 commitlint 配置、自动生成发包日志、编译压缩等,后期有时间我们将继续探索 Lerna的最佳实践


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK