remote-components 0.0.23 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/html/host.cjs +297 -82
  2. package/dist/html/host.cjs.map +1 -1
  3. package/dist/html/host.js +300 -82
  4. package/dist/html/host.js.map +1 -1
  5. package/dist/internal/next/host/app-router-client.cjs +176 -70
  6. package/dist/internal/next/host/app-router-client.cjs.map +1 -1
  7. package/dist/internal/next/host/app-router-client.js +184 -71
  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 +3 -3
  29. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  30. package/dist/internal/shared/client/remote-component.d.ts +1 -1
  31. package/dist/internal/shared/client/remote-component.js +3 -3
  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/next/config.cjs +50 -28
  43. package/dist/next/config.cjs.map +1 -1
  44. package/dist/next/config.js +50 -28
  45. package/dist/next/config.js.map +1 -1
  46. package/dist/next/host/client/index.cjs +16 -1
  47. package/dist/next/host/client/index.cjs.map +1 -1
  48. package/dist/next/host/client/index.js +16 -1
  49. package/dist/next/host/client/index.js.map +1 -1
  50. package/dist/next/host/pages-router-server.cjs +27 -13
  51. package/dist/next/host/pages-router-server.cjs.map +1 -1
  52. package/dist/next/host/pages-router-server.js +27 -13
  53. package/dist/next/host/pages-router-server.js.map +1 -1
  54. package/dist/next/middleware.cjs +5 -2
  55. package/dist/next/middleware.cjs.map +1 -1
  56. package/dist/next/middleware.d.ts +1 -0
  57. package/dist/next/middleware.js +5 -2
  58. package/dist/next/middleware.js.map +1 -1
  59. package/dist/next/remote/pages-router.cjs +3 -1
  60. package/dist/next/remote/pages-router.cjs.map +1 -1
  61. package/dist/next/remote/pages-router.d.ts +1 -0
  62. package/dist/next/remote/pages-router.js +3 -1
  63. package/dist/next/remote/pages-router.js.map +1 -1
  64. package/dist/react/index.cjs +203 -159
  65. package/dist/react/index.cjs.map +1 -1
  66. package/dist/react/index.d.ts +1 -1
  67. package/dist/react/index.js +192 -148
  68. package/dist/react/index.js.map +1 -1
  69. 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,7 +810,7 @@ var init_turbopack = __esm({
753
810
  });
754
811
 
755
812
  // src/html/host/index.tsx
756
- import { startTransition } from "react";
813
+ import { startTransition, useLayoutEffect } from "react";
757
814
  import { hydrateRoot } from "react-dom/client";
758
815
 
759
816
  // src/shared/client/component-loader.ts
@@ -835,6 +892,41 @@ function createRSCStream(name, data) {
835
892
  init_webpack_adapter();
836
893
  init_const();
837
894
 
895
+ // src/shared/client/apply-origin.ts
896
+ var tagNames = [
897
+ "img",
898
+ "source",
899
+ "video",
900
+ "audio",
901
+ "track",
902
+ "iframe",
903
+ "embed",
904
+ "script",
905
+ "link"
906
+ ];
907
+ function applyOriginToNodes(doc, url) {
908
+ const nodes = doc.querySelectorAll(
909
+ tagNames.map((type) => `${type}[src],${type}[srcset]`).join(",")
910
+ );
911
+ nodes.forEach((node) => {
912
+ if (node.hasAttribute("src") && /^[./]+\/?/.test(node.getAttribute("src") ?? "")) {
913
+ node.src = new URL(node.getAttribute("src") ?? "/", url).href;
914
+ }
915
+ if (node.hasAttribute("srcset")) {
916
+ const srcSet = node.getAttribute("srcset")?.split(",").map((entry) => {
917
+ const [urlPart, descriptor] = entry.trim().split(/\s+/);
918
+ if (!urlPart)
919
+ return entry;
920
+ const absoluteUrl = new URL(urlPart, url).href;
921
+ return descriptor ? `${absoluteUrl} ${descriptor}` : absoluteUrl;
922
+ }).join(", ");
923
+ if (srcSet) {
924
+ node.setAttribute("srcset", srcSet);
925
+ }
926
+ }
927
+ });
928
+ }
929
+
838
930
  // src/html/host/runtime/index.ts
839
931
  async function getRuntime(type, url, bundle, shared, remoteShared) {
840
932
  if (typeof globalThis.process === "undefined") {
@@ -857,44 +949,64 @@ import { jsx as jsx2 } from "react/jsx-runtime";
857
949
  if (typeof HTMLElement !== "undefined") {
858
950
  class RemoteComponent extends HTMLElement {
859
951
  constructor() {
860
- super();
952
+ super(...arguments);
861
953
  this.__next = null;
862
954
  this.fouc = null;
863
955
  this.isLoading = false;
864
956
  this.root = null;
865
- this.root = this.attachShadow({
866
- mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
867
- });
868
- this.fallbackSlot = document.createElement("slot");
869
- this.root.appendChild(this.fallbackSlot);
870
- this.name = this.getAttribute("name") || "__vercel_remote_component";
871
- this.bundle = "default";
872
- if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
873
- this.load().catch((e) => {
874
- throw new Error(`Failed to load remote component: ${e}`);
875
- });
876
- }
877
957
  }
878
958
  static get observedAttributes() {
879
- return ["src", "name"];
959
+ return ["src", "name", "mode"];
880
960
  }
881
961
  // watch for src attribute changes
882
962
  // this is required to reload the remote component when the src attribute is added later
883
963
  // this is for rendering the custom element using React
884
964
  attributeChangedCallback(name, oldValue, newValue) {
885
965
  if ((name === "src" || name === "name") && oldValue !== newValue) {
966
+ if (this.getAttribute("src")) {
967
+ this.load().catch((e) => {
968
+ console.error(e);
969
+ throw new Error(
970
+ `Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
971
+ );
972
+ });
973
+ }
974
+ } else if (name === "mode" && oldValue !== newValue && this.root) {
975
+ const newRoot = this.attachShadow({
976
+ mode: newValue === "closed" ? "closed" : "open"
977
+ });
978
+ Array.from(this.root.children).forEach((child) => {
979
+ newRoot.appendChild(child);
980
+ });
981
+ this.root = newRoot;
886
982
  this.load().catch((e) => {
887
- console.error(e);
888
- throw new Error(
889
- `Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
890
- );
983
+ throw new Error(`Failed to load remote component: ${e}`);
891
984
  });
892
985
  }
893
986
  }
894
987
  async load() {
988
+ await new Promise((resolve) => {
989
+ (typeof queueMicrotask === "function" ? queueMicrotask : requestAnimationFrame)(() => {
990
+ resolve(void 0);
991
+ });
992
+ });
895
993
  if (this.isLoading) {
896
994
  return;
897
995
  }
996
+ if (!this.root) {
997
+ this.root = this.attachShadow({
998
+ mode: this.getAttribute("mode") === "closed" ? "closed" : "open"
999
+ });
1000
+ this.fallbackSlot = document.createElement("slot");
1001
+ this.root.appendChild(this.fallbackSlot);
1002
+ }
1003
+ this.name = this.getAttribute("name") || "__vercel_remote_component";
1004
+ this.bundle = "default";
1005
+ if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
1006
+ this.load().catch((e) => {
1007
+ throw new Error(`Failed to load remote component: ${e}`);
1008
+ });
1009
+ }
898
1010
  this.isLoading = true;
899
1011
  const src = this.getAttribute("src");
900
1012
  const remoteComponentChild = this.querySelector("div#__REMOTE_COMPONENT__") || this.querySelector("div[data-bundle][data-route]");
@@ -925,8 +1037,8 @@ if (typeof HTMLElement !== "undefined") {
925
1037
  }
926
1038
  html = await res.text();
927
1039
  }
928
- const doc = document.createElement("div");
929
- doc.innerHTML = html;
1040
+ const parser = new DOMParser();
1041
+ const doc = parser.parseFromString(html, "text/html");
930
1042
  const component = doc.querySelector(`div[data-bundle][data-route][id^="${this.name}"]`) ?? // fallback to the first element with the data-bundle and data-route attributes when not using a named remote component
931
1043
  doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
932
1044
  doc.querySelector("div#__next");
@@ -936,11 +1048,18 @@ if (typeof HTMLElement !== "undefined") {
936
1048
  if (nextData && nextData.buildId === "development" && !this.reactRoot) {
937
1049
  this.fouc = document.createElement("style");
938
1050
  this.fouc.textContent = `:host { display: none; }`;
939
- this.root?.appendChild(this.fouc);
1051
+ this.root.appendChild(this.fouc);
940
1052
  }
941
1053
  this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : this.name);
942
1054
  const rsc = doc.querySelector(`#${this.name}_rsc`);
943
1055
  this.bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || this.bundle;
1056
+ if (url) {
1057
+ const self2 = globalThis;
1058
+ if (!self2.__remote_bundle_url__) {
1059
+ self2.__remote_bundle_url__ = {};
1060
+ }
1061
+ self2.__remote_bundle_url__[this.bundle ?? "default"] = url;
1062
+ }
944
1063
  const metadata = document.createElement("script");
945
1064
  metadata.type = "application/json";
946
1065
  metadata.setAttribute("data-remote-component", "");
@@ -950,47 +1069,81 @@ if (typeof HTMLElement !== "undefined") {
950
1069
  route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
951
1070
  runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
952
1071
  });
953
- this.parentNode?.insertBefore(metadata, this);
954
- const remoteSharedEl = doc.querySelector(`#${this.name}_shared`);
955
- 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 ?? "{}") ?? {});
956
1080
  remoteSharedEl?.parentElement?.removeChild(remoteSharedEl);
957
1081
  if (!component || !(rsc || nextData)) {
958
1082
  throw new Error(`Failed to find component with id "${this.name}"`);
959
1083
  }
960
1084
  const removable = Array.from(this.childNodes);
961
1085
  const links = doc.querySelectorAll("link[href]");
962
- await Promise.all(
963
- Array.from(links).map((link) => {
964
- return new Promise((resolve, reject) => {
965
- const newLink = document.createElement("link");
966
- if (link.rel === "stylesheet") {
967
- 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 {
968
1106
  resolve();
969
- };
970
- newLink.onerror = () => {
971
- reject(
972
- new Error(
973
- `Failed to load link ${link.href} for remote component`
974
- )
975
- );
976
- };
977
- } else {
978
- resolve();
979
- }
980
- for (const attr of link.attributes) {
981
- if (attr.name === "href") {
1107
+ }
1108
+ for (const attr of link.attributes) {
1109
+ if (attr.name === "href") {
1110
+ newLink.setAttribute(
1111
+ attr.name,
1112
+ new URL(attr.value, url ?? location.origin).href
1113
+ );
1114
+ } else {
1115
+ newLink.setAttribute(attr.name, attr.value);
1116
+ }
1117
+ }
1118
+ if (remoteComponentSrc) {
982
1119
  newLink.setAttribute(
983
- attr.name,
984
- new URL(attr.value, url ?? location.origin).href
1120
+ "data-remote-component-src",
1121
+ remoteComponentSrc
985
1122
  );
986
- } else {
987
- newLink.setAttribute(attr.name, attr.value);
988
1123
  }
1124
+ this.root?.appendChild(newLink);
1125
+ });
1126
+ })
1127
+ );
1128
+ const styles = doc.querySelectorAll("style");
1129
+ styles.forEach((style) => {
1130
+ if (style.parentElement?.tagName.toLowerCase() === "head") {
1131
+ const newStyle = document.createElement("style");
1132
+ newStyle.textContent = style.textContent;
1133
+ if (remoteComponentSrc) {
1134
+ newStyle.setAttribute(
1135
+ "data-remote-component-src",
1136
+ remoteComponentSrc
1137
+ );
989
1138
  }
990
- this.root?.appendChild(newLink);
991
- });
992
- })
993
- );
1139
+ this.root?.appendChild(newStyle);
1140
+ }
1141
+ });
1142
+ };
1143
+ if (!this.reactRoot) {
1144
+ await attachLinks();
1145
+ }
1146
+ applyOriginToNodes(doc, url ?? new URL(location.href));
994
1147
  if (!this.reactRoot) {
995
1148
  Array.from(component.children).forEach((el) => {
996
1149
  this.root?.appendChild(el);
@@ -999,12 +1152,32 @@ if (typeof HTMLElement !== "undefined") {
999
1152
  for (const el of removable) {
1000
1153
  el.parentElement?.removeChild(el);
1001
1154
  }
1002
- this.fallbackSlot.remove();
1003
- if (this.getAttribute("reset") !== null && !this.root?.querySelector("style[data-remote-components-reset]")) {
1004
- const allInitial = document.createElement("style");
1005
- allInitial.setAttribute("data-remote-components-reset", "");
1006
- allInitial.textContent = `:host { all: initial; }`;
1007
- this.root?.prepend(allInitial);
1155
+ this.fallbackSlot?.remove();
1156
+ const applyReset = () => {
1157
+ if (this.getAttribute("reset") !== null && !this.root?.querySelector("link[data-remote-components-reset]")) {
1158
+ const allInitial = document.createElement("link");
1159
+ allInitial.setAttribute("data-remote-components-reset", "");
1160
+ const css = `:host { all: initial; }`;
1161
+ const allInitialHref = URL.createObjectURL(
1162
+ new Blob([css], { type: "text/css" })
1163
+ );
1164
+ allInitial.href = allInitialHref;
1165
+ allInitial.rel = "stylesheet";
1166
+ allInitial.onload = () => {
1167
+ URL.revokeObjectURL(allInitialHref);
1168
+ allInitial.removeAttribute("onload");
1169
+ };
1170
+ allInitial.onerror = () => {
1171
+ URL.revokeObjectURL(allInitialHref);
1172
+ allInitial.removeAttribute("onload");
1173
+ };
1174
+ this.root?.prepend(allInitial);
1175
+ } else if (this.getAttribute("reset") === null && this.root?.querySelector("link[data-remote-components-reset]")) {
1176
+ this.root.querySelector("link[data-remote-components-reset]")?.remove();
1177
+ }
1178
+ };
1179
+ if (!this.reactRoot) {
1180
+ applyReset();
1008
1181
  }
1009
1182
  const {
1010
1183
  self,
@@ -1039,6 +1212,20 @@ if (typeof HTMLElement !== "undefined") {
1039
1212
  this.bundle ?? "default",
1040
1213
  this.name ?? "__vercel_remote_component"
1041
1214
  );
1215
+ const doCleanup = () => {
1216
+ if (this.root && remoteComponentSrc) {
1217
+ const selector = `[data-remote-component-src]:not([data-remote-component-src="${remoteComponentSrc}"])`;
1218
+ const prevCleanup = [
1219
+ ...this.root.querySelectorAll(selector),
1220
+ ...document.body.querySelectorAll(selector)
1221
+ ];
1222
+ if (prevCleanup.length > 0) {
1223
+ prevCleanup.forEach((prev) => {
1224
+ prev.remove();
1225
+ });
1226
+ }
1227
+ }
1228
+ };
1042
1229
  if (rsc) {
1043
1230
  rsc.parentElement?.removeChild(rsc);
1044
1231
  const rscClone = document.createElement("script");
@@ -1047,12 +1234,30 @@ if (typeof HTMLElement !== "undefined") {
1047
1234
  document.body.appendChild(rscClone);
1048
1235
  let cache;
1049
1236
  const RemoteComponentFromReadableStream = ({
1050
- name
1237
+ name,
1238
+ initial
1051
1239
  }) => {
1052
1240
  const stream = createRSCStream(name, self[name] ?? [`0:[null]
1053
1241
  `]);
1054
1242
  const Component = cache ?? // cache the component to avoid reloading the RSC flight data
1055
1243
  (cache = createFromReadableStream(stream));
1244
+ useLayoutEffect(() => {
1245
+ if (self[name]) {
1246
+ delete self[name];
1247
+ }
1248
+ const rscScript = document.getElementById(`${name}_rsc`);
1249
+ if (rscScript) {
1250
+ rscScript.remove();
1251
+ }
1252
+ doCleanup();
1253
+ applyReset();
1254
+ if (!initial) {
1255
+ attachLinks().catch((e) => {
1256
+ console.error(e);
1257
+ });
1258
+ }
1259
+ this.isLoading = false;
1260
+ }, [initial, name]);
1056
1261
  return Component;
1057
1262
  };
1058
1263
  if (this.reactRoot) {
@@ -1062,11 +1267,11 @@ if (typeof HTMLElement !== "undefined") {
1062
1267
  /* @__PURE__ */ jsx2(
1063
1268
  RemoteComponentFromReadableStream,
1064
1269
  {
1270
+ initial: false,
1065
1271
  name: this.name ?? "__vercel_remote_component"
1066
1272
  }
1067
1273
  )
1068
1274
  );
1069
- this.isLoading = false;
1070
1275
  });
1071
1276
  return;
1072
1277
  }
@@ -1077,6 +1282,7 @@ if (typeof HTMLElement !== "undefined") {
1077
1282
  /* @__PURE__ */ jsx2(
1078
1283
  RemoteComponentFromReadableStream,
1079
1284
  {
1285
+ initial: true,
1080
1286
  name: this.name ?? "__vercel_remote_component"
1081
1287
  }
1082
1288
  )
@@ -1088,12 +1294,24 @@ if (typeof HTMLElement !== "undefined") {
1088
1294
  this.root
1089
1295
  );
1090
1296
  if (Component) {
1297
+ const RemoteComponentFromNext = ((NextApp, NextComponent, remoteComponent = this) => function RemoteComponentNext({ initial }) {
1298
+ useLayoutEffect(() => {
1299
+ doCleanup();
1300
+ if (!initial) {
1301
+ applyReset();
1302
+ attachLinks().catch((e) => {
1303
+ console.error(e);
1304
+ });
1305
+ }
1306
+ remoteComponent.isLoading = false;
1307
+ }, [initial]);
1308
+ return NextApp ? /* @__PURE__ */ jsx2(NextApp, { Component: NextComponent, ...nextData.props }) : /* @__PURE__ */ jsx2(NextComponent, { ...nextData.props });
1309
+ })(App, Component, this);
1091
1310
  if (this.reactRoot) {
1092
1311
  const root = this.reactRoot;
1093
1312
  startTransition(() => {
1094
- root.render(
1095
- App ? /* @__PURE__ */ jsx2(App, { Component, ...nextData.props }) : /* @__PURE__ */ jsx2(Component, { ...nextData.props })
1096
- );
1313
+ root.render(/* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: false }));
1314
+ doCleanup();
1097
1315
  this.isLoading = false;
1098
1316
  });
1099
1317
  return;
@@ -1102,11 +1320,11 @@ if (typeof HTMLElement !== "undefined") {
1102
1320
  // hydrateRoot expects a document or element, but it works for the shadow DOM too
1103
1321
  // @ts-expect-error support for shadow DOM
1104
1322
  this.root,
1105
- App ? /* @__PURE__ */ jsx2(App, { Component, ...nextData.props }) : /* @__PURE__ */ jsx2(Component, { ...nextData.props })
1323
+ /* @__PURE__ */ jsx2(RemoteComponentFromNext, { initial: true })
1106
1324
  );
1107
1325
  }
1108
1326
  if (this.fouc) {
1109
- this.root?.removeChild(this.fouc);
1327
+ this.root.removeChild(this.fouc);
1110
1328
  }
1111
1329
  }
1112
1330
  this.isLoading = false;