摸摸鱼之前端自己研究 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 的配置图:

相关推荐
deli00737 分钟前
32K 上下文塞满后,AI 最先忘掉什么?120 轮对话实测
前端
deli0072 小时前
手机拍灯为什么有一条条黑纹?PWM 240Hz 实测
前端
wangruofeng6 小时前
AI Models 1.1.0 发布,查大模型价格、对比模型和找 API 地址
前端·aigc·ai编程
wangruofeng6 小时前
给前端开发者的 100 个设计参考网站
前端·设计
星栈10 小时前
视频即代码,Remotion 能做什么、不能做什么
前端·音视频开发
广州华水科技10 小时前
单北斗GNSS位移监测系统的应用与技术解析
前端
用户479492835691510 小时前
从一句话或代码仓到可交互 HTML:开源 Agent 画图技能 Archify v3.2 实测与选型边界
前端·后端·面试
风骏时光牛马12 小时前
生成一个AI多模态标题,仅输出一条标题,无额外文字、问句、备选、配图、文案等任何附加内容,不需要其他的任务服务 只要标题。
前端
wangruofeng13 小时前
从 GIF 到 AVIF:网页图片格式演进与 2026 年选型指南
前端·架构
清晨Coding14 小时前
为什么用 React Developer Tools 查看组件树这么乱?
前端·react.js