remote-components 0.0.23 → 0.0.24
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/html/host.cjs +297 -82
- package/dist/html/host.cjs.map +1 -1
- package/dist/html/host.js +300 -82
- package/dist/html/host.js.map +1 -1
- package/dist/internal/next/host/app-router-client.cjs +176 -70
- package/dist/internal/next/host/app-router-client.cjs.map +1 -1
- package/dist/internal/next/host/app-router-client.js +184 -71
- package/dist/internal/next/host/app-router-client.js.map +1 -1
- package/dist/internal/next/host/app-router-compat.cjs +114 -0
- package/dist/internal/next/host/app-router-compat.cjs.map +1 -0
- package/dist/internal/next/host/app-router-compat.d.ts +31 -0
- package/dist/internal/next/host/app-router-compat.js +79 -0
- package/dist/internal/next/host/app-router-compat.js.map +1 -0
- package/dist/internal/next/remote/render-client.cjs +10 -2
- package/dist/internal/next/remote/render-client.cjs.map +1 -1
- package/dist/internal/next/remote/render-client.js +10 -2
- package/dist/internal/next/remote/render-client.js.map +1 -1
- package/dist/internal/shared/client/apply-origin.cjs +61 -0
- package/dist/internal/shared/client/apply-origin.cjs.map +1 -0
- package/dist/internal/shared/client/apply-origin.d.ts +3 -0
- package/dist/internal/shared/client/apply-origin.js +37 -0
- package/dist/internal/shared/client/apply-origin.js.map +1 -0
- package/dist/internal/shared/client/polyfill.cjs +149 -0
- package/dist/internal/shared/client/polyfill.cjs.map +1 -0
- package/dist/internal/shared/client/polyfill.d.ts +6 -0
- package/dist/internal/shared/client/polyfill.js +124 -0
- package/dist/internal/shared/client/polyfill.js.map +1 -0
- package/dist/internal/shared/client/remote-component.cjs +3 -3
- package/dist/internal/shared/client/remote-component.cjs.map +1 -1
- package/dist/internal/shared/client/remote-component.d.ts +1 -1
- package/dist/internal/shared/client/remote-component.js +3 -3
- package/dist/internal/shared/client/remote-component.js.map +1 -1
- package/dist/internal/shared/ssr/dom-flight.cjs +40 -0
- package/dist/internal/shared/ssr/dom-flight.cjs.map +1 -1
- package/dist/internal/shared/ssr/dom-flight.js +40 -0
- package/dist/internal/shared/ssr/dom-flight.js.map +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.cjs +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.d.ts +6 -0
- package/dist/internal/shared/ssr/fetch-remote-component.js +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
- package/dist/next/config.cjs +50 -28
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +50 -28
- package/dist/next/config.js.map +1 -1
- package/dist/next/host/client/index.cjs +16 -1
- package/dist/next/host/client/index.cjs.map +1 -1
- package/dist/next/host/client/index.js +16 -1
- package/dist/next/host/client/index.js.map +1 -1
- package/dist/next/host/pages-router-server.cjs +27 -13
- package/dist/next/host/pages-router-server.cjs.map +1 -1
- package/dist/next/host/pages-router-server.js +27 -13
- package/dist/next/host/pages-router-server.js.map +1 -1
- package/dist/next/middleware.cjs +5 -2
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.d.ts +1 -0
- package/dist/next/middleware.js +5 -2
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/remote/pages-router.cjs +3 -1
- package/dist/next/remote/pages-router.cjs.map +1 -1
- package/dist/next/remote/pages-router.d.ts +1 -0
- package/dist/next/remote/pages-router.js +3 -1
- package/dist/next/remote/pages-router.js.map +1 -1
- package/dist/react/index.cjs +203 -159
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.js +192 -148
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/dist/html/host.js
CHANGED
|
@@ -373,7 +373,7 @@ function initializeSharedModules(bundle, shared = {}, remoteShared = {}) {
|
|
|
373
373
|
Object.entries(remoteShared).map(async ([id, module]) => {
|
|
374
374
|
if (self.__remote_shared_modules__?.[bundle]) {
|
|
375
375
|
if (shared[module]) {
|
|
376
|
-
self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module]();
|
|
376
|
+
self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module](bundle);
|
|
377
377
|
} else {
|
|
378
378
|
console.error(`Shared module "${module}" not found for "${bundle}".`);
|
|
379
379
|
}
|
|
@@ -386,7 +386,7 @@ function getSharedModule(bundle, id) {
|
|
|
386
386
|
for (const [key, value] of Object.entries(
|
|
387
387
|
self.__remote_shared_modules__?.[bundle] ?? {}
|
|
388
388
|
)) {
|
|
389
|
-
if (typeof id === "string" && id.includes(key) || id === key) {
|
|
389
|
+
if (typeof value !== "undefined" && (typeof id === "string" && id.includes(key) || id === key)) {
|
|
390
390
|
return value;
|
|
391
391
|
}
|
|
392
392
|
}
|
|
@@ -520,6 +520,24 @@ var init_webpack_adapter = __esm({
|
|
|
520
520
|
|
|
521
521
|
// src/shared/client/polyfill.tsx
|
|
522
522
|
import { jsx } from "react/jsx-runtime";
|
|
523
|
+
function applyBundleUrlToSrc(bundle, src) {
|
|
524
|
+
const self = globalThis;
|
|
525
|
+
if (self.__remote_bundle_url__?.[bundle]?.origin === location.origin) {
|
|
526
|
+
return src;
|
|
527
|
+
}
|
|
528
|
+
const { assetPrefix, path } = /^(?<assetPrefix>.*?)\/_next\/(?<path>.*)/.exec(src)?.groups ?? {};
|
|
529
|
+
if (!path) {
|
|
530
|
+
return new URL(src, self.__remote_bundle_url__?.[bundle]?.origin).href;
|
|
531
|
+
}
|
|
532
|
+
return `${self.__remote_bundle_url__?.[bundle]?.origin ?? ""}${assetPrefix}/_next/${path}`;
|
|
533
|
+
}
|
|
534
|
+
function applyBundleUrlToImagePropsSrc(bundle, src) {
|
|
535
|
+
if (typeof src === "string") {
|
|
536
|
+
return applyBundleUrlToSrc(bundle, src);
|
|
537
|
+
}
|
|
538
|
+
const propSrc = src;
|
|
539
|
+
return applyBundleUrlToSrc(bundle, propSrc.src);
|
|
540
|
+
}
|
|
523
541
|
function sharedPolyfills(shared) {
|
|
524
542
|
const self = globalThis;
|
|
525
543
|
const polyfill = {
|
|
@@ -555,18 +573,17 @@ function sharedPolyfills(shared) {
|
|
|
555
573
|
},
|
|
556
574
|
__esModule: true
|
|
557
575
|
})),
|
|
558
|
-
"next/dist/client/image-component": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? (() => Promise.resolve({
|
|
559
|
-
Image: (
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
),
|
|
576
|
+
"next/dist/client/image-component": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
|
|
577
|
+
Image: imageImpl(bundle),
|
|
578
|
+
__esModule: true
|
|
579
|
+
})),
|
|
580
|
+
"next/image": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
|
|
581
|
+
default: imageImpl(bundle),
|
|
582
|
+
getImageProps: (_imgProps) => {
|
|
583
|
+
throw new Error(
|
|
584
|
+
"Next.js getImageProps() is not implemented in remote components"
|
|
585
|
+
);
|
|
586
|
+
},
|
|
570
587
|
__esModule: true
|
|
571
588
|
})),
|
|
572
589
|
"next/dist/client/script": self.__remote_component_host_shared_modules__?.["next/script"] ?? shared?.["next/script"] ?? (() => Promise.resolve({
|
|
@@ -574,19 +591,57 @@ function sharedPolyfills(shared) {
|
|
|
574
591
|
// do not throw an error for now
|
|
575
592
|
default: () => null,
|
|
576
593
|
__esModule: true
|
|
577
|
-
}))
|
|
594
|
+
})),
|
|
595
|
+
"next/router": self.__remote_component_host_shared_modules__?.["next/router"] ?? shared?.["next/router"] ?? (() => (
|
|
596
|
+
// TODO: incomplete implementation
|
|
597
|
+
Promise.resolve({
|
|
598
|
+
useRouter() {
|
|
599
|
+
return {
|
|
600
|
+
push: (routerUrl) => {
|
|
601
|
+
history.pushState({}, "", routerUrl);
|
|
602
|
+
},
|
|
603
|
+
replace: (routerUrl) => {
|
|
604
|
+
history.replaceState({}, "", routerUrl);
|
|
605
|
+
},
|
|
606
|
+
back: () => {
|
|
607
|
+
history.back();
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
},
|
|
611
|
+
__esModule: true
|
|
612
|
+
})
|
|
613
|
+
))
|
|
578
614
|
};
|
|
579
615
|
polyfill["next/navigation"] = polyfill["next/dist/client/components/navigation"];
|
|
580
616
|
polyfill["next/link"] = polyfill["next/dist/client/app-dir/link"];
|
|
581
617
|
polyfill["next/form"] = polyfill["next/dist/client/app-dir/form"];
|
|
582
|
-
polyfill["next/image"] = polyfill["next/dist/client/image-component"];
|
|
583
618
|
polyfill["next/dist/api/image"] = polyfill["next/dist/client/image-component"];
|
|
584
619
|
polyfill["next/script"] = polyfill["next/dist/client/script"];
|
|
585
620
|
return polyfill;
|
|
586
621
|
}
|
|
622
|
+
var imageImpl;
|
|
587
623
|
var init_polyfill = __esm({
|
|
588
624
|
"src/shared/client/polyfill.tsx"() {
|
|
589
625
|
"use strict";
|
|
626
|
+
imageImpl = (bundle) => function RemoteImage({ priority: _, ...props }) {
|
|
627
|
+
const newSrc = applyBundleUrlToImagePropsSrc(
|
|
628
|
+
bundle,
|
|
629
|
+
typeof props.src === "string" ? props.src : props.src.src
|
|
630
|
+
);
|
|
631
|
+
return (
|
|
632
|
+
// eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
|
|
633
|
+
/* @__PURE__ */ jsx(
|
|
634
|
+
"img",
|
|
635
|
+
{
|
|
636
|
+
decoding: "async",
|
|
637
|
+
style: { color: "transparent" },
|
|
638
|
+
...props,
|
|
639
|
+
src: newSrc,
|
|
640
|
+
suppressHydrationWarning: true
|
|
641
|
+
}
|
|
642
|
+
)
|
|
643
|
+
);
|
|
644
|
+
};
|
|
590
645
|
}
|
|
591
646
|
});
|
|
592
647
|
|
|
@@ -629,6 +684,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
|
|
|
629
684
|
const newScript = document.createElement("script");
|
|
630
685
|
newScript.onload = () => {
|
|
631
686
|
resolve2();
|
|
687
|
+
newScript.remove();
|
|
632
688
|
};
|
|
633
689
|
newScript.onerror = () => {
|
|
634
690
|
reject(
|
|
@@ -636,6 +692,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
|
|
|
636
692
|
`Failed to load script ${script.src} for remote component`
|
|
637
693
|
)
|
|
638
694
|
);
|
|
695
|
+
newScript.remove();
|
|
639
696
|
};
|
|
640
697
|
const scriptSrc = script.getAttribute("src") || script.getAttribute("data-src");
|
|
641
698
|
if (scriptSrc) {
|
|
@@ -674,7 +731,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
|
|
|
674
731
|
await Promise.all(
|
|
675
732
|
Object.entries(resolve).map(async ([key, value]) => {
|
|
676
733
|
if (typeof value === "function") {
|
|
677
|
-
resolve[key] = await value();
|
|
734
|
+
resolve[key] = await value(remoteBundle);
|
|
678
735
|
}
|
|
679
736
|
return Promise.resolve(value);
|
|
680
737
|
})
|
|
@@ -753,7 +810,7 @@ var init_turbopack = __esm({
|
|
|
753
810
|
});
|
|
754
811
|
|
|
755
812
|
// src/html/host/index.tsx
|
|
756
|
-
import { startTransition } from "react";
|
|
813
|
+
import { startTransition, useLayoutEffect } from "react";
|
|
757
814
|
import { hydrateRoot } from "react-dom/client";
|
|
758
815
|
|
|
759
816
|
// src/shared/client/component-loader.ts
|
|
@@ -835,6 +892,41 @@ function createRSCStream(name, data) {
|
|
|
835
892
|
init_webpack_adapter();
|
|
836
893
|
init_const();
|
|
837
894
|
|
|
895
|
+
// src/shared/client/apply-origin.ts
|
|
896
|
+
var tagNames = [
|
|
897
|
+
"img",
|
|
898
|
+
"source",
|
|
899
|
+
"video",
|
|
900
|
+
"audio",
|
|
901
|
+
"track",
|
|
902
|
+
"iframe",
|
|
903
|
+
"embed",
|
|
904
|
+
"script",
|
|
905
|
+
"link"
|
|
906
|
+
];
|
|
907
|
+
function applyOriginToNodes(doc, url) {
|
|
908
|
+
const nodes = doc.querySelectorAll(
|
|
909
|
+
tagNames.map((type) => `${type}[src],${type}[srcset]`).join(",")
|
|
910
|
+
);
|
|
911
|
+
nodes.forEach((node) => {
|
|
912
|
+
if (node.hasAttribute("src") && /^[./]+\/?/.test(node.getAttribute("src") ?? "")) {
|
|
913
|
+
node.src = new URL(node.getAttribute("src") ?? "/", url).href;
|
|
914
|
+
}
|
|
915
|
+
if (node.hasAttribute("srcset")) {
|
|
916
|
+
const srcSet = node.getAttribute("srcset")?.split(",").map((entry) => {
|
|
917
|
+
const [urlPart, descriptor] = entry.trim().split(/\s+/);
|
|
918
|
+
if (!urlPart)
|
|
919
|
+
return entry;
|
|
920
|
+
const absoluteUrl = new URL(urlPart, url).href;
|
|
921
|
+
return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
|
|
922
|
+
}).join(", ");
|
|
923
|
+
if (srcSet) {
|
|
924
|
+
node.setAttribute("srcset", srcSet);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
|
|
838
930
|
// src/html/host/runtime/index.ts
|
|
839
931
|
async function getRuntime(type, url, bundle, shared, remoteShared) {
|
|
840
932
|
if (typeof globalThis.process === "undefined") {
|
|
@@ -857,44 +949,64 @@ import { jsx as jsx2 } from "react/jsx-runtime";
|
|
|
857
949
|
if (typeof HTMLElement !== "undefined") {
|
|
858
950
|
class RemoteComponent extends HTMLElement {
|
|
859
951
|
constructor() {
|
|
860
|
-
super();
|
|
952
|
+
super(...arguments);
|
|
861
953
|
this.__next = null;
|
|
862
954
|
this.fouc = null;
|
|
863
955
|
this.isLoading = false;
|
|
864
956
|
this.root = null;
|
|
865
|
-
this.root = this.attachShadow({
|
|
866
|
-
mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
|
|
867
|
-
});
|
|
868
|
-
this.fallbackSlot = document.createElement("slot");
|
|
869
|
-
this.root.appendChild(this.fallbackSlot);
|
|
870
|
-
this.name = this.getAttribute("name") || "__vercel_remote_component";
|
|
871
|
-
this.bundle = "default";
|
|
872
|
-
if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
|
|
873
|
-
this.load().catch((e) => {
|
|
874
|
-
throw new Error(`Failed to load remote component: ${e}`);
|
|
875
|
-
});
|
|
876
|
-
}
|
|
877
957
|
}
|
|
878
958
|
static get observedAttributes() {
|
|
879
|
-
return ["src", "name"];
|
|
959
|
+
return ["src", "name", "mode"];
|
|
880
960
|
}
|
|
881
961
|
// watch for src attribute changes
|
|
882
962
|
// this is required to reload the remote component when the src attribute is added later
|
|
883
963
|
// this is for rendering the custom element using React
|
|
884
964
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
885
965
|
if ((name === "src" || name === "name") && oldValue !== newValue) {
|
|
966
|
+
if (this.getAttribute("src")) {
|
|
967
|
+
this.load().catch((e) => {
|
|
968
|
+
console.error(e);
|
|
969
|
+
throw new Error(
|
|
970
|
+
`Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
|
|
971
|
+
);
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
} else if (name === "mode" && oldValue !== newValue && this.root) {
|
|
975
|
+
const newRoot = this.attachShadow({
|
|
976
|
+
mode: newValue === "closed" ? "closed" : "open"
|
|
977
|
+
});
|
|
978
|
+
Array.from(this.root.children).forEach((child) => {
|
|
979
|
+
newRoot.appendChild(child);
|
|
980
|
+
});
|
|
981
|
+
this.root = newRoot;
|
|
886
982
|
this.load().catch((e) => {
|
|
887
|
-
|
|
888
|
-
throw new Error(
|
|
889
|
-
`Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
|
|
890
|
-
);
|
|
983
|
+
throw new Error(`Failed to load remote component: ${e}`);
|
|
891
984
|
});
|
|
892
985
|
}
|
|
893
986
|
}
|
|
894
987
|
async load() {
|
|
988
|
+
await new Promise((resolve) => {
|
|
989
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : requestAnimationFrame)(() => {
|
|
990
|
+
resolve(void 0);
|
|
991
|
+
});
|
|
992
|
+
});
|
|
895
993
|
if (this.isLoading) {
|
|
896
994
|
return;
|
|
897
995
|
}
|
|
996
|
+
if (!this.root) {
|
|
997
|
+
this.root = this.attachShadow({
|
|
998
|
+
mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
|
|
999
|
+
});
|
|
1000
|
+
this.fallbackSlot = document.createElement("slot");
|
|
1001
|
+
this.root.appendChild(this.fallbackSlot);
|
|
1002
|
+
}
|
|
1003
|
+
this.name = this.getAttribute("name") || "__vercel_remote_component";
|
|
1004
|
+
this.bundle = "default";
|
|
1005
|
+
if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
|
|
1006
|
+
this.load().catch((e) => {
|
|
1007
|
+
throw new Error(`Failed to load remote component: ${e}`);
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
898
1010
|
this.isLoading = true;
|
|
899
1011
|
const src = this.getAttribute("src");
|
|
900
1012
|
const remoteComponentChild = this.querySelector("div#__REMOTE_COMPONENT__") || this.querySelector("div[data-bundle][data-route]");
|
|
@@ -925,8 +1037,8 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
925
1037
|
}
|
|
926
1038
|
html = await res.text();
|
|
927
1039
|
}
|
|
928
|
-
const
|
|
929
|
-
doc
|
|
1040
|
+
const parser = new DOMParser();
|
|
1041
|
+
const doc = parser.parseFromString(html, "text/html");
|
|
930
1042
|
const component = doc.querySelector(`div[data-bundle][data-route][id^="${this.name}"]`) ?? // fallback to the first element with the data-bundle and data-route attributes when not using a named remote component
|
|
931
1043
|
doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
|
|
932
1044
|
doc.querySelector("div#__next");
|
|
@@ -936,11 +1048,18 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
936
1048
|
if (nextData && nextData.buildId === "development" && !this.reactRoot) {
|
|
937
1049
|
this.fouc = document.createElement("style");
|
|
938
1050
|
this.fouc.textContent = `:host { display: none; }`;
|
|
939
|
-
this.root
|
|
1051
|
+
this.root.appendChild(this.fouc);
|
|
940
1052
|
}
|
|
941
1053
|
this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : this.name);
|
|
942
1054
|
const rsc = doc.querySelector(`#${this.name}_rsc`);
|
|
943
1055
|
this.bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || this.bundle;
|
|
1056
|
+
if (url) {
|
|
1057
|
+
const self2 = globalThis;
|
|
1058
|
+
if (!self2.__remote_bundle_url__) {
|
|
1059
|
+
self2.__remote_bundle_url__ = {};
|
|
1060
|
+
}
|
|
1061
|
+
self2.__remote_bundle_url__[this.bundle ?? "default"] = url;
|
|
1062
|
+
}
|
|
944
1063
|
const metadata = document.createElement("script");
|
|
945
1064
|
metadata.type = "application/json";
|
|
946
1065
|
metadata.setAttribute("data-remote-component", "");
|
|
@@ -950,47 +1069,81 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
950
1069
|
route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
|
|
951
1070
|
runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
|
|
952
1071
|
});
|
|
953
|
-
this.
|
|
954
|
-
|
|
955
|
-
|
|
1072
|
+
if (this.previousElementSibling?.getAttribute("data-remote-component") !== null) {
|
|
1073
|
+
this.previousElementSibling?.remove();
|
|
1074
|
+
}
|
|
1075
|
+
this.parentElement?.insertBefore(metadata, this);
|
|
1076
|
+
const remoteSharedEl = doc.querySelector(
|
|
1077
|
+
`#${this.name}_shared[data-remote-components-shared]`
|
|
1078
|
+
);
|
|
1079
|
+
const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
|
|
956
1080
|
remoteSharedEl?.parentElement?.removeChild(remoteSharedEl);
|
|
957
1081
|
if (!component || !(rsc || nextData)) {
|
|
958
1082
|
throw new Error(`Failed to find component with id "${this.name}"`);
|
|
959
1083
|
}
|
|
960
1084
|
const removable = Array.from(this.childNodes);
|
|
961
1085
|
const links = doc.querySelectorAll("link[href]");
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1086
|
+
const remoteComponentSrc = this.getAttribute("src");
|
|
1087
|
+
const attachLinks = async () => {
|
|
1088
|
+
await Promise.all(
|
|
1089
|
+
Array.from(links).filter((link) => {
|
|
1090
|
+
return !component.contains(link);
|
|
1091
|
+
}).map((link) => {
|
|
1092
|
+
return new Promise((resolve, reject) => {
|
|
1093
|
+
const newLink = document.createElement("link");
|
|
1094
|
+
if (link.rel === "stylesheet") {
|
|
1095
|
+
newLink.onload = () => {
|
|
1096
|
+
resolve();
|
|
1097
|
+
};
|
|
1098
|
+
newLink.onerror = () => {
|
|
1099
|
+
reject(
|
|
1100
|
+
new Error(
|
|
1101
|
+
`Failed to load link ${link.href} for remote component`
|
|
1102
|
+
)
|
|
1103
|
+
);
|
|
1104
|
+
};
|
|
1105
|
+
} else {
|
|
968
1106
|
resolve();
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
if (attr.name === "href") {
|
|
1107
|
+
}
|
|
1108
|
+
for (const attr of link.attributes) {
|
|
1109
|
+
if (attr.name === "href") {
|
|
1110
|
+
newLink.setAttribute(
|
|
1111
|
+
attr.name,
|
|
1112
|
+
new URL(attr.value, url ?? location.origin).href
|
|
1113
|
+
);
|
|
1114
|
+
} else {
|
|
1115
|
+
newLink.setAttribute(attr.name, attr.value);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
if (remoteComponentSrc) {
|
|
982
1119
|
newLink.setAttribute(
|
|
983
|
-
|
|
984
|
-
|
|
1120
|
+
"data-remote-component-src",
|
|
1121
|
+
remoteComponentSrc
|
|
985
1122
|
);
|
|
986
|
-
} else {
|
|
987
|
-
newLink.setAttribute(attr.name, attr.value);
|
|
988
1123
|
}
|
|
1124
|
+
this.root?.appendChild(newLink);
|
|
1125
|
+
});
|
|
1126
|
+
})
|
|
1127
|
+
);
|
|
1128
|
+
const styles = doc.querySelectorAll("style");
|
|
1129
|
+
styles.forEach((style) => {
|
|
1130
|
+
if (style.parentElement?.tagName.toLowerCase() === "head") {
|
|
1131
|
+
const newStyle = document.createElement("style");
|
|
1132
|
+
newStyle.textContent = style.textContent;
|
|
1133
|
+
if (remoteComponentSrc) {
|
|
1134
|
+
newStyle.setAttribute(
|
|
1135
|
+
"data-remote-component-src",
|
|
1136
|
+
remoteComponentSrc
|
|
1137
|
+
);
|
|
989
1138
|
}
|
|
990
|
-
this.root?.appendChild(
|
|
991
|
-
}
|
|
992
|
-
})
|
|
993
|
-
|
|
1139
|
+
this.root?.appendChild(newStyle);
|
|
1140
|
+
}
|
|
1141
|
+
});
|
|
1142
|
+
};
|
|
1143
|
+
if (!this.reactRoot) {
|
|
1144
|
+
await attachLinks();
|
|
1145
|
+
}
|
|
1146
|
+
applyOriginToNodes(doc, url ?? new URL(location.href));
|
|
994
1147
|
if (!this.reactRoot) {
|
|
995
1148
|
Array.from(component.children).forEach((el) => {
|
|
996
1149
|
this.root?.appendChild(el);
|
|
@@ -999,12 +1152,32 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
999
1152
|
for (const el of removable) {
|
|
1000
1153
|
el.parentElement?.removeChild(el);
|
|
1001
1154
|
}
|
|
1002
|
-
this.fallbackSlot
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1155
|
+
this.fallbackSlot?.remove();
|
|
1156
|
+
const applyReset = () => {
|
|
1157
|
+
if (this.getAttribute("reset") !== null && !this.root?.querySelector("link[data-remote-components-reset]")) {
|
|
1158
|
+
const allInitial = document.createElement("link");
|
|
1159
|
+
allInitial.setAttribute("data-remote-components-reset", "");
|
|
1160
|
+
const css = `:host { all: initial; }`;
|
|
1161
|
+
const allInitialHref = URL.createObjectURL(
|
|
1162
|
+
new Blob([css], { type: "text/css" })
|
|
1163
|
+
);
|
|
1164
|
+
allInitial.href = allInitialHref;
|
|
1165
|
+
allInitial.rel = "stylesheet";
|
|
1166
|
+
allInitial.onload = () => {
|
|
1167
|
+
URL.revokeObjectURL(allInitialHref);
|
|
1168
|
+
allInitial.removeAttribute("onload");
|
|
1169
|
+
};
|
|
1170
|
+
allInitial.onerror = () => {
|
|
1171
|
+
URL.revokeObjectURL(allInitialHref);
|
|
1172
|
+
allInitial.removeAttribute("onload");
|
|
1173
|
+
};
|
|
1174
|
+
this.root?.prepend(allInitial);
|
|
1175
|
+
} else if (this.getAttribute("reset") === null && this.root?.querySelector("link[data-remote-components-reset]")) {
|
|
1176
|
+
this.root.querySelector("link[data-remote-components-reset]")?.remove();
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
if (!this.reactRoot) {
|
|
1180
|
+
applyReset();
|
|
1008
1181
|
}
|
|
1009
1182
|
const {
|
|
1010
1183
|
self,
|
|
@@ -1039,6 +1212,20 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1039
1212
|
this.bundle ?? "default",
|
|
1040
1213
|
this.name ?? "__vercel_remote_component"
|
|
1041
1214
|
);
|
|
1215
|
+
const doCleanup = () => {
|
|
1216
|
+
if (this.root && remoteComponentSrc) {
|
|
1217
|
+
const selector = `[data-remote-component-src]:not([data-remote-component-src="${remoteComponentSrc}"])`;
|
|
1218
|
+
const prevCleanup = [
|
|
1219
|
+
...this.root.querySelectorAll(selector),
|
|
1220
|
+
...document.body.querySelectorAll(selector)
|
|
1221
|
+
];
|
|
1222
|
+
if (prevCleanup.length > 0) {
|
|
1223
|
+
prevCleanup.forEach((prev) => {
|
|
1224
|
+
prev.remove();
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1042
1229
|
if (rsc) {
|
|
1043
1230
|
rsc.parentElement?.removeChild(rsc);
|
|
1044
1231
|
const rscClone = document.createElement("script");
|
|
@@ -1047,12 +1234,30 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1047
1234
|
document.body.appendChild(rscClone);
|
|
1048
1235
|
let cache;
|
|
1049
1236
|
const RemoteComponentFromReadableStream = ({
|
|
1050
|
-
name
|
|
1237
|
+
name,
|
|
1238
|
+
initial
|
|
1051
1239
|
}) => {
|
|
1052
1240
|
const stream = createRSCStream(name, self[name] ?? [`0:[null]
|
|
1053
1241
|
`]);
|
|
1054
1242
|
const Component = cache ?? // cache the component to avoid reloading the RSC flight data
|
|
1055
1243
|
(cache = createFromReadableStream(stream));
|
|
1244
|
+
useLayoutEffect(() => {
|
|
1245
|
+
if (self[name]) {
|
|
1246
|
+
delete self[name];
|
|
1247
|
+
}
|
|
1248
|
+
const rscScript = document.getElementById(`${name}_rsc`);
|
|
1249
|
+
if (rscScript) {
|
|
1250
|
+
rscScript.remove();
|
|
1251
|
+
}
|
|
1252
|
+
doCleanup();
|
|
1253
|
+
applyReset();
|
|
1254
|
+
if (!initial) {
|
|
1255
|
+
attachLinks().catch((e) => {
|
|
1256
|
+
console.error(e);
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
this.isLoading = false;
|
|
1260
|
+
}, [initial, name]);
|
|
1056
1261
|
return Component;
|
|
1057
1262
|
};
|
|
1058
1263
|
if (this.reactRoot) {
|
|
@@ -1062,11 +1267,11 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1062
1267
|
/* @__PURE__ */ jsx2(
|
|
1063
1268
|
RemoteComponentFromReadableStream,
|
|
1064
1269
|
{
|
|
1270
|
+
initial: false,
|
|
1065
1271
|
name: this.name ?? "__vercel_remote_component"
|
|
1066
1272
|
}
|
|
1067
1273
|
)
|
|
1068
1274
|
);
|
|
1069
|
-
this.isLoading = false;
|
|
1070
1275
|
});
|
|
1071
1276
|
return;
|
|
1072
1277
|
}
|
|
@@ -1077,6 +1282,7 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1077
1282
|
/* @__PURE__ */ jsx2(
|
|
1078
1283
|
RemoteComponentFromReadableStream,
|
|
1079
1284
|
{
|
|
1285
|
+
initial: true,
|
|
1080
1286
|
name: this.name ?? "__vercel_remote_component"
|
|
1081
1287
|
}
|
|
1082
1288
|
)
|
|
@@ -1088,12 +1294,24 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1088
1294
|
this.root
|
|
1089
1295
|
);
|
|
1090
1296
|
if (Component) {
|
|
1297
|
+
const RemoteComponentFromNext = ((NextApp, NextComponent, remoteComponent = this) => function RemoteComponentNext({ initial }) {
|
|
1298
|
+
useLayoutEffect(() => {
|
|
1299
|
+
doCleanup();
|
|
1300
|
+
if (!initial) {
|
|
1301
|
+
applyReset();
|
|
1302
|
+
attachLinks().catch((e) => {
|
|
1303
|
+
console.error(e);
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
remoteComponent.isLoading = false;
|
|
1307
|
+
}, [initial]);
|
|
1308
|
+
return NextApp ? /* @__PURE__ */ jsx2(NextApp, { Component: NextComponent, ...nextData.props }) : /* @__PURE__ */ jsx2(NextComponent, { ...nextData.props });
|
|
1309
|
+
})(App, Component, this);
|
|
1091
1310
|
if (this.reactRoot) {
|
|
1092
1311
|
const root = this.reactRoot;
|
|
1093
1312
|
startTransition(() => {
|
|
1094
|
-
root.render(
|
|
1095
|
-
|
|
1096
|
-
);
|
|
1313
|
+
root.render(/* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: false }));
|
|
1314
|
+
doCleanup();
|
|
1097
1315
|
this.isLoading = false;
|
|
1098
1316
|
});
|
|
1099
1317
|
return;
|
|
@@ -1102,11 +1320,11 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1102
1320
|
// hydrateRoot expects a document or element, but it works for the shadow DOM too
|
|
1103
1321
|
// @ts-expect-error support for shadow DOM
|
|
1104
1322
|
this.root,
|
|
1105
|
-
|
|
1323
|
+
/* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: true })
|
|
1106
1324
|
);
|
|
1107
1325
|
}
|
|
1108
1326
|
if (this.fouc) {
|
|
1109
|
-
this.root
|
|
1327
|
+
this.root.removeChild(this.fouc);
|
|
1110
1328
|
}
|
|
1111
1329
|
}
|
|
1112
1330
|
this.isLoading = false;
|