sufuwang / demo

My study note about technology
0 stars 0 forks source link

Node-Package Manager & Workspace #3

Open sufuwang opened 1 year ago

sufuwang commented 1 year ago

require 的原理

使用 require 引入一个 npm 包,存在这几种情况

  1. 原生模块:直接返回
  2. 非原生模块:从当前路径下的 node_modules 开始不断向父级的 node_modules 中寻找
  3. 未带后缀的路径:从文件夹中按照 index.js, index.json, index.node 的顺序查找
  4. 未带目标文件名的路径:先解析 package.json > main 文件,失败则从文件夹中按照 index.js, index.node 的顺序查找

找到目标文件之后,以 commonjs 为例,require 的原理如以下伪代码所示

function require(targetFileName) {
  const targetFile = readFile(targetFileName)
  const module = {
    name: targetFileName,
    ···
  }
  (new Function(targetFile))(module) 
  return module
}
sufuwang commented 1 year ago

npm & yarn 存在的问题

npm@2 的 node_modules 是嵌套存储的,npm 包的依赖存储于 npm 包的 node_modules 中,如果多个 npm 包依赖同一个 npm 包的话,这个 npm 包会被下载多次,若 npm 包的依赖很复杂,则嵌套的目录很深,Windows 系统路径的最大长度为 260 多个字符,在安装依赖的时候会出现意料之外的问题,并且 npm@2 没有 lock 文件固定 npm 包版本。简而言之,npm@2 的缺陷有:同一个依赖可能被多次安装,依赖嵌套,不能固定 npm 包版本

yarn 采用扁平化的安装结构和 yarn.lock 来解决上述问题,npm 包的依赖会被安装在项目的 node_modules 中,完美解决了上述两个问题,但引入了新的问题,被项目依赖的 npm 包会被安装到 node_modules 中,npm 包的依赖也会被安装到 node_modules 中,所以在项目中就可以引入一些不存在 dependencies / devDependencies 中,而这些不存在 dependencies / devDependencies 中,但存在于 node_modules 中的依赖,被称为幽灵依赖。需要注意的是,yarn 并不是完全不存在嵌套依赖的,当出现版本冲突的时候,yarn 是会采取嵌套依赖来解决的。简而言之,yarn 的缺陷有:解决版本冲突时,同一个依赖可能被多次安装,以及幽灵依赖

npm@3 和 yarn 的安装原理已经一致,且使用了 package-lock

sufuwang commented 1 year ago

pnpm 出现

Screenshot2022_11_30_142357

pnpm 会把 npm 包存储到 .pnpm store 中,即根目录下 node_modules/.pnpm,项目下的 node_modules/.pnpm 使用 hard linksymbolic link 去链接资源,第一次链接包 a 时,使用 hard link ,后续如果再次使用到 a 时,使用 symbolic link 链接到之前的 hard link ,这是 node_modules/.pnpm 的逻辑,对于 node_modules/!.pnpm 则为项目的 dependencies / devDependencies 依赖,而这些文件夹则一定是对于 node_modules/.pnpm 下文件夹的 symbolic link

sufuwang commented 1 year ago

Workspace

npm & yarn 中只需在根目录下的 package.json 添加 Workspace 的地址即可

"workspaces": [
  "apps/*"
],

这两种 Manager 会做两件事情

  1. 将所有依赖以扁平的结构安装在根目录下的 node_modules
  2. 将所有 Workspace 以 symbolic link 进行链接,链接存储在根目录下的 node_modules

这会放大幽灵依赖的缺点,前面提到的幽灵依赖只是针对第三方 npm 包,而这里还包括对 Workspace 的幽灵依赖。优点显而易见,这种管理方式可以减少硬盘存储、安装耗时

pnpm 不支持使用 package.json > Workspace 来定义,而是使用 pnpm-workspace.yaml

packages:
  - "apps/*"

pnpm 会严格按照目录下的 package.json 来安装依赖,避免了幽灵依赖,但安装耗时趋向最大,所以 pnpm 支持 .npmrc 文件来优化,比如对于共用的依赖,可以使用这个文件来提升到根目录下的 node_modules 文件夹,当然还有其他功能

pnpm 需要在 package.json 指定依赖的其他 Workspace

"dependencies": {
  "appa": "workspace:*",
  "appb": "workspace:*"
}
sufuwang commented 1 year ago

Command

npm & yarn 调用 Workspace 的 scripts 的 Command 是相同的

npm run dev --workspaces
npm run dev --workspace=main

pnpm 使用另一种

pnpm -F main dev
pnpm --filter main dev
pnpm -F '*' dev
pnpm -F '!main' -F '!other' dev