介绍
Yarn 从 1.0 版开始支持 Workspace (工作区),提供的monorepo
的依赖管理机制,用于在代码仓库的根目录下管理多个package的依赖。
Workspace 能更好的统一管理有多个项目的仓库,既可在每个项目下使用独立的 package.json 管理依赖,又可便利的享受一条 yarn 命令安装或者升级所有依赖等。更重要的是可以使多个项目共享同一个 node_modules
目录,提升开发效率和降低磁盘空间占用。
开启yarn workspace
workspaces 是 yarn 相对 npm 的一个重要优势(另一个优势是下载更快),它允许我们使用 monorepo 的形式来管理项目。
开启 workspace 的功能也比较简单,只需要在 package.json 里面将 private 设置为 true,并且规定好 workspaces 字段里面的子项目就好了。
{ ... private: true, workspaces: [ "packages/*" ] }
private
:根目录一般是项目的脚手架,无需发布,"private": true
会确保根目录不被发布出去。
workspaces:
声明workspace中package的路径。值是一个字符串数组,支持Glob通配符。其中"packages/*"
是社区的常见写法,也可以枚举所有package: "workspaces": ["package-a", "package-b"]
。
当然,yarn workspace 没有规定你一定要放到 packages 目录下面。你也可以不使用通配符,直接手动声明每个子项目。
{ ... private: true, workspaces: [ "packages/project1", "packages/project2" ] }
在安装 node_modules 的时候它不会安装到每个子项目的 node_modules 里面,而是直接安装到根目录下面,这样每个子项目都可以读取到根目录的 node_modules。
整个项目只有根目录下面会有一份 yarn.lock 文件。子项目也会被 link 到 node_modules 里面,这样就允许我们就可以直接用 import 导入对应的项目。
- node_modules - project1 - project2 - project3 - packages - shared - src - index.ts - project1 - node_modules - src - index.ts - package.json - project2 - node_modules - src - index.ts - package.json - project3 - node_modules - src - index.ts - package.json - yarn.lock - package.json - tsconfig.json
当然,如果你的子项目里面依赖了不同版本的包,那么也会在子项目的 node_modules 里面安装对应版本的包。比如根目录的 package.json 里面是 2.5 的 vue,而 project1 里面安装了 2.6 的 vue,那么就会在根目录的 node_modules 里面安装 2.5 版本,而 project 下面的 node_modules 安装 2.6 版本。
- node_modules - [email protected] - packages - shared - src - index.ts - project1 - node_modules - [email protected] - src - index.ts - package.json - project2 - node_modules - src - index.ts - package.json - project3 - node_modules - src - index.ts - package.json - yarn.lock - package.json - tsconfig.json
如果多个子项目依赖了同一个包的不同版本,那么根目录里面安装的就是版本号最高的那个。
适用场景
1、零散的页面
这种场景就是前面说过的一些 H5 活动页,他们可能都依赖了 React、React-dom 等等,但又需要部署到不同的域名下面,这样就不方便用 React-router 来管理了。
所以这里我们就可以将他们放到同一个仓库里面,用 monorepo 的形式来管理这个仓库。
由于他们使用了相同的技术栈,那么 eslint、prettier,甚至 webpack 配置都可以提取到最外面,不用维护在每个项目里面。
以 create-react-app eject 之后的配置为例:
- node_modules - react - react-dom - redux - lodash - packages - project1 - package.json - project2 - package.json - config - webpack.config.js - webpack.dev.config.js - scripts - create.js - bin.js - build.js - start.js - .eslintrc.js - .prettierrc - commitlint.config.js - jest.config.js - tsconfig.js - package.json - yarn.lock
我们可以看到,通用配置都被提取到了最外层。
如果运行或者构建子项目,只需要在子项目的 package.json 里面这么配置。
"start": "node ../../scripts/start.js", "build": "node ../../scripts/build.js", "test": "node ../../scripts/test.js"
2、前后端项目
有时候我们需要用 NodeJS 为自己开发的前端项目写一些简单接口,常常需要创建一个 server 项目,但这个项目功能很简单,也只有这个前端项目用。
那我们就不必把他们用两个仓库来管理,可以直接放到同一个仓库管理。
- website - package.json - server - package.json - package.json
在构建的时候,可以直接用 server 去渲染 website 最后构建出来的 index.html,这样只需要配置一份 nginx 就行了。
命令
1、执行某个项目下面的命令:yarn workspace <workspace_name> <command> xxx
// 在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
2、执行所有项目下面的某个命令要用:yarn workspaces <command> xxx(若某个package中没有对应的命令则会报错)
// 运行所有package(foo、bar)中package.json的 scripts.build 命令 yarn workspaces run build
3、安装依赖
安装整个项目的依赖和常规的 yarn 用法一样,直接 yarn install
就完事了。
如果你想安装一个依赖,那么分下面三种场景:
- yarn workspaces add package:给所有应用都安装依赖
- yarn workspace <workspace_name> add package:给某个应用安装依赖
- yarn add -W -D package:给根应用安装依赖 (-W: --ignore-workspace-root-check ,允许依赖被安装在workspace的根目录)