html-minifier-next 7.2.0 → 7.4.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 +49 -24
- package/cli.js +40 -1
- package/dist/types/htmlminifier.d.ts +77 -20
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/htmlparser.d.ts +11 -11
- package/dist/types/htmlparser.d.ts.map +1 -1
- package/dist/types/lib/attributes.d.ts +36 -38
- package/dist/types/lib/attributes.d.ts.map +1 -1
- package/dist/types/lib/constants.d.ts +97 -100
- package/dist/types/lib/constants.d.ts.map +1 -1
- package/dist/types/lib/content.d.ts +7 -6
- package/dist/types/lib/content.d.ts.map +1 -1
- package/dist/types/lib/elements.d.ts +13 -18
- package/dist/types/lib/elements.d.ts.map +1 -1
- package/dist/types/lib/option-definitions.d.ts +202 -299
- package/dist/types/lib/option-definitions.d.ts.map +1 -1
- package/dist/types/lib/options.d.ts +7 -14
- package/dist/types/lib/options.d.ts.map +1 -1
- package/dist/types/lib/urls.d.ts +10 -2
- package/dist/types/lib/urls.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts +30 -10
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/lib/whitespace.d.ts +7 -6
- package/dist/types/lib/whitespace.d.ts.map +1 -1
- package/dist/types/presets.d.ts +39 -37
- package/dist/types/presets.d.ts.map +1 -1
- package/dist/types/tokenchain.d.ts +13 -11
- package/dist/types/tokenchain.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/htmlminifier.js +34 -1
- package/src/lib/options.js +43 -31
- package/src/lib/urls.js +1 -1
- package/src/lib/utils.js +14 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,iBAAS,eAAe,CAAC,GAAG,EAHjB,OAGiB,GAFf,MAAM,CAYlB;AAID,cAAM,GAAG;IAEA,KAAK;IACL,IAAI;IACJ,IAAI;IACT,mCAAmC;IAC9B,GAAG,EADG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAJjC,YAAY,KAAK,SAAM,EAMtB;IACD,0BAA0B;IAC1B,GAAG,CAAC,GAAG,EADK,MACL,WAUN;IACD;;;OAGG;IACH,GAAG,CAAC,GAAG,EAHI,MAGJ,EAAE,KAAK,EAFH,OAEG,QAOb;IACD,0BAA0B;IAC1B,MAAM,CAAC,GAAG,EADE,MACF,QAA2B;IACrC,6EAA6E;IAC7E,KAAK,IADS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAGxE;CACF;AAKD,QAAA,MAAM,oBAAoB,QAAc,CAAC;AAIzC,0BAA0B;AAC1B,iBAAS,WAAW,CAAC,GAAG,EADZ,MACY,UAOvB;AAID,4BAA4B;AAC5B,iBAAS,QAAQ,CAAC,KAAK,EADX,MACW,UAMtB;AAID,4BAA4B;AAC5B,iBAAS,QAAQ,CAAC,KAAK,EADX,MACW,UAEtB;AAED;;;GAGG;AACH,iBAAS,UAAU,CAAC,KAAK,EAHd,OAGc,GAFZ,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,CAIrC;AAED,4BAA4B;AAC5B,iBAAS,SAAS,CAAC,KAAK,EADZ,MACY,UAEvB;AAID;;;;;;GAMG;AACH,iBAAe,YAAY,CAAC,GAAG,EALpB,MAKoB,EAAE,KAAK,EAJ3B,MAI2B,EAAE,OAAO,UAAA,GAFlC,OAAO,CAAC,MAAM,CAAC,CAc3B;AAID,qCAAqC;AACrC,iBAAS,WAAW,CAAC,KAAK,EADd,MAAM,GAAG,MACK,sBAUzB;AAID,OAAO,EAAE,eAAe,EAAE,CAAC;AAC3B,OAAO,EAAE,GAAG,EAAE,CAAC;AACf,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @param {string} str */
|
|
2
|
-
|
|
2
|
+
declare const trimWhitespace: (str: string) => string;
|
|
3
3
|
/** @param {string} str */
|
|
4
|
-
|
|
4
|
+
declare function collapseWhitespaceAll(str: string): string;
|
|
5
5
|
/**
|
|
6
6
|
* @param {string} str
|
|
7
7
|
* @param {{preserveLineBreaks?: boolean | undefined, conservativeCollapse?: boolean | undefined}} options
|
|
@@ -9,7 +9,7 @@ export function collapseWhitespaceAll(str: string): string;
|
|
|
9
9
|
* @param {boolean} trimRight
|
|
10
10
|
* @param {boolean} [collapseAll]
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
declare function collapseWhitespace(str: string, options: {
|
|
13
13
|
preserveLineBreaks?: boolean | undefined;
|
|
14
14
|
conservativeCollapse?: boolean | undefined;
|
|
15
15
|
}, trimLeft: boolean, trimRight: boolean, collapseAll?: boolean): string;
|
|
@@ -23,7 +23,7 @@ export function collapseWhitespace(str: string, options: {
|
|
|
23
23
|
* @param {Set<string>} inlineElements
|
|
24
24
|
* @param {Set<string>} inlineTextSet
|
|
25
25
|
*/
|
|
26
|
-
|
|
26
|
+
declare function collapseWhitespaceSmart(str: string, prevTag: string, nextTag: string, prevAttrs: Array<{
|
|
27
27
|
name: string;
|
|
28
28
|
value?: string;
|
|
29
29
|
}>, nextAttrs: Array<{
|
|
@@ -35,7 +35,8 @@ export function collapseWhitespaceSmart(str: string, prevTag: string, nextTag: s
|
|
|
35
35
|
collapseInlineTagWhitespace?: boolean;
|
|
36
36
|
}, inlineElements: Set<string>, inlineTextSet: Set<string>): string;
|
|
37
37
|
/** @param {string} tag */
|
|
38
|
-
|
|
38
|
+
declare function canCollapseWhitespace(tag: string): boolean;
|
|
39
39
|
/** @param {string} tag */
|
|
40
|
-
|
|
40
|
+
declare function canTrimWhitespace(tag: string): boolean;
|
|
41
|
+
export { trimWhitespace, collapseWhitespaceAll, collapseWhitespace, collapseWhitespaceSmart, canCollapseWhitespace, canTrimWhitespace };
|
|
41
42
|
//# sourceMappingURL=whitespace.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"AAeA,0BAA0B;AAC1B,
|
|
1
|
+
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"AAeA,0BAA0B;AAC1B,QAAA,MAAM,cAAc,QADR,MAAM,WAQjB,CAAC;AAIF,0BAA0B;AAC1B,iBAAS,qBAAqB,CAAC,GAAG,EADtB,MACsB,UAgBjC;AAID;;;;;;GAMG;AACH,iBAAS,kBAAkB,CAAC,GAAG,EANpB,MAMoB,EAAE,OAAO,EAL7B;IAAC,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAKxD,EAAE,QAAQ,EAJvC,OAIuC,EAAE,SAAS,EAHlD,OAGkD,EAAE,WAAW,AAFvE,CAA8B,EAAtB,OAEuE,UAqFjF;AAID;;;;;;;;;GASG;AACH,iBAAS,uBAAuB,CAAC,GAAG,EATzB,MASyB,EAAE,OAAO,EARlC,MAQkC,EAAE,OAAO,EAP3C,MAO2C,EAAE,SAAS,EANtD,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAMkB,EAAE,SAAS,EALjE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAK6B,EAAE,OAAO,EAJ1E;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAAC,2BAA2B,CAAC,EAAE,OAAO,CAAA;CAI1B,EAAE,cAAc,EAH1F,GAAG,CAAC,MAAM,CAGgF,EAAE,aAAa,EAFzG,GAAG,CAAC,MAAM,CAE+F,UAwEnH;AAOD,0BAA0B;AAC1B,iBAAS,qBAAqB,CAAC,GAAG,EADtB,MACsB,WAEjC;AAED,0BAA0B;AAC1B,iBAAS,iBAAiB,CAAC,GAAG,EADlB,MACkB,WAE7B;AAID,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,EAClB,CAAC"}
|
package/dist/types/presets.d.ts
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preset configurations
|
|
3
|
+
*
|
|
4
|
+
* Presets provide curated option sets for common use cases:
|
|
5
|
+
* - `conservative`: Safe minification suitable for most projects
|
|
6
|
+
* - `comprehensive`: Aggressive minification for maximum file size reduction
|
|
7
|
+
*/
|
|
8
|
+
export declare const presets: {
|
|
9
|
+
conservative: {
|
|
10
|
+
caseSensitive: boolean;
|
|
11
|
+
collapseBooleanAttributes: boolean;
|
|
12
|
+
collapseWhitespace: boolean;
|
|
13
|
+
conservativeCollapse: boolean;
|
|
14
|
+
preserveLineBreaks: boolean;
|
|
15
|
+
removeComments: boolean;
|
|
16
|
+
removeDefaultTypeAttributes: boolean;
|
|
17
|
+
useShortDoctype: boolean;
|
|
18
|
+
};
|
|
19
|
+
comprehensive: {
|
|
20
|
+
collapseAttributeWhitespace: boolean;
|
|
21
|
+
collapseBooleanAttributes: boolean;
|
|
22
|
+
collapseWhitespace: boolean;
|
|
23
|
+
decodeEntities: boolean;
|
|
24
|
+
mergeScripts: boolean;
|
|
25
|
+
minifyCSS: boolean;
|
|
26
|
+
minifyJS: boolean;
|
|
27
|
+
minifySVG: boolean;
|
|
28
|
+
minifyURLs: boolean;
|
|
29
|
+
removeAttributeQuotes: boolean;
|
|
30
|
+
removeComments: boolean;
|
|
31
|
+
removeDefaultTypeAttributes: boolean;
|
|
32
|
+
removeEmptyAttributes: boolean;
|
|
33
|
+
removeOptionalTags: boolean;
|
|
34
|
+
removeRedundantAttributes: boolean;
|
|
35
|
+
useShortDoctype: boolean;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
1
38
|
/**
|
|
2
39
|
* Get preset configuration by name
|
|
3
40
|
* @param {string} name - Preset name (“conservative” or “comprehensive”)
|
|
4
41
|
* @returns {object|null} Preset options object or null if not found
|
|
5
42
|
*/
|
|
6
|
-
export function getPreset(name: string): object | null;
|
|
43
|
+
export declare function getPreset(name: string): object | null;
|
|
7
44
|
/**
|
|
8
45
|
* Get list of available preset names
|
|
9
46
|
* @returns {string[]} Array of preset names
|
|
10
47
|
*/
|
|
11
|
-
export function getPresetNames(): string[];
|
|
12
|
-
export namespace presets {
|
|
13
|
-
namespace conservative {
|
|
14
|
-
let caseSensitive: boolean;
|
|
15
|
-
let collapseBooleanAttributes: boolean;
|
|
16
|
-
let collapseWhitespace: boolean;
|
|
17
|
-
let conservativeCollapse: boolean;
|
|
18
|
-
let preserveLineBreaks: boolean;
|
|
19
|
-
let removeComments: boolean;
|
|
20
|
-
let removeDefaultTypeAttributes: boolean;
|
|
21
|
-
let useShortDoctype: boolean;
|
|
22
|
-
}
|
|
23
|
-
namespace comprehensive {
|
|
24
|
-
export let collapseAttributeWhitespace: boolean;
|
|
25
|
-
let collapseBooleanAttributes_1: boolean;
|
|
26
|
-
export { collapseBooleanAttributes_1 as collapseBooleanAttributes };
|
|
27
|
-
let collapseWhitespace_1: boolean;
|
|
28
|
-
export { collapseWhitespace_1 as collapseWhitespace };
|
|
29
|
-
export let decodeEntities: boolean;
|
|
30
|
-
export let mergeScripts: boolean;
|
|
31
|
-
export let minifyCSS: boolean;
|
|
32
|
-
export let minifyJS: boolean;
|
|
33
|
-
export let minifySVG: boolean;
|
|
34
|
-
export let minifyURLs: boolean;
|
|
35
|
-
export let removeAttributeQuotes: boolean;
|
|
36
|
-
let removeComments_1: boolean;
|
|
37
|
-
export { removeComments_1 as removeComments };
|
|
38
|
-
let removeDefaultTypeAttributes_1: boolean;
|
|
39
|
-
export { removeDefaultTypeAttributes_1 as removeDefaultTypeAttributes };
|
|
40
|
-
export let removeEmptyAttributes: boolean;
|
|
41
|
-
export let removeOptionalTags: boolean;
|
|
42
|
-
export let removeRedundantAttributes: boolean;
|
|
43
|
-
let useShortDoctype_1: boolean;
|
|
44
|
-
export { useShortDoctype_1 as useShortDoctype };
|
|
45
|
-
}
|
|
46
|
-
}
|
|
48
|
+
export declare function getPresetNames(): string[];
|
|
47
49
|
//# sourceMappingURL=presets.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/presets.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/presets.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,OAAO;IAClB,YAAY;QACV,aAAa;QACb,yBAAyB;QACzB,kBAAkB;QAClB,oBAAoB;QACpB,kBAAkB;QAClB,cAAc;QACd,2BAA2B;QAC3B,eAAe;;IAEjB,aAAa;QACX,2BAA2B;QAC3B,yBAAyB;QACzB,kBAAkB;QAClB,cAAc;QACd,YAAY;QACZ,SAAS;QACT,QAAQ;QACR,SAAS;QACT,UAAU;QACV,qBAAqB;QACrB,cAAc;QACd,2BAA2B;QAC3B,qBAAqB;QACrB,kBAAkB;QAClB,yBAAyB;QACzB,eAAe;;CAElB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAHnB,MAGmB,GAFjB,MAAM,GAAC,IAAI,CAMvB;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAFjB,MAAM,EAAE,CAIpB"}
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
export default TokenChain;
|
|
2
|
-
declare class TokenChain {
|
|
3
|
-
/** @type {Map<string, {arrays: string[][], processed: number}>} */
|
|
4
|
-
map: Map<string, {
|
|
5
|
-
arrays: string[][];
|
|
6
|
-
processed: number;
|
|
7
|
-
}>;
|
|
8
|
-
/** @param {string[]} tokens */
|
|
9
|
-
add(tokens: string[]): void;
|
|
10
|
-
createSorter(): Sorter;
|
|
11
|
-
}
|
|
12
1
|
declare class Sorter {
|
|
13
2
|
/** @type {string[]} */
|
|
14
3
|
keys: string[];
|
|
15
4
|
/** @type {Map<string, Sorter>} */
|
|
16
5
|
sorterMap: Map<string, Sorter>;
|
|
6
|
+
constructor();
|
|
17
7
|
/**
|
|
18
8
|
* @param {string[]} tokens
|
|
19
9
|
* @param {number} fromIndex
|
|
@@ -21,4 +11,16 @@ declare class Sorter {
|
|
|
21
11
|
*/
|
|
22
12
|
sort(tokens: string[], fromIndex?: number): string[];
|
|
23
13
|
}
|
|
14
|
+
declare class TokenChain {
|
|
15
|
+
/** @type {Map<string, {arrays: string[][], processed: number}>} */
|
|
16
|
+
map: Map<string, {
|
|
17
|
+
arrays: string[][];
|
|
18
|
+
processed: number;
|
|
19
|
+
}>;
|
|
20
|
+
constructor();
|
|
21
|
+
/** @param {string[]} tokens */
|
|
22
|
+
add(tokens: string[]): void;
|
|
23
|
+
createSorter(): Sorter;
|
|
24
|
+
}
|
|
25
|
+
export default TokenChain;
|
|
24
26
|
//# sourceMappingURL=tokenchain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenchain.d.ts","sourceRoot":"","sources":["../../src/tokenchain.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"tokenchain.d.ts","sourceRoot":"","sources":["../../src/tokenchain.js"],"names":[],"mappings":"AAAA,cAAM,MAAM;IAER,uBAAuB;IAClB,IAAI,EADE,MAAM,EAAE;IAEnB,kCAAkC;IAC7B,SAAS,EADH,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAHhC,cAKC;IAED;;;;OAIG;IACH,IAAI,CAAC,MAAM,EAJA,MAAM,EAIN,EAAE,SAAS,GAHX,MAGe,GAFb,MAAM,EAAE,CAiCpB;CACF;AAED,cAAM,UAAU;IAEZ,mEAAmE;IAC9D,GAAG,EADG,GAAG,CAAC,MAAM,EAAE;QAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAC;IADjE,cAGC;IAED,+BAA+B;IAC/B,GAAG,CAAC,MAAM,EADE,MAAM,EACR,QAST;IAED,YAAY,WA+CX;CACF;eAEc,UAAU"}
|
package/package.json
CHANGED
|
@@ -9,21 +9,21 @@
|
|
|
9
9
|
"commander": "^15.0.0",
|
|
10
10
|
"entities": "^8.0.0",
|
|
11
11
|
"lightningcss": "^1.32.0",
|
|
12
|
-
"svgo": "^4.0.
|
|
13
|
-
"terser": "^5.
|
|
12
|
+
"svgo": "^4.0.2",
|
|
13
|
+
"terser": "^5.49.0"
|
|
14
14
|
},
|
|
15
15
|
"description": "Super-configurable and well-tested web page minifier (enhanced successor to HTML Minifier)",
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@commitlint/cli": "^21.2.
|
|
17
|
+
"@commitlint/cli": "^21.2.1",
|
|
18
18
|
"@eslint/js": "^10.0.1",
|
|
19
|
-
"@swc/core": "^1.15.
|
|
20
|
-
"@types/node": "^26.1.
|
|
21
|
-
"eslint": "^10.
|
|
22
|
-
"typescript": "^
|
|
23
|
-
"vite": "^8.
|
|
19
|
+
"@swc/core": "^1.15.43",
|
|
20
|
+
"@types/node": "^26.1.1",
|
|
21
|
+
"eslint": "^10.7.0",
|
|
22
|
+
"typescript": "^7.0.2",
|
|
23
|
+
"vite": "^8.1.5"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": ">=22"
|
|
26
|
+
"node": ">=22.13"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"cli.js",
|
|
37
|
+
"dist/types",
|
|
37
38
|
"html-minifier-next.schema.json",
|
|
38
|
-
"
|
|
39
|
-
"src/"
|
|
39
|
+
"src"
|
|
40
40
|
],
|
|
41
41
|
"funding": "https://github.com/j9t/html-minifier-next?sponsor=1",
|
|
42
42
|
"homepage": "https://j9t.github.io/html-minifier-next/",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"test:watch": "node --test --watch tests/*.spec.js"
|
|
94
94
|
},
|
|
95
95
|
"type": "module",
|
|
96
|
-
"version": "7.
|
|
96
|
+
"version": "7.4.0"
|
|
97
97
|
}
|
package/src/htmlminifier.js
CHANGED
|
@@ -529,6 +529,22 @@ let jsMinifyCache = null;
|
|
|
529
529
|
/** @type {LRU | null} */
|
|
530
530
|
let svgMinifyCache = null;
|
|
531
531
|
|
|
532
|
+
/**
|
|
533
|
+
* @typedef {Object} CacheStats
|
|
534
|
+
* Hit/miss statistics and current occupancy for a single minification cache.
|
|
535
|
+
*
|
|
536
|
+
* @prop {number} gets Number of lookups attempted against the cache.
|
|
537
|
+
* @prop {number} hits Number of lookups that found a cached entry.
|
|
538
|
+
* @prop {number} size Number of entries currently held in the cache.
|
|
539
|
+
* @prop {number} limit Maximum number of entries the cache can hold.
|
|
540
|
+
*/
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* @param {LRU | null} cache
|
|
544
|
+
* @returns {CacheStats}
|
|
545
|
+
*/
|
|
546
|
+
const cacheStatsOrEmpty = (cache) => cache ? cache.stats() : { gets: 0, hits: 0, size: 0, limit: 0 };
|
|
547
|
+
|
|
532
548
|
// Pre-compiled patterns for script merging (avoid repeated allocation in hot path)
|
|
533
549
|
const RE_SCRIPT_ATTRS = /([^\s=]+)(?:=(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g;
|
|
534
550
|
const RE_SCRIPT_OPEN = /<script(?=[\s>])/gi; // Finds tag start; use `findTagEnd()` for the actual closing `>`
|
|
@@ -1893,6 +1909,23 @@ function initCaches(options) {
|
|
|
1893
1909
|
return { cssMinifyCache, jsMinifyCache, svgMinifyCache };
|
|
1894
1910
|
}
|
|
1895
1911
|
|
|
1912
|
+
/**
|
|
1913
|
+
* Get hit/miss statistics for the CSS, JavaScript, and SVG minification caches.
|
|
1914
|
+
*
|
|
1915
|
+
* Each cache is created lazily on the first `minify()` call (see `initCaches`); before
|
|
1916
|
+
* that first call, or for a cache never exercised (e.g., `minifyCSS` disabled), its
|
|
1917
|
+
* entry reports all-zero stats.
|
|
1918
|
+
*
|
|
1919
|
+
* @returns {{ css: CacheStats, js: CacheStats, svg: CacheStats }}
|
|
1920
|
+
*/
|
|
1921
|
+
export function getCacheStats() {
|
|
1922
|
+
return {
|
|
1923
|
+
css: cacheStatsOrEmpty(cssMinifyCache),
|
|
1924
|
+
js: cacheStatsOrEmpty(jsMinifyCache),
|
|
1925
|
+
svg: cacheStatsOrEmpty(svgMinifyCache)
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1896
1929
|
/**
|
|
1897
1930
|
* @param {string} value
|
|
1898
1931
|
* @param {MinifierOptions} [options]
|
|
@@ -1926,4 +1959,4 @@ export const minify = async function (value, options) {
|
|
|
1926
1959
|
|
|
1927
1960
|
export { presets, getPreset, getPresetNames };
|
|
1928
1961
|
|
|
1929
|
-
export default { minify, presets, getPreset, getPresetNames };
|
|
1962
|
+
export default { minify, presets, getPreset, getPresetNames, getCacheStats };
|
package/src/lib/options.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createUrlMinifier } from './urls.js';
|
|
2
|
-
import { LRU, stableStringify, hashContent, identity, lowercase, replaceAsync, parseRegExp } from './utils.js';
|
|
2
|
+
import { LRU, MAX_CACHE_ENTRY_SIZE, stableStringify, hashContent, identity, lowercase, replaceAsync, parseRegExp } from './utils.js';
|
|
3
3
|
import { RE_TRAILING_SEMICOLON } from './constants.js';
|
|
4
4
|
import { canCollapseWhitespace, canTrimWhitespace } from './whitespace.js';
|
|
5
5
|
import { wrapCSS, unwrapCSS } from './content.js';
|
|
@@ -183,15 +183,20 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
183
183
|
// Cache key: Content + type + options signature; large inputs are hashed to avoid huge Map keys
|
|
184
184
|
const inputCSS = wrapCSS(text, type);
|
|
185
185
|
const cssSig = stableStringify({ type, opts: lightningCssOptions, cont: !!options.continueOnMinifyError });
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
const isCacheable = inputCSS.length <= MAX_CACHE_ENTRY_SIZE;
|
|
187
|
+
const cssKey = isCacheable
|
|
188
|
+
? (inputCSS.length > 2048
|
|
189
|
+
? (hashContent(inputCSS) + '|' + type + '|' + cssSig)
|
|
190
|
+
: (inputCSS + '|' + type + '|' + cssSig))
|
|
191
|
+
: undefined;
|
|
189
192
|
|
|
190
193
|
try {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
if (cssKey !== undefined) {
|
|
195
|
+
const cached = /** @type {string | Promise<string> | undefined} */ (cssCache.get(cssKey));
|
|
196
|
+
if (cached !== undefined) {
|
|
197
|
+
// Support both resolved values and in-flight promises
|
|
198
|
+
return await cached;
|
|
199
|
+
}
|
|
195
200
|
}
|
|
196
201
|
|
|
197
202
|
// In-flight promise caching: Prevent duplicate concurrent minifications
|
|
@@ -224,12 +229,12 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
224
229
|
return (text.trim() && !outputCSS.trim() && (looksLikeTemplate || hasUID)) ? text : outputCSS;
|
|
225
230
|
})();
|
|
226
231
|
|
|
227
|
-
cssCache.set(cssKey, inFlight);
|
|
232
|
+
if (cssKey !== undefined) cssCache.set(cssKey, inFlight);
|
|
228
233
|
const resolved = await inFlight;
|
|
229
|
-
cssCache.set(cssKey, resolved);
|
|
234
|
+
if (cssKey !== undefined) cssCache.set(cssKey, resolved);
|
|
230
235
|
return resolved;
|
|
231
236
|
} catch (err) {
|
|
232
|
-
cssCache.delete(cssKey);
|
|
237
|
+
if (cssKey !== undefined) cssCache.delete(cssKey);
|
|
233
238
|
if (!options.continueOnMinifyError) {
|
|
234
239
|
throw err;
|
|
235
240
|
}
|
|
@@ -293,19 +298,22 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
293
298
|
// Hybrid strategy: Always use Terser for inline JS (needs bare returns support)
|
|
294
299
|
// Use user’s chosen engine for script blocks
|
|
295
300
|
const useEngine = inline ? 'terser' : engine;
|
|
296
|
-
|
|
297
301
|
let jsKey;
|
|
302
|
+
const isCacheable = code.length <= MAX_CACHE_ENTRY_SIZE;
|
|
303
|
+
|
|
298
304
|
try {
|
|
299
305
|
// Select pre-computed signature based on engine
|
|
300
306
|
const optsSig = useEngine === 'terser' ? terserSig : swcSig;
|
|
301
307
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
308
|
+
if (isCacheable) {
|
|
309
|
+
// For large inputs, hash the full content to avoid storing huge strings as Map keys
|
|
310
|
+
jsKey = (code.length > 2048 ? (hashContent(code) + '|') : (code + '|'))
|
|
311
|
+
+ (inline ? '1' : '0') + '|' + (isModule ? 'm' : '') + '|' + useEngine + '|' + optsSig;
|
|
305
312
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
313
|
+
const cached = /** @type {string | Promise<string> | undefined} */ (jsCache.get(jsKey));
|
|
314
|
+
if (cached !== undefined) {
|
|
315
|
+
return await cached;
|
|
316
|
+
}
|
|
309
317
|
}
|
|
310
318
|
|
|
311
319
|
const inFlight = (async () => {
|
|
@@ -337,12 +345,12 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
337
345
|
throw new Error(`Unknown JS minifier engine: ${useEngine}`);
|
|
338
346
|
})();
|
|
339
347
|
|
|
340
|
-
jsCache.set(jsKey, inFlight);
|
|
348
|
+
if (jsKey !== undefined) jsCache.set(jsKey, inFlight);
|
|
341
349
|
const resolved = await inFlight;
|
|
342
|
-
jsCache.set(jsKey, resolved);
|
|
350
|
+
if (jsKey !== undefined) jsCache.set(jsKey, resolved);
|
|
343
351
|
return resolved;
|
|
344
352
|
} catch (err) {
|
|
345
|
-
if (jsKey) jsCache.delete(jsKey);
|
|
353
|
+
if (jsKey !== undefined) jsCache.delete(jsKey);
|
|
346
354
|
if (!options.continueOnMinifyError) {
|
|
347
355
|
throw err;
|
|
348
356
|
}
|
|
@@ -416,15 +424,19 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
416
424
|
return svgContent;
|
|
417
425
|
}
|
|
418
426
|
|
|
419
|
-
|
|
420
|
-
const svgKey =
|
|
421
|
-
? (
|
|
422
|
-
|
|
427
|
+
const isCacheable = svgContent.length <= MAX_CACHE_ENTRY_SIZE;
|
|
428
|
+
const svgKey = isCacheable
|
|
429
|
+
? (svgContent.length > 2048
|
|
430
|
+
? (hashContent(svgContent) + '|' + svgSig)
|
|
431
|
+
: (svgContent + '|' + svgSig))
|
|
432
|
+
: undefined;
|
|
423
433
|
|
|
424
434
|
try {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
435
|
+
if (svgKey !== undefined) {
|
|
436
|
+
const cached = /** @type {string | Promise<string> | undefined} */ (svgCache.get(svgKey));
|
|
437
|
+
if (cached !== undefined) {
|
|
438
|
+
return await cached;
|
|
439
|
+
}
|
|
428
440
|
}
|
|
429
441
|
|
|
430
442
|
const inFlight = (async () => {
|
|
@@ -433,12 +445,12 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
433
445
|
return result.data;
|
|
434
446
|
})();
|
|
435
447
|
|
|
436
|
-
svgCache.set(svgKey, inFlight);
|
|
448
|
+
if (svgKey !== undefined) svgCache.set(svgKey, inFlight);
|
|
437
449
|
const resolved = await inFlight;
|
|
438
|
-
svgCache.set(svgKey, resolved);
|
|
450
|
+
if (svgKey !== undefined) svgCache.set(svgKey, resolved);
|
|
439
451
|
return resolved;
|
|
440
452
|
} catch (err) {
|
|
441
|
-
svgCache.delete(svgKey);
|
|
453
|
+
if (svgKey !== undefined) svgCache.delete(svgKey);
|
|
442
454
|
if (!options.continueOnMinifyError) {
|
|
443
455
|
throw err;
|
|
444
456
|
}
|
package/src/lib/urls.js
CHANGED
|
@@ -79,7 +79,7 @@ function removeDirectoryIndex(pathname) {
|
|
|
79
79
|
/**
|
|
80
80
|
* Create a URL minifier function for the given site context
|
|
81
81
|
* @param {string} site - The site base URL (used to compute relative URLs)
|
|
82
|
-
* @returns {
|
|
82
|
+
* @returns {(url: string) => string} Minifier function that returns the shortest URL
|
|
83
83
|
*/
|
|
84
84
|
export function createUrlMinifier(site) {
|
|
85
85
|
let baseUrl;
|
package/src/lib/utils.js
CHANGED
|
@@ -21,12 +21,16 @@ function stableStringify(obj) {
|
|
|
21
21
|
class LRU {
|
|
22
22
|
constructor(limit = 200) {
|
|
23
23
|
this.limit = limit;
|
|
24
|
+
this.gets = 0;
|
|
25
|
+
this.hits = 0;
|
|
24
26
|
/** @type {Map<string, unknown>} */
|
|
25
27
|
this.map = new Map();
|
|
26
28
|
}
|
|
27
29
|
/** @param {string} key */
|
|
28
30
|
get(key) {
|
|
31
|
+
this.gets++;
|
|
29
32
|
if (this.map.has(key)) {
|
|
33
|
+
this.hits++;
|
|
30
34
|
const v = this.map.get(key);
|
|
31
35
|
this.map.delete(key);
|
|
32
36
|
this.map.set(key, v);
|
|
@@ -48,8 +52,17 @@ class LRU {
|
|
|
48
52
|
}
|
|
49
53
|
/** @param {string} key */
|
|
50
54
|
delete(key) { this.map.delete(key); }
|
|
55
|
+
/** @returns {{ gets: number, hits: number, size: number, limit: number }} */
|
|
56
|
+
stats() {
|
|
57
|
+
return { gets: this.gets, hits: this.hits, size: this.map.size, limit: this.limit };
|
|
58
|
+
}
|
|
51
59
|
}
|
|
52
60
|
|
|
61
|
+
// Content longer than this (in UTF-16 code units, roughly bytes for typical CSS/JS/SVG) is
|
|
62
|
+
// minified normally but never stored in a minification cache—caps worst-case cache memory
|
|
63
|
+
// (entry count × this size) without affecting realistically sized inline content
|
|
64
|
+
const MAX_CACHE_ENTRY_SIZE = 1024 * 1024; // 1 MB
|
|
65
|
+
|
|
53
66
|
// FNV-1a 32-bit hash for large-input cache keys
|
|
54
67
|
|
|
55
68
|
/** @param {string} str */
|
|
@@ -135,6 +148,7 @@ function parseRegExp(value) {
|
|
|
135
148
|
|
|
136
149
|
export { stableStringify };
|
|
137
150
|
export { LRU };
|
|
151
|
+
export { MAX_CACHE_ENTRY_SIZE };
|
|
138
152
|
export { hashContent };
|
|
139
153
|
export { uniqueId };
|
|
140
154
|
export { identity };
|