惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
WordPress大学
WordPress大学
博客园 - 叶小钗
B
Blog RSS Feed
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
Scott Helme
Scott Helme
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
B
Blog
V
V2EX
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
PCI Perspectives
PCI Perspectives
雷峰网
雷峰网
The Register - Security
The Register - Security
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
N
News and Events Feed by Topic
H
Hackread – Cybersecurity News, Data Breaches, AI and More
U
Unit 42
Security Latest
Security Latest
NISL@THU
NISL@THU
腾讯CDC
S
SegmentFault 最新的问题
小众软件
小众软件
The GitHub Blog
The GitHub Blog
月光博客
月光博客
A
Arctic Wolf
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
Netflix TechBlog - Medium
IT之家
IT之家
D
DataBreaches.Net
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News | PayPal Newsroom
L
LINUX DO - 最新话题
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
J
Java Code Geeks
TaoSecurity Blog
TaoSecurity Blog
P
Privacy International News Feed

記緒漂流

Cloudflare One 集成 OAuth 访问控制 | 記緒漂流 Cloudflare One 集成 OAuth 访问控制 打造专属记账助手 | 記緒漂流 打造专属记账助手 Numb | 記緒漂流 Numb 三月自白 | 記緒漂流 三月自白 相反的你和我・同频的心与心 | 記緒漂流 相反的你和我・同频的心与心 使用 Tailscale 内网穿透 | 記緒漂流 使用 Tailscale 内网穿透 在《HackHub》中成为世界首富 | 記緒漂流 在《HackHub》中成为世界首富 社交距离 | 記緒漂流 社交距离 UNIQLO × Akamai 联名 T 恤 | 記緒漂流 UNIQLO × Akamai 联名 T 恤 Windows 按键重映射 | 記緒漂流 Windows 按键重映射 少女・魔法・救赎 | 記緒漂流 少女・魔法・救赎 Live 初体验 | 記緒漂流 Live 初体验 《剧场版总集篇 GIRLS BAND CRY【后篇】嘿,未来。》观后有感 | 記緒漂流 《剧场版总集篇 GIRLS BAND CRY【后篇】嘿,未来。》观后有感 从 UnoCSS 迁至 Tailwind CSS | 記緒漂流 从 UnoCSS 迁至 Tailwind CSS AI² 与站点 LOGO | 記緒漂流 AI² 与站点 LOGO YAML 多行语法 | 記緒漂流 YAML 多行语法 所以我放弃了 npm 上下求索,以飨四方 | 記緒漂流 上下求索,以飨四方 理想、偏见与「博友圈」 | 記緒漂流 理想、偏见与「博友圈」 甲流就医纪实 | 記緒漂流 甲流就医纪实
所以我放弃了 npm | 記緒漂流
TuyuriTio · 2025-11-13 · via 記緒漂流

在处理某一条 PR 时,由于对方使用 pnpm,而我仍在项目中使用 npm,产生了一些冲突与误会。

我在开发初期的确考虑过使用 pnpm,不过处于一些奇怪的理由,换回了 npm

  1. npm扁平化依赖安装策略导致了幽灵依赖的特性,若模块 A 包含子依赖 B,则可以在不显式安装 B 的情况下直接在项目中 import 使用,这使得 package.json 中只包含最少数量的依赖,看上去比较整洁
  2. 据统计1npm 在多数场景下仍是使用人数最多的 Node.js 包管理器,私以为在开发中使用可以兼顾大多数缺乏开发经验的开发者;
  3. 我是信奉原教旨主义的精神变态。

但在这条 PR 中,为了逐渐使项目趋于规范,我显式安装了一部分幽灵依赖。

既然已经违背了最主要的第 1 条理由,那差不多是时候迁移到 pnpm 了。

性能优势

老生常谈的内容,还是简单概括一下 pnpm 的优势:

pnpm 采用内容寻址的存储方式2,所有模块都保存在磁盘的某一单一位置。

因此在项目中安装依赖时,会从该位置进行硬链接而不占用额外的磁盘空间,进而在安装速度远超 npm 的同时,相较 npm 简单粗暴复制文件的方式,能够节省大量存储空间。

不同场景下主流 Node.js 包管理器的性能表现可参考 Benchmarks

此外,pnpm 亦有许多其独有的特性,详细可阅读 Feature Comparison

工具迁移

最重要的是,pnpm 提供了 pnpm import 命令3,在我的项目中,即可以直接根据 package-lock.json 生成对应的 pnpm-lock.yaml

接着删除原有的 node_modules 目录及 package-lock.json 文件,然后使用 pnpm install 以其特有的结构重新安装依赖。

然后更新脚本命令和 CI/CD 配置,将所有的 npm run ...npx ... 替换为 pnpm ...

对于 GitHub Actions,运行 actions/setup-node 前需使用 pnpm/action-setup 预安装对应的包管理器4

    ...
    - name: Setup pnpm
      uses: pnpm/action-setup@v4
      with:
        version: 10

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '22'
        cache: 'pnpm'
    ...

最后为了增强规范性,可在 .gitignore 中添加对 package-lock.jsonyarn.lock 的忽略。


使用 npm 时,为了实现全覆盖的版本更新,使用了 npm-check-updates 包作为一种曲线救国的方案。

pnpm 则提供了 --interactive | -i 选项,可以说是对 ncu 的全方位升级,至少在更新这件事上无需过多操心。

版本发布配置

这部分才是我想记录的重点。

对于发布包而言,切换包管理或是只是一次 chore 更新,但对需要依靠完整仓库编译的主题项目而言,这无疑是个 BREAKING(破坏性) CHANGE(更新)

其重要性我想并不是像之前那样简单一句注释「This is a breaking change.」就能搪塞过去的,必须清楚地在发布日志中体现出来。

于是必须对先前的发布流程进行改造。

googleapis/release-please-action 提供了其上游配置文件 release-please-config.json 的路径选项,但 googleapis/release-please 似乎并未完整公开其配置文档,只能参照着 Schema 和源码差不多改改。

release-please-action 提供了 release-type 配置,我之前将其配置为 node,即可自动更新 package.json 文件。只是文档中提到,这是一种简单策略,一经提供将无法配置高级选项。

起初没看到这段文字,跌跌撞撞触发了许多不必要的 PR,最后还是在代码中发现的这个事实…

function loadOrBuildManifest(github: GitHub, inputs: ActionInputs): Promise<Manifest> {
  if (inputs.releaseType) {
    core.debug('Building manifest from config');
    return Manifest.fromConfig(
      github,
      github.repository.defaultBranch,
      {
        releaseType: inputs.releaseType,
        includeComponentInTag: inputs.includeComponentInTag,
        changelogHost: inputs.changelogHost,
        versioning: inputs.versioningStrategy,
        releaseAs: inputs.releaseAs,
      },
      {
        fork: inputs.fork,
        skipLabeling: inputs.skipLabeling,
      },
      inputs.path
    );
  }
  // ...
  core.debug('Loading manifest from config file');
  return Manifest.fromManifest(
    github,
    github.repository.defaultBranch,
    inputs.configFile,
    inputs.manifestFile,
    manifestOverrides
  ).then(manifest => {
    // ...
  });
}

那么接下来,创建 release-please-config.json

{
  "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
  "packages": {
    ".": {
      "versioning": "default",
      "release-type": "node",
      "include-component-in-tag": false,
      "bump-minor-pre-major": true,
      "changelog-sections": [
        // ...
        { "type": "chore", "section": "Miscellaneous Chores", "hidden": false },
        // ...
      ]
	}
  }
}
  • release-type:和工作流中一样,指定项目类型;
  • include-component-in-tag:在版本标签中指定组件名称,此处与之前的简单策略保持一致,设置为 false,否则可能无法衔接之前的版本进行迭代;
  • bump-minor-pre-major:这是我所需要的最重要的项,描述为「如果版本 < 1.0.0,则重大更改仅会影响次要版本」,也就是版本规范中第 4 条的内容;
  • changelog-sections:配置在发布日志中显示哪些类型的提交,这里启用了 chore 以记录重要变更,其中 section 的值来自工厂函数的默认值。

然后创建版本追踪文件 .release-please-manifest.json,根据先前的失败 PR 来看,填写当前的版本号即可:

接下来进行了一些毫无必要的脑瘫操作…

我希望这是最后一次提交,且不想再污染 PR 历史了,于是安装了 act 试图在本地测试…

release-please-action 显然是一个强依赖于 GitHub API 的工具,无论是环境还是权限的配置都极为麻烦,且似乎不太可行,最终放弃了。

好在,在想到使用 release-please 命令行工具进行 dry-run 测试之前,版本已经按照预期成功发布了。

Footnotes

  1. 2025 StackOverflow Developer Survey

  2. Saving disk space

  3. pnpm import

  4. actions/setup-node