你是不是也遇到过:改个按钮颜色,得翻 17 个文件?上线前压测,发现光 JS 就加载了 42 个请求,首页白屏三秒起步?别急着加 CDN、上 SSR——先低头看看你那堆“祖传代码”,很可能问题不在新功能,而在老文件没动过刀。
今天不聊理论,只说能立刻见效的合并策略。6 个实操点,全来自我亲手调过的电商后台、SaaS 管理系统和内容平台。不画饼,不列百分比,只告诉你哪一步该删、哪一步该合、哪一步千万别碰。
为什么你合并了文件,加载速度反而变慢了?
合并 ≠ 变快。
合并 ≠ 省事。
合并错了,真会拖垮首屏。
去年接手一个 B2B 后台,前任把轮播图、权限校验、Excel 导出、弹窗组件全塞进一个 common.js 里。结果用户点进首页,浏览器得先下完这个 480KB 的“全家桶”,才肯执行那几行初始化导航的代码。首屏卡顿直接翻倍。
问题出在哪?
不是合并本身,是混装。
你把首页根本用不到的模块,硬塞进所有页面都加载的文件里,等于让每个用户都为别人的功能买单。
试试这个动作:
打开 Chrome DevTools → 「Coverage」标签页 → 刷新首页 → 看看 JS/CSS 里有多少代码标着灰色(未执行)。我见过最夸张的,一个 320KB 的 JS 文件,实际只用了不到 90KB。
真正该合并的,是那些80% 页面都在用、且几乎不改动的代码:比如基础工具函数、UI 组件库、路由核心逻辑。
其余的,按页面拆开,或者更狠一点——等用户滚动到对应区域再加载(IntersectionObserver + 动态 import)。
小提醒:移动端对大文件更敏感。12 个 20KB 的小文件,并行下载往往比 1 个 240KB 大文件更快。别迷信“越少越好”,要看真实网络环境下的表现。
3 个让 CSS 体积缩到 1/3 的合并技巧
属性能合就合
别写:
margin-top: 10px;
margin-right: 20px;
margin-bottom: 10px;
margin-left: 20px;
换成:
margin: 10px 20px;
如果上下左右都一样?一行 margin: 10px 足够。
这种写法在单个文件里省不了多少,但项目里几十个组件一叠加,冗余代码轻松占掉一整个 CSS 文件的 10%。
选择器别套娃
看到 .page .content .list .item a:hover 这种五层嵌套,先停一下。
问问自己:这个样式非得靠这么深的路径才能生效吗?还是只是因为“当时图省事”?
改成 .list-item-link:hover,加个明确类名,既好维护,又减少浏览器匹配开销。
我在一个内部管理系统里干过这事:把所有超过三层的选择器重构一遍,CSS 从 80KB 掉到 35KB,而且开发者改样式时再也不用猜“到底哪个父级影响了它”。
上线前,删掉所有注释
开发时写的 /* 这里兼容 IE11,后面要重构 */ 或 /* 临时方案,勿删 */,上线前必须清空。
这些文字不参与渲染,只增加传输负担。用 cssnano 跑一遍,你会发现注释常占 15%-20% 的体积。
别留念想——Git 里有历史,线上不需要“备忘录”。
如何用文件合并避免“请求地狱”
“请求地狱”不是玄学:当页面同时发起 30+ 个 HTTP 请求,TCP 连接排队、SSL 握手打架、DNS 查询堵车……最后就是用户盯着空白页发呆。
但胡乱合并只会制造“巨无霸地狱”。解法是分层:
第一层:稳如老狗的 vendor
jQuery/Vue/React + 公共工具函数 → 打包成vendor.js。这个文件改得少,缓存设长点(比如Cache-Control: max-age=2592000),用户一个月内都不用重下。第二层:各司其职的页面包
home.js、order-list.js、user-profile.js—— 每个页面只加载自己需要的逻辑。别让订单页替首页背轮播图的锅。第三层:按需召唤的“懒模块”
评论框、搜索建议、分享按钮这类非首屏功能,别一开始就加载。用import('./comments.js')动态导入,或者加个<link rel="prefetch" href="search.js">提前预热。
有个新闻站原来每个文章页要拉 35 个 JS:广告脚本 ×5、统计 ×3、社交按钮 ×2……合并后变成 5 个:1 个 vendor、1 个正文逻辑、1 个广告(延迟加载)、1 个统计(异步)、1 个社交(点击触发)。加载时间缩短了不少,用户划走率也明显下降了。
合并时最容易踩的 4 个坑
坑一:不同版本的库,别硬塞一起
jQuery 2.x 和 3.x 同时存在?两个 $.ajax 方法撞车,轻则报错,重则白屏。
✅ 正确做法:统一升级到一个稳定版;或用 Webpack/Vite 的模块隔离机制,让它们互不干扰。
坑二:顺序乱了,神仙也救不了
a.js 依赖 b.js 里定义的全局变量,但合并后 b 在 a 后面执行?恭喜,页面挂了。
✅ 解法很简单:先把确定不依赖顺序的脚本打上 async 或 defer;剩下的,按 import 关系或文档说明手动排好序,写在配置文件里,别靠运气。
坑三:缓存没配好,合并白干
你把所有业务代码打包成 all.js,改了一行 CSS,哈希全变,用户又得下 500KB。
✅ 拆开缓存策略:vendor.js 用长期缓存,app.js 用内容哈希(比如 app.a1b2c3.js),静态资源更新后只重下业务部分。
坑四:忘了服务器开了 Gzip
合并后文件变大了?别慌。CSS/JS 是文本,Gzip 压缩率通常在 70% 以上。
✅ 合并前先确认 Nginx/Apache 是否启用了 gzip on 和 gzip_types text/css application/javascript。没开的话,合并可能反而更慢。
工具推荐:用这 3 个工具自动完成合并
别手撸 concat,也别每次上线都手动删注释。这三个是我每天都在用的:
Webpack 的
SplitChunksPlugin
配置好chunks: 'all'和minSize: 30000,它会自动把重复引用超 30KB 的模块拎出来,生成独立 chunk。多页应用省心到哭。Gulp 的
gulp-concat+gulp-clean-css
如果你还在用 Gulp(很多传统企业项目还在用),两行任务就能搞定:先按顺序合并 CSS,再压缩去注释。轻量、可控、不用学新概念。PostCSS 的
postcss-merge-rules
自动合并同一选择器下的多段声明。比如.btn { color: blue }和.btn { padding: 8px }合成.btn { color: blue; padding: 8px }。单看不显眼,但跑完整个项目,CSS 体积能稳稳掉 5%-10%。
今天就能执行的操作步骤
打开你的项目根目录,找到那个最大、最不敢动的 CSS 或 JS 文件(通常是 main.css 或 app.js)。
用 VS Code 或任意编辑器打开它,按 Ctrl+F(Mac 是 Cmd+F),搜 .(CSS 里找选择器)或 function(JS 里找函数声明)。
数一数,里面大概有多少个独立样式块或函数?
如果超过 50 个,基本可以断定:它太杂了,该瘦身了。
现在做三件事:
- 把它复制一份,重命名为
[原文件名]_clean(比如main_clean.css); - 打开这个副本,手动删掉所有你100% 确认当前页面用不到的代码(比如首页文件里的「关于我们」样式、后台文件里的「小程序入口」逻辑);
- 保存,对比两个文件大小。
如果新文件小了 20% 以上,说明你切中要害了;如果小了 50% 以上,恭喜,你刚刚完成了最值钱的一次优化。
把这个 _clean 文件,直接替换到线上环境,明天早上第一件事:打开 Lighthouse 跑一次,看看首屏时间有没有变化。