来看看写前端的是怎么混开源的一个很简单的 PR, 背后链接一起个很完整的开源贡献故事线,我很兴奋的想和大家分享。我想这其
前言:
一个很简单的 PR, 但是背后有很长一个故事线,链接一起个很完整的开源贡献故事线,我很兴奋的想和大家分享。我想这其中的某些个流程或许对你有些帮助。
很早之前 antd 的 GitHub 仓库有一个 CI: 每当有人贡献 PR 时,都会对 antd 进行一次构建,并验证构建产物是否能正常运行。
起初采用 CodeSandBox + reproduction 的方式验证(具体细节感兴趣可以翻 Git 历史查看)
如果大家还有印象,antd 官网的 demo 创建 reproduction 一直都是 sanbox 在首位。但随着 sanbox 的商业化,对 antd 这种体量的用户来说是一笔不菲的开销,后面就逐步用 StackBlitz 代替 sanbox。antd #PR(我也是后面才逐步使用 stackblitz,毕竟免费个人使用
前面讲完了,来介绍一下今天的主角 pkg.pr.new , 它主要的作用也是:将构建产物发布在 pkg.pr.new 注册表。并自定义 example, 以验证每次构建产物是否完整。搭配 Github Application 和 GitHub Actions 可以做到持续发布。
主题
本来打算给 dumi 仓库也加入 pkg.pr.new,因为 dumi 接入了 mako,导致有些功能可能会有问题,期望加入持续发布来提前发现问题。
但是就我个人来说,我对 pkg.pr.new 不是很熟悉,所以我在自己个人仓库 Wxh16144/learb-pkg-pr-new 先做了一个测试。
简单介绍一下这个 Learn pkg-pr-new 项目,如果你需要也可以直接 fork 测试。
一个 monorepo 项目,并且使用 pnpm 包管理器
目录结构
.
├── index.js
├── package.json
├── packages
│ ├── bar
│ │ ├── index.js
│ │ └── package.json
│ └── foo
│ ├── index.js
│ └── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── readme.md
根目录是一个主包,并包含两个子包 foo
和 bar
,其中 foo
依赖主目录包,bar
依赖 foo
包。每个包都存在 build 命令,并且这里只是输出,并没有参与构建(主要是测试足够了),然后根据 pkg-pr-new 的文档,先添加 GitHub Application 到个人项目,再将GitHub Actons WorkFlow commit 到仓库。
至此,StackBlitz App 工作的很顺利,并预期的发布了 pkg。
注:有关于如何使用 GitHub Actions 的问题可以先阅读文档,这里篇幅有限,不做赘述。
添加 template
前面持续发布的包需要配合 StackBlitz 进行运行验证。pkg-pr-new 提供的 CLI 有一个默认的模版,但是没有任何代码验证我们持续发布的包,需要自定义,所以我又往仓库提交了 2 个example,并修改了 CLI 入参,example 结构如下
├── examples
│ ├── all
│ │ ├── index.js
│ │ └── package.json
│ └── bar
│ ├── index.js
│ └── package.json
至此,一整个流程应该算结束,预期结果是,每当我 push 了主分支代码,都将构建出 3 个包,并且持续发布这 3 个包,然后 pkg-pr-new CLI 根据 example 创建两个 StackBlitz demo。(请继续往下阅读...
发现问题:
上面两个步骤中,当我在添加 example 时 CI 出现了内存溢出错误。
看到 GC 错误,自然而然的想到和内存有关,想起来之前处理过 jest 测试内存不足问题,所以以为是 GitHub Actions Runner 的 node 分配内存太小了。
顺着这个调试方向我决定利用环境变了提高内存分配。 我将内存上调到 4G 并推送提交,结果又出现内存溢出..
寻思 4G 不够,我又上调到了 8G,结果还是一样挂了...
思考问题
事不过三,意识到可能再多的内存都不够消耗,猜测可能是 pkg-pr-new CLI 的问题, 所以我去官方仓库提交了一个 issue #141
随后,看了一下仓库 CLI 的代码,发现其实也不复杂,将其 clone 到本地调试。找到处理 example 部分逻辑。审查到如下代码
const files = await fg(["**/*"], {
cwd: templateDir,
dot: true,
onlyFiles: true,
});
这里的 fg 是 fast-glob, 经常写 CLI 的应该不陌生
作为一名开发,看到 **/*
自然想到它这个是尝试获取目录下的所有文件,并且设置了 dot:true
, 从前端开发者角度,一定会先想到 node_modules
这个梗图, 并且 .git
也是一个不容小觑的目录...
印象中 fast-glob
有一个 ignore 属性,通过 d.ts
描述文件可以看到,他的默认值是 []
, 也就是说没有默认忽略 node_modules ...
为此我写了一段代码在本地验证:
import fg from 'fast-glob'
const currentPath = process.cwd()
async function main() {
const files = await fg(["**/*"], {
cwd: currentPath,
onlyFiles: true,
dot: true,
// ignore: ['node_modules', '.git']
});
globalThis.console.log({
currentPath,
totalFiles: files.length,
})
}
看到当前目录读取到了 17k 个文件,貌似验证了前面自己的猜测,但是怎么样才能确定内存溢出是不是这个问题导致的呢?
验证问题
为了验证是否是上述问题导致,第一反应是将修改切一个分支进行一个 commit,并且我根据自己以往开发 CLI 经验,添加了一个 DEBUG 调试(应该是一个默认潜规则了,参考 npm 的 debug library)。
前面这个提交如果验证成功,应该可以作为一个 PR 源分支,所以为了进一步验证我的猜测,从当前分支另起一个 release 分支。
将 npm 包添加一个属于自己的 npm space。 修改 package.json 的版本并构建发布。细节部分可以参考我的提交
{
- "name": "pkg-pr-new",
- "version": "0.0.15",
+ "name": "@wuxh/pkg-pr-new",
+ "version": "0.0.15-fork.01",
"description": "",
"main": "index.js",
"type": "module",
...
"@pkg-pr-new/utils": "workspace:^",
"citty": "^0.1.6",
"tsup": "^8.0.2"
+ },
+ "publishConfig": {
+ "access": "public",
+ "registry": "https://registry.npmjs.org/"
}
}
注: 如果是这个免费 space, 一定需要添加
publishConfig.access
字段。并且 fork 的 version 尽可能的和原版本相关联。
将上述包发布到 npmjs 后,回到我最初学习项目的 GitHub Actions 中修改执行命令并再一次推送
- - run: npx pkg-pr-new publish './packages/*' '.' --template './examples/*' --pnpm --comment=update
+ - run: npx -p @wuxh/pkg-pr-new@0.0.15-fork.1 pkg-pr-new publish './packages/*' '.' --template './examples/*' --pnpm --comment=update
注:因为只修改了包名称,并未修改 bin 命令。所以需要使用
npx -p
先安装指定版本包,然后再执行 bin 命令。
最终,在 GitHub Actions 再一次跑起来,并且跑成功后。说明前面的猜测和修复方案都是正确的。
上图的两个 templates 就是前面 examples/* 下的所有模版, 感兴趣的可以 点击上面图片前往!
OK, 既然修复方案验证成功,这个 PR 就可以顺利混到了,将前面第一次切的的分支提交上去即可。
最后 PR #142 奉上,owner 合不合并就听天由命了...
最后
奈何本人不会写文章,上述文章算一个叙事口水话。大家且看且放过... 再会!
转载自:https://juejin.cn/post/7389950978244935721