- 前端
- 开发工具
- 构建工具
【免费下载链接】html-minifier
Javascript-based HTML compressor/minifier (with Node.js support)
HTMLMinifier 是一个基于 JavaScript、高度可配置且经过充分测试的 HTML 压缩(minify)工具,适用于 Node.js 环境,可直接通过命令行、Node.js API 或 Gulp 等构建工具集成到前端工程中。本文以官方 README 为主线,结合仓库源码,系统讲解其全部压缩选项、CLI 与编程用法、特殊场景处理(忽略片段、SVG 保留、无效标记),并深入解析底层实现原理,帮助读者在项目中按需组合选项获得最大压缩收益。
项目概览与版本状态
HTMLMinifier 的定位在 README.md 中表述为:a highlyconfigurable,well-tested, JavaScript-based HTML minifier。其配套能力还包括:
- 在线测试套件:
tests/目录下的 tests/index.html 承载浏览器端测试页面,Node 端测试入口为 tests/minifier.js(基于 QUnit 断言框架,覆盖了约数千条压缩行为断言)。 - 周边生态:官方与社区提供了 Ruby wrapper、Grunt 插件、Gulp 模块、Koa 中间件、Express 中间件等多种集成方式;本仓库的 package.json 中
bin字段声明了html-minifier命令行入口(指向 cli.js),main字段指向 src/htmlminifier.js(exports.minify即编程接口)。 - 附带 HTML 校验风格工具 HTMLLint。
维护状态提醒:README 明确声明当前仓库版本(package.json 中为4.0.0)已不再维护,官方建议使用包含新特性与关键安全修复的后续版本 HTML Minifier Next(HMN)。因此,本文所述内容适用于本仓库代码现状;若用于新项目,建议评估迁移到后继维护版本。
压缩效果对比:一份官方实测数据
README 提供了一份 HTMLMinifier 与 minimize、Will Peavy、htmlcompressor.com 等方案的实测对比表(针对各站点首页 HTML,单位 KB,数值越小越好):
| Site | Original size(KB) | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
|---|---|---|---|---|---|
| 46 | 42 | 46 | 48 | 46 | |
| HTMLMinifier | 125 | 98 | 111 | 117 | 111 |
| 207 | 165 | 200 | 224 | 200 | |
| Stack Overflow | 253 | 195 | 207 | 215 | 204 |
| Bootstrap CSS | 271 | 260 | 269 | 228 | 269 |
| BBC | 298 | 239 | 290 | 291 | 280 |
| Amazon | 422 | 316 | 412 | 425 | n/a |
| NBC | 553 | 530 | 552 | 553 | 534 |
| Wikipedia | 565 | 461 | 548 | 569 | 548 |
| New York Times | 678 | 606 | 675 | 670 | n/a |
| Eloquent Javascript | 870 | 815 | 840 | 864 | n/a |
| ES6 table | 5911 | 5051 | 5595 | n/a | n/a |
| ES draft | 6126 | 5495 | 5664 | n/a | n/a |
需要说明的是:这是一组由项目方发布的对比数据,反映其在特定时间点的测试结果,可作为选择压缩器的参考,但不同页面结构、选项组合下的收益会有差异,实际项目中应针对自身页面实测。压缩逻辑的实现位于 src/htmlminifier.js,基准测试脚本为 benchmark.js。
Options Quick Reference:全部 39 个选项速查表
HTMLMinifier 的核心价值在于"高可配置"。绝大多数选项默认关闭(disabled by default),使用时需按需开启。以下是 README 中的完整选项速查表(默认值与说明均与源码 processOptions 中的默认处理一致):
| Option | Description | Default |
|---|---|---|
caseSensitive | 以大小写敏感方式处理属性(对自定义 HTML 标签有用,例如 SVG 的viewBox) | false |
collapseBooleanAttributes | 省略布尔属性(boolean attributes)的属性值 | false |
collapseInlineTagWhitespace | 折叠display:inline;元素之间的空格;必须与collapseWhitespace=true配合使用 | false |
collapseWhitespace | 折叠文档树中构成文本节点的空白 | false |
conservativeCollapse | 总是折叠为 1 个空格(绝不彻底移除);必须与collapseWhitespace=true配合使用 | false |
continueOnParseError | 遇到解析错误时继续处理而非中止 | false |
customAttrAssign | 正则数组,用于支持自定义属性赋值表达式(如'<div flex?="{{mode != cover}}"></div>') | [ ] |
customAttrCollapse | 指定自定义属性以去除换行的正则(如/ng-class/) | — |
customAttrSurround | 正则数组,用于支持自定义属性环绕表达式(如<input {{#if value}}checked="checked"{{/if}}>) | [ ] |
customEventAttributes | 正则数组,用于为minifyJS支持自定义事件属性(如ng-click) | [ /^on[a-z]{3,}$/ ] |
decodeEntities | 尽可能使用直接 Unicode 字符 | false |
html5 | 按 HTML5 规范解析输入 | true |
ignoreCustomComments | 正则数组,匹配到的注释将被忽略(保留) | [ /^!/ ] |
ignoreCustomFragments | 正则数组,匹配到的片段将被忽略(如<?php ... ?>、{{ ... }}) | [ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ] |
includeAutoGeneratedTags | 插入 HTML 解析器自动生成的标签 | true |
keepClosingSlash | 在单例(singleton)元素上保留尾部斜杠 | false |
maxLineLength | 指定最大行长度;压缩输出将在合法 HTML 分割点处按换行拆分 | — |
minifyCSS | 压缩 style 元素与 style 属性中的 CSS(底层使用 clean-css) | false(可为true、Object、Function(text, type)) |
minifyJS | 压缩 script 元素与事件属性中的 JavaScript(底层使用 UglifyJS) | false(可为true、Object、Function(text, inline)) |
minifyURLs | 压缩各类属性中的 URL(底层使用 relateurl) | false(可为String、Object、Function(text)) |
preserveLineBreaks | 当标签间空白包含换行时,总是折叠为 1 个换行(绝不彻底移除);必须与collapseWhitespace=true配合使用 | false |
preventAttributesEscaping | 阻止属性值被转义 | false |
processConditionalComments | 将条件注释(conditional comments)的内容交给压缩器处理 | false |
processScripts | 字符串数组,对应需要交给压缩器处理的 script 元素 type(如text/ng-template、text/x-handlebars-template等) | [ ] |
quoteCharacter | 属性值使用的引号类型('或") | — |
removeAttributeQuotes | 尽可能移除属性周围的引号 | false |
removeComments | 移除 HTML 注释 | false |
removeEmptyAttributes | 移除所有值仅为空白(whitespace-only)的属性 | false(可为true、Function(attrName, tag)) |
removeEmptyElements | 移除所有内容为空的元素 | false |
removeOptionalTags | 移除可选的标签(optional tags) | false |
removeRedundantAttributes | 当属性值等于默认值时移除该属性 | false |
removeScriptTypeAttributes | 移除 script 标签上的type="text/javascript";其他 type 值保持不变 | false |
removeStyleLinkTypeAttributes | 移除 style 与 link 标签上的type="text/css";其他 type 值保持不变 | false |
removeTagWhitespace | 尽可能移除属性之间的空格。注意:这将导致 HTML 不合法! | false |
sortAttributes | 按频率排序属性(详见下文"排序机制") | false |
sortClassName | 按频率排序样式类(class) | false |
trimCustomFragments | 裁剪ignoreCustomFragments周围的空白 | false |
useShortDoctype | 将 doctype 替换为短 HTML5 doctype | false |
其中caseSensitive、ignoreCustomComments、ignoreCustomFragments、html5、includeAutoGeneratedTags等默认值,在 src/htmlminifier.js 的processOptions中均有对应的初始化代码可验证。
关键选项的源码级解读
空白折叠三兄弟:collapseWhitespace / conservativeCollapse / preserveLineBreaks
collapseWhitespace负责将文档树中构成文本节点的空白折叠。在 src/htmlminifier.js 中可以看到其实现:collapseWhitespaceAll使用正则/[ \n\r\t\f\xA0]+/g压缩连续空白,并对非断行空格(\xA0,即 )做特殊处理以避免误伤;collapseWhitespace函数进一步根据preserveLineBreaks(保留换行)与conservativeCollapse(保守折叠为 1 个空格)两个开关决定裁剪策略。此外还有一组内联标签映射表(src/htmlminifier.js)用于智能折叠:inlineTags、inlineTextTags、selfClosingInlineTags决定了哪些行内标签(如a、span、img)周围的空白应保留,避免压缩破坏内联元素间的可见间距——这正是collapseInlineTagWhitespace选项存在的意义:当它开启时,display:inline元素间的空格也会被折叠。
布尔属性与引号移除
collapseBooleanAttributes:源码中通过isSimpleBoolean映射表(src/htmlminifier.js)与isBooleanAttribute判断(src/htmlminifier.js)识别布尔属性(如checked、disabled、required、async等),随后在buildAttr中省略其值,使<input checked="checked">变为<input checked>。removeAttributeQuotes:只有当属性值满足canRemoveAttributeQuotes正则/^[^ \t\n\f\r"'=<>]+$/`(src/htmlminifier.js,依据 mathiasbynens 关于无引号属性值的研究)时才会安全地去引号;否则保留引号以避免生成无效 HTML。
冗余属性移除的精确规则
removeRedundantAttributes的实现函数isAttributeRedundant(src/htmlminifier.js)内置了一组"属性值等于默认值"的规则,例如:script[language="javascript"]、form[method="get"]、input[type="text"]、a[name](当同时存在id时)等会被移除。removeScriptTypeAttributes与removeStyleLinkTypeAttributes则通过isScriptTypeAttribute(src/htmlminifier.js,含text/javascript等可执行 MIME 列表)与isStyleLinkTypeAttribute(src/htmlminifier.js)判断,仅移除"可省略"的 type 值,其余 type 保持原样。
内联 CSS / JS / URL 压缩的三种取值形式
minifyCSS、minifyJS、minifyURLs三个选项均支持true、Object(透传给底层库的配置)、Function(自定义处理函数)三种取值。源码层面的处理位于 src/htmlminifier.js:
minifyCSS=true/{}时包装为new CleanCSS(value).minify(wrapCSS(text, type)),其中wrapCSS(src/htmlminifier.js)针对inline(style 属性)与media(media query)两种上下文做了包装再解包的处理,并且压缩失败时(clean-css 报错)会回退为原始文本。minifyJS=true/{}时包装为UglifyJS.minify(code, value),并剥离 script 中的<!--/-->注释外壳;inline=true表示事件属性内的 JS,此时设置parse.bare_returns。压缩出错时同样回退原文。minifyURLs传字符串时被当作{ site: value }(即以该站点为基准做相对化),底层调用RelateUrl.relate(text, value)。- URL 压缩的作用面由
isUriTypeAttribute(src/htmlminifier.js)限定,覆盖a[href]、img[src]、form[action]、script[src]等典型 URI 属性;img[srcset]也有专门处理(src/htmlminifier.js)。
模板与框架适配:customAttr* / processScripts / customEventAttributes
这类选项让 HTMLMinifier 可以安全地处理 Angular、Handlebars、服务端模板等非标准语法:
customAttrAssign/customAttrSurround:让解析器理解flex?="{{...}}"、{{#if}}...{{/if}}这类自定义赋值与环绕语法,解析器位于 src/htmlparser.js(其singleAttrAssigns与singleAttrValues正则定义在 src/htmlparser.js)。processScripts:指定如text/ng-template、text/x-handlebars-template类型的<script>内容也走压缩流程(processScript实现见 src/htmlminifier.js),从而让模板内的 HTML 同样被压缩。customEventAttributes:默认[ /^on[a-z]{3,}$/ ],即识别onclick这类原生事件属性;向数组加入如ng-click的正则后,这些自定义事件属性内的 JS 也会被minifyJS处理(isEventAttribute见 src/htmlminifier.js)。
输出形态控制:maxLineLength / quoteCharacter / keepClosingSlash / useShortDoctype
maxLineLength:在最终合并阶段生效,joinResultSegments(src/htmlminifier.js)会逐段拼接输出,在不超过最大行长的前提下于合法 HTML 分割点(标签边界)插入换行,便于调试与人工审阅。quoteCharacter:指定属性值统一使用单引号或双引号;未指定时自动选择出现次数更少的引号(见 src/htmlminifier.js),并转义其中的冲突引号("/')。keepClosingSlash:保留单例元素(如<br/>、<img/>)的尾部斜杠;关闭时输出<br>、<img>。useShortDoctype:将完整 doctype 替换为<!doctype html>(见 src/htmlminifier.js 的 doctype 处理)。
排序机制:sortAttributes 与 sortClassName 为何值得开启
sortAttributes与sortClassName不会减少输出明文大小,但会把属性/类名排成重复性高的长链,显著提升 gzip(HTTP 压缩)的压缩率——这是 README 明确说明的用途。其实现为两阶段:首先对输入做一次完整扫描,统计各标签内属性名、各class中类名的共现频率(createSortFns,见 src/htmlminifier.js);随后用 src/tokenchain.js 中的TokenChain/Sorter构建"马尔可夫链式"排序器:频率高的 token 排在前,同时保持相邻共现(如class="a b"后跟class="b c"时让b尽量保持相邻位置),从而最大化重复子串。需要注意,排序逻辑基于当前输入文档的统计,对单次压缩生效;若希望跨页面统一,可考虑自行收集统计后传入函数形态。
特殊场景处理
用<!-- htmlmin:ignore -->保留整段标记
若存在不希望被压缩的标记片段,可用<!-- htmlmin:ignore -->包裹:
<!-- htmlmin:ignore --> <script type="text/x-template"> 这里面的内容原样保留 </script> <!-- htmlmin:ignore -->源码实现见 src/htmlminifier.js:压缩前用唯一 ID 注释临时替换被包裹的内容,压缩结束再由restoreIgnore恢复原样,因此片段内的任何内容都不会被触碰。
SVG 标签自动保留大小写与闭合斜杠
SVG 标签会被自动识别,并且无论整份文件的压缩设置如何,SVG 内部的大小写敏感性与闭合斜杠都会被保留。这一行为在 src/htmlminifier.js 中实现:解析到svg起始标签时,通过Object.create(options)派生一份选项副本,强制caseSensitive = true、keepClosingSlash = true;遇到</svg>时(src/htmlminifier.js)恢复为原型选项。因此viewBox、preserveAspectRatio等驼峰属性不会被错误地小写化。
无法处理无效或不完整的标记
README 明确指出:HTMLMinifier 无法处理无效(invalid)或不完整(partial)的标记片段。原因在于其工作模型是"树形"流程:
- 输入标记(如
<p id="">foo) - 解析为树形内部表示(如
{ tag: "p", attr: "id", children: ["foo"] }) - 转换内部表示(如移除
id属性) - 输出结果标记(如
<p>foo</p>)
由于它先把输入当作完整树来解析,丢失了"原始标记本是一棵半棵树"这一信息,因此输出阶段也无法再生成不完整/畸形的树。实际表现是:遇到无法解析的内容,解析器会抛出Parse Error(见 src/htmlparser.js);若设置continueOnParseError: true,解析器将把无法识别的<当作普通文本继续处理(src/htmlparser.js),从而以"宽松模式"完成压缩而不是中止。测试用例(如 tests/minifier.js)也验证了<$unicorn>这类畸形输入在默认模式下抛错、在continueOnParseError: true下原样返回的行为。
安装与使用
安装
按 README 提供的三种方式:
# 作为命令行工具全局安装 npm install html-minifier -g # 作为库以编程方式使用(本地安装) npm install html-minifier # 从 Git 克隆后本地链接 git clone git://github.com/kangax/html-minifier.git cd html-minifier npm link .依据 package.json,本版本要求node >= 10,运行时依赖包括 clean-css、commander、he、relateurl、uglify-js、camel-case、param-case 等。
命令行用法(CLI)
命令行入口为 cli.js。运行html-minifier --help可查看全部可用选项(各选项即上表参数的 kebab-case 形式,定义于 cli.js)。README 给出的一个高压缩率组合示例:
html-minifier --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype --minify-css true --minify-js true除单文件/多文件输入外,CLI 还支持:
-o, --output <file>:指定输出文件(默认输出到 STDOUT);-c, --config-file <file>:从 JSON 或 CommonJS 模块读取配置(cli.js),仓库提供了完整示例 sample-cli-config-file.conf;--input-dir <dir>/--output-dir <dir>/--file-ext <ext>:批量处理目录(递归),按扩展名过滤(cli.js);- 无文件参数时从STDIN读取输入(cli.js),便于与管道组合。
命令行参数值需要正则的(如customAttrAssign、ignoreCustomFragments)以 JSON 数组字符串传入(CLI 的parseJSONRegExpArray会把字符串构造成 RegExp,见 cli.js)。
Node.js 编程接口
var minify = require('html-minifier').minify; var result = minify('<p title="blah" id="moo">foo</p>', { removeAttributeQuotes: true }); result; // '<p title=blah id=moo>foo</p>'minify(value, options)导出自 src/htmlminifier.js,内部会先经processOptions合并默认值,再执行压缩,并可通过options.log(函数)接收耗时与压缩错误日志。
Gulp 集成
README 给出的 Gulp 4 示例(含完整选项对象,可作为生产配置模板):
const { src, dest, series } = require('gulp'); const htmlMinify = require('html-minifier'); const options = { includeAutoGeneratedTags: true, removeAttributeQuotes: true, removeComments: true, removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true, sortClassName: true, useShortDoctype: true, collapseWhitespace: true }; function html() { return src('app/**/*.html') .on('data', function(file) { const buferFile = Buffer.from(htmlMinify.minify(file.contents.toString(), options)) return file.contents = buferFile }) .pipe(dest('build')) } exports.html = series(html)配置文件示例
仓库自带的 sample-cli-config-file.conf 展示了近乎全开的"激进压缩"配置,可作为 CLI-c参数或程序内 options 的参考蓝本,要点摘录:
{ "collapseWhitespace": true, "removeComments": true, "removeOptionalTags": true, "removeRedundantAttributes": true, "removeEmptyAttributes": true, "removeEmptyElements": true, "minifyCSS": true, "minifyJS": true, "processConditionalComments": true, "processScripts": ["text/html"], "useShortDoctype": true }需要注意:配置文件中ignoreCustomFragments等正则字段以字符串形式书写;CLI 加载时会将其构造为真正的 RegExp 对象。
运行基准测试
仓库提供 benchmark 脚本(benchmark.js),用于对比 HTMLMinifier 与其他压缩方案在真实页面上的压缩率与耗时:
node benchmark.js该脚本会先按 package.json 的benchmarkDependencies(brotli、minimize、cli-table 等)临时安装对比依赖,再对benchmarks/目录中维护的站点清单(见 benchmarks/index.json)逐一下载并压缩,输出各方案压缩前后体积、节省百分比与耗时的对照表。
实践建议小结
- 从保守起步:先开启
collapseWhitespace、removeComments、removeAttributeQuotes、useShortDoctype这类风险低的选项,再逐步叠加removeOptionalTags、removeRedundantAttributes等;removeTagWhitespace因产生不合法 HTML 需谨慎(例如在追求极限体积的内部工具场景才使用)。 - 模板项目:为 Angular/Handlebars 等框架场景配置
customAttrAssign、customAttrSurround、processScripts与customEventAttributes,避免压缩器误伤模板语法。 - 追求 gzip 收益:额外开启
sortAttributes与sortClassName,它们不减少明文但能提升 gzip/Brotli 压缩率。 - 安全兜底:对无法保证合法输入的页面,设置
continueOnParseError: true让压缩在解析错误下仍能继续;对必须原样保留的片段使用<!-- htmlmin:ignore -->。 - 版本选择:本仓库 4.0.0 已停止维护,新项目请评估官方推荐的后继版本 HTML Minifier Next;若因历史依赖仍使用本版本,建议在 CI 中保留在线测试套件对应的 Node 测试(
npm test,即 Gruntfile.js 中配置的 QUnit 任务)以验证压缩行为。
无论以 CLI、Node.js API 还是构建工具方式接入,理解上述选项的底层行为都是用好 HTMLMinifier 的关键——压缩的本质是在体积收益与输出正确性之间做权衡,而这份"高可配置"正是它给出的答案。
- 前端
- 开发工具
- 构建工具
【免费下载链接】html-minifier
Javascript-based HTML compressor/minifier (with Node.js support)
相关推荐
【亲测免费】 HTMLMinifier:高效压缩HTML的利器
HTMLMinifier:高效压缩HTML的利器 项目介绍 HTMLMinifier https://kangax.github.io/html minifie
前端开发工具构建工具HTMLMinifier终极指南:快速压缩HTML的完整教程
HTMLMinifier终极指南:快速压缩HTML的完整教程 你是否曾经为网页加载速度慢而烦恼?是否想要减少HTML文件大小却不知从何下手?🤔 HTMLMin
前端开发工具构建工具FeHelper 代码压缩工具实战指南:HTML/JavaScript/CSS 三合一压缩的原理与使用
FeHelper 代码压缩工具实战指南:HTML/JavaScript/CSS 三合一压缩的原理与使用 代码压缩是前端发布上线前最常见的优化手段之一。FeHel
开发工具前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考