配置 grunt-contrib-htmlmin 移除空白与布尔属性
解读
面试官抛出这道题,核心意图是验证候选人是否真正在生产环境用过 grunt-contrib-htmlmin,而不仅仅“跑通过 demo”。
国内前端部署普遍要求极致体积优化(SEO 评分、CDN 流量计费、首屏指标),空白字符(空格、换行、制表符)与冗余布尔属性(如 checked="checked")是 HTML 体积膨胀的隐形元凶。
能否在 Gruntfile 里一次性正确配置 collapseWhitespace 与 removeRedundantAttributes,直接决定上线包大小能否再降 3%~8%,这是量化可考核的绩效点。
此外,面试官还会旁敲侧击:
- 是否知道布尔属性在 XHTML5 与 HTML5 的差异;
- 是否能在**多环境(dev、test、prod)**下开关该优化,避免开发环境可读性骤降;
- 是否理解**collapseWhitespace 的“保守模式”与“激进模式”**对 inline SVG、pre、textarea 的影响。
答不到这三层,只能算“会用”,不算“敢上线”。
知识点
- collapseWhitespace: true 时,grunt-contrib-htmlmin 会安全合并相邻空白字符,但保留 pre/textarea/script 标签内格式;若需连换行都删掉,需再开 conservativeCollapse: false。
- removeRedundantAttributes: true 时,默认只删“值与属性名相同”的布尔属性(如 checked="checked"),不会误伤 data-xxx 或自定义属性;若页面需兼容 XHTML 规范,必须同步开启 removeEmptyAttributes,否则可能出现 checked="" 这种无效残留。
- Grunt 目标级覆盖:通过 grunt.option('env') 或 process.env.NODE_ENV,在 prod 目标里强制开启上述两项,在 dev 目标里关闭,保证本地调试可读。
- 与 grunt-contrib-watch 联动:htmlmin 任务必须晚于文件合并(grunt-contrib-concat)早于文件哈希(grunt-filerev),否则 watch 触发顺序错误会导致缓存指纹失效。
- 国内 CDN 缓存策略:很多云厂商(阿里云、腾讯云)默认忽略 html 文件缓存,若 htmlmin 后体积下降明显,可主动提升 Cache-Control max-age,减少回源流量,这是可以写进季度 OKR 的量化收益。
答案
在 Gruntfile.js 中,先确保已安装 grunt-contrib-htmlmin 0.2.0 及以上版本(低版本无 conservativeCollapse 选项),然后按环境区分配置:
module.exports = function(grunt) {
grunt.initConfig({
htmlmin: {
options: {
collapseWhitespace: true, // 移除空白字符
conservativeCollapse: false, // 激进模式,连换行一起删
removeRedundantAttributes: true, // 删除布尔属性冗余值
removeEmptyAttributes: true, // 同步清理空属性,防 XHTML 残留
keepClosingSlash: false // HTML5 无需自关闭斜杠
},
prod: {
files: [{
expand: true,
cwd: 'dist/html',
src: '**/*.html',
dest: 'dist/html'
}]
},
dev: { // 开发环境可读性优先
options: {
collapseWhitespace: false,
removeRedundantAttributes: false
},
files: '<%= htmlmin.prod.files %>'
}
}
});
grunt.loadNpmTasks('grunt-contrib-htmlmin');
grunt.registerTask('build', function() {
var env = grunt.option('env') || process.env.NODE_ENV || 'dev';
if (env === 'prod') {
grunt.task.run(['concat:html', 'htmlmin:prod', 'filerev']);
} else {
grunt.task.run(['concat:html', 'htmlmin:dev']);
}
});
};
上线验证:
- 执行
grunt build --env=prod; - 用
ls -lh dist/html对比前后大小,一般可降 4%~10%; - 抽样 diff 检查,确保 pre、code、svg 标签内格式未被误杀;
- 通过
curl -H "Accept-Encoding: gzip" https://cdn.xxx.com/index.html | wc -c再次验证Gzip 后节省依旧明显,才算闭环。
拓展思考
- 与 grunt-usemin 的集成陷阱:若项目采用 usemin 自动注入构建块,htmlmin 必须在 usemin 之后运行,否则 usemin 的正则匹配会被压缩后的换行缺失干扰,导致路径替换失败。
- 国内移动端特殊场景:微信内置浏览器对checked、disabled、selected 布尔属性有样式级 hack,若页面依赖
[checked]选择器,需关闭 removeRedundantAttributes 或加 ignoreCustomComments 白名单,否则样式会掉。 - 量化收益汇报模板:
“通过 grunt-contrib-htmlmin 开启 collapseWhitespace + removeRedundantAttributes,首屏 HTML 体积由 42.3 kB 降至 38.1 kB,Gzip 后 12.4 kB → 11.2 kB,CDN 流量月省 21 GB,成本下降 180 元/月,SEO 评分 Lighthouse 95 → 98。”——把技术细节转成财务数字,是晋升答辩的杀手锏。