astro-html-minifier-next 0.1.2 → 0.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/dist/index.d.ts CHANGED
@@ -1,23 +1,5 @@
1
1
  import type { AstroIntegration } from "astro";
2
- import type { MinifierOptions as MinifyHTMLOptions } from "html-minifier-next";
3
- export interface HTMLMinifierOptions extends MinifyHTMLOptions {
4
- /**
5
- * Option specific to `astro-html-minifier-next` used to specify the maximum
6
- * number of worker threads to spawn when minifying files.
7
- * When set to `0`, `astro-html-minifier-next` will not create any worker
8
- * threads and will do the minification in the main thread.
9
- *
10
- * Note: If unable to do a structured clone of the `html-minifier-next`
11
- * options according to the
12
- * [HTML structured clone
13
- * algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm),
14
- * `astro-html-minifier-next` will do the minification on the main
15
- * thread, even if this option is not set to `0`.
16
- *
17
- * @default `Math.max(1, os.availableParallelism() - 1)`
18
- */
19
- maxWorkers?: number;
20
- }
2
+ import { type MinifierOptions as HTMLMinifierOptions } from "html-minifier-next";
21
3
  /**
22
4
  * An Astro integration that minifies HTML assets using
23
5
  * [html-minifier-next](https://www.npmjs.com/package/html-minifier-next).
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAI/E,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC7D;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAkBD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CACnC,OAAO,EAAE,mBAAmB,GAC1B,gBAAgB,CAqIlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EACN,KAAK,eAAe,IAAI,mBAAmB,EAE3C,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CACnC,OAAO,EAAE,mBAAmB,GAC1B,gBAAgB,CAyIlB"}
package/dist/index.js CHANGED
@@ -1,25 +1,9 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
1
2
  import { availableParallelism as getAvailableParallelism } from "node:os";
2
3
  import { relative as getRelativePath } from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import { styleText } from "node:util";
5
- import { minifyHTMLFile } from "./minify-html-file.js";
6
- import { MinifyHTMLFileWorkerPool } from "./minify-html-file-worker-pool.js";
7
- /**
8
- * Check if a value can be transferred to a worker.
9
- * @param {*} value
10
- * @returns {boolean}
11
- */
12
- function isTransferable(value) {
13
- try {
14
- // Attempt to do a structured clone of the value.
15
- // If it succeeds, it should be transferable to a worker.
16
- structuredClone(value);
17
- return true;
18
- }
19
- catch {
20
- return false;
21
- }
22
- }
6
+ import { minify as minifyHTML, } from "html-minifier-next";
23
7
  /**
24
8
  * An Astro integration that minifies HTML assets using
25
9
  * [html-minifier-next](https://www.npmjs.com/package/html-minifier-next).
@@ -33,21 +17,9 @@ export default function htmlMinifier(options) {
33
17
  return {
34
18
  name: "astro-html-minifier-next",
35
19
  hooks: {
36
- "astro:build:done": async ({ logger, dir: distUrl, assets }) => {
20
+ "astro:build:done": async ({ assets, dir: distUrl, logger, }) => {
37
21
  logger.info(styleText(["bgGreen", "black"], " minifying html assets "));
38
- const totalTimeStart = performance.now(); // --- TIMED BLOCK START ---
39
- const availableParallelism = getAvailableParallelism();
40
- const { maxWorkers = Math.max(1, availableParallelism - 1), ...minifyHTMLOptions } = options;
41
- let workerPool;
42
- if (maxWorkers > 0 && isTransferable(minifyHTMLOptions)) {
43
- // TODO: Remove again.
44
- logger.info(styleText("yellow", `Using up to ${maxWorkers} worker threads.`));
45
- workerPool = new MinifyHTMLFileWorkerPool(maxWorkers, minifyHTMLOptions);
46
- }
47
- else {
48
- // TODO: Remove again.
49
- logger.info(styleText("yellow", `Not using worker threads.`));
50
- }
22
+ const totalTimeStart = performance.now(); // --- TOTAL TIMED BLOCK START ---
51
23
  const tasks = [];
52
24
  let tasksTotal = 0;
53
25
  let tasksDone = 0;
@@ -64,10 +36,24 @@ export default function htmlMinifier(options) {
64
36
  const relativeAssetPath = getRelativePath(distPath, assetPath);
65
37
  const logLineAssetPath = ` ${logLineArrow} /${relativeAssetPath} `;
66
38
  tasks.push(async () => {
67
- const { savings, time } = workerPool
68
- ? await workerPool.minifyHTMLFile(assetPath)
69
- : await minifyHTMLFile(assetPath, minifyHTMLOptions, signal);
70
- // Log a nice summary of the minification savings and the time it took.
39
+ const timeStart = performance.now(); // --- TIMED BLOCK START ---
40
+ const html = await readFile(assetPath, {
41
+ encoding: "utf8",
42
+ signal,
43
+ });
44
+ const minifiedHTML = await minifyHTML(html, options);
45
+ const savings = Buffer.byteLength(html) - Buffer.byteLength(minifiedHTML);
46
+ if (savings > 0) {
47
+ // Only write the minified HTML to the file if it's smaller.
48
+ await writeFile(assetPath, minifiedHTML, {
49
+ encoding: "utf8",
50
+ signal,
51
+ });
52
+ }
53
+ const timeEnd = performance.now(); // --- TIMED BLOCK END ---
54
+ const time = timeEnd - timeStart;
55
+ // Log a nice summary of the minification savings and the time it
56
+ // took.
71
57
  const savingsSign = savings > 0 ? "-" : "+";
72
58
  const savingsAbs = Math.abs(savings);
73
59
  const savingsWithUnit = savingsAbs < 1024
@@ -85,12 +71,15 @@ export default function htmlMinifier(options) {
85
71
  tasksTotal++;
86
72
  }
87
73
  }
88
- // We use a quadruple of the available parallelism here, even if we don't actually run the tasks in different threads or anything.
89
- // The available parallelism is a good indicator of machine capabilities, and the multiplier gives a good balance of speed and resource usage.
90
- const maxExecutingTasksSize = availableParallelism * 4;
74
+ // We use a quadruple of the available parallelism here, even if we
75
+ // don't actually run the tasks in different threads or anything. The
76
+ // available parallelism is a good indicator of machine capabilities,
77
+ // and the multiplier gives a good balance of speed and resource usage.
78
+ const maxExecutingTasksSize = getAvailableParallelism() * 4;
91
79
  // This holds the current batch of promises that are waiting to fulfill.
92
80
  const executingTasks = new Set();
93
- // Batch the tasks to avoid minifying too many files at once, which could lead to memory and performance issues.
81
+ // Batch the tasks to avoid minifying too many files at once, which
82
+ // could lead to memory and performance issues.
94
83
  for (const task of tasks) {
95
84
  const taskPromise = task()
96
85
  .then(() => {
@@ -104,8 +93,9 @@ export default function htmlMinifier(options) {
104
93
  });
105
94
  executingTasks.add(taskPromise);
106
95
  if (executingTasks.size >= maxExecutingTasksSize) {
107
- // If the amount of executing tasks reaches the limit, we wait until the one of them finishes,
108
- // and therefore gets deleted from the list, before continuing with the next task.
96
+ // If the amount of executing tasks reaches the limit, we wait
97
+ // until the one of them finishes, and therefore gets deleted from
98
+ // the list, before continuing with the next task.
109
99
  await Promise.race(executingTasks);
110
100
  }
111
101
  if (signal.aborted) {
@@ -114,13 +104,13 @@ export default function htmlMinifier(options) {
114
104
  }
115
105
  // Wait for any remaining tasks to finish.
116
106
  await Promise.all(executingTasks);
117
- const totalTimeEnd = performance.now(); // --- TIMED BLOCK END ---
118
- // Log how long processing all assets took.
107
+ const totalTimeEnd = performance.now(); // --- TOTAL TIMED BLOCK END ---
119
108
  const totalTime = totalTimeEnd - totalTimeStart;
120
- const totalTimeStr = totalTime < 1000
109
+ // Log how long processing all assets took.
110
+ const totalTimeWithUnit = totalTime < 1000
121
111
  ? `${Math.round(totalTime)}ms`
122
112
  : `${(totalTime / 1000).toFixed(2)}s`;
123
- logger.info(styleText("green", `✓ Completed in ${totalTimeStr}.`));
113
+ logger.info(styleText("green", `✓ Completed in ${totalTimeWithUnit}.`));
124
114
  },
125
115
  },
126
116
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,IAAI,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAqB7E;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAc;IACrC,IAAI,CAAC;QACJ,iDAAiD;QACjD,yDAAyD;QACzD,eAAe,CAAC,KAAK,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CACnC,OAA4B;IAE5B,+EAA+E;IAC/E,OAAO;QACN,IAAI,EAAE,0BAA0B;QAChC,KAAK,EAAE;YACN,kBAAkB,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE;gBAC9D,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,yBAAyB,CAAC,CAAC,CAAC;gBAExE,MAAM,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,4BAA4B;gBAEtE,MAAM,oBAAoB,GAAG,uBAAuB,EAAE,CAAC;gBACvD,MAAM,EACL,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,oBAAoB,GAAG,CAAC,CAAC,EAClD,GAAG,iBAAiB,EACpB,GAAG,OAAO,CAAC;gBAEZ,IAAI,UAAgD,CAAC;gBACrD,IAAI,UAAU,GAAG,CAAC,IAAI,cAAc,CAAC,iBAAiB,CAAC,EAAE,CAAC;oBACzD,sBAAsB;oBACtB,MAAM,CAAC,IAAI,CACV,SAAS,CAAC,QAAQ,EAAE,eAAe,UAAU,kBAAkB,CAAC,CAChE,CAAC;oBAEF,UAAU,GAAG,IAAI,wBAAwB,CACxC,UAAU,EACV,iBAAiB,CACjB,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACP,sBAAsB;oBACtB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,2BAA2B,CAAC,CAAC,CAAC;gBAC/D,CAAC;gBAED,MAAM,KAAK,GAA4B,EAAE,CAAC;gBAC1C,IAAI,UAAU,GAAG,CAAC,CAAC;gBACnB,IAAI,SAAS,GAAG,CAAC,CAAC;gBAElB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;gBACzC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;gBAEjC,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;gBACxC,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAC7C,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;oBACzC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;wBAClC,MAAM,SAAS,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;wBAC1C,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;4BAChD,SAAS;wBACV,CAAC;wBAED,MAAM,iBAAiB,GAAG,eAAe,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;wBAC/D,MAAM,gBAAgB,GAAG,KAAK,YAAY,KAAK,iBAAiB,GAAG,CAAC;wBACpE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;4BACrB,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,UAAU;gCACnC,CAAC,CAAC,MAAM,UAAU,CAAC,cAAc,CAAC,SAAS,CAAC;gCAC5C,CAAC,CAAC,MAAM,cAAc,CAAC,SAAS,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC;4BAE9D,uEAAuE;4BACvE,MAAM,WAAW,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;4BAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;4BACrC,MAAM,eAAe,GACpB,UAAU,GAAG,IAAI;gCAChB,CAAC,CAAC,GAAG,UAAU,GAAG;gCAClB,CAAC,CAAC,UAAU,GAAG,OAAO;oCACrB,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;oCACvC,CAAC,CAAC,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;4BAC9C,MAAM,YAAY,GACjB,IAAI,GAAG,IAAI;gCACV,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;gCACzB,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;4BACnC,MAAM,CAAC,IAAI,CACV,gBAAgB;gCACf,SAAS,CACR,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAC/B,IAAI,WAAW,GAAG,eAAe,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,CACvE;gCACD,SAAS,CACR,KAAK,EACL,KAAK,YAAY,MAAM,EAAE,SAAS,IAAI,UAAU,GAAG,CACnD,CACF,CAAC;wBACH,CAAC,CAAC,CAAC;wBAEH,UAAU,EAAE,CAAC;oBACd,CAAC;gBACF,CAAC;gBAED,kIAAkI;gBAClI,8IAA8I;gBAC9I,MAAM,qBAAqB,GAAG,oBAAoB,GAAG,CAAC,CAAC;gBAEvD,wEAAwE;gBACxE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAiB,CAAC;gBAEhD,gHAAgH;gBAChH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBAC1B,MAAM,WAAW,GAAG,IAAI,EAAE;yBACxB,IAAI,CAAC,GAAG,EAAE;wBACV,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;oBACpC,CAAC,CAAC;yBACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;wBACZ,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;4BACrB,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;wBACrB,CAAC;wBACD,MAAM,CAAC,CAAC;oBACT,CAAC,CAAC,CAAC;oBAEJ,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;oBAEhC,IAAI,cAAc,CAAC,IAAI,IAAI,qBAAqB,EAAE,CAAC;wBAClD,8FAA8F;wBAC9F,kFAAkF;wBAClF,MAAM,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;oBACpC,CAAC;oBAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;wBACpB,MAAM,MAAM,CAAC,MAAM,CAAC;oBACrB,CAAC;gBACF,CAAC;gBAED,0CAA0C;gBAC1C,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;gBAElC,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,0BAA0B;gBAElE,2CAA2C;gBAC3C,MAAM,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC;gBAChD,MAAM,YAAY,GACjB,SAAS,GAAG,IAAI;oBACf,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI;oBAC9B,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;gBACxC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,kBAAkB,YAAY,GAAG,CAAC,CAAC,CAAC;YACpE,CAAC;SACD;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro-html-minifier-next",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Astro integration for html-minifier-next",
5
5
  "homepage": "https://github.com/jonasgeiler/astro-html-minifier-next#readme",
6
6
  "bugs": "https://github.com/jonasgeiler/astro-html-minifier-next/issues",
@@ -12,7 +12,7 @@
12
12
  "url": "git+https://github.com/jonasgeiler/astro-html-minifier-next.git"
13
13
  },
14
14
  "engines": {
15
- "node": "^20.12.0 || >=21.7.0"
15
+ "node": ">=22.13.0"
16
16
  },
17
17
  "peerDependencies": {
18
18
  "astro": "^5.0.0"
package/src/index.ts CHANGED
@@ -1,46 +1,13 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
1
2
  import { availableParallelism as getAvailableParallelism } from "node:os";
2
3
  import { relative as getRelativePath } from "node:path";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import { styleText } from "node:util";
5
6
  import type { AstroIntegration } from "astro";
6
- import type { MinifierOptions as MinifyHTMLOptions } from "html-minifier-next";
7
- import { minifyHTMLFile } from "./minify-html-file.js";
8
- import { MinifyHTMLFileWorkerPool } from "./minify-html-file-worker-pool.js";
9
-
10
- export interface HTMLMinifierOptions extends MinifyHTMLOptions {
11
- /**
12
- * Option specific to `astro-html-minifier-next` used to specify the maximum
13
- * number of worker threads to spawn when minifying files.
14
- * When set to `0`, `astro-html-minifier-next` will not create any worker
15
- * threads and will do the minification in the main thread.
16
- *
17
- * Note: If unable to do a structured clone of the `html-minifier-next`
18
- * options according to the
19
- * [HTML structured clone
20
- * algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm),
21
- * `astro-html-minifier-next` will do the minification on the main
22
- * thread, even if this option is not set to `0`.
23
- *
24
- * @default `Math.max(1, os.availableParallelism() - 1)`
25
- */
26
- maxWorkers?: number;
27
- }
28
-
29
- /**
30
- * Check if a value can be transferred to a worker.
31
- * @param {*} value
32
- * @returns {boolean}
33
- */
34
- function isTransferable(value: unknown): boolean {
35
- try {
36
- // Attempt to do a structured clone of the value.
37
- // If it succeeds, it should be transferable to a worker.
38
- structuredClone(value);
39
- return true;
40
- } catch {
41
- return false;
42
- }
43
- }
7
+ import {
8
+ type MinifierOptions as HTMLMinifierOptions,
9
+ minify as minifyHTML,
10
+ } from "html-minifier-next";
44
11
 
45
12
  /**
46
13
  * An Astro integration that minifies HTML assets using
@@ -57,32 +24,14 @@ export default function htmlMinifier(
57
24
  return {
58
25
  name: "astro-html-minifier-next",
59
26
  hooks: {
60
- "astro:build:done": async ({ logger, dir: distUrl, assets }) => {
27
+ "astro:build:done": async ({
28
+ assets,
29
+ dir: distUrl,
30
+ logger,
31
+ }): Promise<void> => {
61
32
  logger.info(styleText(["bgGreen", "black"], " minifying html assets "));
62
33
 
63
- const totalTimeStart = performance.now(); // --- TIMED BLOCK START ---
64
-
65
- const availableParallelism = getAvailableParallelism();
66
- const {
67
- maxWorkers = Math.max(1, availableParallelism - 1),
68
- ...minifyHTMLOptions
69
- } = options;
70
-
71
- let workerPool: MinifyHTMLFileWorkerPool | undefined;
72
- if (maxWorkers > 0 && isTransferable(minifyHTMLOptions)) {
73
- // TODO: Remove again.
74
- logger.info(
75
- styleText("yellow", `Using up to ${maxWorkers} worker threads.`),
76
- );
77
-
78
- workerPool = new MinifyHTMLFileWorkerPool(
79
- maxWorkers,
80
- minifyHTMLOptions,
81
- );
82
- } else {
83
- // TODO: Remove again.
84
- logger.info(styleText("yellow", `Not using worker threads.`));
85
- }
34
+ const totalTimeStart = performance.now(); // --- TOTAL TIMED BLOCK START ---
86
35
 
87
36
  const tasks: (() => Promise<void>)[] = [];
88
37
  let tasksTotal = 0;
@@ -103,11 +52,29 @@ export default function htmlMinifier(
103
52
  const relativeAssetPath = getRelativePath(distPath, assetPath);
104
53
  const logLineAssetPath = ` ${logLineArrow} /${relativeAssetPath} `;
105
54
  tasks.push(async () => {
106
- const { savings, time } = workerPool
107
- ? await workerPool.minifyHTMLFile(assetPath)
108
- : await minifyHTMLFile(assetPath, minifyHTMLOptions, signal);
55
+ const timeStart = performance.now(); // --- TIMED BLOCK START ---
56
+
57
+ const html = await readFile(assetPath, {
58
+ encoding: "utf8",
59
+ signal,
60
+ });
61
+ const minifiedHTML = await minifyHTML(html, options);
62
+
63
+ const savings =
64
+ Buffer.byteLength(html) - Buffer.byteLength(minifiedHTML);
65
+ if (savings > 0) {
66
+ // Only write the minified HTML to the file if it's smaller.
67
+ await writeFile(assetPath, minifiedHTML, {
68
+ encoding: "utf8",
69
+ signal,
70
+ });
71
+ }
72
+
73
+ const timeEnd = performance.now(); // --- TIMED BLOCK END ---
74
+ const time = timeEnd - timeStart;
109
75
 
110
- // Log a nice summary of the minification savings and the time it took.
76
+ // Log a nice summary of the minification savings and the time it
77
+ // took.
111
78
  const savingsSign = savings > 0 ? "-" : "+";
112
79
  const savingsAbs = Math.abs(savings);
113
80
  const savingsWithUnit =
@@ -137,14 +104,17 @@ export default function htmlMinifier(
137
104
  }
138
105
  }
139
106
 
140
- // We use a quadruple of the available parallelism here, even if we don't actually run the tasks in different threads or anything.
141
- // The available parallelism is a good indicator of machine capabilities, and the multiplier gives a good balance of speed and resource usage.
142
- const maxExecutingTasksSize = availableParallelism * 4;
107
+ // We use a quadruple of the available parallelism here, even if we
108
+ // don't actually run the tasks in different threads or anything. The
109
+ // available parallelism is a good indicator of machine capabilities,
110
+ // and the multiplier gives a good balance of speed and resource usage.
111
+ const maxExecutingTasksSize = getAvailableParallelism() * 4;
143
112
 
144
113
  // This holds the current batch of promises that are waiting to fulfill.
145
114
  const executingTasks = new Set<Promise<void>>();
146
115
 
147
- // Batch the tasks to avoid minifying too many files at once, which could lead to memory and performance issues.
116
+ // Batch the tasks to avoid minifying too many files at once, which
117
+ // could lead to memory and performance issues.
148
118
  for (const task of tasks) {
149
119
  const taskPromise = task()
150
120
  .then(() => {
@@ -160,8 +130,9 @@ export default function htmlMinifier(
160
130
  executingTasks.add(taskPromise);
161
131
 
162
132
  if (executingTasks.size >= maxExecutingTasksSize) {
163
- // If the amount of executing tasks reaches the limit, we wait until the one of them finishes,
164
- // and therefore gets deleted from the list, before continuing with the next task.
133
+ // If the amount of executing tasks reaches the limit, we wait
134
+ // until the one of them finishes, and therefore gets deleted from
135
+ // the list, before continuing with the next task.
165
136
  await Promise.race(executingTasks);
166
137
  }
167
138
 
@@ -173,15 +144,15 @@ export default function htmlMinifier(
173
144
  // Wait for any remaining tasks to finish.
174
145
  await Promise.all(executingTasks);
175
146
 
176
- const totalTimeEnd = performance.now(); // --- TIMED BLOCK END ---
147
+ const totalTimeEnd = performance.now(); // --- TOTAL TIMED BLOCK END ---
148
+ const totalTime = totalTimeEnd - totalTimeStart;
177
149
 
178
150
  // Log how long processing all assets took.
179
- const totalTime = totalTimeEnd - totalTimeStart;
180
- const totalTimeStr =
151
+ const totalTimeWithUnit =
181
152
  totalTime < 1000
182
153
  ? `${Math.round(totalTime)}ms`
183
154
  : `${(totalTime / 1000).toFixed(2)}s`;
184
- logger.info(styleText("green", `✓ Completed in ${totalTimeStr}.`));
155
+ logger.info(styleText("green", `✓ Completed in ${totalTimeWithUnit}.`));
185
156
  },
186
157
  },
187
158
  };
@@ -1,26 +0,0 @@
1
- import { Worker } from "node:worker_threads";
2
- import type { MinifierOptions as MinifyHTMLOptions } from "html-minifier-next";
3
- import type { MinifyHTMLFileResult } from "./minify-html-file.js";
4
- interface MinifyHTMLFileWorker extends Worker {
5
- _currentResolve?: (result: MinifyHTMLFileResult) => void;
6
- _currentReject?: (error: unknown) => void;
7
- }
8
- export type MinifyHTMLWorkerInput = string;
9
- export type MinifyHTMLWorkerOutput = MinifyHTMLFileResult | {
10
- error: unknown;
11
- };
12
- export declare class MinifyHTMLFileWorkerPool {
13
- protected maxWorkers: number;
14
- protected minifyHTMLOptions: MinifyHTMLOptions;
15
- protected workerUrl: URL;
16
- protected pool: Set<Worker>;
17
- protected idle: Worker[];
18
- protected queue: ((value: Worker) => void)[];
19
- constructor(maxWorkers: number, minifyHTMLOptions: MinifyHTMLOptions);
20
- protected getAvailableWorker(): Promise<MinifyHTMLFileWorker>;
21
- protected releaseWorker(worker: Worker): void;
22
- protected removeWorker(worker: Worker): void;
23
- minifyHTMLFile(htmlFile: string): Promise<MinifyHTMLFileResult>;
24
- }
25
- export {};
26
- //# sourceMappingURL=minify-html-file-worker-pool.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"minify-html-file-worker-pool.d.ts","sourceRoot":"","sources":["../src/minify-html-file-worker-pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,IAAI,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,UAAU,oBAAqB,SAAQ,MAAM;IAC5C,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACzD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAED,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC3C,MAAM,MAAM,sBAAsB,GAAG,oBAAoB,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/E,qBAAa,wBAAwB;IACpC,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAE/C,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC;IACzB,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC;gBAEjC,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,iBAAiB;cAUpD,kBAAkB,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAqDnE,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAc7C,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAU/B,cAAc,CAC1B,QAAQ,EAAE,MAAM,GAEd,OAAO,CAAC,oBAAoB,CAAC;CAWhC"}
@@ -1,89 +0,0 @@
1
- import { Worker } from "node:worker_threads";
2
- export class MinifyHTMLFileWorkerPool {
3
- maxWorkers;
4
- minifyHTMLOptions;
5
- workerUrl;
6
- pool;
7
- idle;
8
- queue;
9
- constructor(maxWorkers, minifyHTMLOptions) {
10
- this.maxWorkers = maxWorkers;
11
- this.minifyHTMLOptions = minifyHTMLOptions;
12
- this.workerUrl = new URL("./minify-html-file-worker.js", import.meta.url);
13
- this.pool = new Set();
14
- this.idle = [];
15
- this.queue = [];
16
- }
17
- async getAvailableWorker() {
18
- // If there is an idle worker, use it.
19
- if (this.idle.length) {
20
- const worker = this.idle.shift();
21
- if (worker !== undefined) {
22
- return worker;
23
- }
24
- }
25
- // If we can create a new worker, do so.
26
- if (this.pool.size < this.maxWorkers) {
27
- const worker = new Worker(this.workerUrl, {
28
- workerData: this.minifyHTMLOptions,
29
- });
30
- worker.on("message", async (message) => {
31
- if ("error" in message) {
32
- worker._currentReject?.(message.error);
33
- }
34
- else {
35
- worker._currentResolve?.(message);
36
- }
37
- worker._currentResolve = worker._currentReject = undefined;
38
- this.releaseWorker(worker);
39
- });
40
- worker.on("error", (error) => {
41
- worker._currentReject?.(error);
42
- worker._currentResolve = worker._currentReject = undefined;
43
- });
44
- worker.on("exit", (exitCode) => {
45
- this.removeWorker(worker);
46
- if (exitCode !== 0) {
47
- worker._currentReject?.(new Error(`Worker failed with exit code ${exitCode}.`));
48
- worker._currentResolve = worker._currentReject = undefined;
49
- }
50
- });
51
- this.pool.add(worker);
52
- return worker;
53
- }
54
- // Otherwise, wait for a worker to free up.
55
- return new Promise((resolve) => {
56
- // When a worker frees up, they will check the queue and resolve this promise.
57
- this.queue.push(resolve);
58
- });
59
- }
60
- releaseWorker(worker) {
61
- // If there is a queued request for a worker, resolve it.
62
- if (this.queue.length) {
63
- const resolve = this.queue.shift();
64
- if (resolve !== undefined) {
65
- resolve(worker);
66
- return;
67
- }
68
- }
69
- // Otherwise, keep the worker as idle.
70
- this.idle.push(worker);
71
- }
72
- removeWorker(worker) {
73
- this.pool.delete(worker);
74
- // If a worker is force stopped by the system, it might still be in the idle list.
75
- const idleIndex = this.idle.indexOf(worker);
76
- if (idleIndex !== -1) {
77
- this.idle.splice(idleIndex, 1);
78
- }
79
- }
80
- async minifyHTMLFile(htmlFile) {
81
- const worker = await this.getAvailableWorker();
82
- return new Promise((resolve, reject) => {
83
- worker._currentResolve = resolve;
84
- worker._currentReject = reject;
85
- worker.postMessage(htmlFile);
86
- });
87
- }
88
- }
89
- //# sourceMappingURL=minify-html-file-worker-pool.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"minify-html-file-worker-pool.js","sourceRoot":"","sources":["../src/minify-html-file-worker-pool.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=minify-html-file-worker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"minify-html-file-worker.d.ts","sourceRoot":"","sources":["../src/minify-html-file-worker.ts"],"names":[],"mappings":""}
@@ -1,16 +0,0 @@
1
- import { isMainThread, workerData as minifyHTMLOptions, parentPort, } from "node:worker_threads";
2
- import { minifyHTMLFile } from "./minify-html-file.js";
3
- if (isMainThread) {
4
- throw new Error("Not a worker thread.");
5
- }
6
- // biome-ignore-start lint/style/noNonNullAssertion: I can assume `parentPort` is not null.
7
- parentPort.on("message", async (htmlFile) => {
8
- try {
9
- parentPort.postMessage((await minifyHTMLFile(htmlFile, minifyHTMLOptions)));
10
- }
11
- catch (error) {
12
- parentPort.postMessage({ error });
13
- }
14
- });
15
- // biome-ignore-end lint/style/noNonNullAssertion: See start.
16
- //# sourceMappingURL=minify-html-file-worker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"minify-html-file-worker.js","sourceRoot":"","sources":["../src/minify-html-file-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACZ,UAAU,IAAI,iBAAiB,EAC/B,UAAU,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,IAAI,YAAY,EAAE,CAAC;IAClB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AACzC,CAAC;AAED,2FAA2F;AAC3F,UAAW,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,QAA+B,EAAE,EAAE;IACnE,IAAI,CAAC;QACJ,UAAW,CAAC,WAAW,CACtB,CAAC,MAAM,cAAc,CACpB,QAAQ,EACR,iBAAiB,CACjB,CAAkC,CACnC,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,UAAW,CAAC,WAAW,CAAC,EAAE,KAAK,EAAmC,CAAC,CAAC;IACrE,CAAC;AACF,CAAC,CAAC,CAAC;AACH,6DAA6D"}
@@ -1,7 +0,0 @@
1
- import { type MinifierOptions as MinifyHTMLOptions } from "html-minifier-next";
2
- export interface MinifyHTMLFileResult {
3
- savings: number;
4
- time: number;
5
- }
6
- export declare function minifyHTMLFile(htmlFile: string, minifyHTMLOptions: MinifyHTMLOptions, signal?: AbortSignal): Promise<MinifyHTMLFileResult>;
7
- //# sourceMappingURL=minify-html-file.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"minify-html-file.d.ts","sourceRoot":"","sources":["../src/minify-html-file.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,eAAe,IAAI,iBAAiB,EAEzC,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,cAAc,CACnC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,iBAAiB,EACpC,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,oBAAoB,CAAC,CAsB/B"}
@@ -1,22 +0,0 @@
1
- import { readFile, writeFile } from "node:fs/promises";
2
- import { minify as minifyHTML, } from "html-minifier-next";
3
- export async function minifyHTMLFile(htmlFile, minifyHTMLOptions, signal) {
4
- const timeStart = performance.now(); // --- TIMED BLOCK START ---
5
- const html = await readFile(htmlFile, {
6
- encoding: "utf8",
7
- signal,
8
- });
9
- const minifiedHTML = await minifyHTML(html, minifyHTMLOptions);
10
- const savings = Buffer.byteLength(html) - Buffer.byteLength(minifiedHTML);
11
- if (savings > 0) {
12
- // Only write the minified HTML to the file if it's smaller.
13
- await writeFile(htmlFile, minifiedHTML, {
14
- encoding: "utf8",
15
- signal,
16
- });
17
- }
18
- const timeEnd = performance.now(); // --- TIMED BLOCK END ---
19
- const time = timeEnd - timeStart;
20
- return { savings, time };
21
- }
22
- //# sourceMappingURL=minify-html-file.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"minify-html-file.js","sourceRoot":"","sources":["../src/minify-html-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAEN,MAAM,IAAI,UAAU,GACpB,MAAM,oBAAoB,CAAC;AAO5B,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,QAAgB,EAChB,iBAAoC,EACpC,MAAoB;IAEpB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,4BAA4B;IAEjE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE;QACrC,QAAQ,EAAE,MAAM;QAChB,MAAM;KACN,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;IAE/D,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAC1E,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QACjB,4DAA4D;QAC5D,MAAM,SAAS,CAAC,QAAQ,EAAE,YAAY,EAAE;YACvC,QAAQ,EAAE,MAAM;YAChB,MAAM;SACN,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,0BAA0B;IAE7D,MAAM,IAAI,GAAG,OAAO,GAAG,SAAS,CAAC;IACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC"}
@@ -1,123 +0,0 @@
1
- import { Worker } from "node:worker_threads";
2
- import type { MinifierOptions as MinifyHTMLOptions } from "html-minifier-next";
3
- import type { MinifyHTMLFileResult } from "./minify-html-file.js";
4
-
5
- interface MinifyHTMLFileWorker extends Worker {
6
- _currentResolve?: (result: MinifyHTMLFileResult) => void;
7
- _currentReject?: (error: unknown) => void;
8
- }
9
-
10
- export type MinifyHTMLWorkerInput = string;
11
- export type MinifyHTMLWorkerOutput = MinifyHTMLFileResult | { error: unknown };
12
-
13
- export class MinifyHTMLFileWorkerPool {
14
- protected maxWorkers: number;
15
- protected minifyHTMLOptions: MinifyHTMLOptions;
16
-
17
- protected workerUrl: URL;
18
- protected pool: Set<Worker>;
19
- protected idle: Worker[];
20
- protected queue: ((value: Worker) => void)[];
21
-
22
- constructor(maxWorkers: number, minifyHTMLOptions: MinifyHTMLOptions) {
23
- this.maxWorkers = maxWorkers;
24
- this.minifyHTMLOptions = minifyHTMLOptions;
25
-
26
- this.workerUrl = new URL("./minify-html-file-worker.js", import.meta.url);
27
- this.pool = new Set();
28
- this.idle = [];
29
- this.queue = [];
30
- }
31
-
32
- protected async getAvailableWorker(): Promise<MinifyHTMLFileWorker> {
33
- // If there is an idle worker, use it.
34
- if (this.idle.length) {
35
- const worker = this.idle.shift();
36
- if (worker !== undefined) {
37
- return worker;
38
- }
39
- }
40
-
41
- // If we can create a new worker, do so.
42
- if (this.pool.size < this.maxWorkers) {
43
- const worker = new Worker(this.workerUrl, {
44
- workerData: this.minifyHTMLOptions,
45
- }) as MinifyHTMLFileWorker;
46
-
47
- worker.on("message", async (message: MinifyHTMLWorkerOutput) => {
48
- if ("error" in message) {
49
- worker._currentReject?.(message.error);
50
- } else {
51
- worker._currentResolve?.(message);
52
- }
53
- worker._currentResolve = worker._currentReject = undefined;
54
-
55
- this.releaseWorker(worker);
56
- });
57
-
58
- worker.on("error", (error) => {
59
- worker._currentReject?.(error);
60
- worker._currentResolve = worker._currentReject = undefined;
61
- });
62
-
63
- worker.on("exit", (exitCode) => {
64
- this.removeWorker(worker);
65
-
66
- if (exitCode !== 0) {
67
- worker._currentReject?.(
68
- new Error(`Worker failed with exit code ${exitCode}.`),
69
- );
70
- worker._currentResolve = worker._currentReject = undefined;
71
- }
72
- });
73
-
74
- this.pool.add(worker);
75
- return worker;
76
- }
77
-
78
- // Otherwise, wait for a worker to free up.
79
- return new Promise<Worker>((resolve) => {
80
- // When a worker frees up, they will check the queue and resolve this promise.
81
- this.queue.push(resolve);
82
- });
83
- }
84
-
85
- protected releaseWorker(worker: Worker): void {
86
- // If there is a queued request for a worker, resolve it.
87
- if (this.queue.length) {
88
- const resolve = this.queue.shift();
89
- if (resolve !== undefined) {
90
- resolve(worker);
91
- return;
92
- }
93
- }
94
-
95
- // Otherwise, keep the worker as idle.
96
- this.idle.push(worker);
97
- }
98
-
99
- protected removeWorker(worker: Worker): void {
100
- this.pool.delete(worker);
101
-
102
- // If a worker is force stopped by the system, it might still be in the idle list.
103
- const idleIndex = this.idle.indexOf(worker);
104
- if (idleIndex !== -1) {
105
- this.idle.splice(idleIndex, 1);
106
- }
107
- }
108
-
109
- public async minifyHTMLFile(
110
- htmlFile: string,
111
- // TODO: Signal?
112
- ): Promise<MinifyHTMLFileResult> {
113
- const worker = await this.getAvailableWorker();
114
-
115
- return new Promise<MinifyHTMLFileResult>((resolve, reject) => {
116
- worker._currentResolve = resolve;
117
- worker._currentReject = reject;
118
- worker.postMessage(htmlFile satisfies MinifyHTMLWorkerInput);
119
- });
120
- }
121
-
122
- // TODO: Destroy function
123
- }
@@ -1,29 +0,0 @@
1
- import {
2
- isMainThread,
3
- workerData as minifyHTMLOptions,
4
- parentPort,
5
- } from "node:worker_threads";
6
- import { minifyHTMLFile } from "./minify-html-file.js";
7
- import type {
8
- MinifyHTMLWorkerInput,
9
- MinifyHTMLWorkerOutput,
10
- } from "./minify-html-file-worker-pool.js";
11
-
12
- if (isMainThread) {
13
- throw new Error("Not a worker thread.");
14
- }
15
-
16
- // biome-ignore-start lint/style/noNonNullAssertion: I can assume `parentPort` is not null.
17
- parentPort!.on("message", async (htmlFile: MinifyHTMLWorkerInput) => {
18
- try {
19
- parentPort!.postMessage(
20
- (await minifyHTMLFile(
21
- htmlFile,
22
- minifyHTMLOptions,
23
- )) satisfies MinifyHTMLWorkerOutput,
24
- );
25
- } catch (error) {
26
- parentPort!.postMessage({ error } satisfies MinifyHTMLWorkerOutput);
27
- }
28
- });
29
- // biome-ignore-end lint/style/noNonNullAssertion: See start.
@@ -1,38 +0,0 @@
1
- import { readFile, writeFile } from "node:fs/promises";
2
- import {
3
- type MinifierOptions as MinifyHTMLOptions,
4
- minify as minifyHTML,
5
- } from "html-minifier-next";
6
-
7
- export interface MinifyHTMLFileResult {
8
- savings: number;
9
- time: number;
10
- }
11
-
12
- export async function minifyHTMLFile(
13
- htmlFile: string,
14
- minifyHTMLOptions: MinifyHTMLOptions,
15
- signal?: AbortSignal,
16
- ): Promise<MinifyHTMLFileResult> {
17
- const timeStart = performance.now(); // --- TIMED BLOCK START ---
18
-
19
- const html = await readFile(htmlFile, {
20
- encoding: "utf8",
21
- signal,
22
- });
23
- const minifiedHTML = await minifyHTML(html, minifyHTMLOptions);
24
-
25
- const savings = Buffer.byteLength(html) - Buffer.byteLength(minifiedHTML);
26
- if (savings > 0) {
27
- // Only write the minified HTML to the file if it's smaller.
28
- await writeFile(htmlFile, minifiedHTML, {
29
- encoding: "utf8",
30
- signal,
31
- });
32
- }
33
-
34
- const timeEnd = performance.now(); // --- TIMED BLOCK END ---
35
-
36
- const time = timeEnd - timeStart;
37
- return { savings, time };
38
- }