Skip to content

feat: switch to htmlnano#156

Open
stevenjoezhang wants to merge 6 commits intomasterfrom
htmlnano
Open

feat: switch to htmlnano#156
stevenjoezhang wants to merge 6 commits intomasterfrom
htmlnano

Conversation

@stevenjoezhang
Copy link
Copy Markdown
Member

@stevenjoezhang stevenjoezhang commented Oct 12, 2025

Check list

  • Add test cases for the changes.
  • Passed the CI test.

Description

Issue resolved: #84
Issue resolved: #148

I managed to complete the migration, and the configuration options were almost entirely unaffected. Users can upgrade seamlessly without any noticeable changes.

Additional information

@tomap
Copy link
Copy Markdown
Contributor

tomap commented Oct 12, 2025

Looks good

@stevenjoezhang stevenjoezhang requested review from a team and Copilot November 5, 2025 06:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR migrates the package from using html-minifier to htmlnano as the HTML minification library. The change updates the minification engine while attempting to maintain compatibility with existing configuration options.

  • Replaced html-minifier with htmlnano and its dependencies (cssnano, postcss, svgo, terser)
  • Updated configuration options to match htmlnano's API (e.g., minifyJSminifyJs, minifyCSSminifyCss)
  • Converted the filter function to async and updated all tests accordingly

Reviewed Changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
package.json Updated dependencies from html-minifier to htmlnano and added required peer dependencies
lib/filter.js Migrated from html-minifier to htmlnano, converted function to async, added custom comment filtering logic
index.js Updated default configuration options to match htmlnano's API
test/index.js Updated all tests to handle async filter function and adjusted expectations for htmlnano behavior
README.md Updated documentation to reflect new configuration options and removed trailing whitespace
.gitignore Added package-lock.json to ignore list

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +16
delete options.exclude;
delete options.ignoreCustomComments;
delete options.removeComments;
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutating the config options object is dangerous. Since options is a reference to this.config.html_minifier, these deletions will permanently modify the configuration for subsequent calls. This will cause issues if the filter is invoked multiple times. Create a shallow copy of options before mutation: const options = { ...this.config.html_minifier };

Copilot uses AI. Check for mistakes.
stevenjoezhang and others added 2 commits November 5, 2025 14:12
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Mimi <stevenjoezhang@gmail.com>
[![Build Status](https://github.com/hexojs/hexo-html-minifier/workflows/Tester/badge.svg)](https://github.com/hexojs/hexo-html-minifier/actions?query=workflow%3ATester)
[![NPM version](https://badge.fury.io/js/hexo-html-minifier.svg)](https://www.npmjs.com/package/hexo-html-minifier)

Minify HTML files with [HTMLMinifier](https://github.com/kangax/html-minifier).
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to fix this link.

Copy link
Copy Markdown
Member

@yoshinorin yoshinorin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation appears to be slower compared to the current one. I tested with the following configuration (there should be no difference between the two):

# Current
html_minifier:  
  collapseBooleanAttributes: true
  collapseWhitespace: true
  ignoreCustomComments: [ !!js/regexp /^\s*more/]
  removeComments: true
  removeEmptyAttributes: true
  removeScriptTypeAttributes: true
  removeStyleLinkTypeAttributes: true
  minifyJS: true
  minifyCSS: true

# This PR
html_minifier:
  collapseBooleanAttributes: true
  collapseWhitespace: true
  ignoreCustomComments: [ !!js/regexp /^\s*more/]
  removeComments: true
  removeEmptyAttributes: true
  removeRedundantAttributes: true
  removeAttributeQuotes: true
  minifyJs: true
  minifyCss: true

I only tested with Cold Processing on Hexo 8.1.1, but when generating around 2000 articles, this PR seems to be approximately 1 to 1.5 minutes slower than the current implementation.

It's unclear whether the slowdown is caused by htmlnano itself or by something in this implementation, but this performance difference might not be acceptable for some users.


- **ignoreCustomComments**: Array of regex'es that allow to ignore certain comments, when matched. Need to prepend [`!!js/regexp`](https://github.com/nodeca/js-yaml#supported-yaml-types) to support regex.

Description of the above options and other available options, see [HTMLMinifier](https://github.com/kangax/html-minifier#options-quick-reference)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here.

removeRedundantAttributes: true
removeAttributeQuotes: true
minifyJs: true
minifyCss: true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO:

We should provide a migration guide since the configuration has changed.

removeRedundantAttributes: true
removeAttributeQuotes: true
minifyJs: true
minifyCss: true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should provide a migration guide since the configuration has changed.

@stevenjoezhang
Copy link
Copy Markdown
Member Author

@yoshinorin If considering runtime speed and performance, another option is to use the Rust-based @minify-html/node: https://www.npmjs.com/package/@minify-html/node

@stevenjoezhang
Copy link
Copy Markdown
Member Author

I'll create another pull request so you can compare it with htmlnano

@D-Sketon
Copy link
Copy Markdown
Member

D-Sketon commented Jan 1, 2026

I have used this library before. While it is fast, it can sometimes produce errors during compression in certain scenarios. wilsonzlin/minify-html#181 Additionally, the library is not very well maintained.

@stevenjoezhang
Copy link
Copy Markdown
Member Author

stevenjoezhang commented Jan 1, 2026

I found a benchmark: https://github.com/maltsev/html-minifiers-benchmark
I modified it to record time used for each configuration. Here are the results:

Website Source (KB) [html-minifier] [html-minifier-terser] [html-minifier-next] [htmlnano] [minify] [minify-html]
stackoverflow.blog 142 4.6% (26.1ms) 3.8% (108.0ms) 32.2% (129.3ms) 8.0% (97.0ms) 4.6% (108.9ms) 4.7% (31.8ms)
github.com 549 5.5% (38.2ms) 2.9% (244.1ms) 42.0% (235.0ms) 17.2% (175.0ms) 7.3% (234.0ms) 5.7% (45.2ms)
en.wikipedia.org 217 5.1% (45.6ms) 4.6% (127.5ms) 7.7% (271.2ms) 7.6% (109.2ms) 6.2% (124.1ms) 2.9% (51.5ms)
developer.mozilla.org 109 39.5% (56.3ms) 37.9% (800.7ms) 42.0% (821.6ms) 49.1% (780.7ms) 40.1% (778.6ms) 39.9% (58.5ms)
tc39.es 7243 9.5% (1316.0ms) 8.5% (4641.8ms) 11.8% (4320.1ms) 9.3% (2518.8ms) 9.5% (4441.7ms) 9.1% (1561.1ms)
apple.com 259 8.8% (24.6ms) 8.6% (115.6ms) 20.3% (109.9ms) 11.2% (67.0ms) 10.0% (123.0ms) 9.2% (28.9ms)
w3.org 51 23.2% (96.9ms) 19.0% (163.6ms) 24.5% (294.0ms) 23.3% (157.3ms) 24.4% (158.7ms) 20.3% (79.3ms)
weather.com 2281 11.1% (912.4ms) 0.3% (1943.6ms) 11.4% (6741.1ms) 18.7% (1894.8ms) 11.1% (1917.7ms) 0.6% (922.8ms)
Avg. minify rate 13.4% 10.7% 24.0% 18.0% 14.1% 11.6%
Avg. minify time (ms) 314.5ms 1018.1ms 1615.3ms 725.0ms 985.8ms 347.4ms

@SukkaW
Copy link
Copy Markdown
Member

SukkaW commented Jan 1, 2026

I found a benchmark: https://github.com/maltsev/html-minifiers-benchmark I modified it to record time used for each configuration. Here are the results:

We might wanna do a real-world hexo project minify benchmark for minify time instead, since hexo might produce hundreds, thousands of HTML files.

Preferably, we might wanna contribute some performance optimization to the upstream (like htmlnano, which responds to pull requests well).

@yoshinorin
Copy link
Copy Markdown
Member

Based on the minify-html issues and benchmark information for each library, htmlnano seems like a reasonable choice at this point. (While forking and maintaining html-minifier is another option, I don't think it's particularly desirable.)

Unless there are better alternatives, IMHO, a reasonable compromise would be to switch to htmlnano, clearly note the performance degradation in the release notes, and bump the major version in the next release.

@D-Sketon
Copy link
Copy Markdown
Member

D-Sketon commented Jan 2, 2026

clk: ~3.93 GHz
cpu: 13th Gen Intel(R) Core(TM) i5-13400F
runtime: node 24.8.0 (x64-win32)

benchmark                                         avg (min … max) p75 / p99    (min … top 1%)
----------------------------------------------------------------- -------------------------------
htmlminifier-tc39.es.html-7.08M                       1.07 s/iter    1.08 s    1.09 s ▅▁▅▅▁▁██▅▅█
htmlminifiernext-tc39.es.html-7.08M                   1.63 s/iter    1.64 s    1.65 s ▆▃▁▃█▃▁▃▁▃▃
htmlminifierterser-tc39.es.html-7.08M                 1.21 s/iter    1.23 s    1.23 s ▅▁▅▅█▅▁▅▅▅█
htmlnano-tc39.es.html-7.08M                        578.95 ms/iter 598.84 ms 651.00 ms ▃█▁▃▆▃▃▁▁▃▃
minify-tc39.es.html-7.08M                           71.67 ms/iter  73.11 ms  74.97 ms ▆▆▁▆▁▁▃█▁▁▃
minifyhtml-tc39.es.html-7.08M                      262.35 ms/iter 266.69 ms 283.06 ms ▅▁▃▃▅▁█▁▁▁▃

----------------------------------------------------------------- -------------------------------
htmlminifier-apple.com.html-259K                    15.57 ms/iter  16.81 ms  18.60 ms ▅▇█▄▂▂▆▃▂▅▂
htmlminifiernext-apple.com.html-259K                29.67 ms/iter  29.65 ms  31.57 ms ▂█▅▃▃▂▂▁▁▁▂
htmlminifierterser-apple.com.html-259K              15.02 ms/iter  15.22 ms  17.17 ms ▄▃▇▅█▂▄▂▂▁▂
htmlnano-apple.com.html-259K                        28.80 ms/iter  30.04 ms  37.61 ms ▂█▆▂▅▂▁▁▂▂▂
minify-apple.com.html-259K                           4.25 ms/iter   4.53 ms   5.89 ms █▇█▄▄▃▄▂▁▁▁
minifyhtml-apple.com.html-259K                       3.97 ms/iter   3.98 ms   6.71 ms ▂█▄▂▁▁▁▁▁▁▁

----------------------------------------------------------------- -------------------------------
htmlminifier-w3.org.html-50.4K                       3.86 ms/iter   3.93 ms   6.08 ms ▁█▄▃▁▁▁▁▁▁▁
htmlminifiernext-w3.org.html-50.4K                   6.30 ms/iter   6.51 ms   7.19 ms ▂▃▂██▇▆▃▄▂▂
htmlminifierterser-w3.org.html-50.4K                 4.34 ms/iter   4.44 ms   7.55 ms █▆▄▂▂▁▁▁▁▁▁
htmlnano-w3.org.html-50.4K                          13.02 ms/iter  14.03 ms  17.30 ms ▆██▆▃▄▃▃▂▂▂
minify-w3.org.html-50.4K                           645.87 µs/iter 646.50 µs   1.41 ms ▅█▃▂▁▂▁▁▁▁▁
minifyhtml-w3.org.html-50.4K                       765.79 µs/iter 734.00 µs   1.43 ms ▅█▂▁▁▁▁▁▂▁▁

----------------------------------------------------------------- -------------------------------
htmlminifier-developer.mozilla.org.html-106K         8.93 ms/iter   9.11 ms  12.11 ms ▂▆█▆▂▁▁▁▁▁▁
htmlminifiernext-developer.mozilla.org.html-106K    15.18 ms/iter  15.20 ms  18.45 ms ▂█▅▃▂▁▁▁▁▂▁
htmlminifierterser-developer.mozilla.org.html-106K   9.71 ms/iter   9.91 ms  12.66 ms ▁▃█▅▄▁▁▂▁▂▂
htmlnano-developer.mozilla.org.html-106K            33.32 ms/iter  34.26 ms  36.94 ms ▅▆█▃▅▃▁▁▅▁▃
minify-developer.mozilla.org.html-106K               1.62 ms/iter   1.73 ms   3.01 ms ▇█▂▂▂▂▂▁▁▁▁
minifyhtml-developer.mozilla.org.html-106K           1.61 ms/iter   1.61 ms   2.87 ms ▂█▃▁▁▁▁▁▁▁▁

Another performance test generated with Mitata shows that htmlnano incurs a relatively high overhead on small files. Additionally, I noticed a significant discrepancy between my benchmark and @stevenjoezhang . I’m not sure how your benchmark was conducted, but if it was modified directly based on https://github.com/maltsev/html-minifiers-benchmark, there could be issues—because its benchmark uses Promise.all to run all minifiers in parallel, which may result in inaccurate timing measurements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Maybe Replace html-minifier with htmlnano or html-minifier-terser due to security vulnerabilities [Proposal] Replace html-minifier with htmlnano

6 participants