remote-components 0.0.22 → 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.
Files changed (78) hide show
  1. package/dist/html/host.cjs +345 -80
  2. package/dist/html/host.cjs.map +1 -1
  3. package/dist/html/host.js +347 -79
  4. package/dist/html/host.js.map +1 -1
  5. package/dist/internal/next/host/app-router-client.cjs +205 -58
  6. package/dist/internal/next/host/app-router-client.cjs.map +1 -1
  7. package/dist/internal/next/host/app-router-client.d.ts +2 -2
  8. package/dist/internal/next/host/app-router-client.js +213 -59
  9. package/dist/internal/next/host/app-router-client.js.map +1 -1
  10. package/dist/internal/next/host/app-router-compat.cjs +114 -0
  11. package/dist/internal/next/host/app-router-compat.cjs.map +1 -0
  12. package/dist/internal/next/host/app-router-compat.d.ts +31 -0
  13. package/dist/internal/next/host/app-router-compat.js +79 -0
  14. package/dist/internal/next/host/app-router-compat.js.map +1 -0
  15. package/dist/internal/next/remote/render-client.cjs +10 -2
  16. package/dist/internal/next/remote/render-client.cjs.map +1 -1
  17. package/dist/internal/next/remote/render-client.js +10 -2
  18. package/dist/internal/next/remote/render-client.js.map +1 -1
  19. package/dist/internal/shared/client/apply-origin.cjs +61 -0
  20. package/dist/internal/shared/client/apply-origin.cjs.map +1 -0
  21. package/dist/internal/shared/client/apply-origin.d.ts +3 -0
  22. package/dist/internal/shared/client/apply-origin.js +37 -0
  23. package/dist/internal/shared/client/apply-origin.js.map +1 -0
  24. package/dist/internal/shared/client/polyfill.cjs +149 -0
  25. package/dist/internal/shared/client/polyfill.cjs.map +1 -0
  26. package/dist/internal/shared/client/polyfill.d.ts +6 -0
  27. package/dist/internal/shared/client/polyfill.js +124 -0
  28. package/dist/internal/shared/client/polyfill.js.map +1 -0
  29. package/dist/internal/shared/client/remote-component.cjs +3 -3
  30. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  31. package/dist/internal/shared/client/remote-component.d.ts +3 -1
  32. package/dist/internal/shared/client/remote-component.js +3 -3
  33. package/dist/internal/shared/client/remote-component.js.map +1 -1
  34. package/dist/internal/shared/ssr/dom-flight.cjs +49 -17
  35. package/dist/internal/shared/ssr/dom-flight.cjs.map +1 -1
  36. package/dist/internal/shared/ssr/dom-flight.js +49 -17
  37. package/dist/internal/shared/ssr/dom-flight.js.map +1 -1
  38. package/dist/internal/shared/ssr/fetch-remote-component.cjs +3 -2
  39. package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
  40. package/dist/internal/shared/ssr/fetch-remote-component.d.ts +6 -0
  41. package/dist/internal/shared/ssr/fetch-remote-component.js +3 -2
  42. package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
  43. package/dist/next/config.cjs +50 -28
  44. package/dist/next/config.cjs.map +1 -1
  45. package/dist/next/config.js +50 -28
  46. package/dist/next/config.js.map +1 -1
  47. package/dist/next/host/app-router-server.cjs +4 -0
  48. package/dist/next/host/app-router-server.cjs.map +1 -1
  49. package/dist/next/host/app-router-server.d.ts +5 -1
  50. package/dist/next/host/app-router-server.js +4 -0
  51. package/dist/next/host/app-router-server.js.map +1 -1
  52. package/dist/next/host/client/index.cjs +16 -1
  53. package/dist/next/host/client/index.cjs.map +1 -1
  54. package/dist/next/host/client/index.d.ts +1 -1
  55. package/dist/next/host/client/index.js +16 -1
  56. package/dist/next/host/client/index.js.map +1 -1
  57. package/dist/next/host/pages-router-server.cjs +37 -16
  58. package/dist/next/host/pages-router-server.cjs.map +1 -1
  59. package/dist/next/host/pages-router-server.d.ts +3 -0
  60. package/dist/next/host/pages-router-server.js +37 -16
  61. package/dist/next/host/pages-router-server.js.map +1 -1
  62. package/dist/next/middleware.cjs +5 -2
  63. package/dist/next/middleware.cjs.map +1 -1
  64. package/dist/next/middleware.d.ts +1 -0
  65. package/dist/next/middleware.js +5 -2
  66. package/dist/next/middleware.js.map +1 -1
  67. package/dist/next/remote/pages-router.cjs +3 -1
  68. package/dist/next/remote/pages-router.cjs.map +1 -1
  69. package/dist/next/remote/pages-router.d.ts +1 -0
  70. package/dist/next/remote/pages-router.js +3 -1
  71. package/dist/next/remote/pages-router.js.map +1 -1
  72. package/dist/react/index.cjs +235 -156
  73. package/dist/react/index.cjs.map +1 -1
  74. package/dist/react/index.d.ts +7 -3
  75. package/dist/react/index.js +225 -146
  76. package/dist/react/index.js.map +1 -1
  77. package/dist/{types-7425dfe1.d.ts → types-b8210fd3.d.ts} +2 -0
  78. 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: (props) => (
560
- // eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
561
- /* @__PURE__ */ jsx(
562
- "img",
563
- {
564
- ...props,
565
- src: props.src,
566
- suppressHydrationWarning: true
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,6 +810,7 @@ var init_turbopack = __esm({
753
810
  });
754
811
 
755
812
  // src/html/host/index.tsx
813
+ import { startTransition, useLayoutEffect } from "react";
756
814
  import { hydrateRoot } from "react-dom/client";
757
815
 
758
816
  // src/shared/client/component-loader.ts
@@ -834,6 +892,41 @@ function createRSCStream(name, data) {
834
892
  init_webpack_adapter();
835
893
  init_const();
836
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
+
837
930
  // src/html/host/runtime/index.ts
838
931
  async function getRuntime(type, url, bundle, shared, remoteShared) {
839
932
  if (typeof globalThis.process === "undefined") {
@@ -856,38 +949,64 @@ import { jsx as jsx2 } from "react/jsx-runtime";
856
949
  if (typeof HTMLElement !== "undefined") {
857
950
  class RemoteComponent extends HTMLElement {
858
951
  constructor() {
859
- super();
952
+ super(...arguments);
860
953
  this.__next = null;
861
954
  this.fouc = null;
862
955
  this.isLoading = false;
863
- this.attachShadow({ mode: "open" });
864
- this.fallbackSlot = document.createElement("slot");
865
- this.shadowRoot?.appendChild(this.fallbackSlot);
866
- this.name = this.getAttribute("name") || "__vercel_remote_component";
867
- this.bundle = "default";
868
- if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
869
- this.load().catch((e) => {
870
- throw new Error(`Failed to load remote component: ${e}`);
871
- });
872
- }
956
+ this.root = null;
873
957
  }
874
958
  static get observedAttributes() {
875
- return ["src"];
959
+ return ["src", "name", "mode"];
876
960
  }
877
961
  // watch for src attribute changes
878
962
  // this is required to reload the remote component when the src attribute is added later
879
963
  // this is for rendering the custom element using React
880
964
  attributeChangedCallback(name, oldValue, newValue) {
881
- if (name === "src" && oldValue !== newValue) {
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;
882
982
  this.load().catch((e) => {
883
983
  throw new Error(`Failed to load remote component: ${e}`);
884
984
  });
885
985
  }
886
986
  }
887
987
  async load() {
988
+ await new Promise((resolve) => {
989
+ (typeof queueMicrotask === "function" ? queueMicrotask : requestAnimationFrame)(() => {
990
+ resolve(void 0);
991
+ });
992
+ });
888
993
  if (this.isLoading) {
889
994
  return;
890
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
+ }
891
1010
  this.isLoading = true;
892
1011
  const src = this.getAttribute("src");
893
1012
  const remoteComponentChild = this.querySelector("div#__REMOTE_COMPONENT__") || this.querySelector("div[data-bundle][data-route]");
@@ -918,22 +1037,29 @@ if (typeof HTMLElement !== "undefined") {
918
1037
  }
919
1038
  html = await res.text();
920
1039
  }
921
- const doc = document.createElement("div");
922
- doc.innerHTML = html;
1040
+ const parser = new DOMParser();
1041
+ const doc = parser.parseFromString(html, "text/html");
923
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
924
1043
  doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
925
1044
  doc.querySelector("div#__next");
926
1045
  const nextData = JSON.parse(
927
1046
  (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
928
1047
  );
929
- if (nextData && nextData.buildId === "development") {
1048
+ if (nextData && nextData.buildId === "development" && !this.reactRoot) {
930
1049
  this.fouc = document.createElement("style");
931
1050
  this.fouc.textContent = `:host { display: none; }`;
932
- this.shadowRoot?.appendChild(this.fouc);
1051
+ this.root.appendChild(this.fouc);
933
1052
  }
934
1053
  this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : this.name);
935
1054
  const rsc = doc.querySelector(`#${this.name}_rsc`);
936
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
+ }
937
1063
  const metadata = document.createElement("script");
938
1064
  metadata.type = "application/json";
939
1065
  metadata.setAttribute("data-remote-component", "");
@@ -943,54 +1069,116 @@ if (typeof HTMLElement !== "undefined") {
943
1069
  route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
944
1070
  runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
945
1071
  });
946
- this.parentNode?.insertBefore(metadata, this);
947
- const remoteSharedEl = doc.querySelector(`#${this.name}_shared`);
948
- const remoteShared = JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {};
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 ?? "{}") ?? {});
949
1080
  remoteSharedEl?.parentElement?.removeChild(remoteSharedEl);
950
1081
  if (!component || !(rsc || nextData)) {
951
1082
  throw new Error(`Failed to find component with id "${this.name}"`);
952
1083
  }
953
1084
  const removable = Array.from(this.childNodes);
954
1085
  const links = doc.querySelectorAll("link[href]");
955
- await Promise.all(
956
- Array.from(links).map((link) => {
957
- return new Promise((resolve, reject) => {
958
- const newLink = document.createElement("link");
959
- if (link.rel === "stylesheet") {
960
- newLink.onload = () => {
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 {
961
1106
  resolve();
962
- };
963
- newLink.onerror = () => {
964
- reject(
965
- new Error(
966
- `Failed to load link ${link.href} for remote component`
967
- )
968
- );
969
- };
970
- } else {
971
- resolve();
972
- }
973
- for (const attr of link.attributes) {
974
- 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) {
975
1119
  newLink.setAttribute(
976
- attr.name,
977
- new URL(attr.value, url ?? location.origin).href
1120
+ "data-remote-component-src",
1121
+ remoteComponentSrc
978
1122
  );
979
- } else {
980
- newLink.setAttribute(attr.name, attr.value);
981
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
+ );
982
1138
  }
983
- this.shadowRoot?.appendChild(newLink);
984
- });
985
- })
986
- );
987
- Array.from(component.children).forEach((el) => {
988
- this.shadowRoot?.appendChild(el);
989
- });
1139
+ this.root?.appendChild(newStyle);
1140
+ }
1141
+ });
1142
+ };
1143
+ if (!this.reactRoot) {
1144
+ await attachLinks();
1145
+ }
1146
+ applyOriginToNodes(doc, url ?? new URL(location.href));
1147
+ if (!this.reactRoot) {
1148
+ Array.from(component.children).forEach((el) => {
1149
+ this.root?.appendChild(el);
1150
+ });
1151
+ }
990
1152
  for (const el of removable) {
991
1153
  el.parentElement?.removeChild(el);
992
1154
  }
993
- this.shadowRoot?.removeChild(this.fallbackSlot);
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();
1181
+ }
994
1182
  const {
995
1183
  self,
996
1184
  createFromReadableStream,
@@ -1018,7 +1206,26 @@ if (typeof HTMLElement !== "undefined") {
1018
1206
  window.location.href
1019
1207
  );
1020
1208
  }
1021
- await preloadScripts(Array.from(scripts), url, this.bundle, this.name);
1209
+ await preloadScripts(
1210
+ Array.from(scripts),
1211
+ url,
1212
+ this.bundle ?? "default",
1213
+ this.name ?? "__vercel_remote_component"
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
+ };
1022
1229
  if (rsc) {
1023
1230
  rsc.parentElement?.removeChild(rsc);
1024
1231
  const rscClone = document.createElement("script");
@@ -1027,36 +1234,97 @@ if (typeof HTMLElement !== "undefined") {
1027
1234
  document.body.appendChild(rscClone);
1028
1235
  let cache;
1029
1236
  const RemoteComponentFromReadableStream = ({
1030
- name
1237
+ name,
1238
+ initial
1031
1239
  }) => {
1032
1240
  const stream = createRSCStream(name, self[name] ?? [`0:[null]
1033
1241
  `]);
1034
1242
  const Component = cache ?? // cache the component to avoid reloading the RSC flight data
1035
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]);
1036
1261
  return Component;
1037
1262
  };
1038
- hydrateRoot(
1263
+ if (this.reactRoot) {
1264
+ const root = this.reactRoot;
1265
+ startTransition(() => {
1266
+ root.render(
1267
+ /* @__PURE__ */ jsx2(
1268
+ RemoteComponentFromReadableStream,
1269
+ {
1270
+ initial: false,
1271
+ name: this.name ?? "__vercel_remote_component"
1272
+ }
1273
+ )
1274
+ );
1275
+ });
1276
+ return;
1277
+ }
1278
+ this.reactRoot = hydrateRoot(
1039
1279
  // hydrateRoot expects a document or element, but it works for the shadow DOM too
1040
1280
  // @ts-expect-error support for shadow DOM
1041
- this.shadowRoot,
1042
- /* @__PURE__ */ jsx2(RemoteComponentFromReadableStream, { name: this.name })
1281
+ this.root,
1282
+ /* @__PURE__ */ jsx2(
1283
+ RemoteComponentFromReadableStream,
1284
+ {
1285
+ initial: true,
1286
+ name: this.name ?? "__vercel_remote_component"
1287
+ }
1288
+ )
1043
1289
  );
1044
1290
  } else if (nextData) {
1045
1291
  const { Component, App } = nextClientPagesLoader2(
1046
- this.bundle,
1292
+ this.bundle ?? "default",
1047
1293
  nextData.page,
1048
- this.shadowRoot
1294
+ this.root
1049
1295
  );
1050
1296
  if (Component) {
1051
- hydrateRoot(
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);
1310
+ if (this.reactRoot) {
1311
+ const root = this.reactRoot;
1312
+ startTransition(() => {
1313
+ root.render(/* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: false }));
1314
+ doCleanup();
1315
+ this.isLoading = false;
1316
+ });
1317
+ return;
1318
+ }
1319
+ this.reactRoot = hydrateRoot(
1052
1320
  // hydrateRoot expects a document or element, but it works for the shadow DOM too
1053
1321
  // @ts-expect-error support for shadow DOM
1054
- this.shadowRoot,
1055
- App ? /* @__PURE__ */ jsx2(App, { Component, ...nextData.props }) : /* @__PURE__ */ jsx2(Component, { ...nextData.props })
1322
+ this.root,
1323
+ /* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: true })
1056
1324
  );
1057
1325
  }
1058
1326
  if (this.fouc) {
1059
- this.shadowRoot?.removeChild(this.fouc);
1327
+ this.root.removeChild(this.fouc);
1060
1328
  }
1061
1329
  }
1062
1330
  this.isLoading = false;