Quiet
  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我

bajiu

  • 主页
  • 归档
  • 分类
  • 标签
  • 链接
  • 关于我
Quiet主题
  • 前端工程化

使用Lerna & Yarn Workspaces 构建mono-repo项目

bajiu
前端

2020-08-01 12:26:27

因为公司项目独立npm包有点儿多,所以管理需要改变一下子项目结构,作筒一项目管理mono-repo管理方式的尝试

一、几种代码管理方式

MonoLith: 一个项目,一个 Git 仓库。

  • 优点:实现简单,一撸到底。
  • 缺点:复杂项目代码复用性低,且不利于团队协作。

Multi-Repo: 划分为多个模块,一个模块一个 Git 仓库

  • 优点:模块划分清晰,每个模块都是独立的 repo,利于团队协作
  • 缺点:代码管理难度增加。比如:1.某个模块出现bug 相应模块都需要编译、上线、涉及到手动控制版本非常繁琐。 2.issue 管理十分麻烦。

Mono-Repo: 划分为多个模块,所有模块放在一个 Git 仓库

  • 优点:代码结构清晰,利于团队协作,同时一个库降低了项目管理、代码管-理以及代码调试难度。
  • 缺点:项目变得庞大,模块变多后同样会遇到各种问题。所以需要有更好的构建工具支持。

二、Lerna & Yarn

Lerna是一种工具,它优化了使用git和npm管理多包存储库的工作流。lerna 提供了近20个指令。在 MonoRepo项目中我们使用lerna 进行版本控制和包发布管理。

// 常用
lerna bootstrap  // 安装所有依赖项并链接任何交叉依赖项
//例: lerna bootstrap --npm-client yarn --use-workspaces

lerna exec       // 在每个包中执行任意命令
//例: lerna exec 'yarn remove lodash' // 删除

lerna add        // 安装依赖,支持交叉依赖
// lerna add packageA --scope=packageB

// 版本发布
lerna changed    // 检查自上次发布以来哪些软件包已经更新
lerna diff       // 自上次发布以来,对所有包或单个包进行区分
lerna publish    // 发布版本

// 常用
lerna clean      // 清除项目中所有 node_modules
lerna init       // 初始化项目
lerna create     // 创建项目中的子package

// 其它
lerna run        // 在包含该脚本的包中运行 npm 脚本
lerna info       // 查看信息
lerna import     // 导入
lerna link       // 软链
lerna version    // 查看版本
lerna ls         // 列出当前 lerna 项目中的公共包

Lerna 的两种模式

  • Fixed(固定模式):默认。所有package 共用一个版本号,比如:babel 任何 package 的 major change 均会导致所有包都会进行 major version的更新。
  • Independent(独立模式):每个包都有自己独立的版本号。lerna会配合git,检查文件变动,只发布有改动的package。

Yarn

关于yarn workspaces,更详细的官方说明:

https://classic.yarnpkg.com/blog/2017/08/02/introducing-workspaces/

​Yarn​ 是 ​facebook​ 开源的一个快速、可靠、安全的依赖管理工具。

在 MonoRepo项目中我们使用Yarn Workspaces 管理我们的依赖关系。 它没有多个node_modules目录,而是智能地优化了依赖关系的安装,并允许在monorepo中进行依赖关系的交叉链接。

// 常用
yarn install    // 安装依赖项
yarn workspaces run clean  // 清除项目中所有 node_modules
// yarn workspaces info
// yarn workspaces run

yarn add        // 添加 package
yarn init       // 初始化
yarn publish    // 发布
yarn remove     // 删除

yarn workspace  // 具体某个工作区 
// yarn workspace awesome-package add react react-dom --dev

三、一个例子

需要了解的工具和类库:

  • Lerna:版本控制,包发布。
  • Yarn workspaces:依赖管理。
  • styled-components:是一个常用的 css in js 类库。
  • Babel:编译下一代JavaScript 的编译器。
  • Storybook:辅助UI组件开发的工具。
  • Jest:JavaScript 测试框架。

安装 Lerna

npm install -g lerna

项目创建

git init mono-repos
cd mono-repos
yarn add -D lerna
lerna init

/package.json

{
  "name": "root",
  "private": true,
  "devDependencies": {
    "lerna": "^3.20.2"
  }
}

/lerna.json

// 对 lerna 做简单修改 
{
  "packages": [
    "packages/*"
  ],
  "version": "independent",  // 【独立模式】每个包都有自己独立的版本号
  "npmClient": "yarn",  // 执行命令的client,默认为npm,我们设置为 yarn
  "useWorkspaces": true // 开启工作区模式 用 yarn 进行依赖管理
}

修改 /​package.json​ ,设置 Yarn workspaces

{
  "name": "root",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "devDependencies": {
    "lerna": "^3.20.2"
  }
}

babel

Babel 是一个 JavaScript 编译器。可以将es6+ 源码编译为 es5,让更多浏览器兼容。

yarn add --dev -W @babel/cli @babel/core @babel/preset-react @babel/preset-env babel-core@7.0.0-bridge.0 babel-loader babel-plugin-styled-components webpack

参数​-W​ 指定 Yarn 为整个 workspace 安装指定依赖。 所有依赖为组件间共享组件。

/.gitignore

.log
.DS_Store
.jest-*
lib
node_modules

/babel.config.js
babel全局配置文件。

module.exports = {
    plugins: ['babel-plugin-styled-components'],
    presets: ['@babel/preset-env', '@babel/preset-react']
};

我们先用简单的方式创建编译脚本,后续引入 webpack 后集成到 webpack中。

/package.json

"scripts": {
    "build": "lerna exec --parallel -- babel --root-mode upward src -d lib --ignore **/*.story.js,**/*.spec.js"
}
  • lerna exec​: 将接受任何命令并在所有 package 上运行。 此命令指示 Babel 将 ​/src​ 文件夹中的源码编译到​/lib​文件夹中。
    ​- –parallel​:在每个 package 上并行执行
  • –root-mode upward​:使用根目录中 babel.config.js 配置
  • –ignore /*.story.js,/*.spec.js​:忽略掉 ​.spec.js​文件 以及 ​.story.js​文件

/package.json
添加安装依赖脚本bootstrap指令:

"scripts": {
  "bootstrap": "lerna bootstrap --use-workspaces"
}

四、jest 测试集成

创建测试环境,然后编写一个简单的测试用例。我们将使用 jest 进行单元测试,它会自动执行以​.spec.js​结尾的文件。

yarn add --dev -W jest jest-styled-components babel-jest react-test-renderer jest-resolve jest-haste-map

接下来,让我们在根目录中对 jest 进行配置。

/jest.config.js

module.exports = {
    cacheDirectory: '.jest-cache',
    coverageDirectory: '.jest-coverage',
    coveragePathIgnorePatterns: ['<rootDir>/packages/(?:.+?)/lib/'],
    coverageReporters: ['html', 'text'],
    coverageThreshold: {
        global: {
            branches: 100,
            functions: 100,
            lines: 100,
            statements: 100
        }
    },
    testPathIgnorePatterns: ['<rootDir>/packages/(?:.+?)/lib/']
};

在 package.json 中添加测试脚本:

"scripts": {
  "coverage": "jest --coverage",
  "unit": "jest"
}

六、版本发布

在发布前,需要先提交源码到代码仓库。参考 GitHub 远程代码推送。

1、查看哪些 package 发生过更改

lerna changed

2、更改的具体内容

lerna diff

3、版本发布

Lerna publish

如果代码未提交,会有以下提示,需要先 提交代码。

转自: https://zhuanlan.zhihu.com/p/108118011

上一篇

EventEmitter API详解(附源码)

下一篇

Linux下命令行查看系统配置

©2024 By bajiu.