IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    解放你的 node_modules —— Plug\'n\'Play

    雨浣潇湘发表于 2019-07-26 07:29:14
    love 0

    node 模块现状

    在我们执行 npm install 时,npm 会做出如下操作:

    1. 向 registry 查询获取模块的地址
    2. 根据 package.json 中的配置确定需要安装的模块版本
    3. 下载对应的压缩包,存放在 ~/.npm 目录
    4. 解压压缩包到当前项目的 node_modules 目录

    而在 Node.js 中,我们提供给 require 方法的参数如果不是一个路径,也不是 node 的核心模块, node 将试图去当前目录的 node_modules 文件夹里搜索。如果当前目录的 node_modules 里没有找到, node 会继续试图在父目录的 node_modules 里搜索,这样递归下去直到根目录。

    这些过程都需要进行大量的文件 I/O 操作,这无疑是非常低效的。为了解决这些问题,Facebook 提出了 Plug’n’Play(PnP) 方案。

    PnP 原理

    在 Yarn 中,当我们开启 PnP 后,Yarn 会生成一个 .png.js 文件来描述项目的依赖信息和所需模块的查找路径。同时,项目目录下不再需要一个 node_modules 目录,取而代之的是一个全局的缓存目录,项目所需依赖都可以从这个目录中获取。

    使用方法

    可以在项目目录下执行 yarn --pnp ,或直接在 package.json 中修改如下字段开启 PnP:

    1
    2
    3
    4
    5
    {
    "installConfig": {
    "pnp": true
    }
    }

    如果你使用 CRA 来创建项目,也可以直接在命令中加入 --use-pnp。

    PnP 速度

    按照官方的说法, Generating it makes up for more than 70% of the time needed to run yarn install with a hot cache.

    在我的一个实际项目中,使用 npm i、yarn 和 PnP 安装依赖完成时间分别为 26.48s、19.71s 和 11.25s,提升极为可观。

    扩展

    pnpm

    pnpm 使用了 symlink 来记录模块路径,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    -> - a symlink (or junction on Windows)

    node_modules
    ├─ foo -> .registry.npmjs.org/foo/1.0.0/node_modules/foo
    └─ .registry.npmjs.org
    ├─ foo/1.0.0/node_modules
    | ├─ bar -> ../../bar/2.0.0/node_modules/bar
    | └─ foo
    | ├─ index.js
    | └─ package.json
    └─ bar/2.0.0/node_modules
    └─ bar
    ├─ index.js
    └─ package.json

    pnpm 在维护了模块层级的同时大幅度提升了安装速度,但是由于它的实现,无法保证和 npm 行为一致。

    tink

    tink 是 npm 官方提出的一种类似 PnP 的解决方案,和 .pnp.js 文件类似, tink 会在项目中生成一个 .package-map.json 文件用来记录各安装包内文件的 hash 值。目前 tink 依然处于测试阶段,在 npm 8 中我们将能尝试这一特性。



沪ICP备19023445号-2号
友情链接