☰
HTMLMinifier 完全指南:基于 JavaScript 的高可配置 HTML 压缩器原理与实战
2026/10/15 2:28:24 网站建设 项目流程
  • 前端
  • 开发工具
  • 构建工具

【免费下载链接】html-minifier

Javascript-based HTML compressor/minifier (with Node.js support)

项目地址:https://gitcode.com/gh_mirrors/ht/html-minifier
点击查看免费下载

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,数值越小越好):

SiteOriginal size(KB)HTMLMinifierminimizeWill Peavyhtmlcompressor.com
Google4642464846
HTMLMinifier12598111117111
Twitter207165200224200
Stack Overflow253195207215204
Bootstrap CSS271260269228269
BBC298239290291280
Amazon422316412425n/a
NBC553530552553534
Wikipedia565461548569548
New York Times678606675670n/a
Eloquent Javascript870815840864n/a
ES6 table591150515595n/an/a
ES draft612654955664n/an/a

需要说明的是:这是一组由项目方发布的对比数据,反映其在特定时间点的测试结果,可作为选择压缩器的参考,但不同页面结构、选项组合下的收益会有差异,实际项目中应针对自身页面实测。压缩逻辑的实现位于 src/htmlminifier.js,基准测试脚本为 benchmark.js。

Options Quick Reference:全部 39 个选项速查表

HTMLMinifier 的核心价值在于"高可配置"。绝大多数选项默认关闭(disabled by default),使用时需按需开启。以下是 README 中的完整选项速查表(默认值与说明均与源码 processOptions 中的默认处理一致):

OptionDescriptionDefault
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 doctypefalse

其中caseSensitive、ignoreCustomComments、ignoreCustomFragments、html5、includeAutoGeneratedTags等默认值,在 src/htmlminifier.js 的processOptions中均有对应的初始化代码可验证。

关键选项的源码级解读

空白折叠三兄弟:collapseWhitespace / conservativeCollapse / preserveLineBreaks

collapseWhitespace负责将文档树中构成文本节点的空白折叠。在 src/htmlminifier.js 中可以看到其实现:collapseWhitespaceAll使用正则/[ \n\r\t\f\xA0]+/g压缩连续空白,并对非断行空格(\xA0,即&nbsp;)做特殊处理以避免误伤;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),并转义其中的冲突引号(&#34;/&#39;)。
  • 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)的标记片段。原因在于其工作模型是"树形"流程:

  1. 输入标记(如<p id="">foo)
  2. 解析为树形内部表示(如{ tag: "p", attr: "id", children: ["foo"] })
  3. 转换内部表示(如移除id属性)
  4. 输出结果标记(如<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)

项目地址:https://gitcode.com/gh_mirrors/ht/html-minifier
点击查看免费下载
上一篇:EB Garamond 12:如何用这款免费开源字体让你的学术写作瞬间升级?
下一篇:HomeMirror多设备同步:实现家庭多镜面信息共享

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询