unhead 3.0.0-beta.8 → 3.0.0-rc.1

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.
Files changed (61) hide show
  1. package/dist/client.d.mts +5 -5
  2. package/dist/client.d.ts +5 -5
  3. package/dist/client.mjs +7 -4
  4. package/dist/index.d.mts +4 -4
  5. package/dist/index.d.ts +4 -4
  6. package/dist/index.mjs +5 -5
  7. package/dist/minify.d.mts +19 -0
  8. package/dist/minify.d.ts +19 -0
  9. package/dist/minify.mjs +138 -0
  10. package/dist/parser.d.mts +1 -1
  11. package/dist/parser.d.ts +1 -1
  12. package/dist/plugins.d.mts +122 -4
  13. package/dist/plugins.d.ts +122 -4
  14. package/dist/plugins.mjs +624 -14
  15. package/dist/scripts.d.mts +4 -4
  16. package/dist/scripts.d.ts +4 -4
  17. package/dist/scripts.mjs +2 -2
  18. package/dist/server.d.mts +6 -10
  19. package/dist/server.d.ts +6 -10
  20. package/dist/server.mjs +5 -5
  21. package/dist/shared/unhead.B825tVHL.d.mts +11 -0
  22. package/dist/shared/{unhead.BYvz9V1x.mjs → unhead.BGFxPGPQ.mjs} +7 -3
  23. package/dist/shared/{unhead.BqsuEzgR.d.ts → unhead.BiaRAmcT.d.mts} +2 -2
  24. package/dist/shared/{unhead.Bkfgmqxw.mjs → unhead.CfgPMHXt.mjs} +1 -0
  25. package/dist/shared/{unhead.Cfuv4vVm.d.ts → unhead.Cp3HtzBy.d.ts} +1 -1
  26. package/dist/shared/{unhead.CdKxe2-O.mjs → unhead.D4TxP3zZ.mjs} +4 -3
  27. package/dist/shared/{unhead.CzbvM4Ih.d.mts → unhead.D6A03PN3.d.mts} +51 -2
  28. package/dist/shared/{unhead.CuATeS8P.d.ts → unhead.DFKqTFly.d.ts} +2 -2
  29. package/dist/shared/{unhead.OoU46jDW.d.mts → unhead.DKz0V2If.d.ts} +2 -2
  30. package/dist/shared/{unhead.zRLmrZrG.mjs → unhead.DQiBmCqH.mjs} +28 -18
  31. package/dist/shared/unhead.D_bywjUE.mjs +236 -0
  32. package/dist/shared/{unhead.B9UFuLCK.d.mts → unhead.Db0zAB-x.d.mts} +2 -2
  33. package/dist/shared/{unhead.C-4k1ONY.d.ts → unhead.DbDvRsnF.d.mts} +1 -1
  34. package/dist/shared/{unhead.D2jdZ2BM.mjs → unhead.DctB-0lW.mjs} +8 -1
  35. package/dist/shared/{unhead.CmjOtSnf.d.ts → unhead.DmIUoNyg.d.ts} +51 -2
  36. package/dist/shared/{unhead.DECeL1s3.d.mts → unhead.DvZZ4Zb_.d.ts} +1 -1
  37. package/dist/shared/{unhead.sufKyII-.d.mts → unhead.DyN7hSCT.d.mts} +1 -1
  38. package/dist/shared/{unhead.5ph757u1.d.mts → unhead.Dyr7L2Ht.d.mts} +108 -34
  39. package/dist/shared/{unhead.5ph757u1.d.ts → unhead.Dyr7L2Ht.d.ts} +108 -34
  40. package/dist/shared/{unhead.CxhEb2IP.mjs → unhead.JWUDzlIs.mjs} +7 -5
  41. package/dist/shared/{unhead.BLJ5lSpj.mjs → unhead.Sr8_Iw6G.mjs} +14 -9
  42. package/dist/shared/unhead.cnX_MFeG.d.ts +11 -0
  43. package/dist/shared/{unhead.C2yODEXq.mjs → unhead.fg-0ge_u.mjs} +1 -1
  44. package/dist/stream/client.d.mts +3 -3
  45. package/dist/stream/client.d.ts +3 -3
  46. package/dist/stream/client.mjs +1 -1
  47. package/dist/stream/iife.d.mts +2 -9
  48. package/dist/stream/iife.d.ts +2 -9
  49. package/dist/stream/iife.global.js +1 -1
  50. package/dist/stream/iife.mjs +2 -2
  51. package/dist/stream/server.d.mts +32 -4
  52. package/dist/stream/server.d.ts +32 -4
  53. package/dist/stream/server.mjs +18 -9
  54. package/dist/stream/vite.mjs +29 -18
  55. package/dist/types.d.mts +6 -6
  56. package/dist/types.d.ts +6 -6
  57. package/dist/utils.d.mts +2 -2
  58. package/dist/utils.d.ts +2 -2
  59. package/dist/utils.mjs +4 -4
  60. package/package.json +11 -4
  61. package/dist/shared/unhead.2y8V0W4A.mjs +0 -148
package/dist/client.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- export { C as ClientUnhead, c as createHead } from './shared/unhead.B9UFuLCK.mjs';
2
- import { R as RenderDomHeadOptions } from './shared/unhead.DECeL1s3.mjs';
3
- import { p as HeadRenderer, q as Unhead } from './shared/unhead.CzbvM4Ih.mjs';
4
- export { n as CreateClientHeadOptions } from './shared/unhead.CzbvM4Ih.mjs';
1
+ export { C as ClientUnhead, c as createHead } from './shared/unhead.Db0zAB-x.mjs';
2
+ import { R as RenderDomHeadOptions } from './shared/unhead.DbDvRsnF.mjs';
3
+ import { p as HeadRenderer, U as Unhead } from './shared/unhead.D6A03PN3.mjs';
4
+ export { c as CreateClientHeadOptions } from './shared/unhead.D6A03PN3.mjs';
5
5
  import 'hookable';
6
- import './shared/unhead.5ph757u1.mjs';
6
+ import './shared/unhead.Dyr7L2Ht.mjs';
7
7
 
8
8
  declare function createDomRenderer(options?: RenderDomHeadOptions): HeadRenderer<boolean>;
9
9
 
package/dist/client.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { C as ClientUnhead, c as createHead } from './shared/unhead.CuATeS8P.js';
2
- import { R as RenderDomHeadOptions } from './shared/unhead.C-4k1ONY.js';
3
- import { p as HeadRenderer, q as Unhead } from './shared/unhead.CmjOtSnf.js';
4
- export { n as CreateClientHeadOptions } from './shared/unhead.CmjOtSnf.js';
1
+ export { C as ClientUnhead, c as createHead } from './shared/unhead.DFKqTFly.js';
2
+ import { R as RenderDomHeadOptions } from './shared/unhead.DvZZ4Zb_.js';
3
+ import { p as HeadRenderer, U as Unhead } from './shared/unhead.DmIUoNyg.js';
4
+ export { c as CreateClientHeadOptions } from './shared/unhead.DmIUoNyg.js';
5
5
  import 'hookable';
6
- import './shared/unhead.5ph757u1.js';
6
+ import './shared/unhead.Dyr7L2Ht.js';
7
7
 
8
8
  declare function createDomRenderer(options?: RenderDomHeadOptions): HeadRenderer<boolean>;
9
9
 
package/dist/client.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { c as createDomRenderer, r as renderDOMHead$1 } from './shared/unhead.CdKxe2-O.mjs';
2
- import { c as createUnhead, r as registerPlugin } from './shared/unhead.Bkfgmqxw.mjs';
1
+ import { c as createDomRenderer, r as renderDOMHead$1 } from './shared/unhead.D4TxP3zZ.mjs';
2
+ import { c as createUnhead, r as registerPlugin } from './shared/unhead.CfgPMHXt.mjs';
3
3
  import { c as createHooks } from './shared/unhead.DvIxXxuO.mjs';
4
- import './shared/unhead.C2yODEXq.mjs';
5
- import './shared/unhead.zRLmrZrG.mjs';
4
+ import './shared/unhead.fg-0ge_u.mjs';
5
+ import './shared/unhead.DQiBmCqH.mjs';
6
6
  import 'hookable';
7
7
 
8
8
  const P = { critical: -8, high: -1, low: 2 };
@@ -32,6 +32,8 @@ function createHead(options = {}) {
32
32
  hooks.callHook("entries:updated", head);
33
33
  },
34
34
  push(input, _options) {
35
+ const onRendered = _options?.onRendered;
36
+ const unhook = onRendered ? hooks.hook("dom:rendered", onRendered) : void 0;
35
37
  const active = core.push(input, _options);
36
38
  core.entries.get(active._i)._o = input;
37
39
  dirty = true;
@@ -44,6 +46,7 @@ function createHead(options = {}) {
44
46
  hooks.callHook("entries:updated", head);
45
47
  },
46
48
  dispose() {
49
+ unhook?.();
47
50
  if (core.entries.has(active._i)) {
48
51
  active.dispose();
49
52
  head.invalidate();
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { H as HeadSafe } from './shared/unhead.OoU46jDW.mjs';
2
- import { aj as ResolvableHead, am as UseSeoMetaInput } from './shared/unhead.5ph757u1.mjs';
3
- import { q as Unhead, o as HeadEntryOptions, k as ActiveHeadEntry, p as HeadRenderer, C as CreateHeadOptions } from './shared/unhead.CzbvM4Ih.mjs';
4
- export { u as useScript } from './shared/unhead.sufKyII-.mjs';
1
+ import { U as Unhead, k as HeadEntryOptions, A as ActiveHeadEntry, p as HeadRenderer, d as CreateHeadOptions } from './shared/unhead.D6A03PN3.mjs';
2
+ import { ak as ResolvableHead, aT as UseSeoMetaInput } from './shared/unhead.Dyr7L2Ht.mjs';
3
+ import { H as HeadSafe } from './shared/unhead.BiaRAmcT.mjs';
4
+ export { u as useScript } from './shared/unhead.DyN7hSCT.mjs';
5
5
  import 'hookable';
6
6
 
7
7
  declare function useHead<T extends Unhead<any>, I = ResolvableHead>(unhead: T, input?: ResolvableHead, options?: HeadEntryOptions): ActiveHeadEntry<I>;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { H as HeadSafe } from './shared/unhead.BqsuEzgR.js';
2
- import { aj as ResolvableHead, am as UseSeoMetaInput } from './shared/unhead.5ph757u1.js';
3
- import { q as Unhead, o as HeadEntryOptions, k as ActiveHeadEntry, p as HeadRenderer, C as CreateHeadOptions } from './shared/unhead.CmjOtSnf.js';
4
- export { u as useScript } from './shared/unhead.Cfuv4vVm.js';
1
+ import { U as Unhead, k as HeadEntryOptions, A as ActiveHeadEntry, p as HeadRenderer, d as CreateHeadOptions } from './shared/unhead.DmIUoNyg.js';
2
+ import { ak as ResolvableHead, aT as UseSeoMetaInput } from './shared/unhead.Dyr7L2Ht.js';
3
+ import { H as HeadSafe } from './shared/unhead.DKz0V2If.js';
4
+ export { u as useScript } from './shared/unhead.Cp3HtzBy.js';
5
5
  import 'hookable';
6
6
 
7
7
  declare function useHead<T extends Unhead<any>, I = ResolvableHead>(unhead: T, input?: ResolvableHead, options?: HeadEntryOptions): ActiveHeadEntry<I>;
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { S as SafeInputPlugin, F as FlatMetaPlugin } from './shared/unhead.2y8V0W4A.mjs';
2
- export { c as createUnhead } from './shared/unhead.Bkfgmqxw.mjs';
3
- export { u as useScript } from './shared/unhead.D2jdZ2BM.mjs';
4
- import './shared/unhead.CxhEb2IP.mjs';
5
- import './shared/unhead.C2yODEXq.mjs';
1
+ import { S as SafeInputPlugin, F as FlatMetaPlugin } from './shared/unhead.D_bywjUE.mjs';
2
+ export { c as createUnhead } from './shared/unhead.CfgPMHXt.mjs';
3
+ export { u as useScript } from './shared/unhead.DctB-0lW.mjs';
4
+ import './shared/unhead.JWUDzlIs.mjs';
5
+ import './shared/unhead.fg-0ge_u.mjs';
6
6
  import './shared/unhead.DvIxXxuO.mjs';
7
7
  import 'hookable';
8
8
 
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Lightweight CSS minifier in pure JS (no native deps).
3
+ * Strips comments and collapses whitespace while preserving string literals.
4
+ */
5
+ declare function minifyCSS(code: string): string;
6
+
7
+ /**
8
+ * Lightweight JS minifier in pure JS (no native deps).
9
+ * Strips comments and collapses whitespace while preserving string literals.
10
+ */
11
+ declare function minifyJS(code: string): string;
12
+
13
+ /**
14
+ * Minify JSON by re-serializing (strips whitespace).
15
+ * Returns the original string unchanged if parsing fails.
16
+ */
17
+ declare function minifyJSON(code: string): string;
18
+
19
+ export { minifyCSS, minifyJS, minifyJSON };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Lightweight CSS minifier in pure JS (no native deps).
3
+ * Strips comments and collapses whitespace while preserving string literals.
4
+ */
5
+ declare function minifyCSS(code: string): string;
6
+
7
+ /**
8
+ * Lightweight JS minifier in pure JS (no native deps).
9
+ * Strips comments and collapses whitespace while preserving string literals.
10
+ */
11
+ declare function minifyJS(code: string): string;
12
+
13
+ /**
14
+ * Minify JSON by re-serializing (strips whitespace).
15
+ * Returns the original string unchanged if parsing fails.
16
+ */
17
+ declare function minifyJSON(code: string): string;
18
+
19
+ export { minifyCSS, minifyJS, minifyJSON };
@@ -0,0 +1,138 @@
1
+ function minifyCSS(code) {
2
+ let result = "";
3
+ let i = 0;
4
+ let parenDepth = 0;
5
+ const len = code.length;
6
+ while (i < len) {
7
+ const ch = code[i];
8
+ if (ch === "'" || ch === '"') {
9
+ const quote = ch;
10
+ result += ch;
11
+ i++;
12
+ while (i < len && code[i] !== quote) {
13
+ if (code[i] === "\\" && i + 1 < len)
14
+ result += code[i++];
15
+ result += code[i++];
16
+ }
17
+ if (i < len)
18
+ result += code[i++];
19
+ } else if (ch === "/" && code[i + 1] === "*") {
20
+ i += 2;
21
+ while (i < len && !(code[i] === "*" && code[i + 1] === "/"))
22
+ i++;
23
+ i += 2;
24
+ } else if (ch === "(") {
25
+ parenDepth++;
26
+ result += ch;
27
+ i++;
28
+ } else if (ch === ")") {
29
+ parenDepth = Math.max(0, parenDepth - 1);
30
+ result += ch;
31
+ i++;
32
+ } else if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
33
+ while (i < len && (code[i] === " " || code[i] === " " || code[i] === "\n" || code[i] === "\r"))
34
+ i++;
35
+ const prev = result.at(-1);
36
+ const next = code[i];
37
+ if (next === "!")
38
+ continue;
39
+ if (parenDepth > 0) {
40
+ if (prev && next && !isCSSCalcPunctuation(prev) && !isCSSCalcPunctuation(next))
41
+ result += " ";
42
+ } else if (prev && next && !isCSSPunctuation(prev) && !isCSSPunctuation(next)) {
43
+ result += " ";
44
+ }
45
+ } else if (ch === ";") {
46
+ let j = i + 1;
47
+ while (j < len && (code[j] === " " || code[j] === " " || code[j] === "\n" || code[j] === "\r"))
48
+ j++;
49
+ if (code[j] === "}") {
50
+ i++;
51
+ } else {
52
+ result += ch;
53
+ i++;
54
+ }
55
+ } else if (ch === "0" && code[i + 1] === "." && code[i + 2] >= "0" && code[i + 2] <= "9") {
56
+ const prev = result.at(-1);
57
+ if (prev && prev >= "0" && prev <= "9") {
58
+ result += ch;
59
+ i++;
60
+ } else {
61
+ i++;
62
+ }
63
+ } else {
64
+ result += ch;
65
+ i++;
66
+ }
67
+ }
68
+ return result.trim();
69
+ }
70
+ function isCSSPunctuation(ch) {
71
+ return ch === "{" || ch === "}" || ch === ";" || ch === ":" || ch === "," || ch === ">" || ch === "~" || ch === "+" || ch === "(" || ch === ")";
72
+ }
73
+ function isCSSCalcPunctuation(ch) {
74
+ return ch === "*" || ch === "/" || ch === "(" || ch === ")" || ch === ",";
75
+ }
76
+
77
+ function minifyJS(code) {
78
+ let result = "";
79
+ let i = 0;
80
+ const len = code.length;
81
+ while (i < len) {
82
+ const ch = code[i];
83
+ if (ch === "'" || ch === '"' || ch === "`") {
84
+ const quote = ch;
85
+ result += ch;
86
+ i++;
87
+ while (i < len && code[i] !== quote) {
88
+ if (code[i] === "\\" && i + 1 < len) {
89
+ result += code[i++];
90
+ }
91
+ result += code[i++];
92
+ }
93
+ if (i < len)
94
+ result += code[i++];
95
+ } else if (ch === "/" && code[i + 1] === "/") {
96
+ i += 2;
97
+ while (i < len && code[i] !== "\n")
98
+ i++;
99
+ } else if (ch === "/" && code[i + 1] === "*") {
100
+ i += 2;
101
+ while (i < len && !(code[i] === "*" && code[i + 1] === "/"))
102
+ i++;
103
+ i += 2;
104
+ } else if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
105
+ let hasNewline = false;
106
+ while (i < len && (code[i] === " " || code[i] === " " || code[i] === "\n" || code[i] === "\r")) {
107
+ if (code[i] === "\n")
108
+ hasNewline = true;
109
+ i++;
110
+ }
111
+ const prev = result.at(-1);
112
+ const next = code[i];
113
+ if (hasNewline && prev && next && prev !== "{" && prev !== "}" && prev !== ";" && next !== "}" && next !== ";")
114
+ result += "\n";
115
+ else if (prev && next && isIdentChar(prev) && isIdentChar(next))
116
+ result += " ";
117
+ else if (prev && next && (prev === "+" && next === "+" || prev === "-" && next === "-"))
118
+ result += " ";
119
+ } else {
120
+ result += ch;
121
+ i++;
122
+ }
123
+ }
124
+ return result.trim();
125
+ }
126
+ function isIdentChar(ch) {
127
+ return ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "_" || ch === "$";
128
+ }
129
+
130
+ function minifyJSON(code) {
131
+ try {
132
+ return JSON.stringify(JSON.parse(code));
133
+ } catch {
134
+ return code;
135
+ }
136
+ }
137
+
138
+ export { minifyCSS, minifyJS, minifyJSON };
package/dist/parser.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { ak as SerializableHead } from './shared/unhead.5ph757u1.mjs';
1
+ import { aD as SerializableHead } from './shared/unhead.Dyr7L2Ht.mjs';
2
2
 
3
3
  declare const TagIdMap: {
4
4
  readonly html: 0;
package/dist/parser.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ak as SerializableHead } from './shared/unhead.5ph757u1.js';
1
+ import { aD as SerializableHead } from './shared/unhead.Dyr7L2Ht.js';
2
2
 
3
3
  declare const TagIdMap: {
4
4
  readonly html: 0;
@@ -1,12 +1,29 @@
1
- import { i as HeadPluginInput, q as Unhead, h as HeadPluginOptions } from './shared/unhead.CzbvM4Ih.mjs';
1
+ import { n as HeadPluginInput, U as Unhead, o as HeadPluginOptions } from './shared/unhead.D6A03PN3.mjs';
2
+ import { p as HeadTag } from './shared/unhead.Dyr7L2Ht.mjs';
2
3
  import 'hookable';
3
- import './shared/unhead.5ph757u1.mjs';
4
4
 
5
5
  declare const AliasSortingPlugin: HeadPluginInput;
6
6
 
7
7
  interface CanonicalPluginOptions {
8
8
  canonicalHost?: string;
9
9
  customResolver?: (url: string) => string;
10
+ /**
11
+ * Query parameters to preserve in canonical and og:url tags.
12
+ * All other query parameters will be stripped by default.
13
+ *
14
+ * Set to `false` to disable query filtering (keep all params).
15
+ *
16
+ * @default [] (strips all query params)
17
+ */
18
+ queryWhitelist?: string[] | false;
19
+ /**
20
+ * Whether canonical URLs should have a trailing slash.
21
+ *
22
+ * - `true` - always add trailing slash
23
+ * - `false` - always remove trailing slash
24
+ * - `undefined` - leave as-is (default)
25
+ */
26
+ trailingSlash?: boolean;
10
27
  }
11
28
  /**
12
29
  * CanonicalPlugin resolves paths in tags that require a canonical host to be set.
@@ -14,6 +31,7 @@ interface CanonicalPluginOptions {
14
31
  * - Resolves paths in meta tags like `og:image` and `twitter:image`.
15
32
  * - Resolves paths in the `og:url` meta tag.
16
33
  * - Resolves paths in the `link` tag with the `rel="canonical"` attribute.
34
+ * - Filters query parameters from canonical and og:url tags.
17
35
  * @example
18
36
  * const plugin = CanonicalPlugin({
19
37
  * canonicalHost: 'https://example.com',
@@ -43,7 +61,7 @@ interface InferSeoMetaPluginOptions {
43
61
  /**
44
62
  * Transform the og description.
45
63
  *
46
- * @param title
64
+ * @param description
47
65
  */
48
66
  ogDescription?: ((description?: string) => string);
49
67
  /**
@@ -55,10 +73,110 @@ interface InferSeoMetaPluginOptions {
55
73
  }
56
74
  declare function InferSeoMetaPlugin(options?: InferSeoMetaPluginOptions): HeadPluginInput;
57
75
 
76
+ interface MinifyPluginOptions {
77
+ /**
78
+ * Custom JS minifier. Set to `false` to disable JS minification.
79
+ * Defaults to built-in lightweight minifier.
80
+ */
81
+ js?: false | ((code: string) => string);
82
+ /**
83
+ * Custom CSS minifier. Set to `false` to disable CSS minification.
84
+ * Defaults to built-in lightweight minifier.
85
+ */
86
+ css?: false | ((code: string) => string);
87
+ /**
88
+ * Minify JSON script types (application/ld+json, application/json).
89
+ * @default true
90
+ */
91
+ json?: boolean;
92
+ }
93
+ /**
94
+ * Minifies inline script and style tag content during SSR rendering.
95
+ *
96
+ * Uses lightweight pure-JS minifiers by default (zero native dependencies, safe for edge/serverless).
97
+ * Custom minifiers can be provided for heavier optimization.
98
+ *
99
+ * Note: The `ssr:render` hook runs synchronously in the render pipeline, so custom minifiers must be synchronous.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { MinifyPlugin } from 'unhead/plugins'
104
+ *
105
+ * const head = createHead({
106
+ * plugins: [MinifyPlugin()]
107
+ * })
108
+ * ```
109
+ */
110
+ declare function MinifyPlugin(options?: MinifyPluginOptions): HeadPluginInput;
111
+
58
112
  declare const PromisesPlugin: HeadPluginInput;
59
113
 
60
114
  declare const SafeInputPlugin: HeadPluginInput;
61
115
 
62
116
  declare const TemplateParamsPlugin: HeadPluginInput;
63
117
 
64
- export { AliasSortingPlugin, CanonicalPlugin, FlatMetaPlugin, InferSeoMetaPlugin, PromisesPlugin, SafeInputPlugin, TemplateParamsPlugin, defineHeadPlugin };
118
+ type RuleSeverity = 'warn' | 'info' | 'off';
119
+ type ValidationRuleId = 'canonical-og-url-mismatch' | 'charset-not-early' | 'defer-on-module-script' | 'deprecated-option-mode' | 'deprecated-prop-body' | 'deprecated-prop-children' | 'deprecated-prop-hid-vmid' | 'duplicate-resource-hint' | 'empty-meta-content' | 'empty-title' | 'html-in-title' | 'inline-script-size' | 'inline-style-size' | 'meta-beyond-1mb' | 'missing-alias-sorting-plugin' | 'missing-description' | 'missing-template-params-plugin' | 'missing-title' | 'non-absolute-canonical' | 'non-absolute-og-url' | 'og-image-missing-dimensions' | 'og-missing-description' | 'og-missing-title' | 'possible-typo' | 'preconnect-missing-crossorigin' | 'prefetch-preload-conflict' | 'preload-async-defer-conflict' | 'preload-fetchpriority-conflict' | 'preload-font-crossorigin' | 'preload-missing-as' | 'preload-not-modulepreload' | 'redundant-dns-prefetch' | 'render-blocking-script' | 'robots-conflict' | 'script-src-with-content' | 'too-many-fetchpriority-high' | 'too-many-preconnects' | 'too-many-preloads' | 'twitter-handle-missing-at' | 'unresolved-template-param' | 'viewport-user-scalable';
120
+ interface ValidationRuleOptions {
121
+ 'charset-not-early': {
122
+ maxPosition: number;
123
+ };
124
+ 'inline-script-size': {
125
+ maxKB: number;
126
+ };
127
+ 'inline-style-size': {
128
+ maxKB: number;
129
+ };
130
+ 'meta-beyond-1mb': {
131
+ maxBytes: number;
132
+ };
133
+ 'too-many-fetchpriority-high': {
134
+ max: number;
135
+ };
136
+ 'too-many-preloads': {
137
+ max: number;
138
+ };
139
+ 'too-many-preconnects': {
140
+ max: number;
141
+ };
142
+ }
143
+ type RuleConfig<Id extends ValidationRuleId> = Id extends keyof ValidationRuleOptions ? RuleSeverity | [severity: RuleSeverity, options: ValidationRuleOptions[Id]] : RuleSeverity;
144
+ type RulesConfig = {
145
+ [K in ValidationRuleId]?: RuleConfig<K>;
146
+ };
147
+ interface HeadValidationRule {
148
+ id: ValidationRuleId;
149
+ message: string;
150
+ severity: 'warn' | 'info';
151
+ source?: string;
152
+ tag?: HeadTag;
153
+ }
154
+ interface ValidatePluginOptions {
155
+ /**
156
+ * Callback to handle validation results. Receives all rules found per resolve cycle.
157
+ * Defaults to `console.warn` for each rule.
158
+ */
159
+ onReport?: (rules: HeadValidationRule[]) => void;
160
+ /**
161
+ * Configure rule severity and options. Accepts a severity string or an ESLint-style
162
+ * `[severity, options]` tuple for rules that support configuration.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * rules: {
167
+ * 'missing-description': 'off',
168
+ * 'too-many-preloads': ['warn', { max: 10 }],
169
+ * 'inline-style-size': ['info', { maxKB: 20 }],
170
+ * }
171
+ * ```
172
+ */
173
+ rules?: RulesConfig;
174
+ /**
175
+ * Project root path. When set, source locations are displayed as relative paths.
176
+ */
177
+ root?: string;
178
+ }
179
+ declare function ValidatePlugin(options?: ValidatePluginOptions): HeadPluginInput;
180
+
181
+ export { AliasSortingPlugin, CanonicalPlugin, FlatMetaPlugin, InferSeoMetaPlugin, MinifyPlugin, PromisesPlugin, SafeInputPlugin, TemplateParamsPlugin, ValidatePlugin, defineHeadPlugin };
182
+ export type { CanonicalPluginOptions, HeadValidationRule, MinifyPluginOptions, RuleConfig, RuleSeverity, RulesConfig, ValidatePluginOptions, ValidationRuleId, ValidationRuleOptions };
package/dist/plugins.d.ts CHANGED
@@ -1,12 +1,29 @@
1
- import { i as HeadPluginInput, q as Unhead, h as HeadPluginOptions } from './shared/unhead.CmjOtSnf.js';
1
+ import { n as HeadPluginInput, U as Unhead, o as HeadPluginOptions } from './shared/unhead.DmIUoNyg.js';
2
+ import { p as HeadTag } from './shared/unhead.Dyr7L2Ht.js';
2
3
  import 'hookable';
3
- import './shared/unhead.5ph757u1.js';
4
4
 
5
5
  declare const AliasSortingPlugin: HeadPluginInput;
6
6
 
7
7
  interface CanonicalPluginOptions {
8
8
  canonicalHost?: string;
9
9
  customResolver?: (url: string) => string;
10
+ /**
11
+ * Query parameters to preserve in canonical and og:url tags.
12
+ * All other query parameters will be stripped by default.
13
+ *
14
+ * Set to `false` to disable query filtering (keep all params).
15
+ *
16
+ * @default [] (strips all query params)
17
+ */
18
+ queryWhitelist?: string[] | false;
19
+ /**
20
+ * Whether canonical URLs should have a trailing slash.
21
+ *
22
+ * - `true` - always add trailing slash
23
+ * - `false` - always remove trailing slash
24
+ * - `undefined` - leave as-is (default)
25
+ */
26
+ trailingSlash?: boolean;
10
27
  }
11
28
  /**
12
29
  * CanonicalPlugin resolves paths in tags that require a canonical host to be set.
@@ -14,6 +31,7 @@ interface CanonicalPluginOptions {
14
31
  * - Resolves paths in meta tags like `og:image` and `twitter:image`.
15
32
  * - Resolves paths in the `og:url` meta tag.
16
33
  * - Resolves paths in the `link` tag with the `rel="canonical"` attribute.
34
+ * - Filters query parameters from canonical and og:url tags.
17
35
  * @example
18
36
  * const plugin = CanonicalPlugin({
19
37
  * canonicalHost: 'https://example.com',
@@ -43,7 +61,7 @@ interface InferSeoMetaPluginOptions {
43
61
  /**
44
62
  * Transform the og description.
45
63
  *
46
- * @param title
64
+ * @param description
47
65
  */
48
66
  ogDescription?: ((description?: string) => string);
49
67
  /**
@@ -55,10 +73,110 @@ interface InferSeoMetaPluginOptions {
55
73
  }
56
74
  declare function InferSeoMetaPlugin(options?: InferSeoMetaPluginOptions): HeadPluginInput;
57
75
 
76
+ interface MinifyPluginOptions {
77
+ /**
78
+ * Custom JS minifier. Set to `false` to disable JS minification.
79
+ * Defaults to built-in lightweight minifier.
80
+ */
81
+ js?: false | ((code: string) => string);
82
+ /**
83
+ * Custom CSS minifier. Set to `false` to disable CSS minification.
84
+ * Defaults to built-in lightweight minifier.
85
+ */
86
+ css?: false | ((code: string) => string);
87
+ /**
88
+ * Minify JSON script types (application/ld+json, application/json).
89
+ * @default true
90
+ */
91
+ json?: boolean;
92
+ }
93
+ /**
94
+ * Minifies inline script and style tag content during SSR rendering.
95
+ *
96
+ * Uses lightweight pure-JS minifiers by default (zero native dependencies, safe for edge/serverless).
97
+ * Custom minifiers can be provided for heavier optimization.
98
+ *
99
+ * Note: The `ssr:render` hook runs synchronously in the render pipeline, so custom minifiers must be synchronous.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { MinifyPlugin } from 'unhead/plugins'
104
+ *
105
+ * const head = createHead({
106
+ * plugins: [MinifyPlugin()]
107
+ * })
108
+ * ```
109
+ */
110
+ declare function MinifyPlugin(options?: MinifyPluginOptions): HeadPluginInput;
111
+
58
112
  declare const PromisesPlugin: HeadPluginInput;
59
113
 
60
114
  declare const SafeInputPlugin: HeadPluginInput;
61
115
 
62
116
  declare const TemplateParamsPlugin: HeadPluginInput;
63
117
 
64
- export { AliasSortingPlugin, CanonicalPlugin, FlatMetaPlugin, InferSeoMetaPlugin, PromisesPlugin, SafeInputPlugin, TemplateParamsPlugin, defineHeadPlugin };
118
+ type RuleSeverity = 'warn' | 'info' | 'off';
119
+ type ValidationRuleId = 'canonical-og-url-mismatch' | 'charset-not-early' | 'defer-on-module-script' | 'deprecated-option-mode' | 'deprecated-prop-body' | 'deprecated-prop-children' | 'deprecated-prop-hid-vmid' | 'duplicate-resource-hint' | 'empty-meta-content' | 'empty-title' | 'html-in-title' | 'inline-script-size' | 'inline-style-size' | 'meta-beyond-1mb' | 'missing-alias-sorting-plugin' | 'missing-description' | 'missing-template-params-plugin' | 'missing-title' | 'non-absolute-canonical' | 'non-absolute-og-url' | 'og-image-missing-dimensions' | 'og-missing-description' | 'og-missing-title' | 'possible-typo' | 'preconnect-missing-crossorigin' | 'prefetch-preload-conflict' | 'preload-async-defer-conflict' | 'preload-fetchpriority-conflict' | 'preload-font-crossorigin' | 'preload-missing-as' | 'preload-not-modulepreload' | 'redundant-dns-prefetch' | 'render-blocking-script' | 'robots-conflict' | 'script-src-with-content' | 'too-many-fetchpriority-high' | 'too-many-preconnects' | 'too-many-preloads' | 'twitter-handle-missing-at' | 'unresolved-template-param' | 'viewport-user-scalable';
120
+ interface ValidationRuleOptions {
121
+ 'charset-not-early': {
122
+ maxPosition: number;
123
+ };
124
+ 'inline-script-size': {
125
+ maxKB: number;
126
+ };
127
+ 'inline-style-size': {
128
+ maxKB: number;
129
+ };
130
+ 'meta-beyond-1mb': {
131
+ maxBytes: number;
132
+ };
133
+ 'too-many-fetchpriority-high': {
134
+ max: number;
135
+ };
136
+ 'too-many-preloads': {
137
+ max: number;
138
+ };
139
+ 'too-many-preconnects': {
140
+ max: number;
141
+ };
142
+ }
143
+ type RuleConfig<Id extends ValidationRuleId> = Id extends keyof ValidationRuleOptions ? RuleSeverity | [severity: RuleSeverity, options: ValidationRuleOptions[Id]] : RuleSeverity;
144
+ type RulesConfig = {
145
+ [K in ValidationRuleId]?: RuleConfig<K>;
146
+ };
147
+ interface HeadValidationRule {
148
+ id: ValidationRuleId;
149
+ message: string;
150
+ severity: 'warn' | 'info';
151
+ source?: string;
152
+ tag?: HeadTag;
153
+ }
154
+ interface ValidatePluginOptions {
155
+ /**
156
+ * Callback to handle validation results. Receives all rules found per resolve cycle.
157
+ * Defaults to `console.warn` for each rule.
158
+ */
159
+ onReport?: (rules: HeadValidationRule[]) => void;
160
+ /**
161
+ * Configure rule severity and options. Accepts a severity string or an ESLint-style
162
+ * `[severity, options]` tuple for rules that support configuration.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * rules: {
167
+ * 'missing-description': 'off',
168
+ * 'too-many-preloads': ['warn', { max: 10 }],
169
+ * 'inline-style-size': ['info', { maxKB: 20 }],
170
+ * }
171
+ * ```
172
+ */
173
+ rules?: RulesConfig;
174
+ /**
175
+ * Project root path. When set, source locations are displayed as relative paths.
176
+ */
177
+ root?: string;
178
+ }
179
+ declare function ValidatePlugin(options?: ValidatePluginOptions): HeadPluginInput;
180
+
181
+ export { AliasSortingPlugin, CanonicalPlugin, FlatMetaPlugin, InferSeoMetaPlugin, MinifyPlugin, PromisesPlugin, SafeInputPlugin, TemplateParamsPlugin, ValidatePlugin, defineHeadPlugin };
182
+ export type { CanonicalPluginOptions, HeadValidationRule, MinifyPluginOptions, RuleConfig, RuleSeverity, RulesConfig, ValidatePluginOptions, ValidationRuleId, ValidationRuleOptions };