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
@@ -395,7 +395,7 @@ function initializeSharedModules(bundle, shared = {}, remoteShared = {}) {
395
395
  Object.entries(remoteShared).map(async ([id, module2]) => {
396
396
  if (self.__remote_shared_modules__?.[bundle]) {
397
397
  if (shared[module2]) {
398
- self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module2]();
398
+ self.__remote_shared_modules__[bundle][id.replace("[app-ssr]", "[app-client]")] = await shared[module2](bundle);
399
399
  } else {
400
400
  console.error(`Shared module "${module2}" not found for "${bundle}".`);
401
401
  }
@@ -408,7 +408,7 @@ function getSharedModule(bundle, id) {
408
408
  for (const [key, value] of Object.entries(
409
409
  self.__remote_shared_modules__?.[bundle] ?? {}
410
410
  )) {
411
- if (typeof id === "string" && id.includes(key) || id === key) {
411
+ if (typeof value !== "undefined" && (typeof id === "string" && id.includes(key) || id === key)) {
412
412
  return value;
413
413
  }
414
414
  }
@@ -541,6 +541,24 @@ var init_webpack_adapter = __esm({
541
541
  });
542
542
 
543
543
  // src/shared/client/polyfill.tsx
544
+ function applyBundleUrlToSrc(bundle, src) {
545
+ const self = globalThis;
546
+ if (self.__remote_bundle_url__?.[bundle]?.origin === location.origin) {
547
+ return src;
548
+ }
549
+ const { assetPrefix, path } = /^(?<assetPrefix>.*?)\/_next\/(?<path>.*)/.exec(src)?.groups ?? {};
550
+ if (!path) {
551
+ return new URL(src, self.__remote_bundle_url__?.[bundle]?.origin).href;
552
+ }
553
+ return `${self.__remote_bundle_url__?.[bundle]?.origin ?? ""}${assetPrefix}/_next/${path}`;
554
+ }
555
+ function applyBundleUrlToImagePropsSrc(bundle, src) {
556
+ if (typeof src === "string") {
557
+ return applyBundleUrlToSrc(bundle, src);
558
+ }
559
+ const propSrc = src;
560
+ return applyBundleUrlToSrc(bundle, propSrc.src);
561
+ }
544
562
  function sharedPolyfills(shared) {
545
563
  const self = globalThis;
546
564
  const polyfill = {
@@ -576,18 +594,17 @@ function sharedPolyfills(shared) {
576
594
  },
577
595
  __esModule: true
578
596
  })),
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
- ),
597
+ "next/dist/client/image-component": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
598
+ Image: imageImpl(bundle),
599
+ __esModule: true
600
+ })),
601
+ "next/image": self.__remote_component_host_shared_modules__?.["next/image"] ?? shared?.["next/image"] ?? ((bundle) => Promise.resolve({
602
+ default: imageImpl(bundle),
603
+ getImageProps: (_imgProps) => {
604
+ throw new Error(
605
+ "Next.js getImageProps() is not implemented in remote components"
606
+ );
607
+ },
591
608
  __esModule: true
592
609
  })),
593
610
  "next/dist/client/script": self.__remote_component_host_shared_modules__?.["next/script"] ?? shared?.["next/script"] ?? (() => Promise.resolve({
@@ -595,21 +612,56 @@ function sharedPolyfills(shared) {
595
612
  // do not throw an error for now
596
613
  default: () => null,
597
614
  __esModule: true
598
- }))
615
+ })),
616
+ "next/router": self.__remote_component_host_shared_modules__?.["next/router"] ?? shared?.["next/router"] ?? (() => (
617
+ // TODO: incomplete implementation
618
+ Promise.resolve({
619
+ useRouter() {
620
+ return {
621
+ push: (routerUrl) => {
622
+ history.pushState({}, "", routerUrl);
623
+ },
624
+ replace: (routerUrl) => {
625
+ history.replaceState({}, "", routerUrl);
626
+ },
627
+ back: () => {
628
+ history.back();
629
+ }
630
+ };
631
+ },
632
+ __esModule: true
633
+ })
634
+ ))
599
635
  };
600
636
  polyfill["next/navigation"] = polyfill["next/dist/client/components/navigation"];
601
637
  polyfill["next/link"] = polyfill["next/dist/client/app-dir/link"];
602
638
  polyfill["next/form"] = polyfill["next/dist/client/app-dir/form"];
603
- polyfill["next/image"] = polyfill["next/dist/client/image-component"];
604
639
  polyfill["next/dist/api/image"] = polyfill["next/dist/client/image-component"];
605
640
  polyfill["next/script"] = polyfill["next/dist/client/script"];
606
641
  return polyfill;
607
642
  }
608
- var import_jsx_runtime;
643
+ var import_jsx_runtime, imageImpl;
609
644
  var init_polyfill = __esm({
610
645
  "src/shared/client/polyfill.tsx"() {
611
646
  "use strict";
647
+ // eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
612
648
  import_jsx_runtime = require("react/jsx-runtime");
649
+ imageImpl = (bundle) => function RemoteImage({ priority: _, ...props }) {
650
+ const newSrc = applyBundleUrlToImagePropsSrc(
651
+ bundle,
652
+ typeof props.src === "string" ? props.src : props.src.src
653
+ );
654
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
655
+ "img",
656
+ {
657
+ decoding: "async",
658
+ style: { color: "transparent" },
659
+ ...props,
660
+ src: newSrc,
661
+ suppressHydrationWarning: true
662
+ }
663
+ );
664
+ };
613
665
  }
614
666
  });
615
667
 
@@ -652,6 +704,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
652
704
  const newScript = document.createElement("script");
653
705
  newScript.onload = () => {
654
706
  resolve2();
707
+ newScript.remove();
655
708
  };
656
709
  newScript.onerror = () => {
657
710
  reject(
@@ -659,6 +712,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
659
712
  `Failed to load script ${script.src} for remote component`
660
713
  )
661
714
  );
715
+ newScript.remove();
662
716
  };
663
717
  const scriptSrc = script.getAttribute("src") || script.getAttribute("data-src");
664
718
  if (scriptSrc) {
@@ -697,7 +751,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
697
751
  await Promise.all(
698
752
  Object.entries(resolve).map(async ([key, value]) => {
699
753
  if (typeof value === "function") {
700
- resolve[key] = await value();
754
+ resolve[key] = await value(remoteBundle);
701
755
  }
702
756
  return Promise.resolve(value);
703
757
  })
@@ -781,6 +835,7 @@ __export(host_exports, {
781
835
  registerSharedModules: () => registerSharedModules
782
836
  });
783
837
  module.exports = __toCommonJS(host_exports);
838
+ var import_react = require("react");
784
839
  var import_client = require("react-dom/client");
785
840
 
786
841
  // src/shared/client/component-loader.ts
@@ -862,6 +917,41 @@ function createRSCStream(name, data) {
862
917
  init_webpack_adapter();
863
918
  init_const();
864
919
 
920
+ // src/shared/client/apply-origin.ts
921
+ var tagNames = [
922
+ "img",
923
+ "source",
924
+ "video",
925
+ "audio",
926
+ "track",
927
+ "iframe",
928
+ "embed",
929
+ "script",
930
+ "link"
931
+ ];
932
+ function applyOriginToNodes(doc, url) {
933
+ const nodes = doc.querySelectorAll(
934
+ tagNames.map((type) => `${type}[src],${type}[srcset]`).join(",")
935
+ );
936
+ nodes.forEach((node) => {
937
+ if (node.hasAttribute("src") && /^[./]+\/?/.test(node.getAttribute("src") ?? "")) {
938
+ node.src = new URL(node.getAttribute("src") ?? "/", url).href;
939
+ }
940
+ if (node.hasAttribute("srcset")) {
941
+ const srcSet = node.getAttribute("srcset")?.split(",").map((entry) => {
942
+ const [urlPart, descriptor] = entry.trim().split(/\s+/);
943
+ if (!urlPart)
944
+ return entry;
945
+ const absoluteUrl = new URL(urlPart, url).href;
946
+ return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
947
+ }).join(", ");
948
+ if (srcSet) {
949
+ node.setAttribute("srcset", srcSet);
950
+ }
951
+ }
952
+ });
953
+ }
954
+
865
955
  // src/html/host/runtime/index.ts
866
956
  async function getRuntime(type, url, bundle, shared, remoteShared) {
867
957
  if (typeof globalThis.process === "undefined") {
@@ -884,38 +974,64 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
884
974
  if (typeof HTMLElement !== "undefined") {
885
975
  class RemoteComponent extends HTMLElement {
886
976
  constructor() {
887
- super();
977
+ super(...arguments);
888
978
  this.__next = null;
889
979
  this.fouc = null;
890
980
  this.isLoading = false;
891
- this.attachShadow({ mode: "open" });
892
- this.fallbackSlot = document.createElement("slot");
893
- this.shadowRoot?.appendChild(this.fallbackSlot);
894
- this.name = this.getAttribute("name") || "__vercel_remote_component";
895
- this.bundle = "default";
896
- if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
897
- this.load().catch((e) => {
898
- throw new Error(`Failed to load remote component: ${e}`);
899
- });
900
- }
981
+ this.root = null;
901
982
  }
902
983
  static get observedAttributes() {
903
- return ["src"];
984
+ return ["src", "name", "mode"];
904
985
  }
905
986
  // watch for src attribute changes
906
987
  // this is required to reload the remote component when the src attribute is added later
907
988
  // this is for rendering the custom element using React
908
989
  attributeChangedCallback(name, oldValue, newValue) {
909
- if (name === "src" && oldValue !== newValue) {
990
+ if ((name === "src" || name === "name") && oldValue !== newValue) {
991
+ if (this.getAttribute("src")) {
992
+ this.load().catch((e) => {
993
+ console.error(e);
994
+ throw new Error(
995
+ `Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
996
+ );
997
+ });
998
+ }
999
+ } else if (name === "mode" && oldValue !== newValue && this.root) {
1000
+ const newRoot = this.attachShadow({
1001
+ mode: newValue === "closed" ? "closed" : "open"
1002
+ });
1003
+ Array.from(this.root.children).forEach((child) => {
1004
+ newRoot.appendChild(child);
1005
+ });
1006
+ this.root = newRoot;
910
1007
  this.load().catch((e) => {
911
1008
  throw new Error(`Failed to load remote component: ${e}`);
912
1009
  });
913
1010
  }
914
1011
  }
915
1012
  async load() {
1013
+ await new Promise((resolve) => {
1014
+ (typeof queueMicrotask === "function" ? queueMicrotask : requestAnimationFrame)(() => {
1015
+ resolve(void 0);
1016
+ });
1017
+ });
916
1018
  if (this.isLoading) {
917
1019
  return;
918
1020
  }
1021
+ if (!this.root) {
1022
+ this.root = this.attachShadow({
1023
+ mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
1024
+ });
1025
+ this.fallbackSlot = document.createElement("slot");
1026
+ this.root.appendChild(this.fallbackSlot);
1027
+ }
1028
+ this.name = this.getAttribute("name") || "__vercel_remote_component";
1029
+ this.bundle = "default";
1030
+ if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
1031
+ this.load().catch((e) => {
1032
+ throw new Error(`Failed to load remote component: ${e}`);
1033
+ });
1034
+ }
919
1035
  this.isLoading = true;
920
1036
  const src = this.getAttribute("src");
921
1037
  const remoteComponentChild = this.querySelector("div#__REMOTE_COMPONENT__") || this.querySelector("div[data-bundle][data-route]");
@@ -946,22 +1062,29 @@ if (typeof HTMLElement !== "undefined") {
946
1062
  }
947
1063
  html = await res.text();
948
1064
  }
949
- const doc = document.createElement("div");
950
- doc.innerHTML = html;
1065
+ const parser = new DOMParser();
1066
+ const doc = parser.parseFromString(html, "text/html");
951
1067
  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
952
1068
  doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
953
1069
  doc.querySelector("div#__next");
954
1070
  const nextData = JSON.parse(
955
1071
  (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
956
1072
  );
957
- if (nextData && nextData.buildId === "development") {
1073
+ if (nextData && nextData.buildId === "development" && !this.reactRoot) {
958
1074
  this.fouc = document.createElement("style");
959
1075
  this.fouc.textContent = `:host { display: none; }`;
960
- this.shadowRoot?.appendChild(this.fouc);
1076
+ this.root.appendChild(this.fouc);
961
1077
  }
962
1078
  this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : this.name);
963
1079
  const rsc = doc.querySelector(`#${this.name}_rsc`);
964
1080
  this.bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || this.bundle;
1081
+ if (url) {
1082
+ const self2 = globalThis;
1083
+ if (!self2.__remote_bundle_url__) {
1084
+ self2.__remote_bundle_url__ = {};
1085
+ }
1086
+ self2.__remote_bundle_url__[this.bundle ?? "default"] = url;
1087
+ }
965
1088
  const metadata = document.createElement("script");
966
1089
  metadata.type = "application/json";
967
1090
  metadata.setAttribute("data-remote-component", "");
@@ -971,54 +1094,116 @@ if (typeof HTMLElement !== "undefined") {
971
1094
  route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
972
1095
  runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
973
1096
  });
974
- this.parentNode?.insertBefore(metadata, this);
975
- const remoteSharedEl = doc.querySelector(`#${this.name}_shared`);
976
- const remoteShared = JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {};
1097
+ if (this.previousElementSibling?.getAttribute("data-remote-component") !== null) {
1098
+ this.previousElementSibling?.remove();
1099
+ }
1100
+ this.parentElement?.insertBefore(metadata, this);
1101
+ const remoteSharedEl = doc.querySelector(
1102
+ `#${this.name}_shared[data-remote-components-shared]`
1103
+ );
1104
+ const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
977
1105
  remoteSharedEl?.parentElement?.removeChild(remoteSharedEl);
978
1106
  if (!component || !(rsc || nextData)) {
979
1107
  throw new Error(`Failed to find component with id "${this.name}"`);
980
1108
  }
981
1109
  const removable = Array.from(this.childNodes);
982
1110
  const links = doc.querySelectorAll("link[href]");
983
- await Promise.all(
984
- Array.from(links).map((link) => {
985
- return new Promise((resolve, reject) => {
986
- const newLink = document.createElement("link");
987
- if (link.rel === "stylesheet") {
988
- newLink.onload = () => {
1111
+ const remoteComponentSrc = this.getAttribute("src");
1112
+ const attachLinks = async () => {
1113
+ await Promise.all(
1114
+ Array.from(links).filter((link) => {
1115
+ return !component.contains(link);
1116
+ }).map((link) => {
1117
+ return new Promise((resolve, reject) => {
1118
+ const newLink = document.createElement("link");
1119
+ if (link.rel === "stylesheet") {
1120
+ newLink.onload = () => {
1121
+ resolve();
1122
+ };
1123
+ newLink.onerror = () => {
1124
+ reject(
1125
+ new Error(
1126
+ `Failed to load link ${link.href} for remote component`
1127
+ )
1128
+ );
1129
+ };
1130
+ } else {
989
1131
  resolve();
990
- };
991
- newLink.onerror = () => {
992
- reject(
993
- new Error(
994
- `Failed to load link ${link.href} for remote component`
995
- )
996
- );
997
- };
998
- } else {
999
- resolve();
1000
- }
1001
- for (const attr of link.attributes) {
1002
- if (attr.name === "href") {
1132
+ }
1133
+ for (const attr of link.attributes) {
1134
+ if (attr.name === "href") {
1135
+ newLink.setAttribute(
1136
+ attr.name,
1137
+ new URL(attr.value, url ?? location.origin).href
1138
+ );
1139
+ } else {
1140
+ newLink.setAttribute(attr.name, attr.value);
1141
+ }
1142
+ }
1143
+ if (remoteComponentSrc) {
1003
1144
  newLink.setAttribute(
1004
- attr.name,
1005
- new URL(attr.value, url ?? location.origin).href
1145
+ "data-remote-component-src",
1146
+ remoteComponentSrc
1006
1147
  );
1007
- } else {
1008
- newLink.setAttribute(attr.name, attr.value);
1009
1148
  }
1149
+ this.root?.appendChild(newLink);
1150
+ });
1151
+ })
1152
+ );
1153
+ const styles = doc.querySelectorAll("style");
1154
+ styles.forEach((style) => {
1155
+ if (style.parentElement?.tagName.toLowerCase() === "head") {
1156
+ const newStyle = document.createElement("style");
1157
+ newStyle.textContent = style.textContent;
1158
+ if (remoteComponentSrc) {
1159
+ newStyle.setAttribute(
1160
+ "data-remote-component-src",
1161
+ remoteComponentSrc
1162
+ );
1010
1163
  }
1011
- this.shadowRoot?.appendChild(newLink);
1012
- });
1013
- })
1014
- );
1015
- Array.from(component.children).forEach((el) => {
1016
- this.shadowRoot?.appendChild(el);
1017
- });
1164
+ this.root?.appendChild(newStyle);
1165
+ }
1166
+ });
1167
+ };
1168
+ if (!this.reactRoot) {
1169
+ await attachLinks();
1170
+ }
1171
+ applyOriginToNodes(doc, url ?? new URL(location.href));
1172
+ if (!this.reactRoot) {
1173
+ Array.from(component.children).forEach((el) => {
1174
+ this.root?.appendChild(el);
1175
+ });
1176
+ }
1018
1177
  for (const el of removable) {
1019
1178
  el.parentElement?.removeChild(el);
1020
1179
  }
1021
- this.shadowRoot?.removeChild(this.fallbackSlot);
1180
+ this.fallbackSlot?.remove();
1181
+ const applyReset = () => {
1182
+ if (this.getAttribute("reset") !== null && !this.root?.querySelector("link[data-remote-components-reset]")) {
1183
+ const allInitial = document.createElement("link");
1184
+ allInitial.setAttribute("data-remote-components-reset", "");
1185
+ const css = `:host { all: initial; }`;
1186
+ const allInitialHref = URL.createObjectURL(
1187
+ new Blob([css], { type: "text/css" })
1188
+ );
1189
+ allInitial.href = allInitialHref;
1190
+ allInitial.rel = "stylesheet";
1191
+ allInitial.onload = () => {
1192
+ URL.revokeObjectURL(allInitialHref);
1193
+ allInitial.removeAttribute("onload");
1194
+ };
1195
+ allInitial.onerror = () => {
1196
+ URL.revokeObjectURL(allInitialHref);
1197
+ allInitial.removeAttribute("onload");
1198
+ };
1199
+ this.root?.prepend(allInitial);
1200
+ } else if (this.getAttribute("reset") === null && this.root?.querySelector("link[data-remote-components-reset]")) {
1201
+ this.root.querySelector("link[data-remote-components-reset]")?.remove();
1202
+ }
1203
+ };
1204
+ if (!this.reactRoot) {
1205
+ applyReset();
1206
+ }
1022
1207
  const {
1023
1208
  self,
1024
1209
  createFromReadableStream,
@@ -1046,7 +1231,26 @@ if (typeof HTMLElement !== "undefined") {
1046
1231
  window.location.href
1047
1232
  );
1048
1233
  }
1049
- await preloadScripts(Array.from(scripts), url, this.bundle, this.name);
1234
+ await preloadScripts(
1235
+ Array.from(scripts),
1236
+ url,
1237
+ this.bundle ?? "default",
1238
+ this.name ?? "__vercel_remote_component"
1239
+ );
1240
+ const doCleanup = () => {
1241
+ if (this.root && remoteComponentSrc) {
1242
+ const selector = `[data-remote-component-src]:not([data-remote-component-src="${remoteComponentSrc}"])`;
1243
+ const prevCleanup = [
1244
+ ...this.root.querySelectorAll(selector),
1245
+ ...document.body.querySelectorAll(selector)
1246
+ ];
1247
+ if (prevCleanup.length > 0) {
1248
+ prevCleanup.forEach((prev) => {
1249
+ prev.remove();
1250
+ });
1251
+ }
1252
+ }
1253
+ };
1050
1254
  if (rsc) {
1051
1255
  rsc.parentElement?.removeChild(rsc);
1052
1256
  const rscClone = document.createElement("script");
@@ -1055,36 +1259,97 @@ if (typeof HTMLElement !== "undefined") {
1055
1259
  document.body.appendChild(rscClone);
1056
1260
  let cache;
1057
1261
  const RemoteComponentFromReadableStream = ({
1058
- name
1262
+ name,
1263
+ initial
1059
1264
  }) => {
1060
1265
  const stream = createRSCStream(name, self[name] ?? [`0:[null]
1061
1266
  `]);
1062
1267
  const Component = cache ?? // cache the component to avoid reloading the RSC flight data
1063
1268
  (cache = createFromReadableStream(stream));
1269
+ (0, import_react.useLayoutEffect)(() => {
1270
+ if (self[name]) {
1271
+ delete self[name];
1272
+ }
1273
+ const rscScript = document.getElementById(`${name}_rsc`);
1274
+ if (rscScript) {
1275
+ rscScript.remove();
1276
+ }
1277
+ doCleanup();
1278
+ applyReset();
1279
+ if (!initial) {
1280
+ attachLinks().catch((e) => {
1281
+ console.error(e);
1282
+ });
1283
+ }
1284
+ this.isLoading = false;
1285
+ }, [initial, name]);
1064
1286
  return Component;
1065
1287
  };
1066
- (0, import_client.hydrateRoot)(
1288
+ if (this.reactRoot) {
1289
+ const root = this.reactRoot;
1290
+ (0, import_react.startTransition)(() => {
1291
+ root.render(
1292
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1293
+ RemoteComponentFromReadableStream,
1294
+ {
1295
+ initial: false,
1296
+ name: this.name ?? "__vercel_remote_component"
1297
+ }
1298
+ )
1299
+ );
1300
+ });
1301
+ return;
1302
+ }
1303
+ this.reactRoot = (0, import_client.hydrateRoot)(
1067
1304
  // hydrateRoot expects a document or element, but it works for the shadow DOM too
1068
1305
  // @ts-expect-error support for shadow DOM
1069
- this.shadowRoot,
1070
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RemoteComponentFromReadableStream, { name: this.name })
1306
+ this.root,
1307
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1308
+ RemoteComponentFromReadableStream,
1309
+ {
1310
+ initial: true,
1311
+ name: this.name ?? "__vercel_remote_component"
1312
+ }
1313
+ )
1071
1314
  );
1072
1315
  } else if (nextData) {
1073
1316
  const { Component, App } = nextClientPagesLoader2(
1074
- this.bundle,
1317
+ this.bundle ?? "default",
1075
1318
  nextData.page,
1076
- this.shadowRoot
1319
+ this.root
1077
1320
  );
1078
1321
  if (Component) {
1079
- (0, import_client.hydrateRoot)(
1322
+ const RemoteComponentFromNext = ((NextApp, NextComponent, remoteComponent = this) => function RemoteComponentNext({ initial }) {
1323
+ (0, import_react.useLayoutEffect)(() => {
1324
+ doCleanup();
1325
+ if (!initial) {
1326
+ applyReset();
1327
+ attachLinks().catch((e) => {
1328
+ console.error(e);
1329
+ });
1330
+ }
1331
+ remoteComponent.isLoading = false;
1332
+ }, [initial]);
1333
+ return NextApp ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NextApp, { Component: NextComponent, ...nextData.props }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NextComponent, { ...nextData.props });
1334
+ })(App, Component, this);
1335
+ if (this.reactRoot) {
1336
+ const root = this.reactRoot;
1337
+ (0, import_react.startTransition)(() => {
1338
+ root.render(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RemoteComponentFromNext, { initial: false }));
1339
+ doCleanup();
1340
+ this.isLoading = false;
1341
+ });
1342
+ return;
1343
+ }
1344
+ this.reactRoot = (0, import_client.hydrateRoot)(
1080
1345
  // hydrateRoot expects a document or element, but it works for the shadow DOM too
1081
1346
  // @ts-expect-error support for shadow DOM
1082
- this.shadowRoot,
1083
- App ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(App, { Component, ...nextData.props }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, { ...nextData.props })
1347
+ this.root,
1348
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RemoteComponentFromNext, { initial: true })
1084
1349
  );
1085
1350
  }
1086
1351
  if (this.fouc) {
1087
- this.shadowRoot?.removeChild(this.fouc);
1352
+ this.root.removeChild(this.fouc);
1088
1353
  }
1089
1354
  }
1090
1355
  this.isLoading = false;