unhead 1.8.19 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +42 -105
- package/dist/index.mjs +43 -106
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -457,48 +457,16 @@ function useServerSeoMeta(input, options) {
|
|
|
457
457
|
});
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
const UseScriptDefaults = {
|
|
461
|
-
defer: true,
|
|
462
|
-
fetchpriority: "low"
|
|
463
|
-
};
|
|
464
|
-
const requestIdleCallback = typeof window === "undefined" ? () => {
|
|
465
|
-
} : globalThis.requestIdleCallback || ((cb) => {
|
|
466
|
-
const start = Date.now();
|
|
467
|
-
const idleDeadline = {
|
|
468
|
-
didTimeout: false,
|
|
469
|
-
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
|
|
470
|
-
};
|
|
471
|
-
return setTimeout(() => {
|
|
472
|
-
cb(idleDeadline);
|
|
473
|
-
}, 1);
|
|
474
|
-
});
|
|
475
460
|
function useScript(_input, _options) {
|
|
476
461
|
const input = typeof _input === "string" ? { src: _input } : _input;
|
|
477
462
|
const options = _options || {};
|
|
478
463
|
const head = options.head || getActiveHead();
|
|
479
464
|
if (!head)
|
|
480
|
-
throw new Error("
|
|
465
|
+
throw new Error("Missing Unhead context.");
|
|
481
466
|
const id = input.key || shared.hashCode(input.src || (typeof input.innerHTML === "string" ? input.innerHTML : ""));
|
|
482
467
|
const key = `use-script.${id}`;
|
|
483
468
|
if (head._scripts?.[id])
|
|
484
469
|
return head._scripts[id];
|
|
485
|
-
async function transform(entry) {
|
|
486
|
-
const script2 = await (options.transform || ((input2) => input2))(entry.script[0]);
|
|
487
|
-
const ctx = { script: script2 };
|
|
488
|
-
await head.hooks.callHook("script:transform", ctx);
|
|
489
|
-
return { script: [ctx.script] };
|
|
490
|
-
}
|
|
491
|
-
function maybeHintEarlyConnection(rel) {
|
|
492
|
-
if (
|
|
493
|
-
// opt-out
|
|
494
|
-
options.skipEarlyConnections || !input.src.includes("//") || !head.ssr
|
|
495
|
-
)
|
|
496
|
-
return;
|
|
497
|
-
const key2 = `use-script.${id}.early-connection`;
|
|
498
|
-
head.push({
|
|
499
|
-
link: [{ key: key2, rel, href: new URL(input.src).origin }]
|
|
500
|
-
}, { mode: "server" });
|
|
501
|
-
}
|
|
502
470
|
const script = {
|
|
503
471
|
id,
|
|
504
472
|
status: "awaitingLoad",
|
|
@@ -513,109 +481,78 @@ function useScript(_input, _options) {
|
|
|
513
481
|
}
|
|
514
482
|
return false;
|
|
515
483
|
},
|
|
516
|
-
waitForLoad() {
|
|
517
|
-
return new Promise((resolve) => {
|
|
518
|
-
if (script.status === "loaded")
|
|
519
|
-
resolve(options.use?.());
|
|
520
|
-
function watchForScriptLoaded({ script: script2 }) {
|
|
521
|
-
if (script2.id === id && script2.status === "loaded") {
|
|
522
|
-
script2.loaded = true;
|
|
523
|
-
resolve(options.use?.());
|
|
524
|
-
head.hooks.removeHook("script:updated", watchForScriptLoaded);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
head.hooks.hook("script:updated", watchForScriptLoaded);
|
|
528
|
-
});
|
|
529
|
-
},
|
|
530
484
|
load() {
|
|
531
485
|
if (script.status !== "awaitingLoad")
|
|
532
|
-
return script.
|
|
486
|
+
return script.loadPromise;
|
|
533
487
|
script.status = "loading";
|
|
534
488
|
head.hooks.callHook(`script:updated`, hookCtx);
|
|
535
489
|
script.entry = head.push({
|
|
536
490
|
script: [
|
|
537
|
-
|
|
538
|
-
{ ...UseScriptDefaults, ...input, key }
|
|
491
|
+
{ defer: true, fetchpriority: "low", ...input, key }
|
|
539
492
|
]
|
|
540
|
-
},
|
|
541
|
-
|
|
542
|
-
// @ts-expect-error untyped
|
|
543
|
-
transform,
|
|
544
|
-
head
|
|
545
|
-
});
|
|
546
|
-
return script.waitForLoad();
|
|
493
|
+
}, options);
|
|
494
|
+
return script.loadPromise;
|
|
547
495
|
}
|
|
548
496
|
};
|
|
497
|
+
script.loadPromise = new Promise((resolve, reject) => {
|
|
498
|
+
const removeHook2 = head.hooks.hook("script:updated", ({ script: script2 }) => {
|
|
499
|
+
if (script2.id === id && (script2.status === "loaded" || script2.status === "error")) {
|
|
500
|
+
script2.status === "loaded" && resolve(options.use?.());
|
|
501
|
+
script2.status === "error" && reject(new Error(`Failed to load script: ${input.src}`));
|
|
502
|
+
removeHook2();
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
});
|
|
549
506
|
const hookCtx = { script };
|
|
550
|
-
shared.
|
|
551
|
-
const _fn = typeof input[fn] === "function" ? input[fn].bind({}) : null;
|
|
507
|
+
shared.ScriptNetworkEvents.forEach((fn) => {
|
|
552
508
|
input[fn] = (e) => {
|
|
553
509
|
script.status = fn === "onload" ? "loaded" : fn === "onerror" ? "error" : "loading";
|
|
554
510
|
head.hooks.callHook(`script:updated`, hookCtx);
|
|
555
|
-
|
|
511
|
+
typeof input[fn] === "function" && input[fn].call(options.eventContext, e);
|
|
556
512
|
};
|
|
557
513
|
});
|
|
558
|
-
|
|
559
|
-
if (trigger)
|
|
560
|
-
const isIdle = trigger === "idle";
|
|
561
|
-
if (isIdle) {
|
|
562
|
-
if (head.ssr)
|
|
563
|
-
trigger = "manual";
|
|
564
|
-
else
|
|
565
|
-
trigger = new Promise((resolve) => requestIdleCallback(() => resolve()));
|
|
566
|
-
}
|
|
567
|
-
trigger === "manual" && (trigger = new Promise(() => {
|
|
568
|
-
}));
|
|
514
|
+
const trigger = options.trigger;
|
|
515
|
+
if (options.trigger)
|
|
569
516
|
trigger instanceof Promise && trigger.then(script.load);
|
|
570
|
-
|
|
571
|
-
} else {
|
|
517
|
+
else
|
|
572
518
|
script.load();
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
if (ctx.tag.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
);
|
|
587
|
-
}
|
|
588
|
-
head.hooks.removeHook("dom:renderTag", resolveInnerHtmlLoad);
|
|
519
|
+
const removeHook = head.hooks.hook("dom:renderTag", (ctx) => {
|
|
520
|
+
if (ctx.tag.key !== key)
|
|
521
|
+
return;
|
|
522
|
+
if (ctx.tag.innerHTML) {
|
|
523
|
+
setTimeout(
|
|
524
|
+
() => {
|
|
525
|
+
script.status = "loaded";
|
|
526
|
+
head.hooks.callHook("script:updated", hookCtx);
|
|
527
|
+
typeof input.onload === "function" && input.onload.call(options.eventContext, new Event("load"));
|
|
528
|
+
},
|
|
529
|
+
5
|
|
530
|
+
/* give inline script a chance to run */
|
|
531
|
+
);
|
|
589
532
|
}
|
|
590
|
-
|
|
591
|
-
|
|
533
|
+
removeHook();
|
|
534
|
+
});
|
|
592
535
|
const instance = new Proxy({}, {
|
|
593
536
|
get(_, fn) {
|
|
594
|
-
const
|
|
537
|
+
const $script = Object.assign(script.loadPromise, script);
|
|
538
|
+
const stub = options.stub?.({ script: $script, fn });
|
|
595
539
|
if (stub)
|
|
596
540
|
return stub;
|
|
597
541
|
if (fn === "$script")
|
|
598
|
-
return script;
|
|
542
|
+
return $script;
|
|
599
543
|
return (...args) => {
|
|
600
544
|
const hookCtx2 = { script, fn, args };
|
|
601
545
|
head.hooks.callHook("script:instance-fn", hookCtx2);
|
|
602
546
|
if (head.ssr || !options.use)
|
|
603
547
|
return;
|
|
604
|
-
|
|
605
|
-
const api = options.use();
|
|
606
|
-
return api[fn](...args);
|
|
607
|
-
} else {
|
|
608
|
-
return script.waitForLoad().then(
|
|
609
|
-
(api) => {
|
|
610
|
-
return api[fn](...args);
|
|
611
|
-
}
|
|
612
|
-
);
|
|
613
|
-
}
|
|
548
|
+
return script.status === "loaded" ? options.use()[fn](...args) : script.loadPromise.then((api) => api[fn](...args));
|
|
614
549
|
};
|
|
615
550
|
}
|
|
616
551
|
});
|
|
617
|
-
head._scripts =
|
|
618
|
-
|
|
552
|
+
head._scripts = Object.assign(
|
|
553
|
+
head._scripts || {},
|
|
554
|
+
{ [id]: instance }
|
|
555
|
+
);
|
|
619
556
|
return instance;
|
|
620
557
|
}
|
|
621
558
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHooks } from 'hookable';
|
|
2
2
|
import { DomPlugin } from '@unhead/dom';
|
|
3
|
-
import { defineHeadPlugin, tagDedupeKey, tagWeight, HasElementTags, NetworkEvents, hashCode, SortModifiers, processTemplateParams, resolveTitleTemplate, IsBrowser, normaliseEntryTags, composableNames, whitelistSafeInput, unpackMeta } from '@unhead/shared';
|
|
3
|
+
import { defineHeadPlugin, tagDedupeKey, tagWeight, HasElementTags, NetworkEvents, hashCode, SortModifiers, processTemplateParams, resolveTitleTemplate, IsBrowser, normaliseEntryTags, composableNames, whitelistSafeInput, unpackMeta, ScriptNetworkEvents } from '@unhead/shared';
|
|
4
4
|
export { composableNames } from '@unhead/shared';
|
|
5
5
|
|
|
6
6
|
const UsesMergeStrategy = ["templateParams", "htmlAttrs", "bodyAttrs"];
|
|
@@ -456,48 +456,16 @@ function useServerSeoMeta(input, options) {
|
|
|
456
456
|
});
|
|
457
457
|
}
|
|
458
458
|
|
|
459
|
-
const UseScriptDefaults = {
|
|
460
|
-
defer: true,
|
|
461
|
-
fetchpriority: "low"
|
|
462
|
-
};
|
|
463
|
-
const requestIdleCallback = typeof window === "undefined" ? () => {
|
|
464
|
-
} : globalThis.requestIdleCallback || ((cb) => {
|
|
465
|
-
const start = Date.now();
|
|
466
|
-
const idleDeadline = {
|
|
467
|
-
didTimeout: false,
|
|
468
|
-
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
|
|
469
|
-
};
|
|
470
|
-
return setTimeout(() => {
|
|
471
|
-
cb(idleDeadline);
|
|
472
|
-
}, 1);
|
|
473
|
-
});
|
|
474
459
|
function useScript(_input, _options) {
|
|
475
460
|
const input = typeof _input === "string" ? { src: _input } : _input;
|
|
476
461
|
const options = _options || {};
|
|
477
462
|
const head = options.head || getActiveHead();
|
|
478
463
|
if (!head)
|
|
479
|
-
throw new Error("
|
|
464
|
+
throw new Error("Missing Unhead context.");
|
|
480
465
|
const id = input.key || hashCode(input.src || (typeof input.innerHTML === "string" ? input.innerHTML : ""));
|
|
481
466
|
const key = `use-script.${id}`;
|
|
482
467
|
if (head._scripts?.[id])
|
|
483
468
|
return head._scripts[id];
|
|
484
|
-
async function transform(entry) {
|
|
485
|
-
const script2 = await (options.transform || ((input2) => input2))(entry.script[0]);
|
|
486
|
-
const ctx = { script: script2 };
|
|
487
|
-
await head.hooks.callHook("script:transform", ctx);
|
|
488
|
-
return { script: [ctx.script] };
|
|
489
|
-
}
|
|
490
|
-
function maybeHintEarlyConnection(rel) {
|
|
491
|
-
if (
|
|
492
|
-
// opt-out
|
|
493
|
-
options.skipEarlyConnections || !input.src.includes("//") || !head.ssr
|
|
494
|
-
)
|
|
495
|
-
return;
|
|
496
|
-
const key2 = `use-script.${id}.early-connection`;
|
|
497
|
-
head.push({
|
|
498
|
-
link: [{ key: key2, rel, href: new URL(input.src).origin }]
|
|
499
|
-
}, { mode: "server" });
|
|
500
|
-
}
|
|
501
469
|
const script = {
|
|
502
470
|
id,
|
|
503
471
|
status: "awaitingLoad",
|
|
@@ -512,109 +480,78 @@ function useScript(_input, _options) {
|
|
|
512
480
|
}
|
|
513
481
|
return false;
|
|
514
482
|
},
|
|
515
|
-
waitForLoad() {
|
|
516
|
-
return new Promise((resolve) => {
|
|
517
|
-
if (script.status === "loaded")
|
|
518
|
-
resolve(options.use?.());
|
|
519
|
-
function watchForScriptLoaded({ script: script2 }) {
|
|
520
|
-
if (script2.id === id && script2.status === "loaded") {
|
|
521
|
-
script2.loaded = true;
|
|
522
|
-
resolve(options.use?.());
|
|
523
|
-
head.hooks.removeHook("script:updated", watchForScriptLoaded);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
head.hooks.hook("script:updated", watchForScriptLoaded);
|
|
527
|
-
});
|
|
528
|
-
},
|
|
529
483
|
load() {
|
|
530
484
|
if (script.status !== "awaitingLoad")
|
|
531
|
-
return script.
|
|
485
|
+
return script.loadPromise;
|
|
532
486
|
script.status = "loading";
|
|
533
487
|
head.hooks.callHook(`script:updated`, hookCtx);
|
|
534
488
|
script.entry = head.push({
|
|
535
489
|
script: [
|
|
536
|
-
|
|
537
|
-
{ ...UseScriptDefaults, ...input, key }
|
|
490
|
+
{ defer: true, fetchpriority: "low", ...input, key }
|
|
538
491
|
]
|
|
539
|
-
},
|
|
540
|
-
|
|
541
|
-
// @ts-expect-error untyped
|
|
542
|
-
transform,
|
|
543
|
-
head
|
|
544
|
-
});
|
|
545
|
-
return script.waitForLoad();
|
|
492
|
+
}, options);
|
|
493
|
+
return script.loadPromise;
|
|
546
494
|
}
|
|
547
495
|
};
|
|
496
|
+
script.loadPromise = new Promise((resolve, reject) => {
|
|
497
|
+
const removeHook2 = head.hooks.hook("script:updated", ({ script: script2 }) => {
|
|
498
|
+
if (script2.id === id && (script2.status === "loaded" || script2.status === "error")) {
|
|
499
|
+
script2.status === "loaded" && resolve(options.use?.());
|
|
500
|
+
script2.status === "error" && reject(new Error(`Failed to load script: ${input.src}`));
|
|
501
|
+
removeHook2();
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
});
|
|
548
505
|
const hookCtx = { script };
|
|
549
|
-
|
|
550
|
-
const _fn = typeof input[fn] === "function" ? input[fn].bind({}) : null;
|
|
506
|
+
ScriptNetworkEvents.forEach((fn) => {
|
|
551
507
|
input[fn] = (e) => {
|
|
552
508
|
script.status = fn === "onload" ? "loaded" : fn === "onerror" ? "error" : "loading";
|
|
553
509
|
head.hooks.callHook(`script:updated`, hookCtx);
|
|
554
|
-
|
|
510
|
+
typeof input[fn] === "function" && input[fn].call(options.eventContext, e);
|
|
555
511
|
};
|
|
556
512
|
});
|
|
557
|
-
|
|
558
|
-
if (trigger)
|
|
559
|
-
const isIdle = trigger === "idle";
|
|
560
|
-
if (isIdle) {
|
|
561
|
-
if (head.ssr)
|
|
562
|
-
trigger = "manual";
|
|
563
|
-
else
|
|
564
|
-
trigger = new Promise((resolve) => requestIdleCallback(() => resolve()));
|
|
565
|
-
}
|
|
566
|
-
trigger === "manual" && (trigger = new Promise(() => {
|
|
567
|
-
}));
|
|
513
|
+
const trigger = options.trigger;
|
|
514
|
+
if (options.trigger)
|
|
568
515
|
trigger instanceof Promise && trigger.then(script.load);
|
|
569
|
-
|
|
570
|
-
} else {
|
|
516
|
+
else
|
|
571
517
|
script.load();
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
if (ctx.tag.
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
);
|
|
586
|
-
}
|
|
587
|
-
head.hooks.removeHook("dom:renderTag", resolveInnerHtmlLoad);
|
|
518
|
+
const removeHook = head.hooks.hook("dom:renderTag", (ctx) => {
|
|
519
|
+
if (ctx.tag.key !== key)
|
|
520
|
+
return;
|
|
521
|
+
if (ctx.tag.innerHTML) {
|
|
522
|
+
setTimeout(
|
|
523
|
+
() => {
|
|
524
|
+
script.status = "loaded";
|
|
525
|
+
head.hooks.callHook("script:updated", hookCtx);
|
|
526
|
+
typeof input.onload === "function" && input.onload.call(options.eventContext, new Event("load"));
|
|
527
|
+
},
|
|
528
|
+
5
|
|
529
|
+
/* give inline script a chance to run */
|
|
530
|
+
);
|
|
588
531
|
}
|
|
589
|
-
|
|
590
|
-
|
|
532
|
+
removeHook();
|
|
533
|
+
});
|
|
591
534
|
const instance = new Proxy({}, {
|
|
592
535
|
get(_, fn) {
|
|
593
|
-
const
|
|
536
|
+
const $script = Object.assign(script.loadPromise, script);
|
|
537
|
+
const stub = options.stub?.({ script: $script, fn });
|
|
594
538
|
if (stub)
|
|
595
539
|
return stub;
|
|
596
540
|
if (fn === "$script")
|
|
597
|
-
return script;
|
|
541
|
+
return $script;
|
|
598
542
|
return (...args) => {
|
|
599
543
|
const hookCtx2 = { script, fn, args };
|
|
600
544
|
head.hooks.callHook("script:instance-fn", hookCtx2);
|
|
601
545
|
if (head.ssr || !options.use)
|
|
602
546
|
return;
|
|
603
|
-
|
|
604
|
-
const api = options.use();
|
|
605
|
-
return api[fn](...args);
|
|
606
|
-
} else {
|
|
607
|
-
return script.waitForLoad().then(
|
|
608
|
-
(api) => {
|
|
609
|
-
return api[fn](...args);
|
|
610
|
-
}
|
|
611
|
-
);
|
|
612
|
-
}
|
|
547
|
+
return script.status === "loaded" ? options.use()[fn](...args) : script.loadPromise.then((api) => api[fn](...args));
|
|
613
548
|
};
|
|
614
549
|
}
|
|
615
550
|
});
|
|
616
|
-
head._scripts =
|
|
617
|
-
|
|
551
|
+
head._scripts = Object.assign(
|
|
552
|
+
head._scripts || {},
|
|
553
|
+
{ [id]: instance }
|
|
554
|
+
);
|
|
618
555
|
return instance;
|
|
619
556
|
}
|
|
620
557
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unhead",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.9.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Harlan Wilton",
|
|
7
7
|
"email": "harlan@harlanzw.com",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"hookable": "^5.5.3",
|
|
37
|
-
"@unhead/
|
|
38
|
-
"@unhead/
|
|
39
|
-
"@unhead/
|
|
37
|
+
"@unhead/schema": "1.9.0",
|
|
38
|
+
"@unhead/shared": "1.9.0",
|
|
39
|
+
"@unhead/dom": "1.9.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "unbuild .",
|