remote-components 0.0.23 → 0.0.25
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 +329 -92
- package/dist/html/host.cjs.map +1 -1
- package/dist/html/host.js +332 -92
- package/dist/html/host.js.map +1 -1
- package/dist/internal/next/host/app-router-client.cjs +180 -71
- package/dist/internal/next/host/app-router-client.cjs.map +1 -1
- package/dist/internal/next/host/app-router-client.js +188 -72
- 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 +20 -13
- package/dist/internal/shared/client/remote-component.cjs.map +1 -1
- package/dist/internal/shared/client/remote-component.d.ts +4 -3
- package/dist/internal/shared/client/remote-component.js +20 -13
- 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/internal/shared/utils.cjs +31 -0
- package/dist/internal/shared/utils.cjs.map +1 -0
- package/dist/internal/shared/utils.d.ts +3 -0
- package/dist/internal/shared/utils.js +7 -0
- package/dist/internal/shared/utils.js.map +1 -0
- 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 +213 -161
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +202 -150
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/dist/html/host.js
CHANGED
|
@@ -157,14 +157,25 @@ var init_next_client_pages_loader = __esm({
|
|
|
157
157
|
}
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
+
// src/shared/utils/index.ts
|
|
161
|
+
function escapeString(str) {
|
|
162
|
+
return str.replace(/[^a-z0-9]/g, "_");
|
|
163
|
+
}
|
|
164
|
+
var init_utils = __esm({
|
|
165
|
+
"src/shared/utils/index.ts"() {
|
|
166
|
+
"use strict";
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
160
170
|
// src/shared/client/const.ts
|
|
161
171
|
function getBundleKey(bundle) {
|
|
162
|
-
return bundle
|
|
172
|
+
return escapeString(bundle);
|
|
163
173
|
}
|
|
164
174
|
var RUNTIME_WEBPACK, RUNTIME_TURBOPACK, REMOTE_COMPONENT_REGEX;
|
|
165
175
|
var init_const = __esm({
|
|
166
176
|
"src/shared/client/const.ts"() {
|
|
167
177
|
"use strict";
|
|
178
|
+
init_utils();
|
|
168
179
|
RUNTIME_WEBPACK = "webpack";
|
|
169
180
|
RUNTIME_TURBOPACK = "turbopack";
|
|
170
181
|
REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
|
|
@@ -373,7 +384,7 @@ function initializeSharedModules(bundle, shared = {}, remoteShared = {}) {
|
|
|
373
384
|
Object.entries(remoteShared).map(async ([id, module]) => {
|
|
374
385
|
if (self.__remote_shared_modules__?.[bundle]) {
|
|
375
386
|
if (shared[module]) {
|
|
376
|
-
self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module]();
|
|
387
|
+
self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module](bundle);
|
|
377
388
|
} else {
|
|
378
389
|
console.error(`Shared module "${module}" not found for "${bundle}".`);
|
|
379
390
|
}
|
|
@@ -386,7 +397,7 @@ function getSharedModule(bundle, id) {
|
|
|
386
397
|
for (const [key, value] of Object.entries(
|
|
387
398
|
self.__remote_shared_modules__?.[bundle] ?? {}
|
|
388
399
|
)) {
|
|
389
|
-
if (typeof id === "string" && id.includes(key) || id === key) {
|
|
400
|
+
if (typeof value !== "undefined" && (typeof id === "string" && id.includes(key) || id === key)) {
|
|
390
401
|
return value;
|
|
391
402
|
}
|
|
392
403
|
}
|
|
@@ -520,6 +531,24 @@ var init_webpack_adapter = __esm({
|
|
|
520
531
|
|
|
521
532
|
// src/shared/client/polyfill.tsx
|
|
522
533
|
import { jsx } from "react/jsx-runtime";
|
|
534
|
+
function applyBundleUrlToSrc(bundle, src) {
|
|
535
|
+
const self = globalThis;
|
|
536
|
+
if (self.__remote_bundle_url__?.[bundle]?.origin === location.origin) {
|
|
537
|
+
return src;
|
|
538
|
+
}
|
|
539
|
+
const { assetPrefix, path } = /^(?<assetPrefix>.*?)\/_next\/(?<path>.*)/.exec(src)?.groups ?? {};
|
|
540
|
+
if (!path) {
|
|
541
|
+
return new URL(src, self.__remote_bundle_url__?.[bundle]?.origin).href;
|
|
542
|
+
}
|
|
543
|
+
return `${self.__remote_bundle_url__?.[bundle]?.origin ?? ""}${assetPrefix}/_next/${path}`;
|
|
544
|
+
}
|
|
545
|
+
function applyBundleUrlToImagePropsSrc(bundle, src) {
|
|
546
|
+
if (typeof src === "string") {
|
|
547
|
+
return applyBundleUrlToSrc(bundle, src);
|
|
548
|
+
}
|
|
549
|
+
const propSrc = src;
|
|
550
|
+
return applyBundleUrlToSrc(bundle, propSrc.src);
|
|
551
|
+
}
|
|
523
552
|
function sharedPolyfills(shared) {
|
|
524
553
|
const self = globalThis;
|
|
525
554
|
const polyfill = {
|
|
@@ -555,18 +584,17 @@ function sharedPolyfills(shared) {
|
|
|
555
584
|
},
|
|
556
585
|
__esModule: true
|
|
557
586
|
})),
|
|
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
|
-
),
|
|
587
|
+
"next/dist/client/image-component": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
|
|
588
|
+
Image: imageImpl(bundle),
|
|
589
|
+
__esModule: true
|
|
590
|
+
})),
|
|
591
|
+
"next/image": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
|
|
592
|
+
default: imageImpl(bundle),
|
|
593
|
+
getImageProps: (_imgProps) => {
|
|
594
|
+
throw new Error(
|
|
595
|
+
"Next.js getImageProps() is not implemented in remote components"
|
|
596
|
+
);
|
|
597
|
+
},
|
|
570
598
|
__esModule: true
|
|
571
599
|
})),
|
|
572
600
|
"next/dist/client/script": self.__remote_component_host_shared_modules__?.["next/script"] ?? shared?.["next/script"] ?? (() => Promise.resolve({
|
|
@@ -574,19 +602,57 @@ function sharedPolyfills(shared) {
|
|
|
574
602
|
// do not throw an error for now
|
|
575
603
|
default: () => null,
|
|
576
604
|
__esModule: true
|
|
577
|
-
}))
|
|
605
|
+
})),
|
|
606
|
+
"next/router": self.__remote_component_host_shared_modules__?.["next/router"] ?? shared?.["next/router"] ?? (() => (
|
|
607
|
+
// TODO: incomplete implementation
|
|
608
|
+
Promise.resolve({
|
|
609
|
+
useRouter() {
|
|
610
|
+
return {
|
|
611
|
+
push: (routerUrl) => {
|
|
612
|
+
history.pushState({}, "", routerUrl);
|
|
613
|
+
},
|
|
614
|
+
replace: (routerUrl) => {
|
|
615
|
+
history.replaceState({}, "", routerUrl);
|
|
616
|
+
},
|
|
617
|
+
back: () => {
|
|
618
|
+
history.back();
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
},
|
|
622
|
+
__esModule: true
|
|
623
|
+
})
|
|
624
|
+
))
|
|
578
625
|
};
|
|
579
626
|
polyfill["next/navigation"] = polyfill["next/dist/client/components/navigation"];
|
|
580
627
|
polyfill["next/link"] = polyfill["next/dist/client/app-dir/link"];
|
|
581
628
|
polyfill["next/form"] = polyfill["next/dist/client/app-dir/form"];
|
|
582
|
-
polyfill["next/image"] = polyfill["next/dist/client/image-component"];
|
|
583
629
|
polyfill["next/dist/api/image"] = polyfill["next/dist/client/image-component"];
|
|
584
630
|
polyfill["next/script"] = polyfill["next/dist/client/script"];
|
|
585
631
|
return polyfill;
|
|
586
632
|
}
|
|
633
|
+
var imageImpl;
|
|
587
634
|
var init_polyfill = __esm({
|
|
588
635
|
"src/shared/client/polyfill.tsx"() {
|
|
589
636
|
"use strict";
|
|
637
|
+
imageImpl = (bundle) => function RemoteImage({ priority: _, ...props }) {
|
|
638
|
+
const newSrc = applyBundleUrlToImagePropsSrc(
|
|
639
|
+
bundle,
|
|
640
|
+
typeof props.src === "string" ? props.src : props.src.src
|
|
641
|
+
);
|
|
642
|
+
return (
|
|
643
|
+
// eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
|
|
644
|
+
/* @__PURE__ */ jsx(
|
|
645
|
+
"img",
|
|
646
|
+
{
|
|
647
|
+
decoding: "async",
|
|
648
|
+
style: { color: "transparent" },
|
|
649
|
+
...props,
|
|
650
|
+
src: newSrc,
|
|
651
|
+
suppressHydrationWarning: true
|
|
652
|
+
}
|
|
653
|
+
)
|
|
654
|
+
);
|
|
655
|
+
};
|
|
590
656
|
}
|
|
591
657
|
});
|
|
592
658
|
|
|
@@ -629,6 +695,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
|
|
|
629
695
|
const newScript = document.createElement("script");
|
|
630
696
|
newScript.onload = () => {
|
|
631
697
|
resolve2();
|
|
698
|
+
newScript.remove();
|
|
632
699
|
};
|
|
633
700
|
newScript.onerror = () => {
|
|
634
701
|
reject(
|
|
@@ -636,6 +703,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
|
|
|
636
703
|
`Failed to load script ${script.src} for remote component`
|
|
637
704
|
)
|
|
638
705
|
);
|
|
706
|
+
newScript.remove();
|
|
639
707
|
};
|
|
640
708
|
const scriptSrc = script.getAttribute("src") || script.getAttribute("data-src");
|
|
641
709
|
if (scriptSrc) {
|
|
@@ -674,7 +742,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
|
|
|
674
742
|
await Promise.all(
|
|
675
743
|
Object.entries(resolve).map(async ([key, value]) => {
|
|
676
744
|
if (typeof value === "function") {
|
|
677
|
-
resolve[key] = await value();
|
|
745
|
+
resolve[key] = await value(remoteBundle);
|
|
678
746
|
}
|
|
679
747
|
return Promise.resolve(value);
|
|
680
748
|
})
|
|
@@ -753,7 +821,7 @@ var init_turbopack = __esm({
|
|
|
753
821
|
});
|
|
754
822
|
|
|
755
823
|
// src/html/host/index.tsx
|
|
756
|
-
import { startTransition } from "react";
|
|
824
|
+
import { startTransition, useLayoutEffect } from "react";
|
|
757
825
|
import { hydrateRoot } from "react-dom/client";
|
|
758
826
|
|
|
759
827
|
// src/shared/client/component-loader.ts
|
|
@@ -786,26 +854,27 @@ function fixPayload(payload) {
|
|
|
786
854
|
}
|
|
787
855
|
}
|
|
788
856
|
}
|
|
789
|
-
function createRSCStream(
|
|
857
|
+
function createRSCStream(rscName, data) {
|
|
790
858
|
return new ReadableStream({
|
|
791
859
|
type: "bytes",
|
|
792
860
|
start(controller) {
|
|
793
861
|
const encoder = new TextEncoder();
|
|
794
862
|
const self = globalThis;
|
|
795
|
-
if (
|
|
863
|
+
if (data.length > 0) {
|
|
796
864
|
data.forEach((chunk) => {
|
|
797
865
|
const lines = chunk.split("\n");
|
|
798
866
|
for (const line of lines) {
|
|
799
867
|
const match = /\.push\("(?<rsc>.*)"\);$/.exec(line);
|
|
800
868
|
if (match?.groups?.rsc) {
|
|
801
|
-
self[
|
|
802
|
-
self[
|
|
869
|
+
self[rscName] = self[rscName] ?? [];
|
|
870
|
+
self[rscName].push(JSON.parse(`"${match.groups.rsc}"`));
|
|
803
871
|
}
|
|
804
872
|
}
|
|
805
873
|
});
|
|
806
874
|
}
|
|
807
|
-
const allChunks = (self[
|
|
875
|
+
const allChunks = (self[rscName] ?? [`0:[null]
|
|
808
876
|
`]).join("");
|
|
877
|
+
self[rscName] = null;
|
|
809
878
|
allChunks.split("\n").forEach((chunk) => {
|
|
810
879
|
if (chunk.length > 0) {
|
|
811
880
|
const { before, id, prefix, payload } = /^(?<before>.*?)?(?<id>[0-9a-zA-Z]+):(?<prefix>[A-Z])?(?<payload>\[.*\])/.exec(
|
|
@@ -835,6 +904,44 @@ function createRSCStream(name, data) {
|
|
|
835
904
|
init_webpack_adapter();
|
|
836
905
|
init_const();
|
|
837
906
|
|
|
907
|
+
// src/html/host/index.tsx
|
|
908
|
+
init_utils();
|
|
909
|
+
|
|
910
|
+
// src/shared/client/apply-origin.ts
|
|
911
|
+
var tagNames = [
|
|
912
|
+
"img",
|
|
913
|
+
"source",
|
|
914
|
+
"video",
|
|
915
|
+
"audio",
|
|
916
|
+
"track",
|
|
917
|
+
"iframe",
|
|
918
|
+
"embed",
|
|
919
|
+
"script",
|
|
920
|
+
"link"
|
|
921
|
+
];
|
|
922
|
+
function applyOriginToNodes(doc, url) {
|
|
923
|
+
const nodes = doc.querySelectorAll(
|
|
924
|
+
tagNames.map((type) => `${type}[src],${type}[srcset]`).join(",")
|
|
925
|
+
);
|
|
926
|
+
nodes.forEach((node) => {
|
|
927
|
+
if (node.hasAttribute("src") && /^[./]+\/?/.test(node.getAttribute("src") ?? "")) {
|
|
928
|
+
node.src = new URL(node.getAttribute("src") ?? "/", url).href;
|
|
929
|
+
}
|
|
930
|
+
if (node.hasAttribute("srcset")) {
|
|
931
|
+
const srcSet = node.getAttribute("srcset")?.split(",").map((entry) => {
|
|
932
|
+
const [urlPart, descriptor] = entry.trim().split(/\s+/);
|
|
933
|
+
if (!urlPart)
|
|
934
|
+
return entry;
|
|
935
|
+
const absoluteUrl = new URL(urlPart, url).href;
|
|
936
|
+
return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
|
|
937
|
+
}).join(", ");
|
|
938
|
+
if (srcSet) {
|
|
939
|
+
node.setAttribute("srcset", srcSet);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
|
|
838
945
|
// src/html/host/runtime/index.ts
|
|
839
946
|
async function getRuntime(type, url, bundle, shared, remoteShared) {
|
|
840
947
|
if (typeof globalThis.process === "undefined") {
|
|
@@ -857,44 +964,64 @@ import { jsx as jsx2 } from "react/jsx-runtime";
|
|
|
857
964
|
if (typeof HTMLElement !== "undefined") {
|
|
858
965
|
class RemoteComponent extends HTMLElement {
|
|
859
966
|
constructor() {
|
|
860
|
-
super();
|
|
967
|
+
super(...arguments);
|
|
861
968
|
this.__next = null;
|
|
862
969
|
this.fouc = null;
|
|
863
970
|
this.isLoading = false;
|
|
864
971
|
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
972
|
}
|
|
878
973
|
static get observedAttributes() {
|
|
879
|
-
return ["src", "name"];
|
|
974
|
+
return ["src", "name", "mode"];
|
|
880
975
|
}
|
|
881
976
|
// watch for src attribute changes
|
|
882
977
|
// this is required to reload the remote component when the src attribute is added later
|
|
883
978
|
// this is for rendering the custom element using React
|
|
884
979
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
885
980
|
if ((name === "src" || name === "name") && oldValue !== newValue) {
|
|
981
|
+
if (this.getAttribute("src")) {
|
|
982
|
+
this.load().catch((e) => {
|
|
983
|
+
console.error(e);
|
|
984
|
+
throw new Error(
|
|
985
|
+
`Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
|
|
986
|
+
);
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
} else if (name === "mode" && oldValue !== newValue && this.root) {
|
|
990
|
+
const newRoot = this.attachShadow({
|
|
991
|
+
mode: newValue === "closed" ? "closed" : "open"
|
|
992
|
+
});
|
|
993
|
+
Array.from(this.root.children).forEach((child) => {
|
|
994
|
+
newRoot.appendChild(child);
|
|
995
|
+
});
|
|
996
|
+
this.root = newRoot;
|
|
886
997
|
this.load().catch((e) => {
|
|
887
|
-
|
|
888
|
-
throw new Error(
|
|
889
|
-
`Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
|
|
890
|
-
);
|
|
998
|
+
throw new Error(`Failed to load remote component: ${e}`);
|
|
891
999
|
});
|
|
892
1000
|
}
|
|
893
1001
|
}
|
|
894
1002
|
async load() {
|
|
1003
|
+
await new Promise((resolve) => {
|
|
1004
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : requestAnimationFrame)(() => {
|
|
1005
|
+
resolve(void 0);
|
|
1006
|
+
});
|
|
1007
|
+
});
|
|
895
1008
|
if (this.isLoading) {
|
|
896
1009
|
return;
|
|
897
1010
|
}
|
|
1011
|
+
if (!this.root) {
|
|
1012
|
+
this.root = this.attachShadow({
|
|
1013
|
+
mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
|
|
1014
|
+
});
|
|
1015
|
+
this.fallbackSlot = document.createElement("slot");
|
|
1016
|
+
this.root.appendChild(this.fallbackSlot);
|
|
1017
|
+
}
|
|
1018
|
+
this.name = this.getAttribute("name") || "__vercel_remote_component";
|
|
1019
|
+
this.bundle = "default";
|
|
1020
|
+
if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
|
|
1021
|
+
this.load().catch((e) => {
|
|
1022
|
+
throw new Error(`Failed to load remote component: ${e}`);
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
898
1025
|
this.isLoading = true;
|
|
899
1026
|
const src = this.getAttribute("src");
|
|
900
1027
|
const remoteComponentChild = this.querySelector("div#__REMOTE_COMPONENT__") || this.querySelector("div[data-bundle][data-route]");
|
|
@@ -925,8 +1052,8 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
925
1052
|
}
|
|
926
1053
|
html = await res.text();
|
|
927
1054
|
}
|
|
928
|
-
const
|
|
929
|
-
doc
|
|
1055
|
+
const parser = new DOMParser();
|
|
1056
|
+
const doc = parser.parseFromString(html, "text/html");
|
|
930
1057
|
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
1058
|
doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
|
|
932
1059
|
doc.querySelector("div#__next");
|
|
@@ -936,11 +1063,18 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
936
1063
|
if (nextData && nextData.buildId === "development" && !this.reactRoot) {
|
|
937
1064
|
this.fouc = document.createElement("style");
|
|
938
1065
|
this.fouc.textContent = `:host { display: none; }`;
|
|
939
|
-
this.root
|
|
1066
|
+
this.root.appendChild(this.fouc);
|
|
940
1067
|
}
|
|
941
1068
|
this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : this.name);
|
|
942
1069
|
const rsc = doc.querySelector(`#${this.name}_rsc`);
|
|
943
1070
|
this.bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || this.bundle;
|
|
1071
|
+
if (url) {
|
|
1072
|
+
const self2 = globalThis;
|
|
1073
|
+
if (!self2.__remote_bundle_url__) {
|
|
1074
|
+
self2.__remote_bundle_url__ = {};
|
|
1075
|
+
}
|
|
1076
|
+
self2.__remote_bundle_url__[this.bundle ?? "default"] = url;
|
|
1077
|
+
}
|
|
944
1078
|
const metadata = document.createElement("script");
|
|
945
1079
|
metadata.type = "application/json";
|
|
946
1080
|
metadata.setAttribute("data-remote-component", "");
|
|
@@ -950,47 +1084,81 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
950
1084
|
route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
|
|
951
1085
|
runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
|
|
952
1086
|
});
|
|
953
|
-
this.
|
|
954
|
-
|
|
955
|
-
|
|
1087
|
+
if (this.previousElementSibling?.getAttribute("data-remote-component") !== null) {
|
|
1088
|
+
this.previousElementSibling?.remove();
|
|
1089
|
+
}
|
|
1090
|
+
this.parentElement?.insertBefore(metadata, this);
|
|
1091
|
+
const remoteSharedEl = doc.querySelector(
|
|
1092
|
+
`#${this.name}_shared[data-remote-components-shared]`
|
|
1093
|
+
);
|
|
1094
|
+
const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
|
|
956
1095
|
remoteSharedEl?.parentElement?.removeChild(remoteSharedEl);
|
|
957
1096
|
if (!component || !(rsc || nextData)) {
|
|
958
1097
|
throw new Error(`Failed to find component with id "${this.name}"`);
|
|
959
1098
|
}
|
|
960
1099
|
const removable = Array.from(this.childNodes);
|
|
961
1100
|
const links = doc.querySelectorAll("link[href]");
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1101
|
+
const remoteComponentSrc = this.getAttribute("src");
|
|
1102
|
+
const attachLinks = async () => {
|
|
1103
|
+
await Promise.all(
|
|
1104
|
+
Array.from(links).filter((link) => {
|
|
1105
|
+
return !component.contains(link);
|
|
1106
|
+
}).map((link) => {
|
|
1107
|
+
return new Promise((resolve, reject) => {
|
|
1108
|
+
const newLink = document.createElement("link");
|
|
1109
|
+
if (link.rel === "stylesheet") {
|
|
1110
|
+
newLink.onload = () => {
|
|
1111
|
+
resolve();
|
|
1112
|
+
};
|
|
1113
|
+
newLink.onerror = () => {
|
|
1114
|
+
reject(
|
|
1115
|
+
new Error(
|
|
1116
|
+
`Failed to load link ${link.href} for remote component`
|
|
1117
|
+
)
|
|
1118
|
+
);
|
|
1119
|
+
};
|
|
1120
|
+
} else {
|
|
968
1121
|
resolve();
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
if (attr.name === "href") {
|
|
1122
|
+
}
|
|
1123
|
+
for (const attr of link.attributes) {
|
|
1124
|
+
if (attr.name === "href") {
|
|
1125
|
+
newLink.setAttribute(
|
|
1126
|
+
attr.name,
|
|
1127
|
+
new URL(attr.value, url ?? location.origin).href
|
|
1128
|
+
);
|
|
1129
|
+
} else {
|
|
1130
|
+
newLink.setAttribute(attr.name, attr.value);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
if (remoteComponentSrc) {
|
|
982
1134
|
newLink.setAttribute(
|
|
983
|
-
|
|
984
|
-
|
|
1135
|
+
"data-remote-component-src",
|
|
1136
|
+
remoteComponentSrc
|
|
985
1137
|
);
|
|
986
|
-
} else {
|
|
987
|
-
newLink.setAttribute(attr.name, attr.value);
|
|
988
1138
|
}
|
|
1139
|
+
this.root?.appendChild(newLink);
|
|
1140
|
+
});
|
|
1141
|
+
})
|
|
1142
|
+
);
|
|
1143
|
+
const styles = doc.querySelectorAll("style");
|
|
1144
|
+
styles.forEach((style) => {
|
|
1145
|
+
if (style.parentElement?.tagName.toLowerCase() === "head") {
|
|
1146
|
+
const newStyle = document.createElement("style");
|
|
1147
|
+
newStyle.textContent = style.textContent;
|
|
1148
|
+
if (remoteComponentSrc) {
|
|
1149
|
+
newStyle.setAttribute(
|
|
1150
|
+
"data-remote-component-src",
|
|
1151
|
+
remoteComponentSrc
|
|
1152
|
+
);
|
|
989
1153
|
}
|
|
990
|
-
this.root?.appendChild(
|
|
991
|
-
}
|
|
992
|
-
})
|
|
993
|
-
|
|
1154
|
+
this.root?.appendChild(newStyle);
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
};
|
|
1158
|
+
if (!this.reactRoot) {
|
|
1159
|
+
await attachLinks();
|
|
1160
|
+
}
|
|
1161
|
+
applyOriginToNodes(doc, url ?? new URL(location.href));
|
|
994
1162
|
if (!this.reactRoot) {
|
|
995
1163
|
Array.from(component.children).forEach((el) => {
|
|
996
1164
|
this.root?.appendChild(el);
|
|
@@ -999,12 +1167,32 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
999
1167
|
for (const el of removable) {
|
|
1000
1168
|
el.parentElement?.removeChild(el);
|
|
1001
1169
|
}
|
|
1002
|
-
this.fallbackSlot
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1170
|
+
this.fallbackSlot?.remove();
|
|
1171
|
+
const applyReset = () => {
|
|
1172
|
+
if (this.getAttribute("reset") !== null && !this.root?.querySelector("link[data-remote-components-reset]")) {
|
|
1173
|
+
const allInitial = document.createElement("link");
|
|
1174
|
+
allInitial.setAttribute("data-remote-components-reset", "");
|
|
1175
|
+
const css = `:host { all: initial; }`;
|
|
1176
|
+
const allInitialHref = URL.createObjectURL(
|
|
1177
|
+
new Blob([css], { type: "text/css" })
|
|
1178
|
+
);
|
|
1179
|
+
allInitial.href = allInitialHref;
|
|
1180
|
+
allInitial.rel = "stylesheet";
|
|
1181
|
+
allInitial.onload = () => {
|
|
1182
|
+
URL.revokeObjectURL(allInitialHref);
|
|
1183
|
+
allInitial.removeAttribute("onload");
|
|
1184
|
+
};
|
|
1185
|
+
allInitial.onerror = () => {
|
|
1186
|
+
URL.revokeObjectURL(allInitialHref);
|
|
1187
|
+
allInitial.removeAttribute("onload");
|
|
1188
|
+
};
|
|
1189
|
+
this.root?.prepend(allInitial);
|
|
1190
|
+
} else if (this.getAttribute("reset") === null && this.root?.querySelector("link[data-remote-components-reset]")) {
|
|
1191
|
+
this.root.querySelector("link[data-remote-components-reset]")?.remove();
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
if (!this.reactRoot) {
|
|
1195
|
+
applyReset();
|
|
1008
1196
|
}
|
|
1009
1197
|
const {
|
|
1010
1198
|
self,
|
|
@@ -1039,20 +1227,59 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1039
1227
|
this.bundle ?? "default",
|
|
1040
1228
|
this.name ?? "__vercel_remote_component"
|
|
1041
1229
|
);
|
|
1230
|
+
const doCleanup = () => {
|
|
1231
|
+
if (this.root && remoteComponentSrc) {
|
|
1232
|
+
const selector = `[data-remote-component-src]:not([data-remote-component-src="${remoteComponentSrc}"])`;
|
|
1233
|
+
const prevCleanup = [
|
|
1234
|
+
...this.root.querySelectorAll(selector),
|
|
1235
|
+
...document.body.querySelectorAll(selector)
|
|
1236
|
+
];
|
|
1237
|
+
if (prevCleanup.length > 0) {
|
|
1238
|
+
prevCleanup.forEach((prev) => {
|
|
1239
|
+
prev.remove();
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1042
1244
|
if (rsc) {
|
|
1043
1245
|
rsc.parentElement?.removeChild(rsc);
|
|
1246
|
+
const rscName = `__remote_component_rsc_${escapeString(url.href)}_${escapeString(this.name)}`;
|
|
1044
1247
|
const rscClone = document.createElement("script");
|
|
1045
|
-
rscClone.id = `${
|
|
1046
|
-
rscClone.textContent = rsc.textContent
|
|
1248
|
+
rscClone.id = `${rscName}_rsc`;
|
|
1249
|
+
rscClone.textContent = rsc.textContent?.replace(
|
|
1250
|
+
new RegExp(`self\\["${this.name}"\\]`, "g"),
|
|
1251
|
+
`self["${rscName}"]`
|
|
1252
|
+
) ?? "";
|
|
1047
1253
|
document.body.appendChild(rscClone);
|
|
1048
1254
|
let cache;
|
|
1049
1255
|
const RemoteComponentFromReadableStream = ({
|
|
1050
|
-
name
|
|
1256
|
+
name,
|
|
1257
|
+
initial
|
|
1051
1258
|
}) => {
|
|
1052
|
-
const stream = createRSCStream(
|
|
1053
|
-
|
|
1259
|
+
const stream = createRSCStream(
|
|
1260
|
+
rscName,
|
|
1261
|
+
self[rscName] ?? [`0:[null]
|
|
1262
|
+
`]
|
|
1263
|
+
);
|
|
1054
1264
|
const Component = cache ?? // cache the component to avoid reloading the RSC flight data
|
|
1055
1265
|
(cache = createFromReadableStream(stream));
|
|
1266
|
+
useLayoutEffect(() => {
|
|
1267
|
+
if (self[name]) {
|
|
1268
|
+
delete self[name];
|
|
1269
|
+
}
|
|
1270
|
+
const rscScript = document.getElementById(`${name}_rsc`);
|
|
1271
|
+
if (rscScript) {
|
|
1272
|
+
rscScript.remove();
|
|
1273
|
+
}
|
|
1274
|
+
doCleanup();
|
|
1275
|
+
applyReset();
|
|
1276
|
+
if (!initial) {
|
|
1277
|
+
attachLinks().catch((e) => {
|
|
1278
|
+
console.error(e);
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
this.isLoading = false;
|
|
1282
|
+
}, [initial, name]);
|
|
1056
1283
|
return Component;
|
|
1057
1284
|
};
|
|
1058
1285
|
if (this.reactRoot) {
|
|
@@ -1062,11 +1289,11 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1062
1289
|
/* @__PURE__ */ jsx2(
|
|
1063
1290
|
RemoteComponentFromReadableStream,
|
|
1064
1291
|
{
|
|
1292
|
+
initial: false,
|
|
1065
1293
|
name: this.name ?? "__vercel_remote_component"
|
|
1066
1294
|
}
|
|
1067
1295
|
)
|
|
1068
1296
|
);
|
|
1069
|
-
this.isLoading = false;
|
|
1070
1297
|
});
|
|
1071
1298
|
return;
|
|
1072
1299
|
}
|
|
@@ -1077,6 +1304,7 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1077
1304
|
/* @__PURE__ */ jsx2(
|
|
1078
1305
|
RemoteComponentFromReadableStream,
|
|
1079
1306
|
{
|
|
1307
|
+
initial: true,
|
|
1080
1308
|
name: this.name ?? "__vercel_remote_component"
|
|
1081
1309
|
}
|
|
1082
1310
|
)
|
|
@@ -1088,12 +1316,24 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1088
1316
|
this.root
|
|
1089
1317
|
);
|
|
1090
1318
|
if (Component) {
|
|
1319
|
+
const RemoteComponentFromNext = ((NextApp, NextComponent, remoteComponent = this) => function RemoteComponentNext({ initial }) {
|
|
1320
|
+
useLayoutEffect(() => {
|
|
1321
|
+
doCleanup();
|
|
1322
|
+
if (!initial) {
|
|
1323
|
+
applyReset();
|
|
1324
|
+
attachLinks().catch((e) => {
|
|
1325
|
+
console.error(e);
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
remoteComponent.isLoading = false;
|
|
1329
|
+
}, [initial]);
|
|
1330
|
+
return NextApp ? /* @__PURE__ */ jsx2(NextApp, { Component: NextComponent, ...nextData.props }) : /* @__PURE__ */ jsx2(NextComponent, { ...nextData.props });
|
|
1331
|
+
})(App, Component, this);
|
|
1091
1332
|
if (this.reactRoot) {
|
|
1092
1333
|
const root = this.reactRoot;
|
|
1093
1334
|
startTransition(() => {
|
|
1094
|
-
root.render(
|
|
1095
|
-
|
|
1096
|
-
);
|
|
1335
|
+
root.render(/* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: false }));
|
|
1336
|
+
doCleanup();
|
|
1097
1337
|
this.isLoading = false;
|
|
1098
1338
|
});
|
|
1099
1339
|
return;
|
|
@@ -1102,11 +1342,11 @@ if (typeof HTMLElement !== "undefined") {
|
|
|
1102
1342
|
// hydrateRoot expects a document or element, but it works for the shadow DOM too
|
|
1103
1343
|
// @ts-expect-error support for shadow DOM
|
|
1104
1344
|
this.root,
|
|
1105
|
-
|
|
1345
|
+
/* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: true })
|
|
1106
1346
|
);
|
|
1107
1347
|
}
|
|
1108
1348
|
if (this.fouc) {
|
|
1109
|
-
this.root
|
|
1349
|
+
this.root.removeChild(this.fouc);
|
|
1110
1350
|
}
|
|
1111
1351
|
}
|
|
1112
1352
|
this.isLoading = false;
|