第9期:打包部署与持续集成

发布于 3 天前  10 次阅读


时长:30-40 分钟


9.1 Electron Builder 配置

9.1.1 多平台配置

  • 配置位置:在 package.jsonbuild 字段中,通过 macwinlinux 分别配置各平台产物与选项。
  • 当前项目(节选):
  • mactarget: [{ target: 'dmg', arch: ['x64', 'arm64'] }],输出 DMG;category: 'public.app-category.developer-tools'identity: null 表示不强制签名(开发或内部分发时可跳过签名)。
  • wintarget: [{ target: 'nsis', arch: ['x64', 'arm64'] }],输出 NSIS 安装包;图标使用 assets/icons/icon.ico
  • linuxtarget: [{ target: 'AppImage', arch: ['x64', 'arm64'] }],输出 AppImage。
  • 构建命令
  • 仅 Mac:electron-builder --mac --x64 --arm64electron-builder --mac dmg --x64 --arm64
  • 仅 Windows:electron-builder --win --x64 --arm64
  • 仅 Linux:electron-builder --linux --x64 --arm64
  • 多平台:electron-builder -mwl(按需加 --x64 --arm64)。
  • 输出目录directories.output: "release",打包产物在项目根目录的 release/ 下。

9.1.2 资源文件管理

  • files

指定被打进 app.asar 或应用包内的文件/目录;未列出的不会被打包。

  • 当前项目(节选):
  "files": [
    "dist/**",
    "electron/**",
    "package.json",
    "assets/icons/**",
    "WebDriverAgent/photo-proxy/*/.js"
  ]
  
  • dist/**:Vite 构建后的前端静态资源。
  • electron/**:主进程与 preload 脚本。
  • package.json:应用元信息。
  • assets/icons/**:应用图标。
  • WebDriverAgent/photo-proxy/*/.js:photo-proxy 编译后的 JS(主进程动态加载用)。
  • extraResources

不放进 asar、而是拷贝到应用资源目录(如 macOS 的 Contents/Resources)的文件,适合可执行文件、二进制、需直接路径访问的资源。

  • 当前项目(节选):
  "extraResources": [
    { "from": "commands", "to": "commands", "filter": ["*/"] },
    { "from": "photo-service/build/photo-service", "to": "photo-service", "filter": ["photo-service"] },
    { "from": "native/ios-screen-recorder/.build/release/ios-screen-recorder", "to": "commands/ios-screen-recorder", "filter": ["ios-screen-recorder"] }
  ]
  
  • commands:adb、hdc、ios、scrcpy、ffmpeg 等命令行工具及 WDA.ipa 等,主进程通过 process.resourcesPathgetAppPath() 解析后调用。
  • photo-service:C++ 构建的 photo-service 可执行文件。
  • ios-screen-recorder:Swift 构建的 iOS 录屏工具。
  • 为何用 extraResources

asar 内文件为只读、且不能直接执行二进制;命令行工具和原生可执行文件必须放在 asar 外,通过文件系统路径访问。

9.1.3 签名配置

  • mac
  • identity

填写 Apple 开发者证书的 Developer ID Application 名称(如 "Developer ID Application: Your Name (TEAM_ID)");正式分发必须签名,否则 Gatekeeper 会拦截。

  • 当前项目"identity": null,即不指定证书,打包出的应用为未签名或使用默认签名;适合内部分发或本机测试。
  • afterSign

钩子脚本,在签名完成后执行;可用于 notarize(公证)等。当前项目配置为 build/afterSign.cjs,脚本内仅 return true,可在此扩展公证或上传符号表等。

  • win
  • 若需签名,在 win 下配置 certificateFilecertificatePassword 等;或使用 afterSign 在打包后调用外部签名工具。
  • 公证(macOS)

若对外分发,除签名外建议做 notarize,在 afterSign 中调用 notarize 相关工具,避免用户打开时被系统拦截。

9.1.4 自动更新

  • Electron 方案

使用 electron-updater(如 electron-builder 配套的 electron-updater)在应用内检查更新、下载并安装。

  • 流程概要
  1. 打包时配置 publish(如 provider: 'generic', url: 'https://your-server.com/releases'),使 builder 生成 latest.yml 等元数据。
  2. 主进程在适当时机(如启动后、定时)调用 autoUpdater.checkForUpdates(),根据 latest.yml 判断是否有新版本。
  3. 若有更新,下载安装包并提示用户重启安装(或静默安装,视配置而定)。
  • 当前项目

未在 package.jsonbuild 中配置 publishelectron-updater;若需自动更新,可增加 publish 配置并在主进程集成 electron-updater,将打包产物与 latest.yml 上传到内网或公网服务器供客户端拉取。


9.2 打包优化

9.2.1 体积优化

  • 前端
  • 使用 Vite 生产构建(vite build),自动 Tree-shaking、压缩 JS/CSS。
  • 依赖按需引入(如 Element Plus 按需导入),减少 bundle 体积。
  • 图片/字体等静态资源放 assets,Vite 会带 hash 并压缩;过大的资源可考虑 CDN 或懒加载。
  • Electron
  • files 只包含必要项,避免把 node_modules 整包打进 asar(通常只打运行时依赖,devDependencies 不打进)。
  • extraResources 只放必要二进制(commands、photo-service、ios-screen-recorder),避免重复或无用文件。
  • 可选:使用 asarUnpack 把部分需解压访问的文件排除在 asar 外,其余保持 asar 以加快读取。
  • 原生/二进制
  • commands 目录下只保留当前平台需要的可执行文件(若做分平台打包,可按平台拷贝不同 commands)。
  • photo-service、ios-screen-recorder 等按需编译,不携带多余符号或调试版本。

9.2.2 启动速度优化

  • 主进程
  • 重量级模块(如 photo-proxy、URL Service)采用懒加载,在首次调用对应 IPC 时再 require/import,避免启动时全部加载。
  • 避免在 main 顶层执行耗时 I/O 或网络请求,必要逻辑放到 app.on('ready') 之后或异步初始化。
  • 渲染进程
  • 首屏路由或 Tab 对应的组件可采用懒加载defineAsyncComponent + import()),减少首屏 JS 体积与解析时间。
  • 前端资源使用 Vite 的代码分割(动态 import 会自动拆 chunk),避免单一大 bundle。
  • Electron 启动参数

可按需启用 --enable-features=... 或禁用部分 Chromium 特性,对启动时间影响较小,以稳定性优先。

9.2.3 资源压缩

  • Vite

生产构建默认对 JS/CSS 做 minify(esbuild/terser);可通过 build.minifybuild.rollupOptions.output.manualChunks 等进一步控制。

  • asar

electron-builder 打包 asar 时会对文件做一定压缩;若不需要 asar 压缩可配置 asar: false(一般不推荐,会失去单文件与一定保护)。

  • 静态资源

图片可使用压缩工具或构建阶段压缩;字体子集化可减小体积。

9.2.4 代码分割

  • 前端
  • Vite 会根据动态 import 自动做代码分割,生成多个 chunk;合理使用 import() 懒加载路由或大组件即可。
  • 若未使用路由,可按“平台面板”懒加载(如 const IOSDeviceSection = defineAsyncComponent(() => import('./IOSDeviceSection.vue'))),切换 Tab 时再加载对应 chunk。
  • 当前项目

vite.config.ts 未显式配置 manualChunks;依赖 Vite 默认行为即可。若分析后发现某依赖体积过大,可将其单独打成 chunk(如 manualChunks: { 'element-plus': ['element-plus'] })以利用缓存。

  • 主进程

Node 侧可按需动态 import() 大模块(如 photo-proxy、url-service),实现“逻辑上的分割”,减少启动时解析量。


9.3 CI/CD 实践

9.3.1 自动化构建

  • 目标:在代码提交或打 tag 时自动执行“前端构建 + 依赖准备 + Electron 打包”,产出安装包或可执行文件。
  • 脚本顺序(与当前 dist/dist:mac 一致):
  1. 固定 Node 版本(如 nvm use 18.18.2)。
  2. yarn build:photo-proxy:编译 photo-proxy 的 TypeScript → JS。
  3. yarn build:photo-service:编译 C++ photo-service(若 CI 环境有 cmake/make)。
  4. yarn build:Vite 前端构建,输出到 dist/
  5. electron-builder --mac --x64 --arm64(或 --win--linux),产出到 release/
  • CI 示例(GitHub Actions 思路):
  • 使用 actions/setup-node 指定 Node 版本;可选 actions/cache 缓存 node_modules 与 Vite 缓存。
  • macOS runner 下安装 Xcode Command Line Tools 或完整 Xcode(若需编译原生模块);Windows runner 下安装 Visual Studio Build Tools(若需 native 模块)。
  • 执行上述脚本;将 release/*.dmgrelease/*.exerelease/*.AppImage 等产物上传为 Artifact 或发布到 Release。
  • 当前项目

根目录未配置主应用的 GitHub Actions;WebDriverAgent 子目录下有独立 workflow(如 wda-package、unit-test)。主应用若需 CI,可在仓库根目录新增 .github/workflows/build.yml,参照上述顺序编写 job。

9.3.2 自动化测试

  • 目标:在 MR/PR 或主干提交时自动跑单测、静态检查,有条件可跑 E2E,防止明显回归。
  • 可执行内容
  • Linteslint .vue-tsc --noEmit(若上 TypeScript)。
  • 单测vitest runjest(若已为 utils/纯逻辑编写单测)。
  • E2E:Playwright 或 Electron 官方 test 方案,对“启动应用 → 关键操作”做少量冒烟(可选,因 Electron 需图形或虚拟显示)。
  • 当前项目

package.json 中有多组 test:* 脚本(如 test:photo-proxy、test:port-forward、test:binary 等),用于 photo-proxy 与连接相关的手动/本地验证;主应用前端暂无统一 testtest:unit。若引入 CI,可先加入 lint + 单测(若有),E2E 视环境再补。

9.3.3 自动化部署

  • 目标:构建通过后,将安装包或可执行文件发布到内网/公网,供用户下载或自动更新拉取。
  • 方式
  • GitHub Release

CI 在打 tag 时构建,并将 release/*.dmg*.exe*.AppImagelatest.yml 上传到该 tag 的 Release 页面;客户端通过 electron-updater 指向 GitHub 的 release 地址即可检查更新。

  • 自建服务器

将产物上传到自建静态站或对象存储,配置 publish.urllatest.yml,客户端指向该地址。

  • 内网分发

上传到内网文件服务或制品库,通过内网链接或内部更新服务器下发。

  • 版本与产物

建议版本号与 package.jsonversion 或 tag 一致;产物命名可带版本与架构(如 小赢MobileTool-0.1.0-arm64.dmg),便于排查与回滚。

9.3.4 版本管理

  • 版本号

使用 package.jsonversion(如 0.1.0);Electron Builder 会将其写入产物名与元数据。可采用语义化版本(主.次.修订),或与内部版本号对齐。

  • 与 Git 联动
  • 主干/开发分支:每次合并可自动构建并产出“最新开发版”安装包(如带 dev 或 commit short sha)。
  • 正式发布:打 tag(如 v0.1.0)触发构建并发布到 Release,同时更新 version 或由 CI 根据 tag 写回 package.json
  • 自动更新兼容

若使用 electron-updater,需保证 latest.yml 与安装包一一对应,且版本号递增;否则客户端可能无法正确检测更新或下载。


小结

  • Electron Builder:通过 package.jsonbuild 配置多平台、files/extraResources 管理资源、identity/afterSign 处理签名与公证;自动更新需额外配置 publishelectron-updater
  • 打包优化:控制 files/extraResources 体积、主进程懒加载、前端代码分割与压缩,兼顾体积与启动速度。
  • CI/CD:按“构建 → 测试 → 部署”串联脚本;版本与 tag 统一管理,便于发布与回滚。当前项目可在此基础上增加主应用 workflow,并与现有 WebDriverAgent 的 CI 并存。

一名测试工作者,专注接口测试、自动化测试、性能测试、Python技术。