微前端把一个仓库拆成一个主应用加七八个子应用之后,本地开发是舒服了,发布这件事却变得很尴尬。全量构建一次要十几分钟,可这次上线明明只改了一个子应用。手动打包再 scp 上去也不是办法,子应用要放进主应用目录下的固定子目录,主应用发布时还不能把这些子目录删掉。
这篇把我用 Jenkins 跑微前端流水线的整套配置写下来,包括按需构建哪几个包、构建产物怎么归拢、构建后 shell 怎么在部署机上做「主应用覆盖但保留子目录」这个动作,最后再补一条阿里云 OSS 加 CDN 的路子和一份上线前 checklist。
在本篇文章中,我们将从浅入深,和大家一起学习以下知识:
- 微前端从提交代码到用户看到页面,整条链路都发生了什么
- Jenkins 的系统管理、凭据、插件、视图、任务这几个概念怎么对上
- 参数化构建怎么配,才能做到「只构建勾选的那几个包」
- 构建 shell 和构建后 shell 的完整代码,以及每一段在防什么坑
- 主应用发布时怎么不误删子应用目录
- 换成阿里云 OSS 加 CDN 部署要配哪几步,
index.html的缓存怎么设 - 一份可以直接抄的上线前 checklist
# 一、先把整条链路画出来
配置界面点来点去很容易迷路,动手之前先把链路捋一遍,后面每一个配置项落在哪一步就清楚了:
开发提交代码
│
▼
┌───────────────────────────────────────────┐
│ Jenkins 构建机 │
│ │
│ ① General │
│ 参数化:mutiParams(勾哪几个包) │
│ isRunInstall(要不要装依赖) │
│ ② 源码管理 Git plugin 拉代码 │
│ → /var/lib/jenkins/workspace/{任务名} │
│ ③ 构建 执行 shell │
│ for 勾选的包: npm install → npm build │
│ 产物统一搬到 publish/{子目录} │
└──────────────────┬────────────────────────┘
│ ④ Send build artifacts over SSH
│ publish/** → 部署机
▼
┌───────────────────────────────────────────┐
│ 部署机 │
│ ⑤ Exec command(构建后 shell) │
│ main → 铺到部署根目录(保留子目录) │
│ subs/* → 各自覆盖到同名子目录 │
│ 最后删掉 publish 临时目录 │
└──────────────────┬────────────────────────┘
│
▼
Nginx 指向部署根目录 / 或 OSS + CDN
│
▼
用户访问页面
整条链路的难点只有一处,就是第 ⑤ 步。主应用的产物要铺在部署根目录下,子应用的产物在同一个根目录下各占一个子目录,那主应用重新发布时,怎么在清掉旧文件的同时不把子应用目录一起删了。后面第四节的 shell 就是在解决这件事。
如果你还不清楚主应用和子应用在运行时是怎么互相找到的,可以先看 微前端实战总结,从 single-spa 到 qiankun 的原理拆解,那边讲的是原理,这篇只讲上线。还没定下来用哪套框架的话,微前端落地方案对比,qiankun 无界 Module Federation 怎么选 里有一条可以照着走的选型路径。
顺便说一句,下面这套流水线其实和你用哪个微前端框架关系不大。不管是 qiankun 还是 icestark,产物都是一堆静态文件,差别只在目录怎么摆。
# 二、Jenkins 的几个概念先对齐
Jenkins 是基于 Java 开发的持续集成工具,免费开源,用于监控持续重复的工作,目标是把软件的持续集成自动化。功能上主要是两块,持续的软件版本发布和测试,以及监控外部调用执行的工作。
它的界面概念不多,但名字起得有点绕,先花几分钟对齐一下。
# 2.1 系统管理
执行者数量是系统可同时并发执行任务的数量,默认 2 个。这个值原则上不要超过服务器 CPU 核数,否则容易出现 CPU 过载把服务拖挂。微前端项目一次构建可能同时跑好几个 npm run build,本来就吃 CPU,这里我一般不往上调。
Jenkins URL 是 Jenkins 的访问地址,改这里的端口号和改服务器配置文件的端口号效果一致。
凭据用来存储需要密文保护的东西,数据库密码、GitLab 密码、Docker 私有仓库密码都放这儿,Jenkins 靠它和第三方应用交互。要安装 Credentials Binding 插件用户才能管理凭据。凭据管理包含凭据本身和凭据所在域的管理,系统默认会创建全局域,你也可以自己添加域再在域下加凭据。为了最大程度提高安全性,在 Jenkins 中配置的凭据以加密形式存储在主实例上,由 Jenkins 实例 ID 加密,使用时靠配置的唯一标识 ID 引用。
可以添加的凭据有五种:用户名和密码、SSH 密钥(SSH 公私钥对)、加密文件、令牌(例如 API 令牌、GitHub 个人访问令牌)、证书。添加时要填种类、范围(全局或系统)、凭据内容、ID、描述。
这里有个坑要注意,ID 字段是可选的,不填 Jenkins 会分配一个全局唯一的 GUID。但一旦设置了凭证 ID,之后就无法再更改。所以如果你打算在 Pipeline 脚本里按 ID 引用凭据,第一次就把名字起对。
插件管理有两条路。一条是在管理平台界面里用插件管理器,路径是「系统管理」→「插件管理」,在「可选插件」标签下搜索需要的插件,勾选后点左下角的下载并重启后安装,等下载完成服务自动重启,重新进入系统即安装成功。另一条是用 Jenkins CLI 的 install-plugin 命令,适合用脚本或者配置管理代码来装插件的场景,不需要在 Web UI 里做人工交互。
用户管理默认使用自带数据库模式存储用户,Jenkins 默认创建 admin 账号,初始密码在 /var/lib/jenkins/secrets/initialAdminPassword,登录之后可以在管理用户里改掉。第一次装完记得改,这个文件路径是公开的常识。
# 2.2 视图和任务
视图主要用来管理不同项目之间的任务,一般是每个项目建一个视图,在视图下管理整个项目的模块。常用的是列表视图(显示简单列表,新建或编辑视图时可以把已有任务加进来,也可以在该视图下新建任务)和我的视图(自动显示当前用户有权限访问的任务)。
新建任务时要填任务名称,选任务模板。新装的 Jenkins 一般只有一个「构建一个自由风格的软件项目」模板,其他模板要下对应的插件,不同模板的构建流程也不一样。还有个复制选项,输入已有任务名可以复制一份新任务,但选了复制就不能再自定义模板了,会以被复制项目的模板为准。
任务详情页里几个常用入口:状态、修改记录(每次构建获取的代码变更记录,也就是这次构建的 git 提交记录)、工作空间(任务的项目文件目录)、立即构建、配置(配置整个构建和部署过程要干什么)、删除工程、重命名。
概念就这些。下面进入正题,一步步配任务。
# 三、任务配置分四步走
任务配置就是把「从拉代码到部署成功」这个过程拆成几段分别配置。
# Step 1. General
这一步是执行构建前对 Jenkins 本身做的一些设置。
丢弃旧的构建默认策略是 Log Rotation,可以设保持构建的天数(保存此天数内的构建记录,为空则全保留)和保持构建的最大个数(保存最近这么多次构建,为空则全保留)。这两个建议一定要设,构建产物加上工作空间很吃磁盘,我见过因为没配这个把构建机磁盘塞满的。
参数化构建过程是微前端场景下最关键的一项,它就是「只构建我勾选的那几个包」的实现方式。
要装 Extended Choice Parameter 插件,它提供多选框类型的参数:

配置项逐条对应关系是这样:
- Name:构建过程使用的参数名,后面 shell 里靠这个名字取值
- Description:参数描述
- Parameter Type:
Check Boxes,也就是多选框 - Number of Visible Items:
8,checkbox 参数值个数,等于项目子包和主包的总数 - Delimiter:
,,各个值的分割符号 - Choose Source for Value:
main,subs/appletuser,subs/college,subs/follow,subs/project,subs/questions,subs/statistics,subs/system,填的是主包和子包相对项目根目录的路径 - Choose Source for Default Value:同上,表示默认全选
这里的取值一定要写成相对项目根目录的路径,因为构建 shell 里会直接 cd 进去。写成应用名而不是路径的话,shell 里还得再做一次映射,没必要。
另外再加一个布尔值参数,用来判断这次构建要不要跑 npm install:
- 名称:
isRunInstall - 默认值:默认是否勾选
- 描述:参数描述
依赖没变的日常发版把它关掉,能省下好几分钟。这个开关是全局的,勾选的所有应用会按同一个规则执行。
# Step 2. 源码管理
用 Git plugin 同步代码仓库。任务执行时代码会被拉到 /var/lib/jenkins/workspace/{任务名称} 目录下,后面 shell 里的 $WORKSPACE 环境变量就是这个路径。
要填的东西不多:
- Repository URL:代码仓库地址
- Credentials:服务器连接代码仓库的凭据,可以在系统管理里加好后在这选,也可以点右边的添加按钮现加,新增方式和系统管理里一样
- Branches to build:指定任务需要拉取的分支,允许配多个
- 源码库浏览器:指定 git 仓库类型,默认自动
# Step 3. 构建
执行 shell 这一步,源码管理插件已经把代码拉下来了。这段 shell 要做的是按参数化构建时勾选的应用逐个打包,再把产物统一放到项目根目录的 publish 文件夹里。
#!/bin/bash
# 项目根目录地址(相对于工作空间)
project_path=""
# 将用户选择需要打包的应用拆分成数组
OLD_IFS="$IFS"
IFS=","
arr=($mutiParams)
IFS="$OLD_IFS"
# 清空上次打包的部署文件
rm -rf $WORKSPACE$project_path/publish
for i in ${arr[@]}
do
# 进入对应的应用中执行打包过程,$WORKSPACE为系统环境变量,值为工作空间地址
cd $WORKSPACE$project_path/$i
rm -rf dist
# 判断是否需要执行环境安装,当前设置为全局设置,所有需要打包的应用会执行相同的判断
if [[ $isRunInstall == "true" ]]
then
npm install
fi
npm run build
# 将子应用和主应用放在同一级,便于后续部署,因为很多微前端项目子应用都会放置在同一个文件夹下
[[ $i == "main" ]] && subdir=$i || subdir=${i##*/}
mkdir -p $WORKSPACE$project_path/publish/$subdir
mv dist/* $WORKSPACE$project_path/publish/$subdir
done
拆开看几处关键的。