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 +1 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -46
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +47 -76
- package/dist/minify-html-file-worker-pool.d.ts +0 -26
- package/dist/minify-html-file-worker-pool.d.ts.map +0 -1
- package/dist/minify-html-file-worker-pool.js +0 -89
- package/dist/minify-html-file-worker-pool.js.map +0 -1
- package/dist/minify-html-file-worker.d.ts +0 -2
- package/dist/minify-html-file-worker.d.ts.map +0 -1
- package/dist/minify-html-file-worker.js +0 -16
- package/dist/minify-html-file-worker.js.map +0 -1
- package/dist/minify-html-file.d.ts +0 -7
- package/dist/minify-html-file.d.ts.map +0 -1
- package/dist/minify-html-file.js +0 -22
- package/dist/minify-html-file.js.map +0 -1
- package/src/minify-html-file-worker-pool.ts +0 -123
- package/src/minify-html-file-worker.ts +0 -29
- package/src/minify-html-file.ts +0 -38
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
import type { AstroIntegration } from "astro";
|
|
2
|
-
import type
|
|
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).
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
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 {
|
|
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 ({
|
|
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
|
|
68
|
-
|
|
69
|
-
:
|
|
70
|
-
|
|
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
|
|
89
|
-
//
|
|
90
|
-
|
|
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
|
|
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
|
|
108
|
-
//
|
|
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
|
-
|
|
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 ${
|
|
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;
|
|
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.
|
|
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": "
|
|
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
|
|
7
|
-
|
|
8
|
-
|
|
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 ({
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
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
|
|
141
|
-
//
|
|
142
|
-
|
|
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
|
|
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
|
|
164
|
-
//
|
|
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
|
|
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 ${
|
|
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 +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"}
|
package/dist/minify-html-file.js
DELETED
|
@@ -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.
|
package/src/minify-html-file.ts
DELETED
|
@@ -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
|
-
}
|