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.
Files changed (74) hide show
  1. package/dist/html/host.cjs +329 -92
  2. package/dist/html/host.cjs.map +1 -1
  3. package/dist/html/host.js +332 -92
  4. package/dist/html/host.js.map +1 -1
  5. package/dist/internal/next/host/app-router-client.cjs +180 -71
  6. package/dist/internal/next/host/app-router-client.cjs.map +1 -1
  7. package/dist/internal/next/host/app-router-client.js +188 -72
  8. package/dist/internal/next/host/app-router-client.js.map +1 -1
  9. package/dist/internal/next/host/app-router-compat.cjs +114 -0
  10. package/dist/internal/next/host/app-router-compat.cjs.map +1 -0
  11. package/dist/internal/next/host/app-router-compat.d.ts +31 -0
  12. package/dist/internal/next/host/app-router-compat.js +79 -0
  13. package/dist/internal/next/host/app-router-compat.js.map +1 -0
  14. package/dist/internal/next/remote/render-client.cjs +10 -2
  15. package/dist/internal/next/remote/render-client.cjs.map +1 -1
  16. package/dist/internal/next/remote/render-client.js +10 -2
  17. package/dist/internal/next/remote/render-client.js.map +1 -1
  18. package/dist/internal/shared/client/apply-origin.cjs +61 -0
  19. package/dist/internal/shared/client/apply-origin.cjs.map +1 -0
  20. package/dist/internal/shared/client/apply-origin.d.ts +3 -0
  21. package/dist/internal/shared/client/apply-origin.js +37 -0
  22. package/dist/internal/shared/client/apply-origin.js.map +1 -0
  23. package/dist/internal/shared/client/polyfill.cjs +149 -0
  24. package/dist/internal/shared/client/polyfill.cjs.map +1 -0
  25. package/dist/internal/shared/client/polyfill.d.ts +6 -0
  26. package/dist/internal/shared/client/polyfill.js +124 -0
  27. package/dist/internal/shared/client/polyfill.js.map +1 -0
  28. package/dist/internal/shared/client/remote-component.cjs +20 -13
  29. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  30. package/dist/internal/shared/client/remote-component.d.ts +4 -3
  31. package/dist/internal/shared/client/remote-component.js +20 -13
  32. package/dist/internal/shared/client/remote-component.js.map +1 -1
  33. package/dist/internal/shared/ssr/dom-flight.cjs +40 -0
  34. package/dist/internal/shared/ssr/dom-flight.cjs.map +1 -1
  35. package/dist/internal/shared/ssr/dom-flight.js +40 -0
  36. package/dist/internal/shared/ssr/dom-flight.js.map +1 -1
  37. package/dist/internal/shared/ssr/fetch-remote-component.cjs +1 -1
  38. package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
  39. package/dist/internal/shared/ssr/fetch-remote-component.d.ts +6 -0
  40. package/dist/internal/shared/ssr/fetch-remote-component.js +1 -1
  41. package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
  42. package/dist/internal/shared/utils.cjs +31 -0
  43. package/dist/internal/shared/utils.cjs.map +1 -0
  44. package/dist/internal/shared/utils.d.ts +3 -0
  45. package/dist/internal/shared/utils.js +7 -0
  46. package/dist/internal/shared/utils.js.map +1 -0
  47. package/dist/next/config.cjs +50 -28
  48. package/dist/next/config.cjs.map +1 -1
  49. package/dist/next/config.js +50 -28
  50. package/dist/next/config.js.map +1 -1
  51. package/dist/next/host/client/index.cjs +16 -1
  52. package/dist/next/host/client/index.cjs.map +1 -1
  53. package/dist/next/host/client/index.js +16 -1
  54. package/dist/next/host/client/index.js.map +1 -1
  55. package/dist/next/host/pages-router-server.cjs +27 -13
  56. package/dist/next/host/pages-router-server.cjs.map +1 -1
  57. package/dist/next/host/pages-router-server.js +27 -13
  58. package/dist/next/host/pages-router-server.js.map +1 -1
  59. package/dist/next/middleware.cjs +5 -2
  60. package/dist/next/middleware.cjs.map +1 -1
  61. package/dist/next/middleware.d.ts +1 -0
  62. package/dist/next/middleware.js +5 -2
  63. package/dist/next/middleware.js.map +1 -1
  64. package/dist/next/remote/pages-router.cjs +3 -1
  65. package/dist/next/remote/pages-router.cjs.map +1 -1
  66. package/dist/next/remote/pages-router.d.ts +1 -0
  67. package/dist/next/remote/pages-router.js +3 -1
  68. package/dist/next/remote/pages-router.js.map +1 -1
  69. package/dist/react/index.cjs +213 -161
  70. package/dist/react/index.cjs.map +1 -1
  71. package/dist/react/index.d.ts +2 -1
  72. package/dist/react/index.js +202 -150
  73. package/dist/react/index.js.map +1 -1
  74. package/package.json +1 -1
@@ -179,14 +179,25 @@ var init_next_client_pages_loader = __esm({
179
179
  }
180
180
  });
181
181
 
182
+ // src/shared/utils/index.ts
183
+ function escapeString(str) {
184
+ return str.replace(/[^a-z0-9]/g, "_");
185
+ }
186
+ var init_utils = __esm({
187
+ "src/shared/utils/index.ts"() {
188
+ "use strict";
189
+ }
190
+ });
191
+
182
192
  // src/shared/client/const.ts
183
193
  function getBundleKey(bundle) {
184
- return bundle.replace(/-/g, "_");
194
+ return escapeString(bundle);
185
195
  }
186
196
  var RUNTIME_WEBPACK, RUNTIME_TURBOPACK, REMOTE_COMPONENT_REGEX;
187
197
  var init_const = __esm({
188
198
  "src/shared/client/const.ts"() {
189
199
  "use strict";
200
+ init_utils();
190
201
  RUNTIME_WEBPACK = "webpack";
191
202
  RUNTIME_TURBOPACK = "turbopack";
192
203
  REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
@@ -395,7 +406,7 @@ function initializeSharedModules(bundle, shared = {}, remoteShared = {}) {
395
406
  Object.entries(remoteShared).map(async ([id, module2]) => {
396
407
  if (self.__remote_shared_modules__?.[bundle]) {
397
408
  if (shared[module2]) {
398
- self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module2]();
409
+ self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module2](bundle);
399
410
  } else {
400
411
  console.error(`Shared module "${module2}" not found for "${bundle}".`);
401
412
  }
@@ -408,7 +419,7 @@ function getSharedModule(bundle, id) {
408
419
  for (const [key, value] of Object.entries(
409
420
  self.__remote_shared_modules__?.[bundle] ?? {}
410
421
  )) {
411
- if (typeof id === "string" && id.includes(key) || id === key) {
422
+ if (typeof value !== "undefined" && (typeof id === "string" && id.includes(key) || id === key)) {
412
423
  return value;
413
424
  }
414
425
  }
@@ -541,6 +552,24 @@ var init_webpack_adapter = __esm({
541
552
  });
542
553
 
543
554
  // src/shared/client/polyfill.tsx
555
+ function applyBundleUrlToSrc(bundle, src) {
556
+ const self = globalThis;
557
+ if (self.__remote_bundle_url__?.[bundle]?.origin === location.origin) {
558
+ return src;
559
+ }
560
+ const { assetPrefix, path } = /^(?<assetPrefix>.*?)\/_next\/(?<path>.*)/.exec(src)?.groups ?? {};
561
+ if (!path) {
562
+ return new URL(src, self.__remote_bundle_url__?.[bundle]?.origin).href;
563
+ }
564
+ return `${self.__remote_bundle_url__?.[bundle]?.origin ?? ""}${assetPrefix}/_next/${path}`;
565
+ }
566
+ function applyBundleUrlToImagePropsSrc(bundle, src) {
567
+ if (typeof src === "string") {
568
+ return applyBundleUrlToSrc(bundle, src);
569
+ }
570
+ const propSrc = src;
571
+ return applyBundleUrlToSrc(bundle, propSrc.src);
572
+ }
544
573
  function sharedPolyfills(shared) {
545
574
  const self = globalThis;
546
575
  const polyfill = {
@@ -576,18 +605,17 @@ function sharedPolyfills(shared) {
576
605
  },
577
606
  __esModule: true
578
607
  })),
579
- "next/dist/client/image-component": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? (() => Promise.resolve({
580
- Image: (props) => (
581
- // eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
582
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
583
- "img",
584
- {
585
- ...props,
586
- src: props.src,
587
- suppressHydrationWarning: true
588
- }
589
- )
590
- ),
608
+ "next/dist/client/image-component": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
609
+ Image: imageImpl(bundle),
610
+ __esModule: true
611
+ })),
612
+ "next/image": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
613
+ default: imageImpl(bundle),
614
+ getImageProps: (_imgProps) => {
615
+ throw new Error(
616
+ "Next.js getImageProps() is not implemented in remote components"
617
+ );
618
+ },
591
619
  __esModule: true
592
620
  })),
593
621
  "next/dist/client/script": self.__remote_component_host_shared_modules__?.["next/script"] ?? shared?.["next/script"] ?? (() => Promise.resolve({
@@ -595,21 +623,56 @@ function sharedPolyfills(shared) {
595
623
  // do not throw an error for now
596
624
  default: () => null,
597
625
  __esModule: true
598
- }))
626
+ })),
627
+ "next/router": self.__remote_component_host_shared_modules__?.["next/router"] ?? shared?.["next/router"] ?? (() => (
628
+ // TODO: incomplete implementation
629
+ Promise.resolve({
630
+ useRouter() {
631
+ return {
632
+ push: (routerUrl) => {
633
+ history.pushState({}, "", routerUrl);
634
+ },
635
+ replace: (routerUrl) => {
636
+ history.replaceState({}, "", routerUrl);
637
+ },
638
+ back: () => {
639
+ history.back();
640
+ }
641
+ };
642
+ },
643
+ __esModule: true
644
+ })
645
+ ))
599
646
  };
600
647
  polyfill["next/navigation"] = polyfill["next/dist/client/components/navigation"];
601
648
  polyfill["next/link"] = polyfill["next/dist/client/app-dir/link"];
602
649
  polyfill["next/form"] = polyfill["next/dist/client/app-dir/form"];
603
- polyfill["next/image"] = polyfill["next/dist/client/image-component"];
604
650
  polyfill["next/dist/api/image"] = polyfill["next/dist/client/image-component"];
605
651
  polyfill["next/script"] = polyfill["next/dist/client/script"];
606
652
  return polyfill;
607
653
  }
608
- var import_jsx_runtime;
654
+ var import_jsx_runtime, imageImpl;
609
655
  var init_polyfill = __esm({
610
656
  "src/shared/client/polyfill.tsx"() {
611
657
  "use strict";
658
+ // eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
612
659
  import_jsx_runtime = require("react/jsx-runtime");
660
+ imageImpl = (bundle) => function RemoteImage({ priority: _, ...props }) {
661
+ const newSrc = applyBundleUrlToImagePropsSrc(
662
+ bundle,
663
+ typeof props.src === "string" ? props.src : props.src.src
664
+ );
665
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
666
+ "img",
667
+ {
668
+ decoding: "async",
669
+ style: { color: "transparent" },
670
+ ...props,
671
+ src: newSrc,
672
+ suppressHydrationWarning: true
673
+ }
674
+ );
675
+ };
613
676
  }
614
677
  });
615
678
 
@@ -652,6 +715,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
652
715
  const newScript = document.createElement("script");
653
716
  newScript.onload = () => {
654
717
  resolve2();
718
+ newScript.remove();
655
719
  };
656
720
  newScript.onerror = () => {
657
721
  reject(
@@ -659,6 +723,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
659
723
  `Failed to load script ${script.src} for remote component`
660
724
  )
661
725
  );
726
+ newScript.remove();
662
727
  };
663
728
  const scriptSrc = script.getAttribute("src") || script.getAttribute("data-src");
664
729
  if (scriptSrc) {
@@ -697,7 +762,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
697
762
  await Promise.all(
698
763
  Object.entries(resolve).map(async ([key, value]) => {
699
764
  if (typeof value === "function") {
700
- resolve[key] = await value();
765
+ resolve[key] = await value(remoteBundle);
701
766
  }
702
767
  return Promise.resolve(value);
703
768
  })
@@ -814,26 +879,27 @@ function fixPayload(payload) {
814
879
  }
815
880
  }
816
881
  }
817
- function createRSCStream(name, data) {
882
+ function createRSCStream(rscName, data) {
818
883
  return new import_web_streams_polyfill.ReadableStream({
819
884
  type: "bytes",
820
885
  start(controller) {
821
886
  const encoder = new TextEncoder();
822
887
  const self = globalThis;
823
- if (!self[name] && data.length > 0) {
888
+ if (data.length > 0) {
824
889
  data.forEach((chunk) => {
825
890
  const lines = chunk.split("\n");
826
891
  for (const line of lines) {
827
892
  const match = /\.push\("(?<rsc>.*)"\);$/.exec(line);
828
893
  if (match?.groups?.rsc) {
829
- self[name] = self[name] ?? [];
830
- self[name].push(JSON.parse(`"${match.groups.rsc}"`));
894
+ self[rscName] = self[rscName] ?? [];
895
+ self[rscName].push(JSON.parse(`"${match.groups.rsc}"`));
831
896
  }
832
897
  }
833
898
  });
834
899
  }
835
- const allChunks = (self[name] ?? [`0:[null]
900
+ const allChunks = (self[rscName] ?? [`0:[null]
836
901
  `]).join("");
902
+ self[rscName] = null;
837
903
  allChunks.split("\n").forEach((chunk) => {
838
904
  if (chunk.length > 0) {
839
905
  const { before, id, prefix, payload } = /^(?<before>.*?)?(?<id>[0-9a-zA-Z]+):(?<prefix>[A-Z])?(?<payload>\[.*\])/.exec(
@@ -863,6 +929,44 @@ function createRSCStream(name, data) {
863
929
  init_webpack_adapter();
864
930
  init_const();
865
931
 
932
+ // src/html/host/index.tsx
933
+ init_utils();
934
+
935
+ // src/shared/client/apply-origin.ts
936
+ var tagNames = [
937
+ "img",
938
+ "source",
939
+ "video",
940
+ "audio",
941
+ "track",
942
+ "iframe",
943
+ "embed",
944
+ "script",
945
+ "link"
946
+ ];
947
+ function applyOriginToNodes(doc, url) {
948
+ const nodes = doc.querySelectorAll(
949
+ tagNames.map((type) => `${type}[src],${type}[srcset]`).join(",")
950
+ );
951
+ nodes.forEach((node) => {
952
+ if (node.hasAttribute("src") && /^[./]+\/?/.test(node.getAttribute("src") ?? "")) {
953
+ node.src = new URL(node.getAttribute("src") ?? "/", url).href;
954
+ }
955
+ if (node.hasAttribute("srcset")) {
956
+ const srcSet = node.getAttribute("srcset")?.split(",").map((entry) => {
957
+ const [urlPart, descriptor] = entry.trim().split(/\s+/);
958
+ if (!urlPart)
959
+ return entry;
960
+ const absoluteUrl = new URL(urlPart, url).href;
961
+ return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
962
+ }).join(", ");
963
+ if (srcSet) {
964
+ node.setAttribute("srcset", srcSet);
965
+ }
966
+ }
967
+ });
968
+ }
969
+
866
970
  // src/html/host/runtime/index.ts
867
971
  async function getRuntime(type, url, bundle, shared, remoteShared) {
868
972
  if (typeof globalThis.process === "undefined") {
@@ -885,44 +989,64 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
885
989
  if (typeof HTMLElement !== "undefined") {
886
990
  class RemoteComponent extends HTMLElement {
887
991
  constructor() {
888
- super();
992
+ super(...arguments);
889
993
  this.__next = null;
890
994
  this.fouc = null;
891
995
  this.isLoading = false;
892
996
  this.root = null;
893
- this.root = this.attachShadow({
894
- mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
895
- });
896
- this.fallbackSlot = document.createElement("slot");
897
- this.root.appendChild(this.fallbackSlot);
898
- this.name = this.getAttribute("name") || "__vercel_remote_component";
899
- this.bundle = "default";
900
- if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
901
- this.load().catch((e) => {
902
- throw new Error(`Failed to load remote component: ${e}`);
903
- });
904
- }
905
997
  }
906
998
  static get observedAttributes() {
907
- return ["src", "name"];
999
+ return ["src", "name", "mode"];
908
1000
  }
909
1001
  // watch for src attribute changes
910
1002
  // this is required to reload the remote component when the src attribute is added later
911
1003
  // this is for rendering the custom element using React
912
1004
  attributeChangedCallback(name, oldValue, newValue) {
913
1005
  if ((name === "src" || name === "name") && oldValue !== newValue) {
1006
+ if (this.getAttribute("src")) {
1007
+ this.load().catch((e) => {
1008
+ console.error(e);
1009
+ throw new Error(
1010
+ `Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
1011
+ );
1012
+ });
1013
+ }
1014
+ } else if (name === "mode" && oldValue !== newValue && this.root) {
1015
+ const newRoot = this.attachShadow({
1016
+ mode: newValue === "closed" ? "closed" : "open"
1017
+ });
1018
+ Array.from(this.root.children).forEach((child) => {
1019
+ newRoot.appendChild(child);
1020
+ });
1021
+ this.root = newRoot;
914
1022
  this.load().catch((e) => {
915
- console.error(e);
916
- throw new Error(
917
- `Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
918
- );
1023
+ throw new Error(`Failed to load remote component: ${e}`);
919
1024
  });
920
1025
  }
921
1026
  }
922
1027
  async load() {
1028
+ await new Promise((resolve) => {
1029
+ (typeof queueMicrotask === "function" ? queueMicrotask : requestAnimationFrame)(() => {
1030
+ resolve(void 0);
1031
+ });
1032
+ });
923
1033
  if (this.isLoading) {
924
1034
  return;
925
1035
  }
1036
+ if (!this.root) {
1037
+ this.root = this.attachShadow({
1038
+ mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
1039
+ });
1040
+ this.fallbackSlot = document.createElement("slot");
1041
+ this.root.appendChild(this.fallbackSlot);
1042
+ }
1043
+ this.name = this.getAttribute("name") || "__vercel_remote_component";
1044
+ this.bundle = "default";
1045
+ if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
1046
+ this.load().catch((e) => {
1047
+ throw new Error(`Failed to load remote component: ${e}`);
1048
+ });
1049
+ }
926
1050
  this.isLoading = true;
927
1051
  const src = this.getAttribute("src");
928
1052
  const remoteComponentChild = this.querySelector("div#__REMOTE_COMPONENT__") || this.querySelector("div[data-bundle][data-route]");
@@ -953,8 +1077,8 @@ if (typeof HTMLElement !== "undefined") {
953
1077
  }
954
1078
  html = await res.text();
955
1079
  }
956
- const doc = document.createElement("div");
957
- doc.innerHTML = html;
1080
+ const parser = new DOMParser();
1081
+ const doc = parser.parseFromString(html, "text/html");
958
1082
  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
959
1083
  doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
960
1084
  doc.querySelector("div#__next");
@@ -964,11 +1088,18 @@ if (typeof HTMLElement !== "undefined") {
964
1088
  if (nextData && nextData.buildId === "development" && !this.reactRoot) {
965
1089
  this.fouc = document.createElement("style");
966
1090
  this.fouc.textContent = `:host { display: none; }`;
967
- this.root?.appendChild(this.fouc);
1091
+ this.root.appendChild(this.fouc);
968
1092
  }
969
1093
  this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : this.name);
970
1094
  const rsc = doc.querySelector(`#${this.name}_rsc`);
971
1095
  this.bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || this.bundle;
1096
+ if (url) {
1097
+ const self2 = globalThis;
1098
+ if (!self2.__remote_bundle_url__) {
1099
+ self2.__remote_bundle_url__ = {};
1100
+ }
1101
+ self2.__remote_bundle_url__[this.bundle ?? "default"] = url;
1102
+ }
972
1103
  const metadata = document.createElement("script");
973
1104
  metadata.type = "application/json";
974
1105
  metadata.setAttribute("data-remote-component", "");
@@ -978,47 +1109,81 @@ if (typeof HTMLElement !== "undefined") {
978
1109
  route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
979
1110
  runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
980
1111
  });
981
- this.parentNode?.insertBefore(metadata, this);
982
- const remoteSharedEl = doc.querySelector(`#${this.name}_shared`);
983
- const remoteShared = JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {};
1112
+ if (this.previousElementSibling?.getAttribute("data-remote-component") !== null) {
1113
+ this.previousElementSibling?.remove();
1114
+ }
1115
+ this.parentElement?.insertBefore(metadata, this);
1116
+ const remoteSharedEl = doc.querySelector(
1117
+ `#${this.name}_shared[data-remote-components-shared]`
1118
+ );
1119
+ const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
984
1120
  remoteSharedEl?.parentElement?.removeChild(remoteSharedEl);
985
1121
  if (!component || !(rsc || nextData)) {
986
1122
  throw new Error(`Failed to find component with id "${this.name}"`);
987
1123
  }
988
1124
  const removable = Array.from(this.childNodes);
989
1125
  const links = doc.querySelectorAll("link[href]");
990
- await Promise.all(
991
- Array.from(links).map((link) => {
992
- return new Promise((resolve, reject) => {
993
- const newLink = document.createElement("link");
994
- if (link.rel === "stylesheet") {
995
- newLink.onload = () => {
1126
+ const remoteComponentSrc = this.getAttribute("src");
1127
+ const attachLinks = async () => {
1128
+ await Promise.all(
1129
+ Array.from(links).filter((link) => {
1130
+ return !component.contains(link);
1131
+ }).map((link) => {
1132
+ return new Promise((resolve, reject) => {
1133
+ const newLink = document.createElement("link");
1134
+ if (link.rel === "stylesheet") {
1135
+ newLink.onload = () => {
1136
+ resolve();
1137
+ };
1138
+ newLink.onerror = () => {
1139
+ reject(
1140
+ new Error(
1141
+ `Failed to load link ${link.href} for remote component`
1142
+ )
1143
+ );
1144
+ };
1145
+ } else {
996
1146
  resolve();
997
- };
998
- newLink.onerror = () => {
999
- reject(
1000
- new Error(
1001
- `Failed to load link ${link.href} for remote component`
1002
- )
1003
- );
1004
- };
1005
- } else {
1006
- resolve();
1007
- }
1008
- for (const attr of link.attributes) {
1009
- if (attr.name === "href") {
1147
+ }
1148
+ for (const attr of link.attributes) {
1149
+ if (attr.name === "href") {
1150
+ newLink.setAttribute(
1151
+ attr.name,
1152
+ new URL(attr.value, url ?? location.origin).href
1153
+ );
1154
+ } else {
1155
+ newLink.setAttribute(attr.name, attr.value);
1156
+ }
1157
+ }
1158
+ if (remoteComponentSrc) {
1010
1159
  newLink.setAttribute(
1011
- attr.name,
1012
- new URL(attr.value, url ?? location.origin).href
1160
+ "data-remote-component-src",
1161
+ remoteComponentSrc
1013
1162
  );
1014
- } else {
1015
- newLink.setAttribute(attr.name, attr.value);
1016
1163
  }
1164
+ this.root?.appendChild(newLink);
1165
+ });
1166
+ })
1167
+ );
1168
+ const styles = doc.querySelectorAll("style");
1169
+ styles.forEach((style) => {
1170
+ if (style.parentElement?.tagName.toLowerCase() === "head") {
1171
+ const newStyle = document.createElement("style");
1172
+ newStyle.textContent = style.textContent;
1173
+ if (remoteComponentSrc) {
1174
+ newStyle.setAttribute(
1175
+ "data-remote-component-src",
1176
+ remoteComponentSrc
1177
+ );
1017
1178
  }
1018
- this.root?.appendChild(newLink);
1019
- });
1020
- })
1021
- );
1179
+ this.root?.appendChild(newStyle);
1180
+ }
1181
+ });
1182
+ };
1183
+ if (!this.reactRoot) {
1184
+ await attachLinks();
1185
+ }
1186
+ applyOriginToNodes(doc, url ?? new URL(location.href));
1022
1187
  if (!this.reactRoot) {
1023
1188
  Array.from(component.children).forEach((el) => {
1024
1189
  this.root?.appendChild(el);
@@ -1027,12 +1192,32 @@ if (typeof HTMLElement !== "undefined") {
1027
1192
  for (const el of removable) {
1028
1193
  el.parentElement?.removeChild(el);
1029
1194
  }
1030
- this.fallbackSlot.remove();
1031
- if (this.getAttribute("reset") !== null && !this.root?.querySelector("style[data-remote-components-reset]")) {
1032
- const allInitial = document.createElement("style");
1033
- allInitial.setAttribute("data-remote-components-reset", "");
1034
- allInitial.textContent = `:host { all: initial; }`;
1035
- this.root?.prepend(allInitial);
1195
+ this.fallbackSlot?.remove();
1196
+ const applyReset = () => {
1197
+ if (this.getAttribute("reset") !== null && !this.root?.querySelector("link[data-remote-components-reset]")) {
1198
+ const allInitial = document.createElement("link");
1199
+ allInitial.setAttribute("data-remote-components-reset", "");
1200
+ const css = `:host { all: initial; }`;
1201
+ const allInitialHref = URL.createObjectURL(
1202
+ new Blob([css], { type: "text/css" })
1203
+ );
1204
+ allInitial.href = allInitialHref;
1205
+ allInitial.rel = "stylesheet";
1206
+ allInitial.onload = () => {
1207
+ URL.revokeObjectURL(allInitialHref);
1208
+ allInitial.removeAttribute("onload");
1209
+ };
1210
+ allInitial.onerror = () => {
1211
+ URL.revokeObjectURL(allInitialHref);
1212
+ allInitial.removeAttribute("onload");
1213
+ };
1214
+ this.root?.prepend(allInitial);
1215
+ } else if (this.getAttribute("reset") === null && this.root?.querySelector("link[data-remote-components-reset]")) {
1216
+ this.root.querySelector("link[data-remote-components-reset]")?.remove();
1217
+ }
1218
+ };
1219
+ if (!this.reactRoot) {
1220
+ applyReset();
1036
1221
  }
1037
1222
  const {
1038
1223
  self,
@@ -1067,20 +1252,59 @@ if (typeof HTMLElement !== "undefined") {
1067
1252
  this.bundle ?? "default",
1068
1253
  this.name ?? "__vercel_remote_component"
1069
1254
  );
1255
+ const doCleanup = () => {
1256
+ if (this.root && remoteComponentSrc) {
1257
+ const selector = `[data-remote-component-src]:not([data-remote-component-src="${remoteComponentSrc}"])`;
1258
+ const prevCleanup = [
1259
+ ...this.root.querySelectorAll(selector),
1260
+ ...document.body.querySelectorAll(selector)
1261
+ ];
1262
+ if (prevCleanup.length > 0) {
1263
+ prevCleanup.forEach((prev) => {
1264
+ prev.remove();
1265
+ });
1266
+ }
1267
+ }
1268
+ };
1070
1269
  if (rsc) {
1071
1270
  rsc.parentElement?.removeChild(rsc);
1271
+ const rscName = `__remote_component_rsc_${escapeString(url.href)}_${escapeString(this.name)}`;
1072
1272
  const rscClone = document.createElement("script");
1073
- rscClone.id = `${this.name}_rsc`;
1074
- rscClone.textContent = rsc.textContent;
1273
+ rscClone.id = `${rscName}_rsc`;
1274
+ rscClone.textContent = rsc.textContent?.replace(
1275
+ new RegExp(`self\\["${this.name}"\\]`, "g"),
1276
+ `self["${rscName}"]`
1277
+ ) ?? "";
1075
1278
  document.body.appendChild(rscClone);
1076
1279
  let cache;
1077
1280
  const RemoteComponentFromReadableStream = ({
1078
- name
1281
+ name,
1282
+ initial
1079
1283
  }) => {
1080
- const stream = createRSCStream(name, self[name] ?? [`0:[null]
1081
- `]);
1284
+ const stream = createRSCStream(
1285
+ rscName,
1286
+ self[rscName] ?? [`0:[null]
1287
+ `]
1288
+ );
1082
1289
  const Component = cache ?? // cache the component to avoid reloading the RSC flight data
1083
1290
  (cache = createFromReadableStream(stream));
1291
+ (0, import_react.useLayoutEffect)(() => {
1292
+ if (self[name]) {
1293
+ delete self[name];
1294
+ }
1295
+ const rscScript = document.getElementById(`${name}_rsc`);
1296
+ if (rscScript) {
1297
+ rscScript.remove();
1298
+ }
1299
+ doCleanup();
1300
+ applyReset();
1301
+ if (!initial) {
1302
+ attachLinks().catch((e) => {
1303
+ console.error(e);
1304
+ });
1305
+ }
1306
+ this.isLoading = false;
1307
+ }, [initial, name]);
1084
1308
  return Component;
1085
1309
  };
1086
1310
  if (this.reactRoot) {
@@ -1090,11 +1314,11 @@ if (typeof HTMLElement !== "undefined") {
1090
1314
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1091
1315
  RemoteComponentFromReadableStream,
1092
1316
  {
1317
+ initial: false,
1093
1318
  name: this.name ?? "__vercel_remote_component"
1094
1319
  }
1095
1320
  )
1096
1321
  );
1097
- this.isLoading = false;
1098
1322
  });
1099
1323
  return;
1100
1324
  }
@@ -1105,6 +1329,7 @@ if (typeof HTMLElement !== "undefined") {
1105
1329
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1106
1330
  RemoteComponentFromReadableStream,
1107
1331
  {
1332
+ initial: true,
1108
1333
  name: this.name ?? "__vercel_remote_component"
1109
1334
  }
1110
1335
  )
@@ -1116,12 +1341,24 @@ if (typeof HTMLElement !== "undefined") {
1116
1341
  this.root
1117
1342
  );
1118
1343
  if (Component) {
1344
+ const RemoteComponentFromNext = ((NextApp, NextComponent, remoteComponent = this) => function RemoteComponentNext({ initial }) {
1345
+ (0, import_react.useLayoutEffect)(() => {
1346
+ doCleanup();
1347
+ if (!initial) {
1348
+ applyReset();
1349
+ attachLinks().catch((e) => {
1350
+ console.error(e);
1351
+ });
1352
+ }
1353
+ remoteComponent.isLoading = false;
1354
+ }, [initial]);
1355
+ return NextApp ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NextApp, { Component: NextComponent, ...nextData.props }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NextComponent, { ...nextData.props });
1356
+ })(App, Component, this);
1119
1357
  if (this.reactRoot) {
1120
1358
  const root = this.reactRoot;
1121
1359
  (0, import_react.startTransition)(() => {
1122
- root.render(
1123
- App ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(App, { Component, ...nextData.props }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, { ...nextData.props })
1124
- );
1360
+ root.render(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RemoteComponentFromNext, { initial: false }));
1361
+ doCleanup();
1125
1362
  this.isLoading = false;
1126
1363
  });
1127
1364
  return;
@@ -1130,11 +1367,11 @@ if (typeof HTMLElement !== "undefined") {
1130
1367
  // hydrateRoot expects a document or element, but it works for the shadow DOM too
1131
1368
  // @ts-expect-error support for shadow DOM
1132
1369
  this.root,
1133
- App ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(App, { Component, ...nextData.props }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, { ...nextData.props })
1370
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RemoteComponentFromNext, { initial: true })
1134
1371
  );
1135
1372
  }
1136
1373
  if (this.fouc) {
1137
- this.root?.removeChild(this.fouc);
1374
+ this.root.removeChild(this.fouc);
1138
1375
  }
1139
1376
  }
1140
1377
  this.isLoading = false;