unhead 3.1.5 → 3.1.7
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/client.d.mts +5 -6
- package/dist/client.d.ts +5 -6
- package/dist/client.mjs +7 -12
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +15 -10
- package/dist/legacy.d.mts +2 -2
- package/dist/legacy.d.ts +2 -2
- package/dist/legacy.mjs +9 -9
- package/dist/parser.mjs +11 -7
- package/dist/plugins.d.mts +2 -2
- package/dist/plugins.d.ts +2 -2
- package/dist/plugins.mjs +7 -7
- package/dist/scripts.d.mts +3 -3
- package/dist/scripts.d.ts +3 -3
- package/dist/scripts.mjs +2 -3
- package/dist/server.d.mts +3 -3
- package/dist/server.d.ts +3 -3
- package/dist/server.mjs +5 -5
- package/dist/shared/{unhead.fg-0ge_u.mjs → unhead.1eoQpFT1.mjs} +6 -1
- package/dist/shared/{unhead.CRVUlr67.d.mts → unhead.BIArU35P.d.mts} +1 -1
- package/dist/shared/{unhead.BSqa2bYq.mjs → unhead.BNhb5t7_.mjs} +4 -6
- package/dist/shared/{unhead.BeIvDlYY.d.mts → unhead.BZy3nXHx.d.mts} +1 -1
- package/dist/shared/{unhead.DvIxXxuO.mjs → unhead.Bm4Y6XQI.mjs} +3 -0
- package/dist/shared/{unhead.B37CPNIq.d.mts → unhead.Bx2bAQEg.d.mts} +1 -1
- package/dist/shared/{unhead.D-W0R71w.mjs → unhead.C-RMAxyM.mjs} +27 -38
- package/dist/shared/{unhead.CS8tFxG3.d.mts → unhead.CELAVVhh.d.mts} +3 -5
- package/dist/shared/unhead.CHEy9ana.mjs +7 -0
- package/dist/shared/{unhead.BhvKU-Uu.d.ts → unhead.CN7FHaDF.d.ts} +1 -1
- package/dist/shared/{unhead.H5gLMTHA.mjs → unhead.CR32jx68.mjs} +125 -35
- package/dist/shared/{unhead.CBkhoTGw.mjs → unhead.CT1xoGPh.mjs} +1 -1
- package/dist/shared/unhead.CaGVnLUe.mjs +231 -0
- package/dist/shared/{unhead.YBmQyFpm.d.ts → unhead.Cnhe7n9-.d.ts} +1 -1
- package/dist/shared/{unhead.Blkhu0Cr.d.ts → unhead.DQadHCLi.d.ts} +1 -1
- package/dist/shared/{unhead.CBj56GgY.d.ts → unhead.Dv-MkoX9.d.ts} +3 -5
- package/dist/shared/{unhead.CfgPMHXt.mjs → unhead.WK9wg_ep.mjs} +2 -0
- package/dist/shared/{unhead.Doc2Fa-a.mjs → unhead.YIW3bMYK.mjs} +64 -33
- package/dist/shared/{unhead.BZYKjYpn.mjs → unhead.b15Kg1OH.mjs} +3 -3
- package/dist/shared/{unhead.J7mPNB3E.mjs → unhead.tpXvlPwt.mjs} +53 -34
- package/dist/shared/{unhead.BWKj-eGY.d.ts → unhead.xa1ebPBp.d.ts} +1 -1
- package/dist/shared/{unhead.BO2PdEL4.d.mts → unhead.zyZmXwAG.d.mts} +1 -1
- package/dist/stream/client.d.mts +2 -2
- package/dist/stream/client.d.ts +2 -2
- package/dist/stream/client.mjs +3 -8
- package/dist/stream/iife.d.cts +2 -0
- package/dist/stream/iife.global.js +1 -1
- package/dist/stream/iife.mjs +2 -2
- package/dist/stream/server.d.mts +2 -2
- package/dist/stream/server.d.ts +2 -2
- package/dist/stream/server.mjs +5 -5
- package/dist/stream/unplugin.d.mts +5 -1
- package/dist/stream/unplugin.d.ts +5 -1
- package/dist/stream/unplugin.mjs +29 -7
- package/dist/types.d.mts +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.mjs +4 -4
- package/package.json +3 -3
- package/dist/shared/unhead.CT3gGqve.mjs +0 -154
- package/dist/shared/unhead.CUXLLRtV.mjs +0 -5
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
import { u as unpackMeta } from './unhead.
|
|
2
|
-
import { d as defineHeadPlugin } from './unhead.
|
|
1
|
+
import { u as unpackMeta } from './unhead.CT1xoGPh.mjs';
|
|
2
|
+
import { d as defineHeadPlugin } from './unhead.CHEy9ana.mjs';
|
|
3
|
+
import { i as isUnsafeKey } from './unhead.1eoQpFT1.mjs';
|
|
3
4
|
|
|
4
5
|
const FlatMetaPlugin = /* @__PURE__ */ defineHeadPlugin({
|
|
5
6
|
key: "flatMeta",
|
|
6
7
|
hooks: {
|
|
7
8
|
"entries:normalize": (ctx) => {
|
|
9
|
+
let hasFlatMeta = false;
|
|
10
|
+
const tags = [];
|
|
8
11
|
const tagsToAdd = [];
|
|
9
|
-
|
|
12
|
+
for (const t of ctx.tags) {
|
|
10
13
|
if (t.tag !== "_flatMeta") {
|
|
11
|
-
|
|
14
|
+
tags.push(t);
|
|
15
|
+
continue;
|
|
12
16
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
tag: "meta",
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return
|
|
19
|
-
|
|
17
|
+
hasFlatMeta = true;
|
|
18
|
+
for (const props of unpackMeta(t.props))
|
|
19
|
+
tagsToAdd.push({ ...t, tag: "meta", props });
|
|
20
|
+
}
|
|
21
|
+
if (!hasFlatMeta)
|
|
22
|
+
return;
|
|
23
|
+
for (const tag of tagsToAdd) tags.push(tag);
|
|
24
|
+
ctx.tags = tags;
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
});
|
|
@@ -31,7 +36,8 @@ const WhitelistAttributes = {
|
|
|
31
36
|
link: /* @__PURE__ */ new Set(["color", "crossorigin", "fetchpriority", "href", "hreflang", "imagesrcset", "imagesizes", "integrity", "media", "referrerpolicy", "rel", "sizes", "type"])
|
|
32
37
|
};
|
|
33
38
|
const BlockedLinkRels = /* @__PURE__ */ new Set(["canonical", "modulepreload", "prerender", "preload", "prefetch", "dns-prefetch", "preconnect", "manifest", "pingback"]);
|
|
34
|
-
const
|
|
39
|
+
const SafeDataAttrName = /^[a-z][a-z0-9-]*[a-z0-9]$/i;
|
|
40
|
+
const AsciiWhitespace = /[\t\n\f\r ]+/;
|
|
35
41
|
const HtmlEntityHex = /&#x([0-9a-f]+);?/gi;
|
|
36
42
|
const HtmlEntityDec = /&#(\d+);?/g;
|
|
37
43
|
const HtmlEntityNamed = /&(tab|newline|colon|semi|lpar|rpar|sol|bsol|comma|period|excl|num|dollar|percnt|amp|apos|ast|plus|lt|gt|equals|quest|at|lsqb|rsqb|lcub|rcub|vert|hat|grave|tilde|nbsp);?/gi;
|
|
@@ -97,7 +103,7 @@ function stripProtoKeys(obj) {
|
|
|
97
103
|
if (obj && typeof obj === "object") {
|
|
98
104
|
const clean = {};
|
|
99
105
|
for (const key of Object.keys(obj)) {
|
|
100
|
-
if (key
|
|
106
|
+
if (isUnsafeKey(key))
|
|
101
107
|
continue;
|
|
102
108
|
clean[key] = stripProtoKeys(obj[key]);
|
|
103
109
|
}
|
|
@@ -106,9 +112,21 @@ function stripProtoKeys(obj) {
|
|
|
106
112
|
return obj;
|
|
107
113
|
}
|
|
108
114
|
function acceptDataAttrs(value, allowId = true) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
const next = {};
|
|
116
|
+
if (!value)
|
|
117
|
+
return next;
|
|
118
|
+
const keys = Object.keys(value);
|
|
119
|
+
for (let i = 0; i < keys.length; i++) {
|
|
120
|
+
const key = keys[i];
|
|
121
|
+
const isData = key.startsWith("data-");
|
|
122
|
+
if ((isData || allowId && key === "id") && SafeDataAttrName.test(key))
|
|
123
|
+
next[key] = value[key];
|
|
124
|
+
}
|
|
125
|
+
return next;
|
|
126
|
+
}
|
|
127
|
+
function hasBlockedRel(rel) {
|
|
128
|
+
const tokens = rel.split(AsciiWhitespace);
|
|
129
|
+
return !tokens.some(Boolean) || tokens.some((token) => BlockedLinkRels.has(token.toLowerCase()));
|
|
112
130
|
}
|
|
113
131
|
function makeTagSafe(tag) {
|
|
114
132
|
let next = {};
|
|
@@ -156,7 +174,7 @@ function makeTagSafe(tag) {
|
|
|
156
174
|
if (!val) {
|
|
157
175
|
return;
|
|
158
176
|
}
|
|
159
|
-
if (key === "rel" && (typeof val !== "string" ||
|
|
177
|
+
if (key === "rel" && (typeof val !== "string" || hasBlockedRel(val))) {
|
|
160
178
|
return;
|
|
161
179
|
}
|
|
162
180
|
if (key === "href" || key === "imagesrcset") {
|
|
@@ -211,23 +229,36 @@ function makeTagSafe(tag) {
|
|
|
211
229
|
}
|
|
212
230
|
return tag;
|
|
213
231
|
}
|
|
214
|
-
const SafeInputPlugin = (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return acc;
|
|
226
|
-
}, []);
|
|
227
|
-
}
|
|
232
|
+
const SafeInputPlugin = /* @__PURE__ */ defineHeadPlugin({
|
|
233
|
+
key: "safe",
|
|
234
|
+
hooks: {
|
|
235
|
+
"entries:normalize": (ctx) => {
|
|
236
|
+
if (ctx.entry.options?._safe) {
|
|
237
|
+
ctx.tags = ctx.tags.reduce((acc, tag) => {
|
|
238
|
+
const safeTag = makeTagSafe(tag);
|
|
239
|
+
if (safeTag)
|
|
240
|
+
acc.push(safeTag);
|
|
241
|
+
return acc;
|
|
242
|
+
}, []);
|
|
228
243
|
}
|
|
244
|
+
},
|
|
245
|
+
"tags:afterResolve": (ctx) => {
|
|
246
|
+
ctx.tags = ctx.tags.reduce((acc, tag) => {
|
|
247
|
+
if (!tag._safe) {
|
|
248
|
+
acc.push(tag);
|
|
249
|
+
return acc;
|
|
250
|
+
}
|
|
251
|
+
if (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs") {
|
|
252
|
+
acc.push(tag);
|
|
253
|
+
return acc;
|
|
254
|
+
}
|
|
255
|
+
const safeTag = makeTagSafe(tag);
|
|
256
|
+
if (safeTag)
|
|
257
|
+
acc.push(safeTag);
|
|
258
|
+
return acc;
|
|
259
|
+
}, []);
|
|
229
260
|
}
|
|
230
|
-
}
|
|
231
|
-
);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
232
263
|
|
|
233
264
|
export { FlatMetaPlugin as F, SafeInputPlugin as S };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { d as defineHeadPlugin } from './unhead.
|
|
1
|
+
import { d as defineHeadPlugin } from './unhead.CHEy9ana.mjs';
|
|
2
2
|
import { p as processTemplateParams } from './unhead.BGFxPGPQ.mjs';
|
|
3
3
|
|
|
4
4
|
const sortTags = (a, b) => a._w === b._w ? a._p - b._p : a._w - b._w;
|
|
5
5
|
const formatKey = (k) => !k.includes(":key") ? k.split(":").join(":key:") : k;
|
|
6
|
-
const AliasSortingPlugin = defineHeadPlugin({
|
|
6
|
+
const AliasSortingPlugin = /* @__PURE__ */ defineHeadPlugin({
|
|
7
7
|
key: "aliasSorting",
|
|
8
8
|
hooks: {
|
|
9
9
|
"tags:resolve": (ctx) => {
|
|
@@ -124,6 +124,6 @@ const TemplateParamsPlugin = /* @__PURE__ */ defineHeadPlugin((head) => {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
};
|
|
127
|
-
});
|
|
127
|
+
}, "template-params");
|
|
128
128
|
|
|
129
129
|
export { AliasSortingPlugin as A, PromisesPlugin as P, TemplateParamsPlugin as T };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { a as callHook } from './unhead.
|
|
2
|
-
import { S as ScriptNetworkEvents } from './unhead.fg-0ge_u.mjs';
|
|
1
|
+
import { a as callHook } from './unhead.Bm4Y6XQI.mjs';
|
|
3
2
|
|
|
4
3
|
function createNoopedRecordingProxy(instance = {}) {
|
|
5
4
|
const stack = [];
|
|
@@ -59,15 +58,12 @@ function replayProxyRecordings(target, stack) {
|
|
|
59
58
|
});
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
function resolveScriptKey(input) {
|
|
63
|
-
return input.key || input.src || (typeof input.innerHTML === "string" ? input.innerHTML : "");
|
|
64
|
-
}
|
|
65
|
-
const PreconnectServerModes = ["preconnect", "dns-prefetch"];
|
|
66
61
|
function useScript(head, _input, _options) {
|
|
67
62
|
const input = typeof _input === "string" ? { src: _input } : _input;
|
|
68
63
|
const options = _options || {};
|
|
69
|
-
const id =
|
|
70
|
-
const
|
|
64
|
+
const id = input.key || input.src || (typeof input.innerHTML === "string" ? input.innerHTML : "");
|
|
65
|
+
const scripts = head._scripts || (head._scripts = /* @__PURE__ */ Object.create(null));
|
|
66
|
+
const prevScript = Object.hasOwn(scripts, id) ? scripts[id] : void 0;
|
|
71
67
|
if (prevScript) {
|
|
72
68
|
prevScript.setupTriggerHandler(options.trigger);
|
|
73
69
|
return prevScript;
|
|
@@ -79,33 +75,47 @@ function useScript(head, _input, _options) {
|
|
|
79
75
|
_events.push({ type: s, timestamp: Date.now() });
|
|
80
76
|
callHook(head, "script:updated", hookCtx);
|
|
81
77
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
78
|
+
const onload = typeof input.onload === "function" ? input.onload.bind(options.eventContext) : null;
|
|
79
|
+
input.onload = (e) => {
|
|
80
|
+
syncStatus("loaded");
|
|
81
|
+
onload?.(e);
|
|
82
|
+
};
|
|
83
|
+
const onerror = typeof input.onerror === "function" ? input.onerror.bind(options.eventContext) : null;
|
|
84
|
+
input.onerror = (e) => {
|
|
85
|
+
syncStatus("error");
|
|
86
|
+
onerror?.(e);
|
|
87
|
+
};
|
|
90
88
|
const _cbs = { loaded: [], error: [] };
|
|
91
89
|
const _uniqueCbs = /* @__PURE__ */ new Set();
|
|
92
90
|
const _registerCb = (key, cb, options2) => {
|
|
93
91
|
if (head.ssr) {
|
|
94
92
|
return;
|
|
95
93
|
}
|
|
94
|
+
let uniqueKey;
|
|
96
95
|
if (options2?.key) {
|
|
97
|
-
|
|
98
|
-
if (_uniqueCbs.has(
|
|
96
|
+
uniqueKey = `${key}:${options2.key}`;
|
|
97
|
+
if (_uniqueCbs.has(uniqueKey)) {
|
|
99
98
|
return;
|
|
100
99
|
}
|
|
101
|
-
_uniqueCbs.add(
|
|
100
|
+
_uniqueCbs.add(uniqueKey);
|
|
102
101
|
}
|
|
103
102
|
if (_cbs[key]) {
|
|
104
|
-
|
|
105
|
-
return () =>
|
|
103
|
+
_cbs[key].push(cb);
|
|
104
|
+
return () => {
|
|
105
|
+
const idx = _cbs[key]?.indexOf(cb) ?? -1;
|
|
106
|
+
if (idx !== -1)
|
|
107
|
+
_cbs[key]?.splice(idx, 1);
|
|
108
|
+
if (uniqueKey)
|
|
109
|
+
_uniqueCbs.delete(uniqueKey);
|
|
110
|
+
};
|
|
106
111
|
}
|
|
107
|
-
|
|
112
|
+
if (key === "loaded" && script.status === "loaded")
|
|
113
|
+
cb(script.instance);
|
|
114
|
+
else if (key === "error" && script.status === "error")
|
|
115
|
+
cb();
|
|
108
116
|
return () => {
|
|
117
|
+
if (uniqueKey)
|
|
118
|
+
_uniqueCbs.delete(uniqueKey);
|
|
109
119
|
};
|
|
110
120
|
};
|
|
111
121
|
const loadPromise = new Promise((resolve) => {
|
|
@@ -114,7 +124,7 @@ function useScript(head, _input, _options) {
|
|
|
114
124
|
const emit = (api) => queueMicrotask(() => resolve(api));
|
|
115
125
|
const unhook = head.hooks?.hook("script:updated", ({ script: script2 }) => {
|
|
116
126
|
const status = script2.status;
|
|
117
|
-
if (script2.id === id && (status === "loaded" || status === "error")) {
|
|
127
|
+
if (script2.id === id && (status === "loaded" || status === "error" || status === "removed")) {
|
|
118
128
|
if (status === "loaded") {
|
|
119
129
|
if (typeof options.use === "function") {
|
|
120
130
|
const api = options.use();
|
|
@@ -124,7 +134,7 @@ function useScript(head, _input, _options) {
|
|
|
124
134
|
} else {
|
|
125
135
|
emit({});
|
|
126
136
|
}
|
|
127
|
-
} else
|
|
137
|
+
} else {
|
|
128
138
|
resolve(false);
|
|
129
139
|
}
|
|
130
140
|
unhook?.();
|
|
@@ -142,23 +152,26 @@ function useScript(head, _input, _options) {
|
|
|
142
152
|
input,
|
|
143
153
|
status: "awaitingLoad",
|
|
144
154
|
remove() {
|
|
155
|
+
const hadEntry = !!script.entry;
|
|
145
156
|
script._triggerAbortControllers?.forEach((ac) => ac.abort());
|
|
146
157
|
script._triggerAbortControllers?.clear();
|
|
147
158
|
script._triggerPromises = [];
|
|
148
159
|
script._warmupEl?.dispose();
|
|
160
|
+
script._warmupEl = void 0;
|
|
149
161
|
if (script.entry) {
|
|
150
162
|
script.entry.dispose();
|
|
151
163
|
script.entry = void 0;
|
|
152
|
-
syncStatus("removed");
|
|
153
|
-
delete head._scripts?.[id];
|
|
154
|
-
return true;
|
|
155
164
|
}
|
|
156
|
-
|
|
165
|
+
if (scripts[id] === script)
|
|
166
|
+
delete scripts[id];
|
|
167
|
+
if (script.status !== "removed")
|
|
168
|
+
syncStatus("removed");
|
|
169
|
+
return hadEntry;
|
|
157
170
|
},
|
|
158
171
|
warmup(rel) {
|
|
159
172
|
const { src } = input;
|
|
160
173
|
const isCrossOrigin = !src.startsWith("/") || src.startsWith("//");
|
|
161
|
-
const isPreconnect = rel
|
|
174
|
+
const isPreconnect = rel === "preconnect" || rel === "dns-prefetch";
|
|
162
175
|
let href = src;
|
|
163
176
|
if (!rel || isPreconnect && !isCrossOrigin) {
|
|
164
177
|
return;
|
|
@@ -228,15 +241,19 @@ function useScript(head, _input, _options) {
|
|
|
228
241
|
});
|
|
229
242
|
script._triggerAbortController = abortController;
|
|
230
243
|
script._triggerPromises = script._triggerPromises || [];
|
|
231
|
-
const
|
|
244
|
+
const triggerPromise = Promise.race([
|
|
232
245
|
trigger.then((v) => typeof v === "undefined" || v ? script.load : void 0),
|
|
233
246
|
abortPromise
|
|
234
247
|
]).catch((error) => {
|
|
235
248
|
}).then((res) => {
|
|
236
249
|
res?.();
|
|
237
250
|
}).finally(() => {
|
|
238
|
-
script.
|
|
239
|
-
|
|
251
|
+
script._triggerAbortControllers?.delete(abortController);
|
|
252
|
+
const idx = script._triggerPromises?.indexOf(triggerPromise) ?? -1;
|
|
253
|
+
if (idx !== -1)
|
|
254
|
+
script._triggerPromises?.splice(idx, 1);
|
|
255
|
+
});
|
|
256
|
+
script._triggerPromises.push(triggerPromise);
|
|
240
257
|
} else if (typeof trigger === "function") {
|
|
241
258
|
trigger(script.load);
|
|
242
259
|
}
|
|
@@ -249,7 +266,9 @@ function useScript(head, _input, _options) {
|
|
|
249
266
|
_cbs.loaded?.forEach((cb) => cb(api));
|
|
250
267
|
_cbs.loaded = null;
|
|
251
268
|
} else {
|
|
252
|
-
|
|
269
|
+
if (script.status === "error")
|
|
270
|
+
_cbs.error?.forEach((cb) => cb());
|
|
271
|
+
_cbs.loaded = null;
|
|
253
272
|
_cbs.error = null;
|
|
254
273
|
}
|
|
255
274
|
});
|
|
@@ -270,7 +289,7 @@ function useScript(head, _input, _options) {
|
|
|
270
289
|
script._warmupStrategy = options.warmupStrategy;
|
|
271
290
|
script.warmup(options.warmupStrategy);
|
|
272
291
|
}
|
|
273
|
-
|
|
292
|
+
scripts[id] = script;
|
|
274
293
|
return script;
|
|
275
294
|
}
|
|
276
295
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HookableCore } from 'hookable';
|
|
2
2
|
import { R as ResolvableHead } from './unhead.Dl7UHSN0.js';
|
|
3
|
-
import { U as Unhead, d as ClientHeadHooks, C as CreateClientHeadOptions } from './unhead.
|
|
3
|
+
import { U as Unhead, d as ClientHeadHooks, C as CreateClientHeadOptions } from './unhead.Dv-MkoX9.js';
|
|
4
4
|
|
|
5
5
|
interface ClientUnhead<T = ResolvableHead> extends Unhead<T, boolean> {
|
|
6
6
|
hooks: HookableCore<ClientHeadHooks>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { U as Unhead, F as UseScriptInput, G as UseScriptOptions, J as UseScriptReturn } from './unhead.
|
|
1
|
+
import { U as Unhead, F as UseScriptInput, G as UseScriptOptions, J as UseScriptReturn } from './unhead.CELAVVhh.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Load third-party scripts with SSR support and a proxied API.
|
package/dist/stream/client.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ClientUnhead } from '../shared/unhead.
|
|
2
|
-
import { U as Unhead, C as CreateClientHeadOptions } from '../shared/unhead.
|
|
1
|
+
import { C as ClientUnhead } from '../shared/unhead.BIArU35P.mjs';
|
|
2
|
+
import { U as Unhead, C as CreateClientHeadOptions } from '../shared/unhead.CELAVVhh.mjs';
|
|
3
3
|
import { S as SerializableHead, R as ResolvableHead } from '../shared/unhead.Dl7UHSN0.mjs';
|
|
4
4
|
import 'hookable';
|
|
5
5
|
|
package/dist/stream/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ClientUnhead } from '../shared/unhead.
|
|
2
|
-
import { U as Unhead, C as CreateClientHeadOptions } from '../shared/unhead.
|
|
1
|
+
import { C as ClientUnhead } from '../shared/unhead.xa1ebPBp.js';
|
|
2
|
+
import { U as Unhead, C as CreateClientHeadOptions } from '../shared/unhead.Dv-MkoX9.js';
|
|
3
3
|
import { S as SerializableHead, R as ResolvableHead } from '../shared/unhead.Dl7UHSN0.js';
|
|
4
4
|
import 'hookable';
|
|
5
5
|
|
package/dist/stream/client.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as registerPlugin } from '../shared/unhead.
|
|
2
|
-
import { c as createHooks } from '../shared/unhead.
|
|
1
|
+
import { r as registerPlugin } from '../shared/unhead.WK9wg_ep.mjs';
|
|
2
|
+
import { c as createHooks } from '../shared/unhead.Bm4Y6XQI.mjs';
|
|
3
3
|
import 'hookable';
|
|
4
4
|
|
|
5
5
|
const DEFAULT_STREAM_KEY = "__unhead__";
|
|
@@ -73,12 +73,7 @@ function createStreamableHead(options = {}) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
|
-
|
|
77
|
-
const initEntries = [
|
|
78
|
-
initialPayload ? JSON.parse(initialPayload) : false,
|
|
79
|
-
...rest.init || []
|
|
80
|
-
];
|
|
81
|
-
initEntries.forEach((e) => e && head.push(e));
|
|
76
|
+
rest.init?.forEach((e) => e && head.push(e));
|
|
82
77
|
if (streamQueue)
|
|
83
78
|
streamQueue._head = head;
|
|
84
79
|
return head;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var __unhead_iife__ = (function (exports) { 'use strict'; const DupeableTags = new Set(["link", "style", "script", "noscript"]); const TagsWithInnerContent = new Set(["title", "titleTemplate", "script", "style", "noscript"]); const HasElementTags = new Set(["base", "meta", "link", "style", "script", "noscript"]); const ValidHeadTags = new Set(["title", "base", "htmlAttrs", "bodyAttrs", "meta", "link", "style", "script", "noscript"]); const UniqueTags = new Set(["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs", "templateParams"]); const TagConfigKeys = new Set(["key", "tagPosition", "tagPriority", "tagDuplicateStrategy", "innerHTML", "textContent", "processTemplateParams"]); const UsesMergeStrategy = new Set(["templateParams", "htmlAttrs", "bodyAttrs"]); const MetaTagsArrayable = new Set([ "theme-color", "google-site-verification", "og", "article", "book", "profile", "twitter", "author" ]); function callHook(head, hook, ctx) { return head.hooks?.callHook(hook, ctx); } const META_NOREWRITE_RE = /^(?:viewport|description|keywords|robots)$/; const META_KEY_ATTRS = ["name", "property", "http-equiv"]; function isMetaArrayDupeKey(v) { return MetaTagsArrayable.has(v.split(":")[1]); } function dedupeKey(tag) { const { props, tag: t, key } = tag; if (UniqueTags.has(t)) return t; if (t === "link" && props.rel === "canonical") return "canonical"; if (t === "link" && props.rel === "alternate") { if (props.hreflang) return `alternate:${props.hreflang}`; if (props.type) return `alternate:${props.type}:${props.href || ""}`; } if (props.charset) return "charset"; if (t === "meta") { for (const n of META_KEY_ATTRS) { const v = props[n]; if (v !== void 0) return `meta:${v}${(typeof v !== "string" || !v.includes(":")) && !META_NOREWRITE_RE.test(v) && key ? `:key:${key}` : ""}`; } } if (key) return `${t}:key:${key}`; if (props.id) return `${t}:id:${props.id}`; if (t === "link" && props.rel === "alternate") return `alternate:${props.href || ""}`; return TagsWithInnerContent.has(t) && (tag.textContent || tag.innerHTML) ? `${t}:content:${tag.textContent || tag.innerHTML}` : void 0; } function hashTag(tag) { return tag._h || tag._d || tag.textContent || tag.innerHTML || `${tag.tag}:${Object.entries(tag.props).map(([k, v]) => `${k}:${String(v)}`).join()}`; } function walkResolver(val, resolve, key) { if (key === "_resolver") return val; if (typeof val === "function" && (!key || key !== "titleTemplate" && !key.startsWith("on"))) val = val(); const v = resolve ? resolve(key, val) : val; if (Array.isArray(v)) return v.map((r) => walkResolver(r, resolve)); if (v?.constructor === Object) { const next = {}; for (const k in v) { if (k === "__proto__" || k === "constructor" || k === "prototype") continue; next[k] = walkResolver(v[k], resolve, k); } return next; } return v; } function normalizeStyleClassProps(key, value) { const isStyle = key === "style"; const store = isStyle ? new Map() : new Set(); const add = (v) => { if (!v) return; if (isStyle) { const i = v.indexOf(":"); i > 0 && store.set(v.slice(0, i).trim(), v.slice(i + 1).trim()); } else { v.split(" ").forEach((c) => c && store.add(c)); } }; if (typeof value === "string") { (isStyle ? value.split(";") : [value]).forEach(add); } else if (Array.isArray(value)) { value.forEach(add); } else if (value && typeof value === "object") { for (const k in value) { const v = value[k]; v && v !== "false" && (isStyle ? store.set(k.trim(), String(v)) : add(k)); } } return store; } function normalizeProps(tag, input) { tag.props = tag.props || {}; if (!input) return tag; if (tag.tag === "templateParams") { tag.props = input; return tag; } const isHtmlTag = HasElementTags.has(tag.tag) || tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"; for (const prop in input) { if (prop === "__proto__" || prop === "constructor" || prop === "prototype") continue; const value = input[prop]; if (value === null) { tag.props[prop] = null; } else if (prop === "class" || prop === "style") { tag.props[prop] = normalizeStyleClassProps(prop, value); } else if (TagConfigKeys.has(prop)) { if ((prop === "textContent" || prop === "innerHTML") && typeof value === "object") { const type = input.type || "application/json"; if (type.endsWith("json") || type === "speculationrules" || type === "importmap") { tag.props.type = input.type = type; tag[prop] = JSON.stringify(value); } } else { tag[prop] = value; } } else if (value !== void 0) { const isData = prop.startsWith("data-"); const key = isHtmlTag && !isData ? prop.toLowerCase() : prop; const str = String(value); const isMeta = tag.tag === "meta" && key === "content"; tag.props[key] = str === "true" || str === "" ? isData || isMeta ? str : true : !value && isData && str === "false" ? "false" : value; } } return tag; } function normalizeTag(tagName, _input) { const input = typeof _input === "object" && typeof _input !== "function" ? _input : { [tagName === "script" || tagName === "noscript" || tagName === "style" ? "innerHTML" : "textContent"]: _input }; const tag = normalizeProps({ tag: tagName, props: {} }, input); if (tag.key && DupeableTags.has(tag.tag)) tag.props["data-hid"] = tag._h = tag.key; if (tag.tag === "script" && typeof tag.innerHTML === "object") { tag.innerHTML = JSON.stringify(tag.innerHTML); tag.props.type = tag.props.type || "application/json"; } return Array.isArray(tag.props.content) ? tag.props.content.map((v) => ({ ...tag, props: { ...tag.props, content: v } })) : tag; } function normalizeEntryToTags(input, propResolvers) { if (!input) return []; if (typeof input === "function") input = input(); let resolve; if (propResolvers.length) { resolve = (key, val) => { for (let i = 0; i < propResolvers.length; i++) val = propResolvers[i](key, val); return val; }; input = resolve(void 0, input); } input = walkResolver(input, resolve); const tags = []; for (const key in input) { const value = input[key]; if (value !== void 0) { for (const v of Array.isArray(value) ? value : [value]) tags.push(normalizeTag(key, v)); } } return tags.flat(); } const LT_RE = /</g; const SCRIPT_END_RE = /<\/script/g; const sortTags = (a, b) => a._w === b._w ? a._p - b._p : a._w - b._w; const DEFAULT_TAG_WEIGHT = () => 100; const TAG_MUTATING_HOOK_RE = /^tags:|:render/; function dedupeTags(ctx) { let hasFlatMeta = false; for (const next of ctx.tags.sort(sortTags)) { const k = next._d || hashTag(next); const prev = ctx.tagMap.get(k); if (!prev) { ctx.tagMap.set(k, next); continue; } const strategy = next.tagDuplicateStrategy || (UsesMergeStrategy.has(next.tag) ? "merge" : null) || (next.key && next.key === prev.key ? "merge" : null); if (strategy === "merge") { const props = { ...prev.props }; for (const p in next.props) { props[p] = p === "style" ? new Map([...prev.props.style || new Map(), ...next.props[p]]) : p === "class" ? new Set([...prev.props.class || [], ...next.props[p]]) : next.props[p]; } ctx.tagMap.set(k, { ...next, props }); } else if (next._p >> 10 === prev._p >> 10 && next.tag === "meta" && isMetaArrayDupeKey(k)) { ctx.tagMap.set(k, Object.assign([...Array.isArray(prev) ? prev : [prev], next], next)); hasFlatMeta = true; } else if (next._w === prev._w ? next._p > prev._p : next._w < prev._w) { ctx.tagMap.set(k, next); } } return hasFlatMeta; } function resolveTitleTemplate(ctx, head) { const title = ctx.tagMap.get("title"); const tpl = ctx.tagMap.get("titleTemplate"); head._title = title?.textContent; if (!tpl) return; const fn = tpl.textContent; head._titleTemplate = fn; if (!fn) return; let v = typeof fn === "function" ? fn(title?.textContent) : fn; if (typeof v === "string" && !head.plugins.has("template-params")) v = v.replace("%s", title?.textContent || ""); if (title) { v === null ? ctx.tagMap.delete("title") : ctx.tagMap.set("title", { ...title, textContent: v }); } else { ctx.tagMap.set("titleTemplate", { ...tpl, tag: "title", textContent: v }); } } function sanitizeTags(tags) { const out = []; for (let t of tags) { const { innerHTML, tag, props } = t; if (!ValidHeadTags.has(tag) || !Object.keys(props).length && !innerHTML && !t.textContent) continue; if (tag === "meta" && !props.content && !props["http-equiv"] && !props.charset) continue; if (tag === "script" && (innerHTML || t.textContent)) { const type = String(props.type); const isJsonLike = type.endsWith("json") || type === "importmap" || type === "speculationrules"; const escape = (content) => isJsonLike ? (typeof content === "string" ? content : JSON.stringify(content)).replace(LT_RE, "\\u003C") : typeof content === "string" ? content.replace(SCRIPT_END_RE, "<\\/script") : content; t = { ...t }; if (innerHTML) t.innerHTML = escape(innerHTML); if (t.textContent) t.textContent = escape(t.textContent); t._d = dedupeKey(t); } out.push(t); } return out; } function resolveTags(head, options) { const weightFn = options?.tagWeight ?? head.resolvedOptions._tagWeight ?? DEFAULT_TAG_WEIGHT; const ctx = { tagMap: new Map(), tags: [] }; const hooks = head.hooks?._hooks || {}; const entries = [...head.entries.values()]; for (const e of entries) { if (e._pending !== void 0) { e.input = e._pending; delete e._pending; delete e._tags; } } callHook(head, "entries:resolve", { entries, ...ctx }); for (const e of entries) { if (!e._tags) { const normalizeCtx = { tags: normalizeEntryToTags(e.input, head.resolvedOptions.propResolvers || []).map((t) => Object.assign(t, e.options)), entry: e }; callHook(head, "entries:normalize", normalizeCtx); e._tags = normalizeCtx.tags.map((t, i) => { t._w = weightFn(t); t._p = (e._i << 10) + i; t._d = dedupeKey(t); if (!t._d) t._h = hashTag(t); return t; }); } } let needsClone = false; for (const k in hooks) { if (TAG_MUTATING_HOOK_RE.test(k) && hooks[k]?.some((f) => !f._nonMutating)) { needsClone = true; break; } } ctx.tags = needsClone ? entries.flatMap((e) => (e._tags || []).map((t) => { const props = { ...t.props }; if (props.class instanceof Set) props.class = new Set(props.class); if (props.style instanceof Map) props.style = new Map(props.style); return { ...t, props }; })) : entries.flatMap((e) => e._tags || []); const hasFlatMeta = dedupeTags(ctx); resolveTitleTemplate(ctx, head); ctx.tags = [...ctx.tagMap.values()]; if (hasFlatMeta) ctx.tags = ctx.tags.flat().sort(sortTags); callHook(head, "tags:beforeResolve", ctx); callHook(head, "tags:resolve", ctx); callHook(head, "tags:afterResolve", ctx); return sanitizeTags(ctx.tags); } const WHITESPACE_RE = /\s+/; function createDomRenderer(options = {}) { return (head) => _renderDOMHead(head, options); } function _renderDOMHead(head, options = {}) { const dom = options.document || head.resolvedOptions.document; if (!dom || !head.dirty && ![...head.entries.values()].some((e) => e._pending !== void 0)) return false; const beforeRenderCtx = { shouldRender: true, tags: [] }; callHook(head, "dom:beforeRender", beforeRenderCtx); if (!beforeRenderCtx.shouldRender || head._du) return false; head._du = true; let state = head._dom; if (!state) { state = { _t: dom.title, _e: new Map([["htmlAttrs", dom.documentElement], ["bodyAttrs", dom.body]]), _p: {}, _s: {} }; for (const el of [...dom.body.children, ...dom.head.children]) { const tag = el.tagName.toLowerCase(); if (!HasElementTags.has(tag)) continue; const props = { innerHTML: el.innerHTML }; for (const n of el.getAttributeNames()) props[n] = el.getAttribute(n); const next = normalizeProps({ tag, props: {} }, props); next.key = el.getAttribute("data-hid") || void 0; let k = next._d = dedupeKey(next) || hashTag(next); let c = 1; while (state._e.has(k)) k = `${next._d}:${c++}`; state._e.set(k, el); } for (const entry of head.entries.values()) { if (entry._o !== void 0) { const orig = entry._o; for (const t of ["bodyAttrs", "htmlAttrs"]) { const cls = orig[t]?.class; if (typeof cls === "string") { const $el = state._e.get(t); for (const c of cls.split(WHITESPACE_RE)) { if (c) state._p[`${t}:attr:class:${c}`] = () => $el.classList.remove(c); } } } delete entry._o; } } } else { state._p = { ...state._s }; } state._s = {}; function track(id, scope, fn) { const k = `${id}:${scope}`; state._s[k] = fn; delete state._p[k]; } function trackCtx({ id, $el, tag }) { const isAttr = tag.tag.endsWith("Attrs"); state._e.set(id, $el); if (!isAttr) { if (tag.textContent && tag.textContent !== $el.textContent) $el.textContent = tag.textContent; if (tag.innerHTML && tag.innerHTML !== $el.innerHTML) $el.innerHTML = tag.innerHTML; track(id, "el", () => { $el?.remove(); state._e.delete(id); }); } for (const k in tag.props) { const v = tag.props[k]; if (k[0] === "o" && k[1] === "n" && typeof v === "function") { const ev = k.slice(2); if ($el?.dataset?.[`${k}fired`]) v.call($el, new Event(ev)); if ($el.getAttribute(`data-${k}`) !== "") { (tag.tag === "bodyAttrs" ? dom.defaultView : $el).addEventListener(ev, v.bind($el)); $el.setAttribute(`data-${k}`, ""); } continue; } const ck = `attr:${k}`; if (k === "class" && v) { for (const c of v) { if (isAttr) track(id, `${ck}:${c}`, () => $el.classList.remove(c)); if (!$el.classList.contains(c)) $el.classList.add(c); } } else if (k === "style" && v) { for (const [sk, sv] of v) { track(id, `${ck}:${sk}`, () => $el.style.removeProperty(sk)); $el.style.setProperty(sk, sv); } } else if (v !== false && v !== null) { if ($el.getAttribute(k) !== v) $el.setAttribute(k, v === true ? "" : String(v)); if (isAttr) track(id, ck, () => $el.removeAttribute(k)); } } } const pending = []; const frag = {}; const rawTags = resolveTags(head, options.tagWeight ? { tagWeight: options.tagWeight } : void 0); const tags = []; const dupeKeyCounter = new Map(); for (const tag of rawTags) { const count = dupeKeyCounter.get(tag._d) || 0; const id = (count ? `${tag._d}:${count}` : tag._d) || tag._h; const ctx = { tag, id, shouldRender: true }; if (tag._d && isMetaArrayDupeKey(tag._d)) dupeKeyCounter.set(tag._d, count + 1); tags.push(ctx); if (tag.tag === "title") { dom.title = tag.textContent; track("title", "", () => dom.title = state._t); continue; } ctx.$el = state._e.get(id); if (ctx.$el) trackCtx(ctx); else if (HasElementTags.has(tag.tag)) pending.push(ctx); } for (const ctx of pending) { ctx.$el = dom.createElement(ctx.tag.tag); trackCtx(ctx); (frag[ctx.tag.tagPosition || "head"] ??= dom.createDocumentFragment()).appendChild(ctx.$el); } if (frag.head) dom.head.appendChild(frag.head); if (frag.bodyOpen) dom.body.insertBefore(frag.bodyOpen, dom.body.firstChild); if (frag.bodyClose) dom.body.appendChild(frag.bodyClose); for (const k in state._p) state._p[k](); head._dom = state; callHook(head, "dom:rendered", { renders: tags }); head._du = false; head.dirty = false; return true; } function registerPlugin(head, p) { const plugin = typeof p === "function" ? p(head) : p; const key = plugin.key || String(head.plugins.size + 1); if (!head.plugins.get(key)) { head.plugins.set(key, plugin); for (const k in plugin.hooks || {}) head.hooks?.hook(k, plugin.hooks[k]); } } function createUnhead(renderer, resolvedOptions = {}) { const ssr = !resolvedOptions.document; const entries = new Map(); const plugins = new Map(); const head = { _entryCount: 1, plugins, resolvedOptions, ssr, entries, render: () => renderer(head), use: (p) => registerPlugin(head, p), push(input, _options) { const _i = _options?._index ?? head._entryCount++; const options = _options ? { ..._options } : {}; delete options.head; delete options.onRendered; const entry = { _i, input, options }; entries.set(_i, entry); const active = { _i, dispose() { entries.delete(_i); }, patch(input2) { if (ssr) { entry.input = input2; delete entry._tags; } else { entry._pending = input2; } if (!entries.has(_i)) entries.set(_i, entry); } }; return active; } }; resolvedOptions.init?.forEach((e) => e && head.push(e)); return head; } const DEFAULT_STREAM_KEY = "__unhead__"; function init(options = {}) { const { streamKey = DEFAULT_STREAM_KEY } = options; const win = typeof window !== "undefined" ? window : void 0; if (!win) return; const queue = win[streamKey]; if (queue?._head) return queue._head; const doc = typeof document !== "undefined" ? document : void 0; const head = createUnhead(createDomRenderer(), { document: doc }); let hydrationLocked = true; queueMicrotask(() => { hydrationLocked = false; }); function pushStreamed(entry) { const active = head.push(entry); const stored = head.entries.get(active._i); if (stored) stored._streamed = true; } if (queue?._q) { for (const entries of queue._q) { for (const entry of entries) { pushStreamed(entry); } } head.dirty = true; head.render(); } win[streamKey] = { _q: queue?._q || [], _head: head, _hydrationLocked: () => hydrationLocked, push: (entries) => { for (const entry of entries) { pushStreamed(entry); } head.dirty = true; head.render(); } }; return head; } init(); exports.init = init; return exports; })({});
|
|
1
|
+
var __unhead_iife__ = (function (exports) { 'use strict'; const DupeableTags = new Set(["link", "style", "script", "noscript"]); const TagsWithInnerContent = new Set(["title", "titleTemplate", "script", "style", "noscript"]); const HasElementTags = new Set(["base", "meta", "link", "style", "script", "noscript"]); const ValidHeadTags = new Set(["title", "base", "htmlAttrs", "bodyAttrs", "meta", "link", "style", "script", "noscript"]); const UniqueTags = new Set(["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs", "templateParams"]); const TagConfigKeys = new Set(["key", "tagPosition", "tagPriority", "tagDuplicateStrategy", "innerHTML", "textContent", "processTemplateParams"]); const UsesMergeStrategy = new Set(["templateParams", "htmlAttrs", "bodyAttrs"]); const MetaTagsArrayable = new Set([ "theme-color", "google-site-verification", "og", "article", "book", "profile", "twitter", "author" ]); function isUnsafeKey(key) { return key === "__proto__" || key === "constructor" || key === "prototype"; } function callHook(head, hook, ctx) { const hooks = head.hooks?._hooks?.[hook]; if (!hooks?.length) return; return head.hooks?.callHook(hook, ctx); } const META_NOREWRITE_RE = /^(?:viewport|description|keywords|robots)$/; const META_KEY_ATTRS = ["name", "property", "http-equiv"]; function isMetaArrayDupeKey(v) { const i = v.indexOf(":"); if (i === -1) return false; const j = v.indexOf(":", i + 1); return MetaTagsArrayable.has(v.slice(i + 1, j === -1 ? v.length : j)); } function dedupeKey(tag) { const { props, tag: t, key } = tag; if (UniqueTags.has(t)) return t; if (t === "link" && props.rel === "canonical") return "canonical"; if (t === "link" && props.rel === "alternate") { if (props.hreflang) return `alternate:${props.hreflang}`; if (props.type) return `alternate:${props.type}:${props.href || ""}`; } if (props.charset) return "charset"; if (t === "meta") { for (const n of META_KEY_ATTRS) { const v = props[n]; if (v !== void 0) return `meta:${v}${(typeof v !== "string" || !v.includes(":")) && !META_NOREWRITE_RE.test(v) && key ? `:key:${key}` : ""}`; } } if (key) return `${t}:key:${key}`; if (props.id) return `${t}:id:${props.id}`; if (t === "link" && props.rel === "alternate") return `alternate:${props.href || ""}`; return TagsWithInnerContent.has(t) && (tag.textContent || tag.innerHTML) ? `${t}:content:${tag.textContent || tag.innerHTML}` : void 0; } function hashTag(tag) { const identity = tag._h || tag._d || tag.textContent || tag.innerHTML; if (identity) return identity; let hash = `${tag.tag}:`; let separator = ""; for (const key in tag.props) { if (Object.hasOwn(tag.props, key)) { hash += `${separator}${key}:${String(tag.props[key])}`; separator = ","; } } return hash; } function walkResolver(val, resolve, key) { if (key === "_resolver") return val; if (typeof val === "function" && (!key || key !== "titleTemplate" && !key.startsWith("on"))) val = val(); const v = resolve ? resolve(key, val) : val; if (Array.isArray(v)) { let out; for (let i = 0; i < v.length; i++) { const r = walkResolver(v[i], resolve); if (out) { out[i] = r; } else if (r !== v[i]) { out = v.slice(0, i); out[i] = r; } } return out || v; } if (v?.constructor === Object) { let next; for (const k in v) { const unsafe = isUnsafeKey(k); const r = unsafe ? void 0 : walkResolver(v[k], resolve, k); if (!next && (unsafe || r !== v[k])) { next = {}; for (const pk in v) { if (pk === k) break; next[pk] = v[pk]; } } if (next && !unsafe) next[k] = r; } return next || v; } return v; } const INVALID_ATTR_NAME_RE = /[\s"'<>/=\x00-\x1F\x7F]/; function normalizeStyleClassProps(key, value) { const isStyle = key === "style"; const store = isStyle ? new Map() : new Set(); const add = (v) => { if (!v) return; if (isStyle) { const i = v.indexOf(":"); i > 0 && store.set(v.slice(0, i).trim(), v.slice(i + 1).trim()); } else { v.split(" ").forEach((c) => c && store.add(c)); } }; if (typeof value === "string") { (isStyle ? value.split(";") : [value]).forEach(add); } else if (Array.isArray(value)) { value.forEach(add); } else if (value && typeof value === "object") { for (const k in value) { const v = value[k]; v && v !== "false" && (isStyle ? store.set(k.trim(), String(v)) : add(k)); } } return store; } function normalizeProps(tag, input) { tag.props = tag.props || {}; if (!input) return tag; if (tag.tag === "templateParams") { tag.props = input; return tag; } const isHtmlTag = HasElementTags.has(tag.tag) || tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"; for (const prop in input) { if (isUnsafeKey(prop)) continue; const isData = prop.startsWith("data-"); const isHtmlAttr = isHtmlTag && !TagConfigKeys.has(prop); const key = isHtmlAttr && !isData ? prop.toLowerCase() : prop; if (isHtmlAttr && (!key || INVALID_ATTR_NAME_RE.test(key))) continue; const value = input[prop]; if (value === null) { tag.props[key] = null; } else if (prop === "class" || prop === "style") { tag.props[prop] = normalizeStyleClassProps(prop, value); } else if (TagConfigKeys.has(prop)) { if ((prop === "textContent" || prop === "innerHTML") && typeof value === "object") { const type = input.type || "application/json"; if (type.endsWith("json") || type === "speculationrules" || type === "importmap") { tag.props.type = input.type = type; tag[prop] = JSON.stringify(value); } } else { tag[prop] = value; } } else if (value !== void 0) { const str = String(value); const isMeta = tag.tag === "meta" && key === "content"; tag.props[key] = str === "true" || str === "" ? isData || isMeta ? str : true : !value && isData && str === "false" ? "false" : value; } } return tag; } function normalizeTag(tagName, _input) { const input = typeof _input === "object" && typeof _input !== "function" ? _input : { [tagName === "script" || tagName === "noscript" || tagName === "style" ? "innerHTML" : "textContent"]: _input }; const tag = normalizeProps({ tag: tagName, props: {} }, input); if (tag.key && DupeableTags.has(tag.tag)) tag.props["data-hid"] = tag._h = tag.key; if (tag.tag === "script" && typeof tag.innerHTML === "object") { tag.innerHTML = JSON.stringify(tag.innerHTML); tag.props.type = tag.props.type || "application/json"; } if (Array.isArray(tag.props.content)) { const tags = []; for (const content of tag.props.content) { tags.push({ ...tag, props: { ...tag.props, content } }); } return tags; } return tag; } function pushNormalizedTag(tags, tag) { if (Array.isArray(tag)) { for (const t of tag) tags.push(t); } else { tags.push(tag); } } function normalizeEntryToTags(input, propResolvers) { if (!input) return []; if (typeof input === "function") input = input(); let resolve; if (propResolvers.length) { resolve = (key, val) => { for (let i = 0; i < propResolvers.length; i++) val = propResolvers[i](key, val); return val; }; input = resolve(void 0, input); } input = walkResolver(input, resolve); const tags = []; for (const key in input) { const value = input[key]; if (value !== void 0) { if (Array.isArray(value)) { for (const v of value) pushNormalizedTag(tags, normalizeTag(key, v)); } else { pushNormalizedTag(tags, normalizeTag(key, value)); } } } return tags; } const LT_RE = /</g; const SCRIPT_END_RE = /<\/script/g; const sortTags = (a, b) => a._w === b._w ? a._p - b._p : a._w - b._w; const DEFAULT_TAG_WEIGHT = () => 100; function isEmptyProps(props) { for (const _ in props) return false; return true; } const TAG_MUTATING_HOOK_RE = /^tags:|:render/; function pushEntryTags(ctx, entries, needsClone) { for (const tags of entries) { for (const t of tags) { if (needsClone) { const props = { ...t.props }; if (props.class instanceof Set) props.class = new Set(props.class); if (props.style instanceof Map) props.style = new Map(props.style); ctx.tags.push({ ...t, props }); } else { ctx.tags.push(t); } } } } function valuesToTags(ctx, sortFlatMeta) { ctx.tags = []; for (const value of ctx.tagMap.values()) { if (Array.isArray(value)) { for (const tag of value) ctx.tags.push(tag); } else { ctx.tags.push(value); } } if (sortFlatMeta) ctx.tags.sort(sortTags); } function dedupeTags(ctx) { let hasFlatMeta = false; for (const next of ctx.tags.sort(sortTags)) { const k = next._d || hashTag(next); if (!k) continue; const prev = ctx.tagMap.get(k); if (!prev) { ctx.tagMap.set(k, next); continue; } const strategy = next.tagDuplicateStrategy || (UsesMergeStrategy.has(next.tag) ? "merge" : null) || (next.key && next.key === prev.key ? "merge" : null); if (strategy === "merge") { const props = { ...prev.props }; for (const p in next.props) { props[p] = p === "style" ? new Map([...prev.props.style || new Map(), ...next.props[p]]) : p === "class" ? new Set([...prev.props.class || [], ...next.props[p]]) : next.props[p]; } ctx.tagMap.set(k, { ...next, props }); } else if (next._p >> 10 === prev._p >> 10 && next.tag === "meta" && isMetaArrayDupeKey(k)) { ctx.tagMap.set(k, Object.assign([...Array.isArray(prev) ? prev : [prev], next], next)); hasFlatMeta = true; } else if (next._w === prev._w ? next._p > prev._p : next._w < prev._w) { ctx.tagMap.set(k, next); } } return hasFlatMeta; } function resolveTitleTemplate(ctx, head) { const title = ctx.tagMap.get("title"); const tpl = ctx.tagMap.get("titleTemplate"); head._title = title?.textContent; if (!tpl) return; const fn = tpl.textContent; head._titleTemplate = fn; if (!fn) return; let v = typeof fn === "function" ? fn(title?.textContent) : fn; if (typeof v === "string" && !head.plugins.has("template-params")) v = v.replace("%s", title?.textContent || ""); if (title) { v === null ? ctx.tagMap.delete("title") : ctx.tagMap.set("title", { ...title, textContent: v }); } else { ctx.tagMap.set("titleTemplate", { ...tpl, tag: "title", textContent: v }); } } function sanitizeTags(tags) { const out = []; for (let t of tags) { const { innerHTML, tag, props } = t; if (!ValidHeadTags.has(tag) || isEmptyProps(props) && !innerHTML && !t.textContent) continue; if (tag === "meta" && !props.content && !props["http-equiv"] && !props.charset) continue; if (tag === "script" && (innerHTML || t.textContent)) { const type = String(props.type); const isJsonLike = type.endsWith("json") || type === "importmap" || type === "speculationrules"; const escape = (content) => isJsonLike ? (typeof content === "string" ? content : JSON.stringify(content)).replace(LT_RE, "\\u003C") : typeof content === "string" ? content.replace(SCRIPT_END_RE, "<\\/script") : content; t = { ...t }; if (innerHTML) t.innerHTML = escape(innerHTML); if (t.textContent) t.textContent = escape(t.textContent); t._d = dedupeKey(t); } out.push(t); } return out; } function resolveTags(head, options) { const weightFn = options?.tagWeight ?? head.resolvedOptions._tagWeight ?? DEFAULT_TAG_WEIGHT; const ctx = { tagMap: new Map(), tags: [] }; const hooks = head.hooks?._hooks || {}; const entries = [...head.entries.values()]; for (const e of entries) { if (e._pending !== void 0) { e.input = e._pending; delete e._pending; delete e._tags; } } callHook(head, "entries:resolve", { entries, ...ctx }); const entryTags = []; for (const e of entries) { if (!e._tags) { const tags = normalizeEntryToTags(e.input, head.resolvedOptions.propResolvers || []); for (const t of tags) Object.assign(t, e.options); const normalizeCtx = { tags, entry: e }; callHook(head, "entries:normalize", normalizeCtx); for (let i = 0; i < normalizeCtx.tags.length; i++) { const t = normalizeCtx.tags[i]; t._w = weightFn(t); t._p = (e._i << 10) + i; t._d = dedupeKey(t); if (!t._d) t._h = hashTag(t); } e._tags = normalizeCtx.tags; } entryTags.push(e._tags); } let needsClone = false; for (const k in hooks) { if (TAG_MUTATING_HOOK_RE.test(k) && hooks[k]?.some((f) => !f._nonMutating)) { needsClone = true; break; } } pushEntryTags(ctx, entryTags, needsClone); const hasFlatMeta = dedupeTags(ctx); resolveTitleTemplate(ctx, head); valuesToTags(ctx, hasFlatMeta); callHook(head, "tags:beforeResolve", ctx); callHook(head, "tags:resolve", ctx); callHook(head, "tags:afterResolve", ctx); return sanitizeTags(ctx.tags); } const WHITESPACE_RE = /\s+/; function createDomRenderer(options = {}) { return (head) => _renderDOMHead(head, options); } function hasPendingEntries(head) { for (const entry of head.entries.values()) { if (entry._pending !== void 0) return true; } return false; } function cleanupDomState(state) { for (const k in state._s) state._s[k](); for (const k in state._p) state._p[k](); state._s = {}; state._p = {}; state._e.clear(); state._l.clear(); } function createDomState(head, dom) { const state = { _d: dom, _t: dom.title, _e: new Map([["htmlAttrs", dom.documentElement], ["bodyAttrs", dom.body]]), _p: {}, _s: {}, _l: new Map() }; for (const el of [...dom.body.children, ...dom.head.children]) { const tag = el.tagName.toLowerCase(); if (!HasElementTags.has(tag)) continue; const props = { innerHTML: el.innerHTML }; for (const n of el.getAttributeNames()) props[n] = el.getAttribute(n); const next = normalizeProps({ tag, props: {} }, props); next.key = el.getAttribute("data-hid") || void 0; const dedupe = dedupeKey(next) || hashTag(next); let k = dedupe; let c = 1; while (state._e.has(k)) k = `${dedupe}:${c++}`; state._e.set(k, el); } for (const entry of head.entries.values()) { if (entry._o !== void 0) { const orig = entry._o; for (const t of ["bodyAttrs", "htmlAttrs"]) { const cls = orig[t]?.class; if (typeof cls === "string") { const $el = state._e.get(t); for (const c of cls.split(WHITESPACE_RE)) { if (c) state._p[`${t}:attr:class:${c}`] = () => $el.classList.remove(c); } } } } } return state; } function _renderDOMHead(head, options = {}) { const dom = options.document || head.resolvedOptions.document; const activeState = head._dom; const documentChanged = !!activeState && activeState._d !== dom; if (!dom || !documentChanged && !head.dirty && !hasPendingEntries(head)) return false; if (head._du) return false; const defaultView = dom.defaultView; head._du = true; let didRender = false; try { let track = function(id, scope, fn, fresh) { const k = `${id}:${scope}`; renderState._s[k] = !fresh && renderState._p[k] || fn; delete renderState._p[k]; }, reclaim = function(key) { const prev = renderState._p[key]; delete renderState._p[key]; return prev; }, trackEvent = function(id, k, ev, source, $el, target) { const scope = `event:${k}`; const key = `${id}:${scope}`; const prev = renderState._l.get(key); if (prev && prev[0] === target && prev[1] === ev && prev[2] === source) { track(id, scope, prev[4]); return; } prev?.[4](); const dk = `data-${k}`; const handler = ((e) => source.call($el, e)); const cleanup = () => { target.removeEventListener(ev, handler); if ($el.getAttribute(dk) === "") $el.removeAttribute(dk); if (renderState._l.get(key)?.[3] === handler) renderState._l.delete(key); }; target.addEventListener(ev, handler); renderState._l.set(key, [target, ev, source, handler, cleanup]); $el.setAttribute(dk, ""); track(id, scope, cleanup, true); }, trackCtx = function({ id, $el, tag }) { const isAttr = tag.tag.endsWith("Attrs"); renderState._e.set(id, $el); if (!isAttr) { const text = tag.textContent; if (text != null && text !== "") { if (text !== $el.textContent) $el.textContent = text; track(id, "text", () => { if ($el.textContent === text) $el.textContent = ""; }, true); } const html = tag.innerHTML; if (html != null && html !== "") { if (html !== $el.innerHTML) $el.innerHTML = html; track(id, "html", () => { if ($el.innerHTML === html) $el.innerHTML = ""; }, true); } const elKey = `${id}:el`; renderState._s[elKey] = reclaim(elKey) || (() => { $el?.remove(); renderState._e.delete(id); }); } for (const k in tag.props) { const v = tag.props[k]; if (k[0] === "o" && k[1] === "n" && typeof v === "function") { const ev = k.slice(2); if ($el?.dataset?.[`${k}fired`]) v.call($el, new (defaultView?.Event || Event)(ev)); trackEvent(id, k, ev, v, $el, tag.tag === "bodyAttrs" && defaultView ? defaultView : $el); continue; } const ck = `${id}:attr:${k}`; if (k === "class" && v) { for (const c of v) { const key = `${ck}:${c}`; renderState._s[key] = reclaim(key) || (() => $el.classList.remove(c)); if (!$el.classList.contains(c)) $el.classList.add(c); } } else if (k === "style" && v) { for (const [sk, sv] of v) { const key = `${ck}:${sk}`; renderState._s[key] = reclaim(key) || (() => $el.style.removeProperty(sk)); $el.style.setProperty(sk, sv); } } else if (v !== false && v !== null) { if ($el.getAttribute(k) !== v) $el.setAttribute(k, v === true ? "" : String(v)); renderState._s[ck] = reclaim(ck) || (() => $el.removeAttribute(k)); } } }; const beforeRenderCtx = { shouldRender: true, tags: [] }; callHook(head, "dom:beforeRender", beforeRenderCtx); if (!beforeRenderCtx.shouldRender) return false; let state = head._dom; if (state?._d !== dom) { if (state) cleanupDomState(state); state = void 0; } if (!state) { state = createDomState(head, dom); } else { state._p = state._s; } state._s = {}; const renderState = state; const pending = []; const frag = {}; head.dirty = false; const rawTags = resolveTags(head, options.tagWeight ? { tagWeight: options.tagWeight } : void 0); const tags = []; const dupeKeyCounter = {}; for (const tag of rawTags) { const count = dupeKeyCounter[tag._d] || 0; const id = (count ? `${tag._d}:${count}` : tag._d) || tag._h; const ctx = { tag, id, shouldRender: true }; if (tag._d && isMetaArrayDupeKey(tag._d)) dupeKeyCounter[tag._d] = count + 1; tags.push(ctx); if (tag.tag === "title") { dom.title = tag.textContent; track("title", "", () => dom.title = renderState._t); continue; } ctx.$el = renderState._e.get(id); if (ctx.$el) trackCtx(ctx); else if (HasElementTags.has(tag.tag)) pending.push(ctx); } for (const ctx of pending) { ctx.$el = dom.createElement(ctx.tag.tag); trackCtx(ctx); (frag[ctx.tag.tagPosition || "head"] ??= dom.createDocumentFragment()).appendChild(ctx.$el); } if (frag.head) dom.head.appendChild(frag.head); if (frag.bodyOpen) dom.body.insertBefore(frag.bodyOpen, dom.body.firstChild); if (frag.bodyClose) dom.body.appendChild(frag.bodyClose); for (const k in renderState._p) renderState._p[k](); head._dom = renderState; didRender = true; callHook(head, "dom:rendered", { renders: tags }); } catch (e) { head.dirty = true; throw e; } finally { head._du = false; } if (didRender && (head.dirty || hasPendingEntries(head))) _renderDOMHead(head, options); return didRender; } function registerPlugin(head, p) { if (typeof p === "function" && p.key && head.plugins.has(p.key)) return; const plugin = typeof p === "function" ? p(head) : p; const key = plugin.key || String(head.plugins.size + 1); if (!head.plugins.get(key)) { head.plugins.set(key, plugin); for (const k in plugin.hooks || {}) head.hooks?.hook(k, plugin.hooks[k]); } } function createUnhead(renderer, resolvedOptions = {}) { const ssr = !resolvedOptions.document; const entries = new Map(); const plugins = new Map(); const head = { _entryCount: 1, plugins, resolvedOptions, ssr, entries, render: () => renderer(head), use: (p) => registerPlugin(head, p), push(input, _options) { const _i = _options?._index ?? head._entryCount++; const options = _options ? { ..._options } : {}; delete options.head; delete options.onRendered; const entry = { _i, input, options }; entries.set(_i, entry); const active = { _i, dispose() { entries.delete(_i); }, patch(input2) { if (ssr) { entry.input = input2; delete entry._tags; } else { entry._pending = input2; } if (!entries.has(_i)) entries.set(_i, entry); } }; return active; } }; resolvedOptions.init?.forEach((e) => e && head.push(e)); return head; } const DEFAULT_STREAM_KEY = "__unhead__"; function init(options = {}) { const { streamKey = DEFAULT_STREAM_KEY } = options; const win = typeof window !== "undefined" ? window : void 0; if (!win) return; const queue = win[streamKey]; if (queue?._head) return queue._head; const doc = typeof document !== "undefined" ? document : void 0; const head = createUnhead(createDomRenderer(), { document: doc }); let hydrationLocked = true; queueMicrotask(() => { hydrationLocked = false; }); function pushStreamed(entry) { const active = head.push(entry); const stored = head.entries.get(active._i); if (stored) stored._streamed = true; } if (queue?._q) { for (const entries of queue._q) { for (const entry of entries) { pushStreamed(entry); } } head.dirty = true; head.render(); } win[streamKey] = { _q: queue?._q || [], _head: head, _hydrationLocked: () => hydrationLocked, push: (entries) => { for (const entry of entries) { pushStreamed(entry); } head.dirty = true; head.render(); } }; return head; } exports.init = init; return exports; })({});__unhead_iife__.init();
|
package/dist/stream/iife.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const streamingIifeCode = "var __unhead_iife__ = (function (exports) { 'use strict'; const DupeableTags = new Set([\"link\", \"style\", \"script\", \"noscript\"]); const TagsWithInnerContent = new Set([\"title\", \"titleTemplate\", \"script\", \"style\", \"noscript\"]); const HasElementTags = new Set([\"base\", \"meta\", \"link\", \"style\", \"script\", \"noscript\"]); const ValidHeadTags = new Set([\"title\", \"base\", \"htmlAttrs\", \"bodyAttrs\", \"meta\", \"link\", \"style\", \"script\", \"noscript\"]); const UniqueTags = new Set([\"base\", \"title\", \"titleTemplate\", \"bodyAttrs\", \"htmlAttrs\", \"templateParams\"]); const TagConfigKeys = new Set([\"key\", \"tagPosition\", \"tagPriority\", \"tagDuplicateStrategy\", \"innerHTML\", \"textContent\", \"processTemplateParams\"]); const UsesMergeStrategy = new Set([\"templateParams\", \"htmlAttrs\", \"bodyAttrs\"]); const MetaTagsArrayable = new Set([ \"theme-color\", \"google-site-verification\", \"og\", \"article\", \"book\", \"profile\", \"twitter\", \"author\" ]); function callHook(head, hook, ctx) { return head.hooks?.callHook(hook, ctx); } const META_NOREWRITE_RE = /^(?:viewport|description|keywords|robots)$/; const META_KEY_ATTRS = [\"name\", \"property\", \"http-equiv\"]; function isMetaArrayDupeKey(v) { return MetaTagsArrayable.has(v.split(\":\")[1]); } function dedupeKey(tag) { const { props, tag: t, key } = tag; if (UniqueTags.has(t)) return t; if (t === \"link\" && props.rel === \"canonical\") return \"canonical\"; if (t === \"link\" && props.rel === \"alternate\") { if (props.hreflang) return `alternate:${props.hreflang}`; if (props.type) return `alternate:${props.type}:${props.href || \"\"}`; } if (props.charset) return \"charset\"; if (t === \"meta\") { for (const n of META_KEY_ATTRS) { const v = props[n]; if (v !== void 0) return `meta:${v}${(typeof v !== \"string\" || !v.includes(\":\")) && !META_NOREWRITE_RE.test(v) && key ? `:key:${key}` : \"\"}`; } } if (key) return `${t}:key:${key}`; if (props.id) return `${t}:id:${props.id}`; if (t === \"link\" && props.rel === \"alternate\") return `alternate:${props.href || \"\"}`; return TagsWithInnerContent.has(t) && (tag.textContent || tag.innerHTML) ? `${t}:content:${tag.textContent || tag.innerHTML}` : void 0; } function hashTag(tag) { return tag._h || tag._d || tag.textContent || tag.innerHTML || `${tag.tag}:${Object.entries(tag.props).map(([k, v]) => `${k}:${String(v)}`).join()}`; } function walkResolver(val, resolve, key) { if (key === \"_resolver\") return val; if (typeof val === \"function\" && (!key || key !== \"titleTemplate\" && !key.startsWith(\"on\"))) val = val(); const v = resolve ? resolve(key, val) : val; if (Array.isArray(v)) return v.map((r) => walkResolver(r, resolve)); if (v?.constructor === Object) { const next = {}; for (const k in v) { if (k === \"__proto__\" || k === \"constructor\" || k === \"prototype\") continue; next[k] = walkResolver(v[k], resolve, k); } return next; } return v; } function normalizeStyleClassProps(key, value) { const isStyle = key === \"style\"; const store = isStyle ? new Map() : new Set(); const add = (v) => { if (!v) return; if (isStyle) { const i = v.indexOf(\":\"); i > 0 && store.set(v.slice(0, i).trim(), v.slice(i + 1).trim()); } else { v.split(\" \").forEach((c) => c && store.add(c)); } }; if (typeof value === \"string\") { (isStyle ? value.split(\";\") : [value]).forEach(add); } else if (Array.isArray(value)) { value.forEach(add); } else if (value && typeof value === \"object\") { for (const k in value) { const v = value[k]; v && v !== \"false\" && (isStyle ? store.set(k.trim(), String(v)) : add(k)); } } return store; } function normalizeProps(tag, input) { tag.props = tag.props || {}; if (!input) return tag; if (tag.tag === \"templateParams\") { tag.props = input; return tag; } const isHtmlTag = HasElementTags.has(tag.tag) || tag.tag === \"htmlAttrs\" || tag.tag === \"bodyAttrs\"; for (const prop in input) { if (prop === \"__proto__\" || prop === \"constructor\" || prop === \"prototype\") continue; const value = input[prop]; if (value === null) { tag.props[prop] = null; } else if (prop === \"class\" || prop === \"style\") { tag.props[prop] = normalizeStyleClassProps(prop, value); } else if (TagConfigKeys.has(prop)) { if ((prop === \"textContent\" || prop === \"innerHTML\") && typeof value === \"object\") { const type = input.type || \"application/json\"; if (type.endsWith(\"json\") || type === \"speculationrules\" || type === \"importmap\") { tag.props.type = input.type = type; tag[prop] = JSON.stringify(value); } } else { tag[prop] = value; } } else if (value !== void 0) { const isData = prop.startsWith(\"data-\"); const key = isHtmlTag && !isData ? prop.toLowerCase() : prop; const str = String(value); const isMeta = tag.tag === \"meta\" && key === \"content\"; tag.props[key] = str === \"true\" || str === \"\" ? isData || isMeta ? str : true : !value && isData && str === \"false\" ? \"false\" : value; } } return tag; } function normalizeTag(tagName, _input) { const input = typeof _input === \"object\" && typeof _input !== \"function\" ? _input : { [tagName === \"script\" || tagName === \"noscript\" || tagName === \"style\" ? \"innerHTML\" : \"textContent\"]: _input }; const tag = normalizeProps({ tag: tagName, props: {} }, input); if (tag.key && DupeableTags.has(tag.tag)) tag.props[\"data-hid\"] = tag._h = tag.key; if (tag.tag === \"script\" && typeof tag.innerHTML === \"object\") { tag.innerHTML = JSON.stringify(tag.innerHTML); tag.props.type = tag.props.type || \"application/json\"; } return Array.isArray(tag.props.content) ? tag.props.content.map((v) => ({ ...tag, props: { ...tag.props, content: v } })) : tag; } function normalizeEntryToTags(input, propResolvers) { if (!input) return []; if (typeof input === \"function\") input = input(); let resolve; if (propResolvers.length) { resolve = (key, val) => { for (let i = 0; i < propResolvers.length; i++) val = propResolvers[i](key, val); return val; }; input = resolve(void 0, input); } input = walkResolver(input, resolve); const tags = []; for (const key in input) { const value = input[key]; if (value !== void 0) { for (const v of Array.isArray(value) ? value : [value]) tags.push(normalizeTag(key, v)); } } return tags.flat(); } const LT_RE = /</g; const SCRIPT_END_RE = /<\\/script/g; const sortTags = (a, b) => a._w === b._w ? a._p - b._p : a._w - b._w; const DEFAULT_TAG_WEIGHT = () => 100; const TAG_MUTATING_HOOK_RE = /^tags:|:render/; function dedupeTags(ctx) { let hasFlatMeta = false; for (const next of ctx.tags.sort(sortTags)) { const k = next._d || hashTag(next); const prev = ctx.tagMap.get(k); if (!prev) { ctx.tagMap.set(k, next); continue; } const strategy = next.tagDuplicateStrategy || (UsesMergeStrategy.has(next.tag) ? \"merge\" : null) || (next.key && next.key === prev.key ? \"merge\" : null); if (strategy === \"merge\") { const props = { ...prev.props }; for (const p in next.props) { props[p] = p === \"style\" ? new Map([...prev.props.style || new Map(), ...next.props[p]]) : p === \"class\" ? new Set([...prev.props.class || [], ...next.props[p]]) : next.props[p]; } ctx.tagMap.set(k, { ...next, props }); } else if (next._p >> 10 === prev._p >> 10 && next.tag === \"meta\" && isMetaArrayDupeKey(k)) { ctx.tagMap.set(k, Object.assign([...Array.isArray(prev) ? prev : [prev], next], next)); hasFlatMeta = true; } else if (next._w === prev._w ? next._p > prev._p : next._w < prev._w) { ctx.tagMap.set(k, next); } } return hasFlatMeta; } function resolveTitleTemplate(ctx, head) { const title = ctx.tagMap.get(\"title\"); const tpl = ctx.tagMap.get(\"titleTemplate\"); head._title = title?.textContent; if (!tpl) return; const fn = tpl.textContent; head._titleTemplate = fn; if (!fn) return; let v = typeof fn === \"function\" ? fn(title?.textContent) : fn; if (typeof v === \"string\" && !head.plugins.has(\"template-params\")) v = v.replace(\"%s\", title?.textContent || \"\"); if (title) { v === null ? ctx.tagMap.delete(\"title\") : ctx.tagMap.set(\"title\", { ...title, textContent: v }); } else { ctx.tagMap.set(\"titleTemplate\", { ...tpl, tag: \"title\", textContent: v }); } } function sanitizeTags(tags) { const out = []; for (let t of tags) { const { innerHTML, tag, props } = t; if (!ValidHeadTags.has(tag) || !Object.keys(props).length && !innerHTML && !t.textContent) continue; if (tag === \"meta\" && !props.content && !props[\"http-equiv\"] && !props.charset) continue; if (tag === \"script\" && (innerHTML || t.textContent)) { const type = String(props.type); const isJsonLike = type.endsWith(\"json\") || type === \"importmap\" || type === \"speculationrules\"; const escape = (content) => isJsonLike ? (typeof content === \"string\" ? content : JSON.stringify(content)).replace(LT_RE, \"\\\\u003C\") : typeof content === \"string\" ? content.replace(SCRIPT_END_RE, \"<\\\\/script\") : content; t = { ...t }; if (innerHTML) t.innerHTML = escape(innerHTML); if (t.textContent) t.textContent = escape(t.textContent); t._d = dedupeKey(t); } out.push(t); } return out; } function resolveTags(head, options) { const weightFn = options?.tagWeight ?? head.resolvedOptions._tagWeight ?? DEFAULT_TAG_WEIGHT; const ctx = { tagMap: new Map(), tags: [] }; const hooks = head.hooks?._hooks || {}; const entries = [...head.entries.values()]; for (const e of entries) { if (e._pending !== void 0) { e.input = e._pending; delete e._pending; delete e._tags; } } callHook(head, \"entries:resolve\", { entries, ...ctx }); for (const e of entries) { if (!e._tags) { const normalizeCtx = { tags: normalizeEntryToTags(e.input, head.resolvedOptions.propResolvers || []).map((t) => Object.assign(t, e.options)), entry: e }; callHook(head, \"entries:normalize\", normalizeCtx); e._tags = normalizeCtx.tags.map((t, i) => { t._w = weightFn(t); t._p = (e._i << 10) + i; t._d = dedupeKey(t); if (!t._d) t._h = hashTag(t); return t; }); } } let needsClone = false; for (const k in hooks) { if (TAG_MUTATING_HOOK_RE.test(k) && hooks[k]?.some((f) => !f._nonMutating)) { needsClone = true; break; } } ctx.tags = needsClone ? entries.flatMap((e) => (e._tags || []).map((t) => { const props = { ...t.props }; if (props.class instanceof Set) props.class = new Set(props.class); if (props.style instanceof Map) props.style = new Map(props.style); return { ...t, props }; })) : entries.flatMap((e) => e._tags || []); const hasFlatMeta = dedupeTags(ctx); resolveTitleTemplate(ctx, head); ctx.tags = [...ctx.tagMap.values()]; if (hasFlatMeta) ctx.tags = ctx.tags.flat().sort(sortTags); callHook(head, \"tags:beforeResolve\", ctx); callHook(head, \"tags:resolve\", ctx); callHook(head, \"tags:afterResolve\", ctx); return sanitizeTags(ctx.tags); } const WHITESPACE_RE = /\\s+/; function createDomRenderer(options = {}) { return (head) => _renderDOMHead(head, options); } function _renderDOMHead(head, options = {}) { const dom = options.document || head.resolvedOptions.document; if (!dom || !head.dirty && ![...head.entries.values()].some((e) => e._pending !== void 0)) return false; const beforeRenderCtx = { shouldRender: true, tags: [] }; callHook(head, \"dom:beforeRender\", beforeRenderCtx); if (!beforeRenderCtx.shouldRender || head._du) return false; head._du = true; let state = head._dom; if (!state) { state = { _t: dom.title, _e: new Map([[\"htmlAttrs\", dom.documentElement], [\"bodyAttrs\", dom.body]]), _p: {}, _s: {} }; for (const el of [...dom.body.children, ...dom.head.children]) { const tag = el.tagName.toLowerCase(); if (!HasElementTags.has(tag)) continue; const props = { innerHTML: el.innerHTML }; for (const n of el.getAttributeNames()) props[n] = el.getAttribute(n); const next = normalizeProps({ tag, props: {} }, props); next.key = el.getAttribute(\"data-hid\") || void 0; let k = next._d = dedupeKey(next) || hashTag(next); let c = 1; while (state._e.has(k)) k = `${next._d}:${c++}`; state._e.set(k, el); } for (const entry of head.entries.values()) { if (entry._o !== void 0) { const orig = entry._o; for (const t of [\"bodyAttrs\", \"htmlAttrs\"]) { const cls = orig[t]?.class; if (typeof cls === \"string\") { const $el = state._e.get(t); for (const c of cls.split(WHITESPACE_RE)) { if (c) state._p[`${t}:attr:class:${c}`] = () => $el.classList.remove(c); } } } delete entry._o; } } } else { state._p = { ...state._s }; } state._s = {}; function track(id, scope, fn) { const k = `${id}:${scope}`; state._s[k] = fn; delete state._p[k]; } function trackCtx({ id, $el, tag }) { const isAttr = tag.tag.endsWith(\"Attrs\"); state._e.set(id, $el); if (!isAttr) { if (tag.textContent && tag.textContent !== $el.textContent) $el.textContent = tag.textContent; if (tag.innerHTML && tag.innerHTML !== $el.innerHTML) $el.innerHTML = tag.innerHTML; track(id, \"el\", () => { $el?.remove(); state._e.delete(id); }); } for (const k in tag.props) { const v = tag.props[k]; if (k[0] === \"o\" && k[1] === \"n\" && typeof v === \"function\") { const ev = k.slice(2); if ($el?.dataset?.[`${k}fired`]) v.call($el, new Event(ev)); if ($el.getAttribute(`data-${k}`) !== \"\") { (tag.tag === \"bodyAttrs\" ? dom.defaultView : $el).addEventListener(ev, v.bind($el)); $el.setAttribute(`data-${k}`, \"\"); } continue; } const ck = `attr:${k}`; if (k === \"class\" && v) { for (const c of v) { if (isAttr) track(id, `${ck}:${c}`, () => $el.classList.remove(c)); if (!$el.classList.contains(c)) $el.classList.add(c); } } else if (k === \"style\" && v) { for (const [sk, sv] of v) { track(id, `${ck}:${sk}`, () => $el.style.removeProperty(sk)); $el.style.setProperty(sk, sv); } } else if (v !== false && v !== null) { if ($el.getAttribute(k) !== v) $el.setAttribute(k, v === true ? \"\" : String(v)); if (isAttr) track(id, ck, () => $el.removeAttribute(k)); } } } const pending = []; const frag = {}; const rawTags = resolveTags(head, options.tagWeight ? { tagWeight: options.tagWeight } : void 0); const tags = []; const dupeKeyCounter = new Map(); for (const tag of rawTags) { const count = dupeKeyCounter.get(tag._d) || 0; const id = (count ? `${tag._d}:${count}` : tag._d) || tag._h; const ctx = { tag, id, shouldRender: true }; if (tag._d && isMetaArrayDupeKey(tag._d)) dupeKeyCounter.set(tag._d, count + 1); tags.push(ctx); if (tag.tag === \"title\") { dom.title = tag.textContent; track(\"title\", \"\", () => dom.title = state._t); continue; } ctx.$el = state._e.get(id); if (ctx.$el) trackCtx(ctx); else if (HasElementTags.has(tag.tag)) pending.push(ctx); } for (const ctx of pending) { ctx.$el = dom.createElement(ctx.tag.tag); trackCtx(ctx); (frag[ctx.tag.tagPosition || \"head\"] ??= dom.createDocumentFragment()).appendChild(ctx.$el); } if (frag.head) dom.head.appendChild(frag.head); if (frag.bodyOpen) dom.body.insertBefore(frag.bodyOpen, dom.body.firstChild); if (frag.bodyClose) dom.body.appendChild(frag.bodyClose); for (const k in state._p) state._p[k](); head._dom = state; callHook(head, \"dom:rendered\", { renders: tags }); head._du = false; head.dirty = false; return true; } function registerPlugin(head, p) { const plugin = typeof p === \"function\" ? p(head) : p; const key = plugin.key || String(head.plugins.size + 1); if (!head.plugins.get(key)) { head.plugins.set(key, plugin); for (const k in plugin.hooks || {}) head.hooks?.hook(k, plugin.hooks[k]); } } function createUnhead(renderer, resolvedOptions = {}) { const ssr = !resolvedOptions.document; const entries = new Map(); const plugins = new Map(); const head = { _entryCount: 1, plugins, resolvedOptions, ssr, entries, render: () => renderer(head), use: (p) => registerPlugin(head, p), push(input, _options) { const _i = _options?._index ?? head._entryCount++; const options = _options ? { ..._options } : {}; delete options.head; delete options.onRendered; const entry = { _i, input, options }; entries.set(_i, entry); const active = { _i, dispose() { entries.delete(_i); }, patch(input2) { if (ssr) { entry.input = input2; delete entry._tags; } else { entry._pending = input2; } if (!entries.has(_i)) entries.set(_i, entry); } }; return active; } }; resolvedOptions.init?.forEach((e) => e && head.push(e)); return head; } const DEFAULT_STREAM_KEY = \"__unhead__\"; function init(options = {}) { const { streamKey = DEFAULT_STREAM_KEY } = options; const win = typeof window !== \"undefined\" ? window : void 0; if (!win) return; const queue = win[streamKey]; if (queue?._head) return queue._head; const doc = typeof document !== \"undefined\" ? document : void 0; const head = createUnhead(createDomRenderer(), { document: doc }); let hydrationLocked = true; queueMicrotask(() => { hydrationLocked = false; }); function pushStreamed(entry) { const active = head.push(entry); const stored = head.entries.get(active._i); if (stored) stored._streamed = true; } if (queue?._q) { for (const entries of queue._q) { for (const entry of entries) { pushStreamed(entry); } } head.dirty = true; head.render(); } win[streamKey] = { _q: queue?._q || [], _head: head, _hydrationLocked: () => hydrationLocked, push: (entries) => { for (const entry of entries) { pushStreamed(entry); } head.dirty = true; head.render(); } }; return head; } init(); exports.init = init; return exports; })({});";
|
|
2
|
-
export const streamingIifeSize =
|
|
1
|
+
export const streamingIifeCode = "var __unhead_iife__ = (function (exports) { 'use strict'; const DupeableTags = new Set([\"link\", \"style\", \"script\", \"noscript\"]); const TagsWithInnerContent = new Set([\"title\", \"titleTemplate\", \"script\", \"style\", \"noscript\"]); const HasElementTags = new Set([\"base\", \"meta\", \"link\", \"style\", \"script\", \"noscript\"]); const ValidHeadTags = new Set([\"title\", \"base\", \"htmlAttrs\", \"bodyAttrs\", \"meta\", \"link\", \"style\", \"script\", \"noscript\"]); const UniqueTags = new Set([\"base\", \"title\", \"titleTemplate\", \"bodyAttrs\", \"htmlAttrs\", \"templateParams\"]); const TagConfigKeys = new Set([\"key\", \"tagPosition\", \"tagPriority\", \"tagDuplicateStrategy\", \"innerHTML\", \"textContent\", \"processTemplateParams\"]); const UsesMergeStrategy = new Set([\"templateParams\", \"htmlAttrs\", \"bodyAttrs\"]); const MetaTagsArrayable = new Set([ \"theme-color\", \"google-site-verification\", \"og\", \"article\", \"book\", \"profile\", \"twitter\", \"author\" ]); function isUnsafeKey(key) { return key === \"__proto__\" || key === \"constructor\" || key === \"prototype\"; } function callHook(head, hook, ctx) { const hooks = head.hooks?._hooks?.[hook]; if (!hooks?.length) return; return head.hooks?.callHook(hook, ctx); } const META_NOREWRITE_RE = /^(?:viewport|description|keywords|robots)$/; const META_KEY_ATTRS = [\"name\", \"property\", \"http-equiv\"]; function isMetaArrayDupeKey(v) { const i = v.indexOf(\":\"); if (i === -1) return false; const j = v.indexOf(\":\", i + 1); return MetaTagsArrayable.has(v.slice(i + 1, j === -1 ? v.length : j)); } function dedupeKey(tag) { const { props, tag: t, key } = tag; if (UniqueTags.has(t)) return t; if (t === \"link\" && props.rel === \"canonical\") return \"canonical\"; if (t === \"link\" && props.rel === \"alternate\") { if (props.hreflang) return `alternate:${props.hreflang}`; if (props.type) return `alternate:${props.type}:${props.href || \"\"}`; } if (props.charset) return \"charset\"; if (t === \"meta\") { for (const n of META_KEY_ATTRS) { const v = props[n]; if (v !== void 0) return `meta:${v}${(typeof v !== \"string\" || !v.includes(\":\")) && !META_NOREWRITE_RE.test(v) && key ? `:key:${key}` : \"\"}`; } } if (key) return `${t}:key:${key}`; if (props.id) return `${t}:id:${props.id}`; if (t === \"link\" && props.rel === \"alternate\") return `alternate:${props.href || \"\"}`; return TagsWithInnerContent.has(t) && (tag.textContent || tag.innerHTML) ? `${t}:content:${tag.textContent || tag.innerHTML}` : void 0; } function hashTag(tag) { const identity = tag._h || tag._d || tag.textContent || tag.innerHTML; if (identity) return identity; let hash = `${tag.tag}:`; let separator = \"\"; for (const key in tag.props) { if (Object.hasOwn(tag.props, key)) { hash += `${separator}${key}:${String(tag.props[key])}`; separator = \",\"; } } return hash; } function walkResolver(val, resolve, key) { if (key === \"_resolver\") return val; if (typeof val === \"function\" && (!key || key !== \"titleTemplate\" && !key.startsWith(\"on\"))) val = val(); const v = resolve ? resolve(key, val) : val; if (Array.isArray(v)) { let out; for (let i = 0; i < v.length; i++) { const r = walkResolver(v[i], resolve); if (out) { out[i] = r; } else if (r !== v[i]) { out = v.slice(0, i); out[i] = r; } } return out || v; } if (v?.constructor === Object) { let next; for (const k in v) { const unsafe = isUnsafeKey(k); const r = unsafe ? void 0 : walkResolver(v[k], resolve, k); if (!next && (unsafe || r !== v[k])) { next = {}; for (const pk in v) { if (pk === k) break; next[pk] = v[pk]; } } if (next && !unsafe) next[k] = r; } return next || v; } return v; } const INVALID_ATTR_NAME_RE = /[\\s\"'<>/=\\x00-\\x1F\\x7F]/; function normalizeStyleClassProps(key, value) { const isStyle = key === \"style\"; const store = isStyle ? new Map() : new Set(); const add = (v) => { if (!v) return; if (isStyle) { const i = v.indexOf(\":\"); i > 0 && store.set(v.slice(0, i).trim(), v.slice(i + 1).trim()); } else { v.split(\" \").forEach((c) => c && store.add(c)); } }; if (typeof value === \"string\") { (isStyle ? value.split(\";\") : [value]).forEach(add); } else if (Array.isArray(value)) { value.forEach(add); } else if (value && typeof value === \"object\") { for (const k in value) { const v = value[k]; v && v !== \"false\" && (isStyle ? store.set(k.trim(), String(v)) : add(k)); } } return store; } function normalizeProps(tag, input) { tag.props = tag.props || {}; if (!input) return tag; if (tag.tag === \"templateParams\") { tag.props = input; return tag; } const isHtmlTag = HasElementTags.has(tag.tag) || tag.tag === \"htmlAttrs\" || tag.tag === \"bodyAttrs\"; for (const prop in input) { if (isUnsafeKey(prop)) continue; const isData = prop.startsWith(\"data-\"); const isHtmlAttr = isHtmlTag && !TagConfigKeys.has(prop); const key = isHtmlAttr && !isData ? prop.toLowerCase() : prop; if (isHtmlAttr && (!key || INVALID_ATTR_NAME_RE.test(key))) continue; const value = input[prop]; if (value === null) { tag.props[key] = null; } else if (prop === \"class\" || prop === \"style\") { tag.props[prop] = normalizeStyleClassProps(prop, value); } else if (TagConfigKeys.has(prop)) { if ((prop === \"textContent\" || prop === \"innerHTML\") && typeof value === \"object\") { const type = input.type || \"application/json\"; if (type.endsWith(\"json\") || type === \"speculationrules\" || type === \"importmap\") { tag.props.type = input.type = type; tag[prop] = JSON.stringify(value); } } else { tag[prop] = value; } } else if (value !== void 0) { const str = String(value); const isMeta = tag.tag === \"meta\" && key === \"content\"; tag.props[key] = str === \"true\" || str === \"\" ? isData || isMeta ? str : true : !value && isData && str === \"false\" ? \"false\" : value; } } return tag; } function normalizeTag(tagName, _input) { const input = typeof _input === \"object\" && typeof _input !== \"function\" ? _input : { [tagName === \"script\" || tagName === \"noscript\" || tagName === \"style\" ? \"innerHTML\" : \"textContent\"]: _input }; const tag = normalizeProps({ tag: tagName, props: {} }, input); if (tag.key && DupeableTags.has(tag.tag)) tag.props[\"data-hid\"] = tag._h = tag.key; if (tag.tag === \"script\" && typeof tag.innerHTML === \"object\") { tag.innerHTML = JSON.stringify(tag.innerHTML); tag.props.type = tag.props.type || \"application/json\"; } if (Array.isArray(tag.props.content)) { const tags = []; for (const content of tag.props.content) { tags.push({ ...tag, props: { ...tag.props, content } }); } return tags; } return tag; } function pushNormalizedTag(tags, tag) { if (Array.isArray(tag)) { for (const t of tag) tags.push(t); } else { tags.push(tag); } } function normalizeEntryToTags(input, propResolvers) { if (!input) return []; if (typeof input === \"function\") input = input(); let resolve; if (propResolvers.length) { resolve = (key, val) => { for (let i = 0; i < propResolvers.length; i++) val = propResolvers[i](key, val); return val; }; input = resolve(void 0, input); } input = walkResolver(input, resolve); const tags = []; for (const key in input) { const value = input[key]; if (value !== void 0) { if (Array.isArray(value)) { for (const v of value) pushNormalizedTag(tags, normalizeTag(key, v)); } else { pushNormalizedTag(tags, normalizeTag(key, value)); } } } return tags; } const LT_RE = /</g; const SCRIPT_END_RE = /<\\/script/g; const sortTags = (a, b) => a._w === b._w ? a._p - b._p : a._w - b._w; const DEFAULT_TAG_WEIGHT = () => 100; function isEmptyProps(props) { for (const _ in props) return false; return true; } const TAG_MUTATING_HOOK_RE = /^tags:|:render/; function pushEntryTags(ctx, entries, needsClone) { for (const tags of entries) { for (const t of tags) { if (needsClone) { const props = { ...t.props }; if (props.class instanceof Set) props.class = new Set(props.class); if (props.style instanceof Map) props.style = new Map(props.style); ctx.tags.push({ ...t, props }); } else { ctx.tags.push(t); } } } } function valuesToTags(ctx, sortFlatMeta) { ctx.tags = []; for (const value of ctx.tagMap.values()) { if (Array.isArray(value)) { for (const tag of value) ctx.tags.push(tag); } else { ctx.tags.push(value); } } if (sortFlatMeta) ctx.tags.sort(sortTags); } function dedupeTags(ctx) { let hasFlatMeta = false; for (const next of ctx.tags.sort(sortTags)) { const k = next._d || hashTag(next); if (!k) continue; const prev = ctx.tagMap.get(k); if (!prev) { ctx.tagMap.set(k, next); continue; } const strategy = next.tagDuplicateStrategy || (UsesMergeStrategy.has(next.tag) ? \"merge\" : null) || (next.key && next.key === prev.key ? \"merge\" : null); if (strategy === \"merge\") { const props = { ...prev.props }; for (const p in next.props) { props[p] = p === \"style\" ? new Map([...prev.props.style || new Map(), ...next.props[p]]) : p === \"class\" ? new Set([...prev.props.class || [], ...next.props[p]]) : next.props[p]; } ctx.tagMap.set(k, { ...next, props }); } else if (next._p >> 10 === prev._p >> 10 && next.tag === \"meta\" && isMetaArrayDupeKey(k)) { ctx.tagMap.set(k, Object.assign([...Array.isArray(prev) ? prev : [prev], next], next)); hasFlatMeta = true; } else if (next._w === prev._w ? next._p > prev._p : next._w < prev._w) { ctx.tagMap.set(k, next); } } return hasFlatMeta; } function resolveTitleTemplate(ctx, head) { const title = ctx.tagMap.get(\"title\"); const tpl = ctx.tagMap.get(\"titleTemplate\"); head._title = title?.textContent; if (!tpl) return; const fn = tpl.textContent; head._titleTemplate = fn; if (!fn) return; let v = typeof fn === \"function\" ? fn(title?.textContent) : fn; if (typeof v === \"string\" && !head.plugins.has(\"template-params\")) v = v.replace(\"%s\", title?.textContent || \"\"); if (title) { v === null ? ctx.tagMap.delete(\"title\") : ctx.tagMap.set(\"title\", { ...title, textContent: v }); } else { ctx.tagMap.set(\"titleTemplate\", { ...tpl, tag: \"title\", textContent: v }); } } function sanitizeTags(tags) { const out = []; for (let t of tags) { const { innerHTML, tag, props } = t; if (!ValidHeadTags.has(tag) || isEmptyProps(props) && !innerHTML && !t.textContent) continue; if (tag === \"meta\" && !props.content && !props[\"http-equiv\"] && !props.charset) continue; if (tag === \"script\" && (innerHTML || t.textContent)) { const type = String(props.type); const isJsonLike = type.endsWith(\"json\") || type === \"importmap\" || type === \"speculationrules\"; const escape = (content) => isJsonLike ? (typeof content === \"string\" ? content : JSON.stringify(content)).replace(LT_RE, \"\\\\u003C\") : typeof content === \"string\" ? content.replace(SCRIPT_END_RE, \"<\\\\/script\") : content; t = { ...t }; if (innerHTML) t.innerHTML = escape(innerHTML); if (t.textContent) t.textContent = escape(t.textContent); t._d = dedupeKey(t); } out.push(t); } return out; } function resolveTags(head, options) { const weightFn = options?.tagWeight ?? head.resolvedOptions._tagWeight ?? DEFAULT_TAG_WEIGHT; const ctx = { tagMap: new Map(), tags: [] }; const hooks = head.hooks?._hooks || {}; const entries = [...head.entries.values()]; for (const e of entries) { if (e._pending !== void 0) { e.input = e._pending; delete e._pending; delete e._tags; } } callHook(head, \"entries:resolve\", { entries, ...ctx }); const entryTags = []; for (const e of entries) { if (!e._tags) { const tags = normalizeEntryToTags(e.input, head.resolvedOptions.propResolvers || []); for (const t of tags) Object.assign(t, e.options); const normalizeCtx = { tags, entry: e }; callHook(head, \"entries:normalize\", normalizeCtx); for (let i = 0; i < normalizeCtx.tags.length; i++) { const t = normalizeCtx.tags[i]; t._w = weightFn(t); t._p = (e._i << 10) + i; t._d = dedupeKey(t); if (!t._d) t._h = hashTag(t); } e._tags = normalizeCtx.tags; } entryTags.push(e._tags); } let needsClone = false; for (const k in hooks) { if (TAG_MUTATING_HOOK_RE.test(k) && hooks[k]?.some((f) => !f._nonMutating)) { needsClone = true; break; } } pushEntryTags(ctx, entryTags, needsClone); const hasFlatMeta = dedupeTags(ctx); resolveTitleTemplate(ctx, head); valuesToTags(ctx, hasFlatMeta); callHook(head, \"tags:beforeResolve\", ctx); callHook(head, \"tags:resolve\", ctx); callHook(head, \"tags:afterResolve\", ctx); return sanitizeTags(ctx.tags); } const WHITESPACE_RE = /\\s+/; function createDomRenderer(options = {}) { return (head) => _renderDOMHead(head, options); } function hasPendingEntries(head) { for (const entry of head.entries.values()) { if (entry._pending !== void 0) return true; } return false; } function cleanupDomState(state) { for (const k in state._s) state._s[k](); for (const k in state._p) state._p[k](); state._s = {}; state._p = {}; state._e.clear(); state._l.clear(); } function createDomState(head, dom) { const state = { _d: dom, _t: dom.title, _e: new Map([[\"htmlAttrs\", dom.documentElement], [\"bodyAttrs\", dom.body]]), _p: {}, _s: {}, _l: new Map() }; for (const el of [...dom.body.children, ...dom.head.children]) { const tag = el.tagName.toLowerCase(); if (!HasElementTags.has(tag)) continue; const props = { innerHTML: el.innerHTML }; for (const n of el.getAttributeNames()) props[n] = el.getAttribute(n); const next = normalizeProps({ tag, props: {} }, props); next.key = el.getAttribute(\"data-hid\") || void 0; const dedupe = dedupeKey(next) || hashTag(next); let k = dedupe; let c = 1; while (state._e.has(k)) k = `${dedupe}:${c++}`; state._e.set(k, el); } for (const entry of head.entries.values()) { if (entry._o !== void 0) { const orig = entry._o; for (const t of [\"bodyAttrs\", \"htmlAttrs\"]) { const cls = orig[t]?.class; if (typeof cls === \"string\") { const $el = state._e.get(t); for (const c of cls.split(WHITESPACE_RE)) { if (c) state._p[`${t}:attr:class:${c}`] = () => $el.classList.remove(c); } } } } } return state; } function _renderDOMHead(head, options = {}) { const dom = options.document || head.resolvedOptions.document; const activeState = head._dom; const documentChanged = !!activeState && activeState._d !== dom; if (!dom || !documentChanged && !head.dirty && !hasPendingEntries(head)) return false; if (head._du) return false; const defaultView = dom.defaultView; head._du = true; let didRender = false; try { let track = function(id, scope, fn, fresh) { const k = `${id}:${scope}`; renderState._s[k] = !fresh && renderState._p[k] || fn; delete renderState._p[k]; }, reclaim = function(key) { const prev = renderState._p[key]; delete renderState._p[key]; return prev; }, trackEvent = function(id, k, ev, source, $el, target) { const scope = `event:${k}`; const key = `${id}:${scope}`; const prev = renderState._l.get(key); if (prev && prev[0] === target && prev[1] === ev && prev[2] === source) { track(id, scope, prev[4]); return; } prev?.[4](); const dk = `data-${k}`; const handler = ((e) => source.call($el, e)); const cleanup = () => { target.removeEventListener(ev, handler); if ($el.getAttribute(dk) === \"\") $el.removeAttribute(dk); if (renderState._l.get(key)?.[3] === handler) renderState._l.delete(key); }; target.addEventListener(ev, handler); renderState._l.set(key, [target, ev, source, handler, cleanup]); $el.setAttribute(dk, \"\"); track(id, scope, cleanup, true); }, trackCtx = function({ id, $el, tag }) { const isAttr = tag.tag.endsWith(\"Attrs\"); renderState._e.set(id, $el); if (!isAttr) { const text = tag.textContent; if (text != null && text !== \"\") { if (text !== $el.textContent) $el.textContent = text; track(id, \"text\", () => { if ($el.textContent === text) $el.textContent = \"\"; }, true); } const html = tag.innerHTML; if (html != null && html !== \"\") { if (html !== $el.innerHTML) $el.innerHTML = html; track(id, \"html\", () => { if ($el.innerHTML === html) $el.innerHTML = \"\"; }, true); } const elKey = `${id}:el`; renderState._s[elKey] = reclaim(elKey) || (() => { $el?.remove(); renderState._e.delete(id); }); } for (const k in tag.props) { const v = tag.props[k]; if (k[0] === \"o\" && k[1] === \"n\" && typeof v === \"function\") { const ev = k.slice(2); if ($el?.dataset?.[`${k}fired`]) v.call($el, new (defaultView?.Event || Event)(ev)); trackEvent(id, k, ev, v, $el, tag.tag === \"bodyAttrs\" && defaultView ? defaultView : $el); continue; } const ck = `${id}:attr:${k}`; if (k === \"class\" && v) { for (const c of v) { const key = `${ck}:${c}`; renderState._s[key] = reclaim(key) || (() => $el.classList.remove(c)); if (!$el.classList.contains(c)) $el.classList.add(c); } } else if (k === \"style\" && v) { for (const [sk, sv] of v) { const key = `${ck}:${sk}`; renderState._s[key] = reclaim(key) || (() => $el.style.removeProperty(sk)); $el.style.setProperty(sk, sv); } } else if (v !== false && v !== null) { if ($el.getAttribute(k) !== v) $el.setAttribute(k, v === true ? \"\" : String(v)); renderState._s[ck] = reclaim(ck) || (() => $el.removeAttribute(k)); } } }; const beforeRenderCtx = { shouldRender: true, tags: [] }; callHook(head, \"dom:beforeRender\", beforeRenderCtx); if (!beforeRenderCtx.shouldRender) return false; let state = head._dom; if (state?._d !== dom) { if (state) cleanupDomState(state); state = void 0; } if (!state) { state = createDomState(head, dom); } else { state._p = state._s; } state._s = {}; const renderState = state; const pending = []; const frag = {}; head.dirty = false; const rawTags = resolveTags(head, options.tagWeight ? { tagWeight: options.tagWeight } : void 0); const tags = []; const dupeKeyCounter = {}; for (const tag of rawTags) { const count = dupeKeyCounter[tag._d] || 0; const id = (count ? `${tag._d}:${count}` : tag._d) || tag._h; const ctx = { tag, id, shouldRender: true }; if (tag._d && isMetaArrayDupeKey(tag._d)) dupeKeyCounter[tag._d] = count + 1; tags.push(ctx); if (tag.tag === \"title\") { dom.title = tag.textContent; track(\"title\", \"\", () => dom.title = renderState._t); continue; } ctx.$el = renderState._e.get(id); if (ctx.$el) trackCtx(ctx); else if (HasElementTags.has(tag.tag)) pending.push(ctx); } for (const ctx of pending) { ctx.$el = dom.createElement(ctx.tag.tag); trackCtx(ctx); (frag[ctx.tag.tagPosition || \"head\"] ??= dom.createDocumentFragment()).appendChild(ctx.$el); } if (frag.head) dom.head.appendChild(frag.head); if (frag.bodyOpen) dom.body.insertBefore(frag.bodyOpen, dom.body.firstChild); if (frag.bodyClose) dom.body.appendChild(frag.bodyClose); for (const k in renderState._p) renderState._p[k](); head._dom = renderState; didRender = true; callHook(head, \"dom:rendered\", { renders: tags }); } catch (e) { head.dirty = true; throw e; } finally { head._du = false; } if (didRender && (head.dirty || hasPendingEntries(head))) _renderDOMHead(head, options); return didRender; } function registerPlugin(head, p) { if (typeof p === \"function\" && p.key && head.plugins.has(p.key)) return; const plugin = typeof p === \"function\" ? p(head) : p; const key = plugin.key || String(head.plugins.size + 1); if (!head.plugins.get(key)) { head.plugins.set(key, plugin); for (const k in plugin.hooks || {}) head.hooks?.hook(k, plugin.hooks[k]); } } function createUnhead(renderer, resolvedOptions = {}) { const ssr = !resolvedOptions.document; const entries = new Map(); const plugins = new Map(); const head = { _entryCount: 1, plugins, resolvedOptions, ssr, entries, render: () => renderer(head), use: (p) => registerPlugin(head, p), push(input, _options) { const _i = _options?._index ?? head._entryCount++; const options = _options ? { ..._options } : {}; delete options.head; delete options.onRendered; const entry = { _i, input, options }; entries.set(_i, entry); const active = { _i, dispose() { entries.delete(_i); }, patch(input2) { if (ssr) { entry.input = input2; delete entry._tags; } else { entry._pending = input2; } if (!entries.has(_i)) entries.set(_i, entry); } }; return active; } }; resolvedOptions.init?.forEach((e) => e && head.push(e)); return head; } const DEFAULT_STREAM_KEY = \"__unhead__\"; function init(options = {}) { const { streamKey = DEFAULT_STREAM_KEY } = options; const win = typeof window !== \"undefined\" ? window : void 0; if (!win) return; const queue = win[streamKey]; if (queue?._head) return queue._head; const doc = typeof document !== \"undefined\" ? document : void 0; const head = createUnhead(createDomRenderer(), { document: doc }); let hydrationLocked = true; queueMicrotask(() => { hydrationLocked = false; }); function pushStreamed(entry) { const active = head.push(entry); const stored = head.entries.get(active._i); if (stored) stored._streamed = true; } if (queue?._q) { for (const entries of queue._q) { for (const entry of entries) { pushStreamed(entry); } } head.dirty = true; head.render(); } win[streamKey] = { _q: queue?._q || [], _head: head, _hydrationLocked: () => hydrationLocked, push: (entries) => { for (const entry of entries) { pushStreamed(entry); } head.dirty = true; head.render(); } }; return head; } exports.init = init; return exports; })({});__unhead_iife__.init();";
|
|
2
|
+
export const streamingIifeSize = 20484;
|
package/dist/stream/server.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as ServerUnhead } from '../shared/unhead.
|
|
2
|
-
import { e as CreateStreamableServerHeadOptions, U as Unhead, S as SSRHeadPayload } from '../shared/unhead.
|
|
1
|
+
import { S as ServerUnhead } from '../shared/unhead.Bx2bAQEg.mjs';
|
|
2
|
+
import { e as CreateStreamableServerHeadOptions, U as Unhead, S as SSRHeadPayload } from '../shared/unhead.CELAVVhh.mjs';
|
|
3
3
|
import { R as ResolvableHead } from '../shared/unhead.Dl7UHSN0.mjs';
|
|
4
4
|
import 'hookable';
|
|
5
5
|
|
package/dist/stream/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as ServerUnhead } from '../shared/unhead.
|
|
2
|
-
import { e as CreateStreamableServerHeadOptions, U as Unhead, S as SSRHeadPayload } from '../shared/unhead.
|
|
1
|
+
import { S as ServerUnhead } from '../shared/unhead.DQadHCLi.js';
|
|
2
|
+
import { e as CreateStreamableServerHeadOptions, U as Unhead, S as SSRHeadPayload } from '../shared/unhead.Dv-MkoX9.js';
|
|
3
3
|
import { R as ResolvableHead } from '../shared/unhead.Dl7UHSN0.js';
|
|
4
4
|
import 'hookable';
|
|
5
5
|
|