博客优化:提升gitea action构建速度

在之前的《Blog部署演进之路》中,我曾提到博客目前是借助 Gitea Action 实现项目部署。过去一年里,它出色地完成了“提交→编译→部署”这一流程。然而从上次提交了编写的图片压缩插件后,项目部署耗时便大幅增加,有些时候甚至会导致任务卡死。

编译部署的耗时翻了几倍编译部署的耗时翻了几倍

正好端午这几天,杭州阴雨不断,我可以在家细细琢磨,给博客部署提提速。

01 切换Npm镜像

我先随意点开了几个任务,查看哪个步骤最耗时。经过排查,发现主要问题是 npm 拉取项目依赖包的过程耗时太久

npm install的耗时占比约65%npm install的耗时占比约65%

这个问题其实很好解决,只要在拉取前设置好 npm 镜像地址就行(调整后的 workflows 配置见下方)。配置好镜像地址后,拉取时间从10分钟缩短至2分钟,提速约80%。

1
2
3
4
5
6
7
8
# 其他步骤....

- name: Install Npm Package
run: |
npm config set registry https://registry.npmmirror.com #提前切换到淘宝镜像地址
npm install

# 其他步骤....

拉取步骤的提速非常明显拉取步骤的提速非常明显

02 添加optionalDependencies(可选依赖)

在开头的图片中,可以看到Build Hexo的步骤也比较耗时(约占30%)。于是我点开了任务日志,发现有一项报错:

无法在Linux中安装sharp无法在Linux中安装sharp

sharp是图片压缩插件所依赖的库,而该插件是以命令行形式运行的,在项目编译阶段其实并不需要它。也就是说,我得想个办法,在编译阶段把它给“屏蔽”掉。

经过一番资料查找,我发现了“optionalDependencies(可选依赖)”这个功能,它能完美解决我的问题。只要按下列操作进行,就能实现安装依赖时自动忽略可选依赖项啦。

  1. package.json里,先把那些非必须引用的插件,从“dependencies”挪到“optionalDependencies”中;
1
2
3
4
5
6
7
8
{
"dependencies": {
"pluginName": "1.0.0",
},
"optionalDependencies": {
"sharp": "^0.32.6",
}
}
  1. 然后在工作流文件中,把“npm install”命令调整为“npm install –omit=optional”。
1
2
3
4
5
6
7
8
# 其他步骤....

- name: Install Npm Package
run: |
npm config set registry https://registry.npmmirror.com
npm install --omit=optional #提前切换到淘宝镜像地址

# 其他步骤....

需要注意的是:Hexo会在编译/运行时自动注册插件,如果在插件注册时找不到对应依赖,项目编译时仍会报错!所以需要修改插件compress-images.js内容,增加环境判断条件才能完全解决问题!

1
2
3
4
5
6
7
8
9
const os = require('os');
const platform = os.platform();

if (platform === 'win32') {
// 仅在windows下注册插件
hexo.extend.console.register('compress-images', '...', {}, () => {
//...
})
}

到这一步时,整个编译部署时间已经缩短到了5~8分钟(小有成效😁)。

忽略加载一部分npm包和插件后,Build时间缩短了一半!忽略加载一部分npm包和插件后,Build时间缩短了一半!

03 使用@actions/cache缓存依赖包

虽然前面我已经设置了 npm 镜像地址,但网络波动仍会导致拉取时间偶尔变慢。于是,我琢磨着有没有办法缓存 npm 包,好在查阅资料后,还真让我找到了解决方法:

  1. 使用 @actions/setup-nodecache属性简单开启npm包缓存功能;
1
2
3
4
5
6
7
8
9
# 其他步骤...

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '18' # 设置node版本
cache: 'npm' # 启用 npm 缓存

# 其他步骤...
  1. 使用 @actions/cache 来缓存和恢复npm包(下方代码来自Gitea官方案例);
1
2
3
4
5
6
7
8
9
10
11
# 其他步骤...

- name: Cache node modules
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

# 其他步骤...

两者的区别可以参考下表。由于我的工作流里已经用 container.image 属性,指定了自带Node版本的容器镜像,如果再用 @actions/setup-node 重复拉取一次Node就有点多余了,所以我采用了第二种办法。

功能 @actions/setup-node @actions/cache
主要用途 设置 Node.js 环境 缓存依赖项和构建输出
功能细节 下载并缓存指定版本的 Node.js
添加 Node.js 到系统环境变量
缓存 npm、yarn 或 pnpm 依赖
配置 GPR 或 npm 认证
缓存指定路径下的文件
通过 key 和 restore-keys 控制缓存的命中和恢复
适用场景 在 CI/CD 流程中自动化设置 Node.js 环境
测试不同 Node.js 版本对项目的影响
需要缓存依赖项以提高构建效率
缓存依赖项,减少重复下载时间
缓存构建输出,加速后续构建
配置复杂度 相对简单,主要配置 Node.js 版本和缓存策略 需要指定缓存路径、key 和 restore-keys 等

执行报错“::error::Input required and not supplied: key”的解决办法:

我尝试通过echo输出runner.oshashFiles()的结果,发现runner.os正常、hashFiles无法获取结果导致key生成失败。于是改为使用sha256sum来生成hash(步骤见下方代码)。

1
2
3
4
5
6
7
8
9
10
11
12
# 先通过sha256sum计算出package-lock.json的hash值
- name: Calculate hash manually
id: hash
run: |
echo "hash=$(sha256sum package-lock.json | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT

# 再通过steps.hash.outputs.hash来获取hash值,设置缓存key值
- name: Cache Npm Package
uses: https://gitea.com/actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ steps.hash.outputs.hash }}

经过这一步缓存 npm 包的操作,每次编译部署时,系统都会自动比对package-lock.json文件的 hash 值。如果文件内容没有变动,就会优先从缓存中读取所需数据,这样一来,拉取 npm 包的速度又得到了显著提升——从原来的 2 分钟缩短到了 30 秒

耗时缩短至30秒内,提速约75%;耗时缩短至30秒内,提速约75%;

04 移除未使用的依赖包

打开package.json后,我又逐项对比并移除了项目中未使用的四款插件,这在一定程度上能减少项目依赖的npm包数量,小幅提升项目编译的速度。

相比第二步时,Build耗时又缩短了60%相比第二步时,Build耗时又缩短了60%

05 替换为npm ci

npm ci相比npm install优势显著:它严格按照package-lock.json安装依赖,确保版本一致,避免因版本范围不同导致最终差异。另一方面它能有效利用缓存,减少从远程仓库的下载次数,这使得其在工作流阶段的安装速度更快。

1
2
3
4
npm install --omit=optional

# 替换为
npm ci --omit=optional

尾:最终效果

通过上述方法调整后,目前博客的编译部署时间已经从十多分钟缩短至三分钟左右,整体优化效果还是非常明显的,也不再出现编译部署时任务卡死的情况了,舒服了❤。

耗时2分4秒,舒服了耗时2分4秒,舒服了

博客优化:提升gitea action构建速度

作者:有点东西

链接: https://www.youdiandongxi.com/article/optimize-gitea-action-build-speed.html

协议:本文采用 CC BY-NC-SA 4.0 隐私协议,转载请注明出处!

评论区