在 GitHub Actions 中一行打包网页:Pake Composite Action(`tw93/Pake@v3`)全解析
2026/9/5 19:10:28 网站建设 项目流程

在 GitHub Actions 中一行打包网页:Pake Composite Action(tw93/Pake@v3)全解析

【免费下载链接】Pake🤱🏻 Turn any webpage into a desktop app with one command.项目地址: https://gitcode.com/GitHub_Trending/pa/Pake

Pake 是一个基于 Rust + Tauri 的命令行工具,能把任意网页打包成轻量级桌面应用。除了本地运行 CLI 之外,Pake 在仓库根目录内置了一个 Composite Action(docs/pake-action.md的讲解对象),让你的仓库只需添加一个uses: tw93/Pake@v3步骤,就能在 CI 中自动完成环境搭建、构建并产出可分发的安装包。读完本文,你将掌握该 Action 的全部输入/输出参数、各平台产物形态、跨平台矩阵构建写法,以及它内部的调用链与安全设计(环境变量传参、临时文件、换行注入防护),并能将其直接落地到自己的 CI 流程中。

快速开始:一个步骤即可构建

最简单的用法是在 workflow 中添加一个 step:

- name: Build Pake App uses: tw93/Pake@v3 with: url: "https://example.com" name: "MyApp"

一个完整的最小 workflow 如下(官方示例):

name: Build Web App on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: tw93/Pake@v3 with: url: "https://weekly.tw93.fun" name: "WeeklyApp"

需要注意的一个前提:该 Composite Action 的构建脚本依赖工作区里的dist/cli.jssrc-tauri模板,因此它设计用于在Pake 仓库的 fork(或包含 Pake 完整代码的仓库)中运行——这正是 内建工作流使用指南 建议"Fork 仓库后运行 workflow"的原因。如果你的仓库不含 Pake 源码,Action 里的npm run cli:build(基于 rollup.config.js)将无法产出 CLI。

输入参数(Inputs)逐项说明

docs/pake-action.md 给出的参数表如下,定义源头是 action.yml 第 8–39 行的inputs:段:

参数说明必填默认值
url要打包的目标 URL
name应用名称
output-dir产物输出目录dist
icon自定义应用图标(URL 或路径)(未提供时自动抓取站点图标)
width窗口宽度1200
height窗口高度780
debug启用调试模式false

几个结合实现与 CLI 文档的补充点:

  • url/nameurl是必填的打包对象;name会原样传给 CLI 的--name。关于应用名在 Windows/macOS 保留空格与大小写、在 Linux 转为小写连字符的规则,见 CLI 使用文档。
  • icon:Action 只在值非空时才追加--icon参数(见下文调用链)。留空时 Pake CLI 会自动抓取网站图标并转换为平台对应格式,完整行为参考 CLI 文档的 icon 章节。
  • width/height:默认值1200/780与 Pake CLI 的默认窗口尺寸一致(action.yml 中default: "1200"default: "780",与 cli-usage.md 中--width/--height的默认值相互印证)。
  • output-dir:脚本会先mkdir -p该目录,再把构建产物移入(action.yml)。该参数还会经过换行符校验,防止通过注入换行写入额外的GITHUB_OUTPUT键值对(详见"安全设计"一节)。
  • debug:仅在字符串严格等于"true"时追加--debug标志。它对应 CLI 的 debug 选项(构建调试版并输出更多日志),而非浏览器开发者工具开关。

输出(Outputs)

输出说明
package-path生成安装包的路径

在 action.yml 中,package-path通过value: ${{ steps.build.outputs.package-path }}从名为build的步骤透出。也就是说,后续步骤可以直接消费它:

- uses: tw93/Pake@v3 id: pake - name: Show result run: echo "Package is at: ${{ steps.pake.outputs.package-path }}"

官方示例:自定义图标与多平台矩阵构建

带自定义图标、指定窗口尺寸

- uses: tw93/Pake@v3 with: url: "https://example.com" name: "MyApp" icon: "https://example.com/icon.png" width: 1400 height: 900

多平台矩阵构建

利用 GitHub 的 matrix 策略,可以在一次 workflow 中并行构建多个平台:

jobs: build: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: tw93/Pake@v3 with: url: "https://example.com" name: "CrossPlatformApp"

文档建议的矩阵写法就是"哪种 runner 产出哪个平台的包",各平台的产物形态如下:

平台Runner产物
Linuxubuntu-latest.deb
macOSmacos-latest.app.dmg
Windowswindows-latest.exe.msi

一个值得注意的实现细节:Action 在 macOS 上构建时导出了环境变量PAKE_CREATE_APP=1(action.yml)。对照 MacBuilder.ts 的构造逻辑——当process.env.PAKE_CREATE_APP === '1'时,buildFormat被强制设为app(而非默认的dmg),这解释了为什么 Action 的find查找逻辑会"先找文件类安装包、找不到再回退到.app目录":在 CI 的无头环境里,.appbundle 是默认产物形态。

How It Works:Action 内部执行流程

docs/pake-action.md 概述了三步流程,下面对照 action.yml 的runs:段(using: "composite",两个 composite step)逐步展开。

第 1 步:Setup Environment(自动搭建工具链)

对应 action.yml 的 "Setup Environment" 步骤,shell: bash,做了三件事:

  1. 安装 Node.js 依赖:直接npm install
  2. 按需构建 Pake CLI:仅当dist/cli.js不存在时执行npm run cli:build。该脚本定义在 package.json 的scripts段("cli:build": "cross-env NODE_ENV=production rollup -c"),产物即bin声明的 CLI 入口dist/cli.js
  3. 按需安装 Rust/Cargo:若cargo不在 PATH 中,用curl --proto '=https' --tlsv1.2 -sSf下载 rustup 安装脚本并静默执行,然后把$HOME/.cargo/bin追加到$GITHUB_PATH供后续步骤使用。这里使用了mktemp生成唯一临时文件存放安装脚本,并以trap 'rm -f "$rustup_init"' EXIT保证退出时清理(action.yml)——这是对共享 runner 上固定路径(如/tmp/rustup-init.sh)竞争覆盖问题的修复。

第 2 步:Build Pake App(拼装并执行 CLI 命令)

对应 action.yml 的 "Build Pake App" 步骤(id: build)。

输入通过环境变量传递,而非行内插值。该步骤先声明env:块,把 7 个 input 映射为INPUT_*环境变量(action.yml):

env: INPUT_URL: ${{ inputs.url }} INPUT_NAME: ${{ inputs.name }} INPUT_ICON: ${{ inputs.icon }} INPUT_WIDTH: ${{ inputs.width }} INPUT_HEIGHT: ${{ inputs.height }} INPUT_DEBUG: ${{ inputs.debug }} INPUT_OUTPUT_DIR: ${{ inputs.output-dir }}

这个设计有明确的测试保障:tests/unit/action-input-security.test.ts 会读取action.yml源码并断言——run:脚本中不得出现${{ inputs.* }}行内表达式(正则/\$\{\{\s*inputs\./必须不匹配),且上述 7 条env映射必须逐一存在。其含义是:用户输入永远不会被拼进 shell 命令文本,而是作为环境变量由 shell 在运行时读取,从结构上杜绝了输入内容改写脚本的可能性。

参数拼装逻辑(action.yml):

  • 先校验INPUT_OUTPUT_DIR不含换行符(\n/\r),违规直接报错退出;
  • ARGS=("$INPUT_URL")以 URL 位置参数开头,随后追加--name "$INPUT_NAME"
  • icon仅在非空时追加--icon
  • --width--height始终追加(未传时为 action 默认值);
  • debug仅在等于"true"时追加--debug
  • mkdir -p输出目录并export PAKE_CREATE_APP=1
  • 最后以printf ' %q'打印完整命令(便于在 CI 日志中复核),再执行node dist/cli.js "${ARGS[@]}"

也就是说,Action 并没有绕过 Pake CLI,而是把它完整包了一层:CLI 内部由 BuilderProvider.ts 按当前 OS 分发到 LinuxBuilder.ts、MacBuilder.ts 或 WinBuilder.ts,真正执行 Tauri 构建。

第 3 步:Package Output(查找并搬运产物)

构建完成后,脚本在src-tauri/target下查找产物(action.yml):

  1. find文件类安装包:*.deb*.exe*.msi*.dmg,取第一个命中(head -1);
  2. 若未找到,回退查找 macOS 的.app目录(呼应上面PAKE_CREATE_APP=1的产物形态差异);
  3. 找到后mv$INPUT_OUTPUT_DIR/<basename>,移动失败则退回cp -r;写入前再次校验PACKAGE_PATH无换行符,防止污染GITHUB_OUTPUT
  4. 成功则printf 'package-path=%s\n' "$PACKAGE_PATH" >> "$GITHUB_OUTPUT"并打印确认;找不到任何产物则打印 "No package found" 并以退出码 1 失败。

以上三条输出相关的断言(id: buildGITHUB_OUTPUT写入格式、output 值映射)同样被 action-input-security.test.ts 固化,属于"文档承诺即代码契约"的验证方式。

安全设计:为什么输入处理要这么讲究

docs/pake-action.md 没有专门展开安全部分,但 action.yml 的实现里体现了几处对 CI 注入场景的防御,值得了解:

  • 表达式与脚本分离run:脚本中不出现任何${{ inputs.* }},所有输入经env:传递(见上文),测试用例逐条断言该约束;
  • 换行注入防护GITHUB_OUTPUT采用key=value逐行追加格式,若output-dir或最终包路径中含换行符,攻击者可以追加任意键(例如覆盖steps.*.outputs或触发后续步骤执行)。脚本在写入前对两处路径做了$'\n'/$'\r'检查并直接失败退出(action.yml 与 action.yml);
  • 临时文件唯一化:rustup 安装脚本经mktemp生成、trap清理,不再使用固定的/tmp/rustup-init.sh(测试显式断言源码中不再包含该路径);
  • 命令打印与执行分离printf ' %q'让日志中的命令与实际执行内容一一对应,便于审计参数是否被意外篡改。

与仓库内建 Workflow 的关系

Pake 项目自身维护了两套基于 GitHub Actions 的构建方式,不要混淆:

  • 本文的主角——Composite Action(action.yml):供你自己的项目通过uses: tw93/Pake@v3引用的通用打包步骤,参数即上文 Inputs 表。
  • 项目内建 workflow:位于 .github/workflows/single-app.yaml 的 "Build Single Popular App",支持workflow_dispatch表单触发,参数更丰富(new_windowincognito--targets deb,appimage、macOS--targets universal --multi-arch、签名与公证 secrets 等),使用actions/upload-artifact上传产物、打 tag 时推送到 Release。其使用方式见 GitHub Actions Usage。

两者底层调用的是同一个 CLI(node dist/cli.js),差异只在于 workflow 层能传--targets等 Action 未暴露的 CLI 选项。更多 CLI 选项请参考 CLI Usage 与 Advanced Usage(均有中文版本:cli-usage_CN.md、advanced-usage_CN.md)。

小结

  • 用法:在(fork 的)Pake 仓库 workflow 里加一步uses: tw93/Pake@v3,必填url+name,可选iconwidth(默认 1200)、height(默认 780)、output-dir(默认dist)、debug;输出package-path供后续步骤使用。
  • 原理:composite action 自动完成npm install→ 按需cli:build→ 按需装 Rust → 环境变量传参调用node dist/cli.js→ 在src-tauri/target中定位.deb/.exe/.msi/.dmg/.app并搬运到输出目录。
  • 平台:Ubuntu runner 出.deb,macOS runner 出.app/.dmg(CI 中默认.app形态),Windows runner 出.exe/.msi;矩阵策略可并行多平台。
  • 可验证依据:参数定义见 action.yml,安全约束见 tests/unit/action-input-security.test.ts,macOS 产物形态见 bin/builders/MacBuilder.ts,文档主体见 docs/pake-action.md。

【免费下载链接】Pake🤱🏻 Turn any webpage into a desktop app with one command.项目地址: https://gitcode.com/GitHub_Trending/pa/Pake

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询