html-minifier-next 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  HTML Minifier Next (HMN) is a highly **configurable, well-tested, JavaScript-based HTML minifier**.
6
6
 
7
- The project has been based on [Terser’s html-minifier-terser](https://github.com/terser/html-minifier-terser), which in turn had been based on [Juriy Zaytsev’s html-minifier](https://github.com/kangax/html-minifier) (HMN offers additional features, but is compatible with both). It was set up because as of 2025, both html-minifier-terser and html-minifier have been unmaintained for some time. As the project seems maintainable [to me, [Jens](https://meiert.com/)]—even more so with community support—, it’s being updated and documented further in this place.
7
+ The project has been based on [HTML Minifier Terser](https://github.com/terser/html-minifier-terser), which in turn had been based on [Juriy Zaytsev’s HTML Minifier](https://github.com/kangax/html-minifier) (HMN offers additional features, but is compatible with both). It was set up because as of 2025, both HTML Minifier Terser and HTML Minifier have been unmaintained for some time. As the project seems maintainable [to me, [Jens](https://meiert.com/)]—even more so with community support—, it’s being updated and documented further in this place.
8
8
 
9
9
  ## Installation
10
10
 
@@ -2160,7 +2160,7 @@ var htmlminifier = { minify };
2160
2160
  *
2161
2161
  * Default: No limit
2162
2162
  *
2163
- * @prop {boolean | import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules> | ((text: string, type?: string) => Promise<string> | string)} [minifyCSS]
2163
+ * @prop {boolean | Partial<import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules>> | ((text: string, type?: string) => Promise<string> | string)} [minifyCSS]
2164
2164
  * When true, enables CSS minification for inline `<style>` tags or
2165
2165
  * `style` attributes. If an object is provided, it is passed to
2166
2166
  * [Lightning CSS](https://www.npmjs.com/package/lightningcss)
@@ -22332,8 +22332,8 @@ function remove_initializers(var_statement) {
22332
22332
  return decls.length ? make_node(AST_Var, var_statement, { definitions: decls }) : null;
22333
22333
  }
22334
22334
 
22335
- /** Called on code which we know is unreachable, to keep elements that affect outside of it. */
22336
- function trim_unreachable_code(compressor, stat, target) {
22335
+ /** Called on code which won't be executed but has an effect outside of itself: `var`, `function` statements, `export`, `import`. */
22336
+ function extract_from_unreachable_code(compressor, stat, target) {
22337
22337
  walk(stat, node => {
22338
22338
  if (node instanceof AST_Var) {
22339
22339
  const no_initializers = remove_initializers(node);
@@ -22358,7 +22358,8 @@ function trim_unreachable_code(compressor, stat, target) {
22358
22358
  target.push(node);
22359
22359
  return true;
22360
22360
  }
22361
- if (node instanceof AST_Scope) {
22361
+ if (node instanceof AST_Scope || node instanceof AST_Class) {
22362
+ // Do not go into nested scopes
22362
22363
  return true;
22363
22364
  }
22364
22365
  });
@@ -23382,7 +23383,7 @@ function tighten_body(statements, compressor) {
23382
23383
  CHANGED = n != len;
23383
23384
  if (has_quit)
23384
23385
  has_quit.forEach(function (stat) {
23385
- trim_unreachable_code(compressor, stat, statements);
23386
+ extract_from_unreachable_code(compressor, stat, statements);
23386
23387
  });
23387
23388
  }
23388
23389
 
@@ -24565,6 +24566,11 @@ class Compressor extends TreeWalker {
24565
24566
  }
24566
24567
  }
24567
24568
 
24569
+ /** True if compressor.self()'s result will be turned into a 32-bit integer.
24570
+ * ex:
24571
+ * ~{expr}
24572
+ * (1, 2, {expr}) | 0
24573
+ **/
24568
24574
  in_32_bit_context(other_operand_must_be_number) {
24569
24575
  if (!this.option("evaluate")) return false;
24570
24576
  var self = this.self();
@@ -24582,9 +24588,10 @@ class Compressor extends TreeWalker {
24582
24588
  if (
24583
24589
  p instanceof AST_Binary
24584
24590
  && (
24585
- p.operator == "&&"
24586
- || p.operator == "||"
24587
- || p.operator == "??"
24591
+ // Don't talk about p.left. Can change branch taken
24592
+ p.operator == "&&" && p.right === self
24593
+ || p.operator == "||" && p.right === self
24594
+ || p.operator == "??" && p.right === self
24588
24595
  )
24589
24596
  || p instanceof AST_Conditional && p.condition !== self
24590
24597
  || p.tail_node() === self
@@ -25187,7 +25194,7 @@ function if_break_in_loop(self, compressor) {
25187
25194
  body: self.condition
25188
25195
  }));
25189
25196
  }
25190
- trim_unreachable_code(compressor, self.body, body);
25197
+ extract_from_unreachable_code(compressor, self.body, body);
25191
25198
  return make_node(AST_BlockStatement, self, {
25192
25199
  body: body
25193
25200
  });
@@ -25258,7 +25265,7 @@ def_optimize(AST_For, function(self, compressor) {
25258
25265
  if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
25259
25266
  if (!cond) {
25260
25267
  var body = [];
25261
- trim_unreachable_code(compressor, self.body, body);
25268
+ extract_from_unreachable_code(compressor, self.body, body);
25262
25269
  if (self.init instanceof AST_Statement) {
25263
25270
  body.push(self.init);
25264
25271
  } else if (self.init) {
@@ -25294,7 +25301,7 @@ def_optimize(AST_If, function(self, compressor) {
25294
25301
  if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
25295
25302
  if (!cond) {
25296
25303
  var body = [];
25297
- trim_unreachable_code(compressor, self.body, body);
25304
+ extract_from_unreachable_code(compressor, self.body, body);
25298
25305
  body.push(make_node(AST_SimpleStatement, self.condition, {
25299
25306
  body: self.condition
25300
25307
  }));
@@ -25307,7 +25314,7 @@ def_optimize(AST_If, function(self, compressor) {
25307
25314
  }));
25308
25315
  body.push(self.body);
25309
25316
  if (self.alternative) {
25310
- trim_unreachable_code(compressor, self.alternative, body);
25317
+ extract_from_unreachable_code(compressor, self.alternative, body);
25311
25318
  }
25312
25319
  return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
25313
25320
  }
@@ -25435,6 +25442,9 @@ def_optimize(AST_Switch, function(self, compressor) {
25435
25442
  var body = [];
25436
25443
  var default_branch;
25437
25444
  var exact_match;
25445
+ // - compress self.body into `body`
25446
+ // - find and deduplicate default branch
25447
+ // - find the exact match (`case 1234` inside `switch(1234)`)
25438
25448
  for (var i = 0, len = self.body.length; i < len && !exact_match; i++) {
25439
25449
  branch = self.body[i];
25440
25450
  if (branch instanceof AST_Default) {
@@ -25464,6 +25474,7 @@ def_optimize(AST_Switch, function(self, compressor) {
25464
25474
  }
25465
25475
  body.push(branch);
25466
25476
  }
25477
+ // i < len if we found an exact_match. eliminate the rest
25467
25478
  while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]);
25468
25479
  self.body = body;
25469
25480
 
@@ -25535,7 +25546,7 @@ def_optimize(AST_Switch, function(self, compressor) {
25535
25546
  let i = body.length - 1;
25536
25547
  for (; i >= 0; i--) {
25537
25548
  let bbody = body[i].body;
25538
- if (is_break(bbody[bbody.length - 1], compressor)) bbody.pop();
25549
+ while (is_break(bbody[bbody.length - 1], compressor)) bbody.pop();
25539
25550
  if (!is_inert_body(body[i])) break;
25540
25551
  }
25541
25552
  // i now points to the index of a branch that contains a body. By incrementing, it's
@@ -25551,9 +25562,9 @@ def_optimize(AST_Switch, function(self, compressor) {
25551
25562
  let branch = body[j];
25552
25563
  if (branch === default_or_exact) {
25553
25564
  default_or_exact = null;
25554
- body.pop();
25565
+ eliminate_branch(body.pop());
25555
25566
  } else if (!branch.expression.has_side_effects(compressor)) {
25556
- body.pop();
25567
+ eliminate_branch(body.pop());
25557
25568
  } else {
25558
25569
  break;
25559
25570
  }
@@ -25667,15 +25678,16 @@ def_optimize(AST_Switch, function(self, compressor) {
25667
25678
  // and there's a side-effect somewhere. Just let the below paths take care of it.
25668
25679
  }
25669
25680
 
25681
+ // Reintegrate `decl` (var statements)
25670
25682
  if (body.length > 0) {
25671
25683
  body[0].body = decl.concat(body[0].body);
25672
25684
  }
25673
-
25674
25685
  if (body.length == 0) {
25675
25686
  return make_node(AST_BlockStatement, self, {
25676
25687
  body: decl.concat(statement(self.expression))
25677
25688
  }).optimize(compressor);
25678
25689
  }
25690
+
25679
25691
  if (body.length == 1 && !has_nested_break(self)) {
25680
25692
  // This is the last case body, and we've already pruned any breaks, so it's
25681
25693
  // safe to hoist.
@@ -25755,7 +25767,7 @@ def_optimize(AST_Switch, function(self, compressor) {
25755
25767
  if (prev && !aborts(prev)) {
25756
25768
  prev.body = prev.body.concat(branch.body);
25757
25769
  } else {
25758
- trim_unreachable_code(compressor, branch, decl);
25770
+ extract_from_unreachable_code(compressor, branch, decl);
25759
25771
  }
25760
25772
  }
25761
25773
  function branches_equivalent(branch, prev, insertBreak) {
@@ -25809,7 +25821,7 @@ def_optimize(AST_Try, function(self, compressor) {
25809
25821
  if (compressor.option("dead_code") && self.body.body.every(is_empty)) {
25810
25822
  var body = [];
25811
25823
  if (self.bcatch) {
25812
- trim_unreachable_code(compressor, self.bcatch, body);
25824
+ extract_from_unreachable_code(compressor, self.bcatch, body);
25813
25825
  }
25814
25826
  if (self.bfinally) body.push(...self.bfinally.body);
25815
25827
  return make_node(AST_BlockStatement, self, {
@@ -41201,7 +41213,7 @@ var htmlminifier = { minify };
41201
41213
  *
41202
41214
  * Default: No limit
41203
41215
  *
41204
- * @prop {boolean | import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules> | ((text: string, type?: string) => Promise<string> | string)} [minifyCSS]
41216
+ * @prop {boolean | Partial<import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules>> | ((text: string, type?: string) => Promise<string> | string)} [minifyCSS]
41205
41217
  * When true, enables CSS minification for inline `<style>` tags or
41206
41218
  * `style` attributes. If an object is provided, it is passed to
41207
41219
  * [Lightning CSS](https://www.npmjs.com/package/lightningcss)
@@ -197,7 +197,7 @@ export type MinifierOptions = {
197
197
  *
198
198
  * Default: `false`
199
199
  */
200
- minifyCSS?: boolean | import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules> | ((text: string, type?: string) => Promise<string> | string);
200
+ minifyCSS?: boolean | Partial<import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules>> | ((text: string, type?: string) => Promise<string> | string);
201
201
  /**
202
202
  * When true, enables JS minification for `<script>` contents and
203
203
  * event handler attributes. If an object is provided, it is passed to
@@ -1 +1 @@
1
- {"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"AAm7CO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAQ3B;;;;;;;;;UAQS,MAAM;YACN,MAAM;YACN,MAAM;mBACN,MAAM;iBACN,MAAM;kBACN,MAAM;;;;;;;;;;;;;4BAQN,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,qBAAqB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;wBAMjG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;;oBAMhH,OAAO;;;;;;;;gCAOP,OAAO;;;;;;;;kCAOP,OAAO;;;;;;;;yBAOP,OAAO;;;;;;;;2BAOP,OAAO;;;;;;;2BAOP,OAAO;;;;;;;;uBAMP,MAAM,EAAE;;;;;;yBAOR,MAAM;;;;;;yBAKN,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;;;;;;;4BAKlB,MAAM,EAAE;;;;;;;oCAMR,MAAM;;;;;;;qBAMN,OAAO;;;;;;;YAMP,OAAO;;;;;;;;2BAMP,MAAM,EAAE;;;;;;;;;4BAOR,MAAM,EAAE;;;;;;;+BAQR,OAAO;;;;;;;2BAMP,SAAS,CAAC,MAAM,CAAC;;;;;;uBAMjB,OAAO;;;;;;;;UAKP,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI;;;;;;;;qBAO1B,MAAM;;;;;;;oBAON,MAAM;;;;;;;;;;gBAMN,OAAO,GAAG,OAAO,cAAc,EAAE,gBAAgB,CAAC,OAAO,cAAc,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;eASrJ,OAAO,GAAG,OAAO,QAAQ,EAAE,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;iBASzG,OAAO,GAAG,MAAM,GAAG,OAAO,WAAW,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;WAS7F,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;;;;;;;+BAOxB,OAAO;;;;;;;;yBAMP,OAAO;;;;;;;gCAOP,OAAO;;;;;;;;iCAMP,OAAO;;;;;;;;;;qBAOP,MAAM,EAAE;;;;;;;qBASR,IAAI,GAAG,GAAG;;;;;;;4BAMV,OAAO;;;;;;;;qBAMP,OAAO;;;;;;;;;4BAOP,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;;;;;;;;0BAQtD,OAAO;;;;;;;;yBAOP,OAAO;;;;;;;;gCAOP,OAAO;;;;;;;iCAOP,OAAO;;;;;;;oCAMP,OAAO;;;;;;;;;;0BAMP,OAAO;;;;;;;;;qBASP,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;;;;;;;;;oBAQzD,OAAO,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;;;;;;;;0BAQrC,OAAO;;;;;;;sBAOP,OAAO"}
1
+ {"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"AAm7CO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAQ3B;;;;;;;;;UAQS,MAAM;YACN,MAAM;YACN,MAAM;mBACN,MAAM;iBACN,MAAM;kBACN,MAAM;;;;;;;;;;;;;4BAQN,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,qBAAqB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;wBAMjG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;;oBAMhH,OAAO;;;;;;;;gCAOP,OAAO;;;;;;;;kCAOP,OAAO;;;;;;;;yBAOP,OAAO;;;;;;;;2BAOP,OAAO;;;;;;;2BAOP,OAAO;;;;;;;;uBAMP,MAAM,EAAE;;;;;;yBAOR,MAAM;;;;;;yBAKN,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;;;;;;;4BAKlB,MAAM,EAAE;;;;;;;oCAMR,MAAM;;;;;;;qBAMN,OAAO;;;;;;;YAMP,OAAO;;;;;;;;2BAMP,MAAM,EAAE;;;;;;;;;4BAOR,MAAM,EAAE;;;;;;;+BAQR,OAAO;;;;;;;2BAMP,SAAS,CAAC,MAAM,CAAC;;;;;;uBAMjB,OAAO;;;;;;;;UAKP,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI;;;;;;;;qBAO1B,MAAM;;;;;;;oBAON,MAAM;;;;;;;;;;gBAMN,OAAO,GAAG,OAAO,CAAC,OAAO,cAAc,EAAE,gBAAgB,CAAC,OAAO,cAAc,EAAE,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;eAS9J,OAAO,GAAG,OAAO,QAAQ,EAAE,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;iBASzG,OAAO,GAAG,MAAM,GAAG,OAAO,WAAW,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;WAS7F,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;;;;;;;+BAOxB,OAAO;;;;;;;;yBAMP,OAAO;;;;;;;gCAOP,OAAO;;;;;;;;iCAMP,OAAO;;;;;;;;;;qBAOP,MAAM,EAAE;;;;;;;qBASR,IAAI,GAAG,GAAG;;;;;;;4BAMV,OAAO;;;;;;;;qBAMP,OAAO;;;;;;;;;4BAOP,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;;;;;;;;0BAQtD,OAAO;;;;;;;;yBAOP,OAAO;;;;;;;;gCAOP,OAAO;;;;;;;iCAOP,OAAO;;;;;;;oCAMP,OAAO;;;;;;;;;;0BAMP,OAAO;;;;;;;;;qBASP,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;;;;;;;;;oBAQzD,OAAO,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;;;;;;;;0BAQrC,OAAO;;;;;;;sBAOP,OAAO"}
package/package.json CHANGED
@@ -11,17 +11,17 @@
11
11
  "entities": "^7.0.0",
12
12
  "lightningcss": "^1.28.2",
13
13
  "relateurl": "^0.2.7",
14
- "terser": "^5.44.0"
14
+ "terser": "^5.44.1"
15
15
  },
16
16
  "description": "Highly configurable, well-tested, JavaScript-based HTML minifier",
17
17
  "devDependencies": {
18
18
  "@commitlint/cli": "^20.1.0",
19
- "@eslint/js": "^9.37.0",
20
- "@rollup/plugin-commonjs": "^28.0.9",
19
+ "@eslint/js": "^9.39.1",
20
+ "@rollup/plugin-commonjs": "^29.0.0",
21
21
  "@rollup/plugin-json": "^6.1.0",
22
22
  "@rollup/plugin-node-resolve": "^16.0.3",
23
23
  "@rollup/plugin-terser": "^0.4.4",
24
- "eslint": "^9.37.0",
24
+ "eslint": "^9.39.1",
25
25
  "rollup": "^4.52.5",
26
26
  "rollup-plugin-polyfill-node": "^0.13.0",
27
27
  "typescript": "^5.9.3",
@@ -84,5 +84,5 @@
84
84
  "test:watch": "node --test --watch tests/*.spec.js"
85
85
  },
86
86
  "type": "module",
87
- "version": "4.1.0"
87
+ "version": "4.2.0"
88
88
  }
@@ -1630,7 +1630,7 @@ export default { minify };
1630
1630
  *
1631
1631
  * Default: No limit
1632
1632
  *
1633
- * @prop {boolean | import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules> | ((text: string, type?: string) => Promise<string> | string)} [minifyCSS]
1633
+ * @prop {boolean | Partial<import("lightningcss").TransformOptions<import("lightningcss").CustomAtRules>> | ((text: string, type?: string) => Promise<string> | string)} [minifyCSS]
1634
1634
  * When true, enables CSS minification for inline `<style>` tags or
1635
1635
  * `style` attributes. If an object is provided, it is passed to
1636
1636
  * [Lightning CSS](https://www.npmjs.com/package/lightningcss)