生产环境 Rollup 打包优化
解读
在国内 PHP 面试里,面试官问“生产环境 Rollup 打包优化”并不是想让你去写 JS,而是考察你对“前后端资源交付链”的整体认知:
- PHP 项目(Laravel、ThinkPHP、Hyperf 等)最终要把 JS/CSS 吐给浏览器,Rollup 只是可选的打包器之一;
- 优化目标必须符合国内网络特点——移动端占比高、弱网、CDN 按流量计费、备案域名拆分、微信/支付宝小程序环境;
- 优化动作必须能落地到“PHP 工程化”流程:Composer 钩子、GitLab-CI、Jenkins、Docker 多阶段构建、Kubernetes ConfigMap 注入版本号;
- 结果要能量化:首屏时间、FCP、Lighthouse 评分、服务器带宽节省、回源失败率。
一句话:让你用“PHP 视角”把 Rollup 的产出物压榨到极致,并保证上线回滚不出事故。
知识点
- 国内主流构建选型对比
Webpack5 模块联邦、Vite 预构建、Rollup 树摇,为什么 Laravel 官方脚手架 vite.config.js 里仍留 rollupOptions。 - Rollup 核心优化配置
output.manualChunks、treeshake.moduleSideEffects、external 把 @vue/shared 甩到 CDN,生成 legacy 与 modern 双包。 - 压缩与混淆
terser 插件开 mangle.properties 保留 PHP 需要调用的全局变量;esbuild 压缩比 terser 快 20 倍,但会踩国内三星旧机兼容坑。 - 哈希与缓存
[name]-[hash:8].js 解决微信浏览器“假刷新”,配合 Laravel Mix 的 mix.version() 在 manifest.json 里映射,PHP 模板用 mix() 助手自动拼 CDN 域名。 - Gzip/Brotli 预压缩
Rollup 插件 rollup-plugin-gzip 在 CI 里提前生成 .gz .br,Nginx 开启 gzip_static 和 brotli_static,减少 CPU 热点,压测 QPS 提升 18%。 - CDN 与跨域
国内阿里云全站加速、腾讯云 ECDN、又拍云,支持 HTTP2 + Quic;Rollup 输出 publicPath 设为 //cdn.xxx.com,配合 PHP 设置 Access-Control-Allow-Origin 只允许白名单域名,防止流量被盗刷。 - 差异化加载
生成 importmap.json,PHP 根据 UA 判断 Blink 内核还是老 WebKit,决定吐 module/nomodule,减少 30 kB polyfill。 - 灰度与回滚
把 Rollup 产物上传到 OSS 后,PHP 在 Redis 里写版本号,按用户 UID 尾号灰度;紧急回滚时改 Redis 键,无需重新打包。 - 监控
前端 Sentry 上报 sourcemap,Rollup 插件 sentryRollupPlugin 自动上传,PHP 后端通过 X-Sentry-Token 校验,避免 sourcemap 泄露到公网。 - 合规
输出文件必须过“全国互联网信息安全备案管理系统”敏感词扫描,Rollup 插件 rollup-plugin-chinese-filter 在构建阶段正则匹配,失败即中断 CI,防止上线后被强制下线。
答案
“生产环境 Rollup 打包优化”我会分五步落地:
第一步,双包策略。Rollup 配置两个入口,modern 包用 ES2020 语法,legacy 包通过 @rollup/plugin-babel 注入 core-js3,PHP 根据浏览器 UA 自动切换,保证老安卓 5.1 也能跑。
第二步,极致拆包。把 node_modules 里超过 10 kB 的库全部 external,走国内 CDN,手动拆出 vue.runtime.esm.js、dayjs、lodash-es,减少业务包 42% 体积;同时开 manualChunks,把后台管理路由和前台商城路由分开,后台代码只在管理员访问时才加载。
第三步,预压缩与缓存。CI 阶段用 rollup-plugin-gzip 同时生成 .gz 和 .br,文件名带 8 位 hash;Nginx 开启 gzip_static、brotli_static 和 etag,配合 PHP 的 mix() 助手在模板里自动拼版本号,实现“永久强缓存 + 即时刷新”。
第四步,灰度发布。构建完成后把静态资源上传到阿里云 OSS,OSS 触发函数计算刷新 CDN;PHP 在 Redis 里维护一套灰度名单,按用户 UID 尾号 0-9 分批切换,一旦监控到 JS 报错率突增,5 秒内改 Redis 键即可回滚,无需重新打包。
第五步,合规与监控。Rollup 插件里插入 rollup-plugin-chinese-filter 做敏感词预检;sourcemap 只上传到公司内网 Sentry,外网不可访问;Lighthouse CI 评分低于 85 即中断流水线,保证每次上线都达到国内主流电商的性能基线。
通过以上五步,我们把首屏 JS 体积从 380 kB 压到 110 kB,Gzip 后 34 kB,Brotli 后 29 kB;移动端 FCP 从 2.8 s 降到 1.4 s,CDN 流量费用下降 27%,上线三个月零回滚事故。
拓展思考
- 如果公司强制使用 Vite,如何复用上述 Rollup 优化?
Vite 生产环境也是 Rollup,可在 vite.config.ts 里直接写 rollupOptions,把 manualChunks、terser 配置搬过去;但 Vite 的预构建会打乱 node_modules 路径,需要写 optimizeDeps.exclude 把大库甩到 CDN。 - 小程序场景下没有浏览器 UA,如何拆包?
小程序基础库版本号可类比 UA,PHP 接口返回基础库版本,前端根据版本号决定拉 v1 还是 v2 分包,Rollup 输出多份产物,上传至小程序云开发静态存储。 - 金融客户要求“零外网依赖”,所有静态文件必须走内网 CDN,如何继续 external?
在内网 Harbor 搭建私有 npm 镜像,把 vue、lodash 重新发布为 @company/vue,Rollup external 指向 //internal-cdn.xxx.com,配合内网 DNS 解析,既满足合规又保留拆包收益。