摸摸鱼之前端自己研究 Jenkins 自动化部署

一、背景与目标

H5 项目频繁发版,手动部署流程繁琐:

arduino 复制代码
开发 → 本地 npm run build → 手动登录 OSS 控制台 → 清空旧文件 → 上传新文件 → 通知测试

存在以下痛点:

  • 步骤多:每次发布需要 5-7 个手动步骤
  • 易出错:忘记清空旧文件导致缓存问题、上传错目录、漏传文件
  • 不可追溯:无法确定当前线上是哪个 commit 构建的
  • 环境不统一:开发者本地 Node.js 版本各不相同

目标:Push 代码即自动部署,全程无需人工干预,构建可追溯、可回滚。


二、整体架构

scss 复制代码
┌──────────┐    Webhook      ┌──────────┐   ossutil sync   ┌──────────┐   CDN   ┌──────────┐
│  GitLab  │ ───────────────▶│ Jenkins  │ ────────────────▶│ 阿里云   │ ──────▶│ 用户浏览器 │
│ (代码仓库) │                 │ (CI 流水线)│                   │ OSS      │        │          │
└──────────┘                 └──────────┘                  └──────────┘        └──────────┘
  • GitLab:存放业务代码和 Jenkins Pipeline 脚本
  • Jenkins:接收 Webhook,执行 Pipeline Job,完成拉代码 → 装依赖 → 构建 → 上传
  • 阿里云 OSS:静态资源存储,通过 CDN 分发

三、仓库与职责

仓库 职责 内容
部署脚本仓库 集中管理所有项目的 Jenkins Pipeline 脚本 Groovy 脚本文件
业务仓库 H5 应用源码 Vue 业务代码、构建配置

四、Jenkins 环境

  • 节点:Linux (CentOS 7),系统自带 Node.js 22.0.0
  • 凭据管理:所有敏感信息(Git SSH Key、OSS AK/SK)通过 Jenkins 凭据管理,不在脚本中明文暴露
凭据类型 用途
SSH Key 拉取 GitLab 代码
Username / Password 阿里云 OSS AccessKey(testing 环境)

五、Pipeline 脚本设计

为了方便统一管理,所有项目的 Jenkins Pipeline 脚本统一存放在部署脚本仓库中。Jenkins 任务创建时配置 SCM 指向部署脚本仓库,Script Path 指向对应的 .groovy 文件。这种脚本与应用分离的设计,使得脚本可以独立迭代、多个项目共享相同的基础设施配置,不需要在每个业务仓库里创建 Jenkinsfile。

5.1 目录结构

css 复制代码
deployment-scripts/
└── scripts/
    └── h5-app.groovy               # H5 应用部署

5.2 通用阶段

每个项目的 Pipeline 都包含以下 6 个标准阶段:

arduino 复制代码
┌──────────────────┐
│ 1. Validate       │  校验触发分支,非目标分支直接终止
│    Branch         │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 2. Checkout       │  浅克隆目标业务仓库(depth=1,加速拉取)
│    App            │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 3. Setup          │  下载 Node.js / pnpm / ossutil(缓存复用)
│    Tools          │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 4. Install        │  pnpm install(下载依赖)
│                   │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 5. Build          │  pnpm run build:xxx(构建产物)
│                   │
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 6. Deploy         │  ossutil sync 上传至 OSS(--delete 同步)
│    OSS            │
└──────────────────┘

六、H5 应用部署

6.1 触发方式

GitLab testing 分支 Push → Webhook → Jenkins。

6.2 构建配置

触发分支 testing
包管理器 pnpm 9.15.0
安装命令 pnpm install --no-frozen-lockfile
构建命令 pnpm run build:test
产物目录 dist/
OSS 路径 应用目录

6.3 执行流程

bash 复制代码
┌──────────────────────────────────────────────────────────────────┐
│ Stage 1: Validate Branch                                         │
│ ─────────────────────                                            │
│ 仅放行 testing 分支,其余分支 push 直接 ABORTED                       │
└────────────────────────┬─────────────────────────────────────────┘
                         │ testing ✓
                         ▼
┌──────────────────────────────────────────────────────────────────┐
│ Stage 2: Checkout App                                            │
│ ────────────────────                                             │
│ 浅克隆 H5 应用仓库 testing 分支 → WORKSPACE/app/                    │
└────────────────────────┬─────────────────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────────────┐
│ Stage 3: Setup Tools                                             │
│ ────────────────────                                             │
│ 在工作目录 .tools/ 下准备构建工具(首次下载后缓存复用):              │
│                                                                  │
│ ├─ Node.js 22.21.0                                              │
│ │   curl https://nodejs.org/dist/v22.21.0/node-v22.21.0-...     │
│ │   tar -xJf → .tools/node-v22.21.0-linux-x64/                   │
│ │                                                                 │
│ ├─ pnpm 9.15.0                                                   │
│ └─ ossutil 1.7.19                                                │
└────────────────────────┬─────────────────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────────────┐
│ Stage 4: Install                                                 │
│ ─────────────────                                                │
│ ★ 关键:export PATH=.tools/node-xxx/bin:$PATH                    │
│   确保 pnpm 及 vite 子进程使用 22.21.0,而非系统的 22.0.0           │
│                                                                  │
│ pnpm install --no-frozen-lockfile                                │
│ · 不使用 frozen-lockfile,允许 pnpm 根据 package.json 更新 lockfile │
└────────────────────────┬─────────────────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────────────┐
│ Stage 5: Build                                                   │
│ ───────────────                                                  │
│ export PATH=.tools/node-xxx/bin:$PATH  (同上)                    │
│ pnpm run build:test                                              │
│   └─ vite build --mode test                                       │
│      └─ 产物写入 dist/ 目录                                        │
│                                                                  │
│ test -d dist  ← 校验产物存在                                       │
└────────────────────────┬─────────────────────────────────────────┘
                         │
                         ▼
┌──────────────────────────────────────────────────────────────────┐
│ Stage 6: Deploy OSS                                              │
│ ──────────────────                                               │
│ ossutil sync -f dist/ oss://bucket/应用目录/ --delete              │
└──────────────────────────────────────────────────────────────────┘
                         │
                         ▼
                   ┌──────────┐
                   │ 部署成功! │
                   └──────────┘

6.4 为什么需要自建 Node.js

go 复制代码
系统 Node.js 版本:22.0.0

H5 应用 package.json 的 engines:
  "node": "^20.19.0 || >=22.12.0"
                        ^^^^^^^^
                        22.0.0 不满足 >=22.12.0

Vite 7 依赖 oxc-parser 需要原生 binding:
  · Node.js 22.0.0  →  不兼容,构建报错 "Cannot find native binding"
  · Node.js 22.21.0 →  兼容 ✓

解决方案 不是在 Jenkins 服务器上升级 Node.js(影响其他任务),而是在流水线内自行下载兼容版本到工作目录,通过 export PATH 确保所有子进程使用正确版本。Job 之间互不影响。

七、Jenkins 任务配置指南

以下流程图描述了新建一个项目的完整配置步骤。

7.1 新建 Jenkins Pipeline 任务的完整流程

vbnet 复制代码
┌─────────────────────────────────────────────────────────────────────────────┐
│                          Jenkins 新建任务 全流程                            │
└─────────────────────────────────────────────────────────────────────────────┘

  STEP 1:Jenkins 首页 → 新建 Item
 ┌──────────────────────────────────────────┐
 │                                          │
 │  ┌─────────────────────────────────────┐ │
 │  │  输入任务名称                         │ │
 │  │  ┌─────────────────────────────────┐ │ │
 │  │  │ component-library-deploy        │ │ │
 │  │  └─────────────────────────────────┘ │ │
 │  │                                      │ │
 │  │  ○ Freestyle project                 │ │
 │  │  ● Pipeline(★ 选这个)               │ │
 │  │  ○ Multi-branch Pipeline             │ │
 │  │  ○ Folder                            │ │
 │  │  ○ GitHub Organization               │ │
 │  │                                      │ │
 │  │           [ 确定 ]                    │ │
 │  └─────────────────────────────────────┘ │
 │                                          │
 └──────────────────────────────────────────┘

  STEP 2:General 配置
 ┌──────────────────────────────────────────┐
 │                                          │
 │  ☑ GitHub project                        │
 │  ☑ 丢弃旧的构建                           │
 │    策略:Log Rotation                     │
 │    保持构建的天数:30                      │
 │    保持构建的最大个数:50                   │
 │                                          │
 └──────────────────────────────────────────┘

  STEP 3:构建触发器
 ┌──────────────────────────────────────────┐
 │                                          │
 │  ● 触发远程构建 (例如, 使用脚本)            │
 │    身份验证令牌:<自动生成的 Token>         │
 │                                          │
 │  → Webhook URL 将生成为:                  │
 │    http://<jenkins>/job/<任务名>/           │
 │    build?token=<Token>                    │
 │                                          │
 │  注:如使用 GitLab Plugin 则选              │
 │  ☑ Build when a change is pushed         │
 │    to GitLab. GitLab webhook URL:         │
 │    http://<jenkins>/project/<任务名>       │
 │                                          │
 └──────────────────────────────────────────┘

  STEP 4:流水线定义(★ 关键步骤)
 ┌──────────────────────────────────────────┐
 │                                          │
 │  定义:● Pipeline script from SCM         │
 │                                          │
 │  SCM:Git                                │
 │  ┌─────────────────────────────────────┐ │
 │  │ Repository URL:                     │ │
 │  │ git@<gitlab>:xxx/deployment-scripts  │ │
 │  │                                     │ │
 │  │ Credentials:GitLab (SSH Key)        │ │
 │  │                                     │ │
 │  │ Branches to build:*/master          │ │
 │  │                                     │ │
 │  │ Script Path:scripts/app.groovy      │ │
 │  │                                     │ │
 │  │ Lightweight checkout:☑              │ │
 │  └─────────────────────────────────────┘ │
 │                                          │
 │           [ 保存 ]                        │
 └──────────────────────────────────────────┘

  STEP 5:GitLab Webhook 配置
 ┌──────────────────────────────────────────┐
 │                                          │
 │  进入 GitLab 目标项目 → Settings →        │
 │  Webhooks                                 │
 │                                          │
 │  ┌─────────────────────────────────────┐ │
 │  │ URL:http://<jenkins>/project/<任务名>│ │
 │  │ Secret Token:<留空或与 Jenkins 一致> │ │
 │  │                                     │ │
 │  │ Trigger:                            │ │
 │  │  ☑ Push events                      │ │
 │  │  ☐ Tag push events                  │ │
 │  │  ☐ Merge request events             │ │
 │  │                                     │ │
 │  │ 如有分支过滤:输入 testing             │ │
 │  │                                     │ │
 │  │ ☑ Enable SSL verification           │ │
 │  │                                     │ │
 │  │        [ Add webhook ]              │ │
 │  └─────────────────────────────────────┘ │
 │                                          │
 │  添加后点击 Test → Push events 验证       │
 │  返回 HTTP 200 即表示成功                 │
 │                                          │
 └──────────────────────────────────────────┘

  STEP 6:手动触发验证
 ┌──────────────────────────────────────────┐
 │                                          │
 │  Jenkins → 任务名 → Build with          │
 │  Parameters / Build Now                  │
 │                                          │
 │  观察 Console Output 确认每个 Stage       │
 │  执行成功                                 │
 │                                          │
 │  检查 OSS 控制台确认文件已更新             │
 │                                          │
 └──────────────────────────────────────────┘

7.2 凭据配置

vbnet 复制代码
Jenkins → Manage Jenkins → Manage Credentials → 全局凭据 → Add Credentials

  ┌─────────────────────────────────────────────────────┐
  │ Kind:SSH Username with private key                 │
  │ ┌─────────────────────────────────────────────────┐ │
  │ │ ID:        GitLab                              │ │
  │ │ Username:  git                                  │ │
  │ │ Private Key:<粘贴 SSH 私钥>                      │ │
  │ └─────────────────────────────────────────────────┘ │
  └─────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────┐
  │ Kind:Username with password                        │
  │ ┌─────────────────────────────────────────────────┐ │
  │ │ ID:        oss-test                            │ │
  │ │ Username:  <OSS AccessKey ID>                   │ │
  │ │ Password:  <OSS AccessKey Secret>               │ │
  │ └─────────────────────────────────────────────────┘ │
  └─────────────────────────────────────────────────────┘

八、分支保护策略

流水线在第一个 Stage 就进行分支校验:

objectivec 复制代码
                      ┌──────────────┐
                      │ GitLab Push  │
                      └──────┬───────┘
                             │
                             ▼
                    ┌──────────────────┐
                    │ Validate Branch   │
                    │                  │
                    │ 分支 == testing ? │
                    └────┬──────┬──────┘
                         │ YES  │ NO
                         ▼      ▼
                   ┌─────────┐ ┌──────────┐
                   │ 继续构建  │ │ ABORTED  │
                   └─────────┘ │ 流水线终止 │
                               └──────────┘
groovy 复制代码
script {
  def pushedBranch = env.gitlabBranch?.trim()
  if (pushedBranch && pushedBranch != APP_BRANCH) {
    currentBuild.result = 'ABORTED'
    error("仅允许 ${APP_BRANCH} 分支触发构建,当前分支: ${pushedBranch}")
  }
}

即使 GitLab Webhook 配了分支过滤也不完全可靠(可被人为修改),Pipeline 内部的二次校验是最后一道防线。


九、如何新增一个项目的自动化部署

9.1 步骤总览

vbnet 复制代码
Step 1 ────▶  Step 2 ────▶  Step 3 ────▶  Step 4 ────▶  Step 5
编写        commit &     Jenkins       GitLab        Push 测试
Groovy       push 到      新建          配置          业务代码
脚本        部署仓库      Pipeline       Webhook       验证

9.2 详细步骤

Step 1:编写 Pipeline 脚本

在部署脚本仓库 scripts/ 目录下新建 项目名.groovy,复制已有模板并修改以下变量:

变量 说明 示例
APP_GIT_URL 目标项目的 GitLab 地址 git@<gitlab>:xxx/project.git
APP_BRANCH 触发分支 testing
OSS_PREFIX OSS 上的目录名 myApp/
安装命令 pnpm install 及参数 pnpm install --no-frozen-lockfile
构建命令 pnpm run build:xxx pnpm run build:test
产物目录 build 后文件所在目录 dist/
是否需要自建 Node.js Jenkins 系统版本不兼容时 添加 NODE_VERSION 等变量

Step 2:提交推送

bash 复制代码
cd deployment-scripts/
git add scripts/项目名.groovy
git commit -m "feat: 新增 项目名 的自动化部署脚本"
git push origin master

Step 3:Jenkins 新建任务

参考第七章流程图完成配置。

Step 4:GitLab 配置 Webhook

目标项目 → Settings → Webhooks → 填入 URL(http://<jenkins>/project/<任务名>)。

Step 5:验证

往业务代码的 testing 分支 push 一个 commit,观察 Jenkins Console Output 中各 Stage 是否全部通过。


十、常见问题

Q1:构建时 frozen-lockfile 报错

vbnet 复制代码
ERR_PNPM_OUTDATED_LOCKFILE Cannot install with "frozen-lockfile"
because pnpm-lock.yaml is not up to date with package.json

原因 :CI 环境下 pnpm 默认启用 --frozen-lockfile,但 lockfile 与 package.json 不同步。

解决 :改用 pnpm install --no-frozen-lockfile

Q2:Node.js 版本不兼容

arduino 复制代码
You are using Node.js 22.0.0. Vite requires Node.js version 20.19+ or 22.12+.
Error: Cannot find native binding.

原因:Jenkins 服务器的 Node.js 版本不满足项目的 engines 要求。

解决 :在 Setup Tools 阶段自行下载兼容版本,并将 bin/ 加入 PATH。详见第七章。

Q3:Groovy 脚本注释解析错误(重中之重!!出现了 N 次!!)

arduino 复制代码
unexpected token: * @ line 10, column 2

原因 :Jenkins Pipeline 的 Groovy 解析器对 /** */ 块注释有兼容性问题。特别是注释内容中出现 */ 字符(如 Branch:origin/*/master)时,*/ 会被错误识别为注释结束,后续的 * 变成裸乘法运算符。

解决 :统一使用 // 单行注释。

Q4:ossutil sync 后文件未更新

原因:浏览器或 CDN 缓存了旧文件。OSS 上的文件已更新,但 CDN 节点或浏览器本地缓存未刷新。

解决

  • CDN 控制台手动刷新缓存
  • 或等待缓存过期(取决于 CDN 缓存策略配置)
  • HTML 入口文件设置较短的缓存时间(index.html 建议 no-cache)

Q5:部署后页面白屏

排查流程

ini 复制代码
白屏
 │
 ├─ 1. 打开浏览器 F12 → Console,看是否有 JS 报错
 │    └─ 404 错误 → OSS 文件不存在,检查产物目录是否正确
 │    └─ CORS 错误 → OSS 跨域配置问题
 │
 ├─ 2. 打开 F12 → Network,看 chunk-vendor.js 是否加载成功
 │    └─ 加载失败 → 公共路径(base)配置错误
 │
 ├─ 3. 检查 index.html 中的 <script src="./static/...">
 │    相对路径是否正确
 │
 └─ 4. 检查 OSS 控制台,确认文件是否已上传
      └─ 对比本地 dist/ 目录和 OSS 文件列表

附带几张 Jenkins 的配置图:

相关推荐
snpgroupcn2 小时前
SAP实施风险管控注意事项:四大风险域与防范策略
前端·数据库·人工智能
阿成学长_Cain2 小时前
Linux talk 命令详解:经典终端实时聊天工具,无需图形界面即可对话
linux·运维·前端
lichenyang4532 小时前
从零开始写 HarmonyOS Web 容器:先让 ArkWeb 加载本地 H5
前端
kyriewen2 小时前
一个看不见的撇号,让Claude Code追踪了中国开发者三个月
前端·ai编程·claude
莫生灬灬2 小时前
DY联系人聊天Web面板支持获取联系人/聊天记录/发送消息
前端·chrome·websocket·c#
郑州光合科技余经理3 小时前
海外外卖平台源码改造实战——多语言核心代码实现
java·开发语言·前端·后端·mysql·架构·php
一tiao咸鱼3 小时前
前端转 agent # 02 - FastAPI 框架入门与原理
前端·python
wanghowie3 小时前
LangGraph4j 落地(二)— ReAct 多步工具与 trace 扩展
前端·react.js·前端框架
大家的林语冰3 小时前
Rust 再次打败 Go,Astro 7 首发,什么叫“万物皆可锈化“!
前端·javascript·性能优化