@unhead/vue 1.0.21 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +24 -941
- package/dist/index.d.ts +3 -11
- package/dist/index.mjs +7 -922
- package/package.json +9 -8
package/dist/index.mjs
CHANGED
|
@@ -1,738 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getActiveHead, createHead as createHead$1, unpackMeta, composableNames } from 'unhead';
|
|
2
|
+
export { createHeadCore } from 'unhead';
|
|
2
3
|
import { unref, isRef, version, getCurrentInstance, inject, nextTick, ref, watchEffect, watch, onBeforeUnmount, onDeactivated, onActivated } from 'vue';
|
|
3
|
-
|
|
4
|
-
const TagsWithInnerContent = ["script", "style", "noscript"];
|
|
5
|
-
const HasElementTags$1 = [
|
|
6
|
-
"base",
|
|
7
|
-
"meta",
|
|
8
|
-
"link",
|
|
9
|
-
"style",
|
|
10
|
-
"script",
|
|
11
|
-
"noscript"
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
const UniqueTags$1 = ["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"];
|
|
15
|
-
function tagDedupeKey$1(tag, fn) {
|
|
16
|
-
const { props, tag: tagName } = tag;
|
|
17
|
-
if (UniqueTags$1.includes(tagName))
|
|
18
|
-
return tagName;
|
|
19
|
-
if (tagName === "link" && props.rel === "canonical")
|
|
20
|
-
return "canonical";
|
|
21
|
-
if (props.charset)
|
|
22
|
-
return "charset";
|
|
23
|
-
const name = ["id"];
|
|
24
|
-
if (tagName === "meta")
|
|
25
|
-
name.push(...["name", "property", "http-equiv"]);
|
|
26
|
-
for (const n of name) {
|
|
27
|
-
if (typeof props[n] !== "undefined") {
|
|
28
|
-
const val = String(props[n]);
|
|
29
|
-
if (fn && !fn(val))
|
|
30
|
-
return false;
|
|
31
|
-
return `${tagName}:${n}:${val}`;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const setAttrs = (ctx, markSideEffect) => {
|
|
38
|
-
const { tag, $el } = ctx;
|
|
39
|
-
if (!$el)
|
|
40
|
-
return;
|
|
41
|
-
Object.entries(tag.props).forEach(([k, value]) => {
|
|
42
|
-
value = String(value);
|
|
43
|
-
const attrSdeKey = `attr:${k}`;
|
|
44
|
-
if (k === "class") {
|
|
45
|
-
if (!value)
|
|
46
|
-
return;
|
|
47
|
-
for (const c of value.split(" ")) {
|
|
48
|
-
const classSdeKey = `${attrSdeKey}:${c}`;
|
|
49
|
-
if (markSideEffect)
|
|
50
|
-
markSideEffect(ctx, classSdeKey, () => $el.classList.remove(c));
|
|
51
|
-
if (!$el.classList.contains(c))
|
|
52
|
-
$el.classList.add(c);
|
|
53
|
-
}
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
if (markSideEffect && !k.startsWith("data-h-"))
|
|
57
|
-
markSideEffect(ctx, attrSdeKey, () => $el.removeAttribute(k));
|
|
58
|
-
if ($el.getAttribute(k) !== value)
|
|
59
|
-
$el.setAttribute(k, value);
|
|
60
|
-
});
|
|
61
|
-
if (TagsWithInnerContent.includes(tag.tag) && $el.innerHTML !== (tag.children || ""))
|
|
62
|
-
$el.innerHTML = tag.children || "";
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
function hashCode(s) {
|
|
66
|
-
let h = 9;
|
|
67
|
-
for (let i = 0; i < s.length; )
|
|
68
|
-
h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
|
|
69
|
-
return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 8).toLowerCase();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function renderDOMHead(head, options = {}) {
|
|
73
|
-
const ctx = { shouldRender: true };
|
|
74
|
-
await head.hooks.callHook("dom:beforeRender", ctx);
|
|
75
|
-
if (!ctx.shouldRender)
|
|
76
|
-
return;
|
|
77
|
-
const dom = options.document || window.document;
|
|
78
|
-
const staleSideEffects = head._popSideEffectQueue();
|
|
79
|
-
head.headEntries().map((entry) => entry._sde).forEach((sde) => {
|
|
80
|
-
Object.entries(sde).forEach(([key, fn]) => {
|
|
81
|
-
staleSideEffects[key] = fn;
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
const preRenderTag = async (tag) => {
|
|
85
|
-
const entry = head.headEntries().find((e) => e._i === tag._e);
|
|
86
|
-
const renderCtx = {
|
|
87
|
-
renderId: tag._d || hashCode(JSON.stringify({ ...tag, _e: void 0, _p: void 0 })),
|
|
88
|
-
$el: null,
|
|
89
|
-
shouldRender: true,
|
|
90
|
-
tag,
|
|
91
|
-
entry,
|
|
92
|
-
staleSideEffects
|
|
93
|
-
};
|
|
94
|
-
await head.hooks.callHook("dom:beforeRenderTag", renderCtx);
|
|
95
|
-
return renderCtx;
|
|
96
|
-
};
|
|
97
|
-
const renders = [];
|
|
98
|
-
const pendingRenders = {
|
|
99
|
-
body: [],
|
|
100
|
-
head: []
|
|
101
|
-
};
|
|
102
|
-
const markSideEffect = (ctx2, key, fn) => {
|
|
103
|
-
key = `${ctx2.renderId}:${key}`;
|
|
104
|
-
if (ctx2.entry)
|
|
105
|
-
ctx2.entry._sde[key] = fn;
|
|
106
|
-
delete staleSideEffects[key];
|
|
107
|
-
};
|
|
108
|
-
const markEl = (ctx2) => {
|
|
109
|
-
head._elMap[ctx2.renderId] = ctx2.$el;
|
|
110
|
-
renders.push(ctx2);
|
|
111
|
-
markSideEffect(ctx2, "el", () => {
|
|
112
|
-
ctx2.$el?.remove();
|
|
113
|
-
delete head._elMap[ctx2.renderId];
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
for (const t of await head.resolveTags()) {
|
|
117
|
-
const ctx2 = await preRenderTag(t);
|
|
118
|
-
if (!ctx2.shouldRender)
|
|
119
|
-
continue;
|
|
120
|
-
const { tag } = ctx2;
|
|
121
|
-
if (tag.tag === "title") {
|
|
122
|
-
dom.title = tag.children || "";
|
|
123
|
-
renders.push(ctx2);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
if (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs") {
|
|
127
|
-
ctx2.$el = dom[tag.tag === "htmlAttrs" ? "documentElement" : "body"];
|
|
128
|
-
setAttrs(ctx2, markSideEffect);
|
|
129
|
-
renders.push(ctx2);
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
ctx2.$el = head._elMap[ctx2.renderId];
|
|
133
|
-
if (!ctx2.$el && tag._hash) {
|
|
134
|
-
ctx2.$el = dom.querySelector(`${tag.tagPosition?.startsWith("body") ? "body" : "head"} > ${tag.tag}[data-h-${tag._hash}]`);
|
|
135
|
-
}
|
|
136
|
-
if (ctx2.$el) {
|
|
137
|
-
if (ctx2.tag._d)
|
|
138
|
-
setAttrs(ctx2);
|
|
139
|
-
markEl(ctx2);
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
ctx2.$el = dom.createElement(tag.tag);
|
|
143
|
-
setAttrs(ctx2);
|
|
144
|
-
pendingRenders[tag.tagPosition?.startsWith("body") ? "body" : "head"].push(ctx2);
|
|
145
|
-
}
|
|
146
|
-
Object.entries(pendingRenders).forEach(([pos, queue]) => {
|
|
147
|
-
if (!queue.length)
|
|
148
|
-
return;
|
|
149
|
-
const children = dom?.[pos]?.children;
|
|
150
|
-
if (!children)
|
|
151
|
-
return;
|
|
152
|
-
for (const $el of [...children].reverse()) {
|
|
153
|
-
const elTag = $el.tagName.toLowerCase();
|
|
154
|
-
if (!HasElementTags$1.includes(elTag))
|
|
155
|
-
continue;
|
|
156
|
-
const dedupeKey = tagDedupeKey$1({
|
|
157
|
-
tag: elTag,
|
|
158
|
-
// convert attributes to object
|
|
159
|
-
props: $el.getAttributeNames().reduce((props, name) => ({ ...props, [name]: $el.getAttribute(name) }), {})
|
|
160
|
-
});
|
|
161
|
-
const matchIdx = queue.findIndex((ctx2) => ctx2 && (ctx2.tag._d === dedupeKey || $el.isEqualNode?.(ctx2.$el)));
|
|
162
|
-
if (matchIdx !== -1) {
|
|
163
|
-
const ctx2 = queue[matchIdx];
|
|
164
|
-
ctx2.$el = $el;
|
|
165
|
-
setAttrs(ctx2);
|
|
166
|
-
markEl(ctx2);
|
|
167
|
-
delete queue[matchIdx];
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
queue.forEach((ctx2) => {
|
|
171
|
-
if (!ctx2.$el)
|
|
172
|
-
return;
|
|
173
|
-
switch (ctx2.tag.tagPosition) {
|
|
174
|
-
case "bodyClose":
|
|
175
|
-
dom.body.appendChild(ctx2.$el);
|
|
176
|
-
break;
|
|
177
|
-
case "bodyOpen":
|
|
178
|
-
dom.body.insertBefore(ctx2.$el, dom.body.firstChild);
|
|
179
|
-
break;
|
|
180
|
-
case "head":
|
|
181
|
-
default:
|
|
182
|
-
dom.head.appendChild(ctx2.$el);
|
|
183
|
-
break;
|
|
184
|
-
}
|
|
185
|
-
markEl(ctx2);
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
for (const ctx2 of renders)
|
|
189
|
-
await head.hooks.callHook("dom:renderTag", ctx2);
|
|
190
|
-
Object.values(staleSideEffects).forEach((fn) => fn());
|
|
191
|
-
}
|
|
192
|
-
let domUpdatePromise = null;
|
|
193
|
-
async function debouncedRenderDOMHead(head, options = {}) {
|
|
194
|
-
function doDomUpdate() {
|
|
195
|
-
domUpdatePromise = null;
|
|
196
|
-
return renderDOMHead(head, options);
|
|
197
|
-
}
|
|
198
|
-
const delayFn = options.delayFn || ((fn) => setTimeout(fn, 10));
|
|
199
|
-
return domUpdatePromise = domUpdatePromise || new Promise((resolve) => delayFn(() => resolve(doDomUpdate())));
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const index = {
|
|
203
|
-
__proto__: null,
|
|
204
|
-
debouncedRenderDOMHead: debouncedRenderDOMHead,
|
|
205
|
-
get domUpdatePromise () { return domUpdatePromise; },
|
|
206
|
-
hashCode: hashCode,
|
|
207
|
-
renderDOMHead: renderDOMHead
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
const ValidHeadTags = [
|
|
211
|
-
"title",
|
|
212
|
-
"titleTemplate",
|
|
213
|
-
"base",
|
|
214
|
-
"htmlAttrs",
|
|
215
|
-
"bodyAttrs",
|
|
216
|
-
"meta",
|
|
217
|
-
"link",
|
|
218
|
-
"style",
|
|
219
|
-
"script",
|
|
220
|
-
"noscript"
|
|
221
|
-
];
|
|
222
|
-
const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
|
|
223
|
-
|
|
224
|
-
async function normaliseTag(tagName, input) {
|
|
225
|
-
const tag = { tag: tagName, props: {} };
|
|
226
|
-
if (tagName === "title" || tagName === "titleTemplate") {
|
|
227
|
-
tag.children = input instanceof Promise ? await input : input;
|
|
228
|
-
return tag;
|
|
229
|
-
}
|
|
230
|
-
tag.props = await normaliseProps({ ...input });
|
|
231
|
-
["children", "innerHtml", "innerHTML"].forEach((key) => {
|
|
232
|
-
if (typeof tag.props[key] !== "undefined") {
|
|
233
|
-
tag.children = tag.props[key];
|
|
234
|
-
if (typeof tag.children === "object")
|
|
235
|
-
tag.children = JSON.stringify(tag.children);
|
|
236
|
-
delete tag.props[key];
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
Object.keys(tag.props).filter((k) => TagConfigKeys.includes(k)).forEach((k) => {
|
|
240
|
-
tag[k] = tag.props[k];
|
|
241
|
-
delete tag.props[k];
|
|
242
|
-
});
|
|
243
|
-
if (typeof tag.props.class === "object" && !Array.isArray(tag.props.class)) {
|
|
244
|
-
tag.props.class = Object.keys(tag.props.class).filter((k) => tag.props.class[k]);
|
|
245
|
-
}
|
|
246
|
-
if (Array.isArray(tag.props.class))
|
|
247
|
-
tag.props.class = tag.props.class.join(" ");
|
|
248
|
-
if (tag.props.content && Array.isArray(tag.props.content)) {
|
|
249
|
-
return tag.props.content.map((v, i) => {
|
|
250
|
-
const newTag = { ...tag, props: { ...tag.props } };
|
|
251
|
-
newTag.props.content = v;
|
|
252
|
-
newTag.key = `${tag.props.name || tag.props.property}:${i}`;
|
|
253
|
-
return newTag;
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
return tag;
|
|
257
|
-
}
|
|
258
|
-
async function normaliseProps(props) {
|
|
259
|
-
for (const k of Object.keys(props)) {
|
|
260
|
-
if (props[k] instanceof Promise) {
|
|
261
|
-
props[k] = await props[k];
|
|
262
|
-
}
|
|
263
|
-
if (String(props[k]) === "true") {
|
|
264
|
-
props[k] = "";
|
|
265
|
-
} else if (String(props[k]) === "false") {
|
|
266
|
-
delete props[k];
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
return props;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const tagWeight = (tag) => {
|
|
273
|
-
if (typeof tag.tagPriority === "number")
|
|
274
|
-
return tag.tagPriority;
|
|
275
|
-
switch (tag.tagPriority) {
|
|
276
|
-
case "critical":
|
|
277
|
-
return 2;
|
|
278
|
-
case "high":
|
|
279
|
-
return 9;
|
|
280
|
-
case "low":
|
|
281
|
-
return 12;
|
|
282
|
-
}
|
|
283
|
-
switch (tag.tag) {
|
|
284
|
-
case "base":
|
|
285
|
-
return -1;
|
|
286
|
-
case "title":
|
|
287
|
-
return 1;
|
|
288
|
-
case "meta":
|
|
289
|
-
if (tag.props.charset)
|
|
290
|
-
return -2;
|
|
291
|
-
if (tag.props["http-equiv"] === "content-security-policy")
|
|
292
|
-
return 0;
|
|
293
|
-
return 10;
|
|
294
|
-
default:
|
|
295
|
-
return 10;
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
const sortTags = (aTag, bTag) => {
|
|
299
|
-
return tagWeight(aTag) - tagWeight(bTag);
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
const UniqueTags = ["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"];
|
|
303
|
-
function tagDedupeKey(tag, fn) {
|
|
304
|
-
const { props, tag: tagName } = tag;
|
|
305
|
-
if (UniqueTags.includes(tagName))
|
|
306
|
-
return tagName;
|
|
307
|
-
if (tagName === "link" && props.rel === "canonical")
|
|
308
|
-
return "canonical";
|
|
309
|
-
if (props.charset)
|
|
310
|
-
return "charset";
|
|
311
|
-
const name = ["id"];
|
|
312
|
-
if (tagName === "meta")
|
|
313
|
-
name.push(...["name", "property", "http-equiv"]);
|
|
314
|
-
for (const n of name) {
|
|
315
|
-
if (typeof props[n] !== "undefined") {
|
|
316
|
-
const val = String(props[n]);
|
|
317
|
-
if (fn && !fn(val))
|
|
318
|
-
return false;
|
|
319
|
-
return `${tagName}:${n}:${val}`;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return false;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const renderTitleTemplate = (template, title) => {
|
|
326
|
-
if (template == null)
|
|
327
|
-
return title || null;
|
|
328
|
-
if (typeof template === "function")
|
|
329
|
-
return template(title);
|
|
330
|
-
return template.replace("%s", title ?? "");
|
|
331
|
-
};
|
|
332
|
-
function resolveTitleTemplateFromTags(tags) {
|
|
333
|
-
let titleTemplateIdx = tags.findIndex((i) => i.tag === "titleTemplate");
|
|
334
|
-
const titleIdx = tags.findIndex((i) => i.tag === "title");
|
|
335
|
-
if (titleIdx !== -1 && titleTemplateIdx !== -1) {
|
|
336
|
-
const newTitle = renderTitleTemplate(
|
|
337
|
-
tags[titleTemplateIdx].children,
|
|
338
|
-
tags[titleIdx].children
|
|
339
|
-
);
|
|
340
|
-
if (newTitle !== null) {
|
|
341
|
-
tags[titleIdx].children = newTitle || tags[titleIdx].children;
|
|
342
|
-
} else {
|
|
343
|
-
delete tags[titleIdx];
|
|
344
|
-
}
|
|
345
|
-
} else if (titleTemplateIdx !== -1) {
|
|
346
|
-
const newTitle = renderTitleTemplate(
|
|
347
|
-
tags[titleTemplateIdx].children
|
|
348
|
-
);
|
|
349
|
-
if (newTitle !== null) {
|
|
350
|
-
tags[titleTemplateIdx].children = newTitle;
|
|
351
|
-
tags[titleTemplateIdx].tag = "title";
|
|
352
|
-
titleTemplateIdx = -1;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
if (titleTemplateIdx !== -1) {
|
|
356
|
-
delete tags[titleTemplateIdx];
|
|
357
|
-
}
|
|
358
|
-
return tags.filter(Boolean);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
const DedupesTagsPlugin = (options) => {
|
|
362
|
-
options = options || {};
|
|
363
|
-
const dedupeKeys = options.dedupeKeys || ["hid", "vmid", "key"];
|
|
364
|
-
return defineHeadPlugin({
|
|
365
|
-
hooks: {
|
|
366
|
-
"tag:normalise": function({ tag }) {
|
|
367
|
-
dedupeKeys.forEach((key) => {
|
|
368
|
-
if (tag.props[key]) {
|
|
369
|
-
tag.key = tag.props[key];
|
|
370
|
-
delete tag.props[key];
|
|
371
|
-
}
|
|
372
|
-
});
|
|
373
|
-
const dedupe = tag.key ? `${tag.tag}:${tag.key}` : tagDedupeKey(tag);
|
|
374
|
-
if (dedupe)
|
|
375
|
-
tag._d = dedupe;
|
|
376
|
-
},
|
|
377
|
-
"tags:resolve": function(ctx) {
|
|
378
|
-
const deduping = {};
|
|
379
|
-
ctx.tags.forEach((tag) => {
|
|
380
|
-
let dedupeKey = tag._d || tag._p;
|
|
381
|
-
const dupedTag = deduping[dedupeKey];
|
|
382
|
-
if (dupedTag) {
|
|
383
|
-
let strategy = tag?.tagDuplicateStrategy;
|
|
384
|
-
if (!strategy && (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"))
|
|
385
|
-
strategy = "merge";
|
|
386
|
-
if (strategy === "merge") {
|
|
387
|
-
const oldProps = dupedTag.props;
|
|
388
|
-
["class", "style"].forEach((key) => {
|
|
389
|
-
if (tag.props[key] && oldProps[key]) {
|
|
390
|
-
if (key === "style" && !oldProps[key].endsWith(";"))
|
|
391
|
-
oldProps[key] += ";";
|
|
392
|
-
tag.props[key] = `${oldProps[key]} ${tag.props[key]}`;
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
deduping[dedupeKey].props = {
|
|
396
|
-
...oldProps,
|
|
397
|
-
...tag.props
|
|
398
|
-
};
|
|
399
|
-
return;
|
|
400
|
-
} else if (tag._e === dupedTag._e) {
|
|
401
|
-
dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
|
|
402
|
-
}
|
|
403
|
-
const propCount = Object.keys(tag.props).length;
|
|
404
|
-
if ((propCount === 0 || propCount === 1 && typeof tag.props["data-h-key"] !== "undefined") && !tag.children) {
|
|
405
|
-
delete deduping[dedupeKey];
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
deduping[dedupeKey] = tag;
|
|
410
|
-
});
|
|
411
|
-
ctx.tags = Object.values(deduping);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
};
|
|
416
|
-
|
|
417
|
-
const SortTagsPlugin = () => {
|
|
418
|
-
return defineHeadPlugin({
|
|
419
|
-
hooks: {
|
|
420
|
-
"tags:resolve": (ctx) => {
|
|
421
|
-
const tagIndexForKey = (key) => ctx.tags.find((tag) => tag._d === key)?._p;
|
|
422
|
-
for (const tag of ctx.tags) {
|
|
423
|
-
if (!tag.tagPriority || typeof tag.tagPriority === "number")
|
|
424
|
-
continue;
|
|
425
|
-
const modifiers = [{ prefix: "before:", offset: -1 }, { prefix: "after:", offset: 1 }];
|
|
426
|
-
for (const { prefix, offset } of modifiers) {
|
|
427
|
-
if (tag.tagPriority.startsWith(prefix)) {
|
|
428
|
-
const key = tag.tagPriority.replace(prefix, "");
|
|
429
|
-
const index = tagIndexForKey(key);
|
|
430
|
-
if (typeof index !== "undefined")
|
|
431
|
-
tag._p = index + offset;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
ctx.tags.sort((a, b) => a._p - b._p).sort(sortTags);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
});
|
|
439
|
-
};
|
|
440
|
-
|
|
441
|
-
const TitleTemplatePlugin = () => {
|
|
442
|
-
return defineHeadPlugin({
|
|
443
|
-
hooks: {
|
|
444
|
-
"tags:resolve": (ctx) => {
|
|
445
|
-
ctx.tags = resolveTitleTemplateFromTags(ctx.tags);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
const DeprecatedTagAttrPlugin = () => {
|
|
452
|
-
return defineHeadPlugin({
|
|
453
|
-
hooks: {
|
|
454
|
-
"tag:normalise": function({ tag }) {
|
|
455
|
-
if (typeof tag.props.body !== "undefined") {
|
|
456
|
-
tag.tagPosition = "bodyClose";
|
|
457
|
-
delete tag.props.body;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
const IsBrowser$1 = typeof window !== "undefined";
|
|
465
|
-
|
|
466
|
-
const ProvideTagHashPlugin = () => {
|
|
467
|
-
return defineHeadPlugin({
|
|
468
|
-
hooks: {
|
|
469
|
-
"tag:normalise": (ctx) => {
|
|
470
|
-
const { tag, entry } = ctx;
|
|
471
|
-
const isDynamic = typeof tag.props._dynamic !== "undefined";
|
|
472
|
-
if (!HasElementTags.includes(tag.tag) || !tag.key)
|
|
473
|
-
return;
|
|
474
|
-
tag._hash = hashCode(JSON.stringify({ tag: tag.tag, key: tag.key }));
|
|
475
|
-
if (IsBrowser$1 || getActiveHead()?.resolvedOptions?.document)
|
|
476
|
-
return;
|
|
477
|
-
if (entry._m === "server" || isDynamic) {
|
|
478
|
-
tag.props[`data-h-${tag._hash}`] = "";
|
|
479
|
-
}
|
|
480
|
-
},
|
|
481
|
-
"tags:resolve": (ctx) => {
|
|
482
|
-
ctx.tags = ctx.tags.map((t) => {
|
|
483
|
-
delete t.props._dynamic;
|
|
484
|
-
return t;
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
const PatchDomOnEntryUpdatesPlugin = (options) => {
|
|
492
|
-
return defineHeadPlugin({
|
|
493
|
-
hooks: {
|
|
494
|
-
"entries:updated": function(head) {
|
|
495
|
-
if (typeof options?.document === "undefined" && typeof window === "undefined")
|
|
496
|
-
return;
|
|
497
|
-
let delayFn = options?.delayFn;
|
|
498
|
-
if (!delayFn && typeof requestAnimationFrame !== "undefined")
|
|
499
|
-
delayFn = requestAnimationFrame;
|
|
500
|
-
Promise.resolve().then(function () { return index; }).then(({ debouncedRenderDOMHead }) => {
|
|
501
|
-
debouncedRenderDOMHead(head, { document: options?.document || window.document, delayFn });
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
});
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
const EventHandlersPlugin = () => {
|
|
509
|
-
const stripEventHandlers = (mode, tag) => {
|
|
510
|
-
const props = {};
|
|
511
|
-
const eventHandlers = {};
|
|
512
|
-
Object.entries(tag.props).forEach(([key, value]) => {
|
|
513
|
-
if (key.startsWith("on") && typeof value === "function")
|
|
514
|
-
eventHandlers[key] = value;
|
|
515
|
-
else
|
|
516
|
-
props[key] = value;
|
|
517
|
-
});
|
|
518
|
-
let delayedSrc;
|
|
519
|
-
if (mode === "dom" && tag.tag === "script" && typeof props.src === "string" && typeof eventHandlers.onload !== "undefined") {
|
|
520
|
-
delayedSrc = props.src;
|
|
521
|
-
delete props.src;
|
|
522
|
-
}
|
|
523
|
-
return { props, eventHandlers, delayedSrc };
|
|
524
|
-
};
|
|
525
|
-
return defineHeadPlugin({
|
|
526
|
-
hooks: {
|
|
527
|
-
"ssr:render": function(ctx) {
|
|
528
|
-
ctx.tags = ctx.tags.map((tag) => {
|
|
529
|
-
tag.props = stripEventHandlers("ssr", tag).props;
|
|
530
|
-
return tag;
|
|
531
|
-
});
|
|
532
|
-
},
|
|
533
|
-
"dom:beforeRenderTag": function(ctx) {
|
|
534
|
-
const { props, eventHandlers, delayedSrc } = stripEventHandlers("dom", ctx.tag);
|
|
535
|
-
if (!Object.keys(eventHandlers).length)
|
|
536
|
-
return;
|
|
537
|
-
ctx.tag.props = props;
|
|
538
|
-
ctx.tag._eventHandlers = eventHandlers;
|
|
539
|
-
ctx.tag._delayedSrc = delayedSrc;
|
|
540
|
-
},
|
|
541
|
-
"dom:renderTag": function(ctx) {
|
|
542
|
-
const $el = ctx.$el;
|
|
543
|
-
if (!ctx.tag._eventHandlers || !$el)
|
|
544
|
-
return;
|
|
545
|
-
const $eventListenerTarget = ctx.tag.tag === "bodyAttrs" && typeof window !== "undefined" ? window : $el;
|
|
546
|
-
Object.entries(ctx.tag._eventHandlers).forEach(([k, value]) => {
|
|
547
|
-
const sdeKey = `${ctx.tag._d || ctx.tag._p}:${k}`;
|
|
548
|
-
const eventName = k.slice(2).toLowerCase();
|
|
549
|
-
const eventDedupeKey = `data-h-${eventName}`;
|
|
550
|
-
delete ctx.staleSideEffects[sdeKey];
|
|
551
|
-
if ($el.hasAttribute(eventDedupeKey))
|
|
552
|
-
return;
|
|
553
|
-
const handler = value;
|
|
554
|
-
$el.setAttribute(eventDedupeKey, "");
|
|
555
|
-
$eventListenerTarget.addEventListener(eventName, handler);
|
|
556
|
-
if (ctx.entry) {
|
|
557
|
-
ctx.entry._sde[sdeKey] = () => {
|
|
558
|
-
$eventListenerTarget.removeEventListener(eventName, handler);
|
|
559
|
-
$el.removeAttribute(eventDedupeKey);
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
if (ctx.tag._delayedSrc) {
|
|
564
|
-
$el.setAttribute("src", ctx.tag._delayedSrc);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
});
|
|
569
|
-
};
|
|
570
|
-
|
|
571
|
-
function asArray$1(value) {
|
|
572
|
-
return Array.isArray(value) ? value : [value];
|
|
573
|
-
}
|
|
574
|
-
const HasElementTags = [
|
|
575
|
-
"base",
|
|
576
|
-
"meta",
|
|
577
|
-
"link",
|
|
578
|
-
"style",
|
|
579
|
-
"script",
|
|
580
|
-
"noscript"
|
|
581
|
-
];
|
|
582
|
-
|
|
583
|
-
let activeHead;
|
|
584
|
-
const setActiveHead = (head) => activeHead = head;
|
|
585
|
-
const getActiveHead = () => activeHead;
|
|
586
|
-
|
|
587
|
-
const TagEntityBits = 10;
|
|
588
|
-
|
|
589
|
-
async function normaliseEntryTags(e) {
|
|
590
|
-
const tagPromises = [];
|
|
591
|
-
Object.entries(e.resolvedInput || e.input).filter(([k, v]) => typeof v !== "undefined" && ValidHeadTags.includes(k)).forEach(([k, value]) => {
|
|
592
|
-
const v = asArray$1(value);
|
|
593
|
-
tagPromises.push(...v.map((props) => normaliseTag(k, props)).flat());
|
|
594
|
-
});
|
|
595
|
-
return (await Promise.all(tagPromises)).flat().map((t, i) => {
|
|
596
|
-
t._e = e._i;
|
|
597
|
-
t._p = (e._i << TagEntityBits) + i;
|
|
598
|
-
return t;
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
const CorePlugins = () => [
|
|
603
|
-
// dedupe needs to come first
|
|
604
|
-
DedupesTagsPlugin(),
|
|
605
|
-
SortTagsPlugin(),
|
|
606
|
-
TitleTemplatePlugin(),
|
|
607
|
-
ProvideTagHashPlugin(),
|
|
608
|
-
EventHandlersPlugin(),
|
|
609
|
-
DeprecatedTagAttrPlugin()
|
|
610
|
-
];
|
|
611
|
-
const DOMPlugins = (options = {}) => [
|
|
612
|
-
PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn })
|
|
613
|
-
];
|
|
614
|
-
function createHead$1(options = {}) {
|
|
615
|
-
const head = createHeadCore({
|
|
616
|
-
...options,
|
|
617
|
-
plugins: [...DOMPlugins(options), ...options?.plugins || []]
|
|
618
|
-
});
|
|
619
|
-
setActiveHead(head);
|
|
620
|
-
return head;
|
|
621
|
-
}
|
|
622
|
-
function createHeadCore(options = {}) {
|
|
623
|
-
let entries = [];
|
|
624
|
-
let _sde = {};
|
|
625
|
-
let _eid = 0;
|
|
626
|
-
const hooks = createHooks();
|
|
627
|
-
if (options?.hooks)
|
|
628
|
-
hooks.addHooks(options.hooks);
|
|
629
|
-
options.plugins = [
|
|
630
|
-
...CorePlugins(),
|
|
631
|
-
...options?.plugins || []
|
|
632
|
-
];
|
|
633
|
-
options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
|
|
634
|
-
const updated = () => hooks.callHook("entries:updated", head);
|
|
635
|
-
const head = {
|
|
636
|
-
resolvedOptions: options,
|
|
637
|
-
headEntries() {
|
|
638
|
-
return entries;
|
|
639
|
-
},
|
|
640
|
-
get hooks() {
|
|
641
|
-
return hooks;
|
|
642
|
-
},
|
|
643
|
-
use(plugin) {
|
|
644
|
-
if (plugin.hooks)
|
|
645
|
-
hooks.addHooks(plugin.hooks);
|
|
646
|
-
},
|
|
647
|
-
push(input, options2) {
|
|
648
|
-
const activeEntry = {
|
|
649
|
-
_i: _eid++,
|
|
650
|
-
input,
|
|
651
|
-
_sde: {}
|
|
652
|
-
};
|
|
653
|
-
if (options2?.mode)
|
|
654
|
-
activeEntry._m = options2?.mode;
|
|
655
|
-
entries.push(activeEntry);
|
|
656
|
-
updated();
|
|
657
|
-
return {
|
|
658
|
-
dispose() {
|
|
659
|
-
entries = entries.filter((e) => {
|
|
660
|
-
if (e._i !== activeEntry._i)
|
|
661
|
-
return true;
|
|
662
|
-
_sde = { ..._sde, ...e._sde || {} };
|
|
663
|
-
e._sde = {};
|
|
664
|
-
updated();
|
|
665
|
-
return false;
|
|
666
|
-
});
|
|
667
|
-
},
|
|
668
|
-
// a patch is the same as creating a new entry, just a nice DX
|
|
669
|
-
patch(input2) {
|
|
670
|
-
entries = entries.map((e) => {
|
|
671
|
-
if (e._i === activeEntry._i) {
|
|
672
|
-
activeEntry.input = e.input = input2;
|
|
673
|
-
updated();
|
|
674
|
-
}
|
|
675
|
-
return e;
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
},
|
|
680
|
-
async resolveTags() {
|
|
681
|
-
const resolveCtx = { tags: [], entries: [...entries] };
|
|
682
|
-
await hooks.callHook("entries:resolve", resolveCtx);
|
|
683
|
-
for (const entry of resolveCtx.entries) {
|
|
684
|
-
for (const tag of await normaliseEntryTags(entry)) {
|
|
685
|
-
const tagCtx = { tag, entry };
|
|
686
|
-
await hooks.callHook("tag:normalise", tagCtx);
|
|
687
|
-
resolveCtx.tags.push(tagCtx.tag);
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
await hooks.callHook("tags:resolve", resolveCtx);
|
|
691
|
-
return resolveCtx.tags;
|
|
692
|
-
},
|
|
693
|
-
_elMap: {},
|
|
694
|
-
_popSideEffectQueue() {
|
|
695
|
-
const sde = { ..._sde };
|
|
696
|
-
_sde = {};
|
|
697
|
-
return sde;
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
head.hooks.callHook("init", head);
|
|
701
|
-
return head;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
function defineHeadPlugin(plugin) {
|
|
705
|
-
return plugin;
|
|
706
|
-
}
|
|
707
|
-
const composableNames = [
|
|
708
|
-
"useHead",
|
|
709
|
-
"useTagTitle",
|
|
710
|
-
"useTagBase",
|
|
711
|
-
"useTagMeta",
|
|
712
|
-
"useTagMetaFlat",
|
|
713
|
-
// alias
|
|
714
|
-
"useSeoMeta",
|
|
715
|
-
"useTagLink",
|
|
716
|
-
"useTagScript",
|
|
717
|
-
"useTagStyle",
|
|
718
|
-
"useTagNoscript",
|
|
719
|
-
"useHtmlAttrs",
|
|
720
|
-
"useBodyAttrs",
|
|
721
|
-
"useTitleTemplate",
|
|
722
|
-
// server only composables
|
|
723
|
-
"useServerHead",
|
|
724
|
-
"useServerTagTitle",
|
|
725
|
-
"useServerTagBase",
|
|
726
|
-
"useServerTagMeta",
|
|
727
|
-
"useServerTagMetaFlat",
|
|
728
|
-
"useServerTagLink",
|
|
729
|
-
"useServerTagScript",
|
|
730
|
-
"useServerTagStyle",
|
|
731
|
-
"useServerTagNoscript",
|
|
732
|
-
"useServerHtmlAttrs",
|
|
733
|
-
"useServerBodyAttrs",
|
|
734
|
-
"useServerTitleTemplate"
|
|
735
|
-
];
|
|
4
|
+
import { HasElementTags, defineHeadPlugin, asArray } from '@unhead/shared';
|
|
736
5
|
|
|
737
6
|
function resolveUnref(r) {
|
|
738
7
|
return typeof r === "function" ? r() : unref(r);
|
|
@@ -762,9 +31,6 @@ function resolveUnrefHeadInput(ref, lastKey = "") {
|
|
|
762
31
|
}
|
|
763
32
|
return root;
|
|
764
33
|
}
|
|
765
|
-
function asArray(value) {
|
|
766
|
-
return Array.isArray(value) ? value : [value];
|
|
767
|
-
}
|
|
768
34
|
|
|
769
35
|
const Vue3 = version.startsWith("3");
|
|
770
36
|
const IsBrowser = typeof window !== "undefined";
|
|
@@ -839,197 +105,16 @@ const Vue2ProvideUnheadPlugin = function(_Vue, head) {
|
|
|
839
105
|
});
|
|
840
106
|
};
|
|
841
107
|
|
|
842
|
-
function unpackToArray(input, options) {
|
|
843
|
-
const unpacked = [];
|
|
844
|
-
const kFn = options.resolveKeyData || ((ctx) => ctx.key);
|
|
845
|
-
const vFn = options.resolveValueData || ((ctx) => ctx.value);
|
|
846
|
-
for (const [k, v] of Object.entries(input)) {
|
|
847
|
-
unpacked.push(...(Array.isArray(v) ? v : [v]).map((i) => {
|
|
848
|
-
const ctx = { key: k, value: i };
|
|
849
|
-
const val = vFn(ctx);
|
|
850
|
-
if (typeof val === "object")
|
|
851
|
-
return unpackToArray(val, options);
|
|
852
|
-
if (Array.isArray(val))
|
|
853
|
-
return val;
|
|
854
|
-
return {
|
|
855
|
-
[typeof options.key === "function" ? options.key(ctx) : options.key]: kFn(ctx),
|
|
856
|
-
[typeof options.value === "function" ? options.value(ctx) : options.value]: val
|
|
857
|
-
};
|
|
858
|
-
}).flat());
|
|
859
|
-
}
|
|
860
|
-
return unpacked;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
function unpackToString(value, options) {
|
|
864
|
-
return Object.entries(value).map(([key, value2]) => {
|
|
865
|
-
if (typeof value2 === "object")
|
|
866
|
-
value2 = unpackToString(value2, options);
|
|
867
|
-
if (options.resolve) {
|
|
868
|
-
const resolved = options.resolve({ key, value: value2 });
|
|
869
|
-
if (resolved)
|
|
870
|
-
return resolved;
|
|
871
|
-
}
|
|
872
|
-
if (typeof value2 === "number")
|
|
873
|
-
value2 = value2.toString();
|
|
874
|
-
if (typeof value2 === "string" && options.wrapValue) {
|
|
875
|
-
value2 = value2.replace(new RegExp(options.wrapValue, "g"), `\\${options.wrapValue}`);
|
|
876
|
-
value2 = `${options.wrapValue}${value2}${options.wrapValue}`;
|
|
877
|
-
}
|
|
878
|
-
return `${key}${options.keyValueSeparator || ""}${value2}`;
|
|
879
|
-
}).join(options.entrySeparator || "");
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
const MetaPackingSchema = {
|
|
883
|
-
robots: {
|
|
884
|
-
unpack: {
|
|
885
|
-
keyValueSeparator: ":"
|
|
886
|
-
}
|
|
887
|
-
},
|
|
888
|
-
// Pragma directives
|
|
889
|
-
contentSecurityPolicy: {
|
|
890
|
-
unpack: {
|
|
891
|
-
keyValueSeparator: " ",
|
|
892
|
-
entrySeparator: "; "
|
|
893
|
-
},
|
|
894
|
-
metaKey: "http-equiv"
|
|
895
|
-
},
|
|
896
|
-
fbAppId: {
|
|
897
|
-
keyValue: "fb:app_id",
|
|
898
|
-
metaKey: "property"
|
|
899
|
-
},
|
|
900
|
-
msapplicationTileImage: {
|
|
901
|
-
keyValue: "msapplication-TileImage"
|
|
902
|
-
},
|
|
903
|
-
/**
|
|
904
|
-
* Tile colour for windows
|
|
905
|
-
*/
|
|
906
|
-
msapplicationTileColor: {
|
|
907
|
-
keyValue: "msapplication-TileColor"
|
|
908
|
-
},
|
|
909
|
-
/**
|
|
910
|
-
* URL of a config for windows tile.
|
|
911
|
-
*/
|
|
912
|
-
msapplicationConfig: {
|
|
913
|
-
keyValue: "msapplication-Config"
|
|
914
|
-
},
|
|
915
|
-
charset: {
|
|
916
|
-
metaKey: "charset"
|
|
917
|
-
},
|
|
918
|
-
contentType: {
|
|
919
|
-
metaKey: "http-equiv"
|
|
920
|
-
},
|
|
921
|
-
defaultStyle: {
|
|
922
|
-
metaKey: "http-equiv"
|
|
923
|
-
},
|
|
924
|
-
xUaCompatible: {
|
|
925
|
-
metaKey: "http-equiv"
|
|
926
|
-
},
|
|
927
|
-
refresh: {
|
|
928
|
-
metaKey: "http-equiv"
|
|
929
|
-
}
|
|
930
|
-
};
|
|
931
|
-
function resolveMetaKeyType(key) {
|
|
932
|
-
return PropertyPrefixKeys.test(key) ? "property" : MetaPackingSchema[key]?.metaKey || "name";
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
const ArrayableInputs = ["Image", "Video", "Audio"];
|
|
936
|
-
function unpackMeta(input) {
|
|
937
|
-
const extras = [];
|
|
938
|
-
ArrayableInputs.forEach((key) => {
|
|
939
|
-
const ogKey = `og:${key.toLowerCase()}`;
|
|
940
|
-
const inputKey = `og${key}`;
|
|
941
|
-
const val = input[inputKey];
|
|
942
|
-
if (typeof val === "object") {
|
|
943
|
-
(Array.isArray(val) ? val : [val]).forEach((entry) => {
|
|
944
|
-
if (!entry)
|
|
945
|
-
return;
|
|
946
|
-
const unpackedEntry = unpackToArray(entry, {
|
|
947
|
-
key: "property",
|
|
948
|
-
value: "content",
|
|
949
|
-
resolveKeyData({ key: key2 }) {
|
|
950
|
-
return fixKeyCase(`${ogKey}${key2 !== "url" ? `:${key2}` : ""}`);
|
|
951
|
-
},
|
|
952
|
-
resolveValueData({ value }) {
|
|
953
|
-
return typeof value === "number" ? value.toString() : value;
|
|
954
|
-
}
|
|
955
|
-
});
|
|
956
|
-
extras.push(
|
|
957
|
-
...unpackedEntry.sort((a, b) => a.property === ogKey ? -1 : b.property === ogKey ? 1 : 0)
|
|
958
|
-
);
|
|
959
|
-
});
|
|
960
|
-
delete input[inputKey];
|
|
961
|
-
}
|
|
962
|
-
});
|
|
963
|
-
const meta = unpackToArray(input, {
|
|
964
|
-
key({ key }) {
|
|
965
|
-
return resolveMetaKeyType(key);
|
|
966
|
-
},
|
|
967
|
-
value({ key }) {
|
|
968
|
-
return key === "charset" ? "charset" : "content";
|
|
969
|
-
},
|
|
970
|
-
resolveKeyData({ key }) {
|
|
971
|
-
return MetaPackingSchema[key]?.keyValue || fixKeyCase(key);
|
|
972
|
-
},
|
|
973
|
-
resolveValueData({ value, key }) {
|
|
974
|
-
if (value === null)
|
|
975
|
-
return "_null";
|
|
976
|
-
if (typeof value === "object") {
|
|
977
|
-
const definition = MetaPackingSchema[key];
|
|
978
|
-
if (key === "refresh")
|
|
979
|
-
return `${value.seconds};url=${value.url}`;
|
|
980
|
-
return unpackToString(
|
|
981
|
-
changeKeyCasingDeep(value),
|
|
982
|
-
{
|
|
983
|
-
entrySeparator: ", ",
|
|
984
|
-
keyValueSeparator: "=",
|
|
985
|
-
resolve({ value: value2, key: key2 }) {
|
|
986
|
-
if (value2 === null)
|
|
987
|
-
return "";
|
|
988
|
-
if (typeof value2 === "boolean")
|
|
989
|
-
return `${key2}`;
|
|
990
|
-
},
|
|
991
|
-
...definition?.unpack
|
|
992
|
-
}
|
|
993
|
-
);
|
|
994
|
-
}
|
|
995
|
-
return typeof value === "number" ? value.toString() : value;
|
|
996
|
-
}
|
|
997
|
-
});
|
|
998
|
-
return [...extras, ...meta].filter((v) => typeof v.content === "undefined" || v.content !== "_null");
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
const PropertyPrefixKeys = /^(og|fb)/;
|
|
1002
|
-
const ColonPrefixKeys = /^(og|twitter|fb)/;
|
|
1003
|
-
function fixKeyCase(key) {
|
|
1004
|
-
key = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
1005
|
-
if (ColonPrefixKeys.test(key)) {
|
|
1006
|
-
key = key.replace("secure-url", "secure_url").replace(/-/g, ":");
|
|
1007
|
-
}
|
|
1008
|
-
return key;
|
|
1009
|
-
}
|
|
1010
|
-
function changeKeyCasingDeep(input) {
|
|
1011
|
-
if (Array.isArray(input)) {
|
|
1012
|
-
return input.map((entry) => changeKeyCasingDeep(entry));
|
|
1013
|
-
}
|
|
1014
|
-
if (typeof input !== "object" || Array.isArray(input))
|
|
1015
|
-
return input;
|
|
1016
|
-
const output = {};
|
|
1017
|
-
for (const [key, value] of Object.entries(input))
|
|
1018
|
-
output[fixKeyCase(key)] = changeKeyCasingDeep(value);
|
|
1019
|
-
return output;
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
108
|
function clientUseHead(input, options = {}) {
|
|
1023
109
|
const head = injectHead();
|
|
1024
110
|
const deactivated = ref(false);
|
|
1025
111
|
const resolvedInput = ref({});
|
|
1026
112
|
watchEffect(() => {
|
|
1027
|
-
resolvedInput.value = resolveUnrefHeadInput(input);
|
|
113
|
+
resolvedInput.value = deactivated.value ? {} : resolveUnrefHeadInput(input);
|
|
1028
114
|
});
|
|
1029
115
|
const entry = head.push(resolvedInput.value, options);
|
|
1030
|
-
watch(
|
|
1031
|
-
|
|
1032
|
-
entry.patch(e);
|
|
116
|
+
watch(resolvedInput, (e) => {
|
|
117
|
+
entry.patch(e);
|
|
1033
118
|
});
|
|
1034
119
|
const vm = getCurrentInstance();
|
|
1035
120
|
if (vm) {
|
|
@@ -1120,4 +205,4 @@ const unheadVueComposablesImports = {
|
|
|
1120
205
|
"@unhead/vue": [...coreComposableNames, ...composableNames]
|
|
1121
206
|
};
|
|
1122
207
|
|
|
1123
|
-
export { Vue2ProvideUnheadPlugin, VueHeadMixin, VueReactiveUseHeadPlugin,
|
|
208
|
+
export { Vue2ProvideUnheadPlugin, VueHeadMixin, VueReactiveUseHeadPlugin, createHead, headSymbol, injectHead, resolveUnrefHeadInput, unheadVueComposablesImports, useBodyAttrs, useHead, useHtmlAttrs, useSeoMeta, useServerBodyAttrs, useServerHead, useServerHtmlAttrs, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate };
|