NPM Workspace 的基本概念


NPM Workspace 的基本概念

Owner: fredbrock

描述

工作区(Workspace)的概念

用于管理多个相互关联的包(子项目)在同一个代码仓库中的依赖和脚本,用于Monorepo 项目。

在 npm 工作区(Workspaces)的概念中,每个子项目(子包)通常对应一个工作区。换句话说,一个工作区就是一个独立的 npm 包,具有自己的 package.json 文件和独立的依赖管理。这些子项目(工作区)可以位于同一个 Monorepo 仓库中,并由顶层的 package.json 文件来统一管理。

作用:

  1. 集中管理依赖:在顶层执行一次安装,无需每个项目单独使用命令安装依赖。
  2. 共享依赖:将多个子项目的共享依赖提升到顶层,避免重复安装。
  3. 跨包脚本执行:在任意目录运行子项目的命令。
  4. 内部链接:本地的子包(比如组件库,工具库),可以通过符号链接并使用。

工作区的结构和关系

顶层项目:这是 Monorepo 项目的根目录,包含一个顶层的 package.json 文件,定义了整个项目的工作区结构。

子项目(工作区):这些是位于特定路径下的独立 npm 包,每个子项目都有自己的 package.json 文件,负责定义自己的依赖、脚本和其他配置,一般放在packages/目录中。

基本结构示例

my-workspaces/
├── package.json         // 顶层 package.json
├── packages/
│   ├── project-a/       // 子项目 A
│   │   ├── package.json // Project A 的 package.json
│   ├── project-b/       // 子项目 B
│   │   ├── package.json // Project B 的 package.json
│   └── project-c/       // 子项目 C
│       ├── package.json // Project C 的 package.json

创建工作区

 mkdir my-workspaces
 cd my-workspaces
 npm init -y    // 初始一个npm项目
 npm init -w ./packages/project-a -y  // 创建子项目,project-a
 npm init -w ./packages/project-b -y  // 创建子项目,project-b

根目录 package.json 将添加如下配置

  "workspaces": [
    "packages/project-a",
    "packages/project-b"
  ]
  ...

表示定义了两个工作区(可以理解为子项目),project-aproject-b

使用工作区

向工作区添加依赖项

比如:这里我要 project-a 工作区使用 lodash 这个包

npm install lodash -w project-a

-w:是—workspace命令选项的简写,值是要添加的工作区的名称,如果不加-w参数,依赖包将添加到顶层依赖中,用于多个工作区共享。

向project-a工作添加一些基本代码

创建index.js文件,添加一些工具方法。

// project-a/index.js
const _ = require("lodash");
module.exports = {
  add: (a, b) => a + b,
  print(a) {
    console.log(_.join(["Hello", a], " ~"));
  },
};

解释:这里我导出了使用NodeJS CommonJS语法导出了两个工具函数。

add:一个用于计算两个值加法。

print:接收一个参数,使用lodash的join向控制台输入拼接的字符串。

向project-b工作添加一些基本代码

创建 index.js 文件, 导入project-a工作区的模块,调用project-aprint方法,打印输出。

// project-b/index.js
const moduleA = require("project-a");
console.log(moduleA.print("World")); 

测试功能能否运行

命令行定位到project-b工作区目录,运行如下命令

node index.js

在工作区上下文中运行命令

每个工作区都有自己的npm scripts 脚本,传统方式是定位到特定项目,然后在当前目录运行脚本。

通过npm workspace 可以在项目任意目录执行特定工作区的脚本。

现在我们要运行 project-b工作区的命令

在project-b/package.json,添加一条 npm 脚本。

  "scripts": {
    "dev": "node index.js",
  },
  ...

在项目任意目录运行下面命令,比如我在 my-workspaces/packages 目录中运行如下脚本

 npm run dev --workspace=project-b

输出如下结果

@fredbrock packages npm run dev --workspace=project-b

> [email protected] dev
> node index.js

Hello ~World
undefined

工作区上下文命令的其他方法

在特定工作区运行脚本

npm run test --workspace=project-b

在工作区内运行脚本

cd packages/project-b && npm run test 

指定多个工作区运行脚本

npm run test --workspace=a --workspace=b

指定文件夹下的所有工作区运行脚本

npm run test --workspace=packages

所有定义的工作区中执行脚本。

npm run test --workspaces --if-present

完整代码:my-workspaces

总结

它利用 npm 的工作区功能,这使得在所有子项目中运行测试、构建、清理等操作变得非常简单,简化了Monorepo项目中的流程。

测试

什么是工作区? Monorepo中的子项目。

如何在根 package.json 指定工作区?
  "workspaces": [
    ...
  ]
}
如何在特定工作区安装依赖?
npm install lodash -w project-a
工作区之间如何相互使用依赖?
npm install project-b -w packages/project-a
如何添加依赖到顶层?
npm install react

参考链接