阅读 894

Yarn Workspace使用指南

Yarn Workspaces(工作区)是Yarn提供的monorepo的依赖管理机制,从Yarn 1.0开始默认支持,用于在代码仓库的根目录下管理多个package的依赖。

Monorepo

假如你是一个npm工具的维护者,管理着多个功能相近的包,或者这些包之间存在依赖关系。如果将这些包拆分在不同仓库里,那么面临要跨多个包进行更改时,工作会非常繁琐和复杂。

为了简化流程,很多大型项目采用了menorepo的做法,即把所有的包放在一个仓库中管理。Babel、React、Vue、Jest等都使用了menorepo的管理方式。

Menorepo的优点是可以在一个仓库里维护多个package,可统一构建,跨package调试、依赖管理、版本发布都十分方便,搭配工具还能统一生成CHANGELOG;

缺点是代码仓库体积会变大,只开发其中一个package也需要安装整个项目的依赖。

来看一下Babel的仓库目录(简化):

babel/
|--package.json
|--yarn.lock
|--packages/
|  |--babel-cli/
|  |  |--package.json
|  |--babel-core/
|  |  |--package.json
|  |--babel-parser/
|  |  |--package.json
复制代码

Why Yarn Workspace?

  • 开发多个互相依赖的package时,workspace会自动对package的引用设置软链接(symlink),比yarn link更加方便,且链接仅局限在当前workspace中,不会对整个系统造成影响
  • 所有package的依赖会安装在最根目录的node_modules下,节省磁盘空间,且给了yarn更大的依赖优化空间
  • 所有package使用同一个yarn.lock,更少造成冲突且易于审查

如何使用Workspace

根目录的package.json设置:

{
  "name": "mono-demo",
  "version": "1.0.0",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
}
复制代码

private

根目录一般是项目的脚手架,无需发布,"private": true会确保根目录不被发布出去。

workspaces:

声明workspace中package的路径。值是一个字符串数组,支持Glob通配符。

其中"packages/*"是社区的常见写法,也可以枚举所有package: "workspaces": ["package-a", "package-b"]

命令和示例

PS:以下命令基于yarn@1.x

假设项目中有foo和bar两个package:

mono-demo/
|--package.json
|--packages/
|  |--foo/
|  |  |--package.json
|  |--bar/
|  |  |--package.json
复制代码

yarn workspace <workspace_name> <command>

在指定的package中运行指定的命令。

# 在foo中添加react,react-dom作为devDependencies
yarn workspace foo add react react-dom --dev

# 移除bar中的lodash依赖
yarn workspace bar remove lodash

# 运行bar中package.json的 scripts.test 命令
yarn workspace bar run test

复制代码

yarn workspaces run <command>

在所有package中运行指定的命令,若某个package中没有对应的命令则会报错。

# 运行所有package(foo、bar)中package.json的 scripts.build 命令
yarn workspaces run build
复制代码

yarn workspaces info [--json]

查看项目中的workspace依赖树。

例如我的bar依赖了foo,如下:

// bar/package.json
{
  "name": "bar",
  "version": "1.0.0",
  "dependencies": {
    "foo": "^1.0.0"
  }
}
复制代码

在项目中的依赖结构是这样的(假设foo/package.json的版本匹配bar的依赖版本,否则会另外安装一个匹配的foo):

/package.json
/yarn.lock

/node_modules
/node_modules/foo -> /packages/foo

/packages/foo/package.json
/packages/bar/package.json
复制代码

那么运行yarn workspaces info会得到如下输出:

yarn workspaces v1.22.4
{
  "bar": {
    "location": "packages/bar",
    "workspaceDependencies": [
      "foo"
    ],
    "mismatchedWorkspaceDependencies": []
  },
  "foo": {
    "location": "packages/foo",
    "workspaceDependencies": [],
    "mismatchedWorkspaceDependencies": []
  }
}
复制代码

yarn <add|remove> <package> -W

  • -W: --ignore-workspace-root-check ,允许依赖被安装在workspace的根目录

管理根目录的依赖。

# 安装eslint作为根目录的devDependencies
yarn add eslint -D -W
复制代码

Yarn Workspace与Lerna

Lerna是社区主流的monorepo管理工具之一,集成了依赖管理、版本发布管理等功能。

使用Learn管理的项目的目录结构和yarn workspace类似。

Lerna的依赖管理是也基于yarn/npm,但是安装依赖的方式和yarn workspace有些差异:

Yarn workspace只会在根目录安装一个node_modules,这有利于提升依赖的安装效率和不同package间的版本复用。而Lerna默认会进到每一个package中运行yarn/npm install,并在每个package中创建一个node_modules。

目前社区中最主流的方案,也是yarn官方推荐的方案,是集成yarn workspace和lerna。使用yarn workspace来管理依赖,使用lerna来管理npm包的版本发布。

参考

文章分类
前端
文章标签