remote-components 0.0.32 → 0.0.34

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 (109) hide show
  1. package/dist/{component-loader-e5513139.d.ts → component-loader-8951c052.d.ts} +6 -3
  2. package/dist/html/host.cjs +330 -39
  3. package/dist/html/host.cjs.map +1 -1
  4. package/dist/html/host.js +330 -39
  5. package/dist/html/host.js.map +1 -1
  6. package/dist/html/remote.cjs +198 -0
  7. package/dist/html/remote.cjs.map +1 -0
  8. package/dist/html/remote.d.ts +2 -0
  9. package/dist/html/remote.js +197 -0
  10. package/dist/html/remote.js.map +1 -0
  11. package/dist/internal/next/host/app-router-client.cjs +62 -6
  12. package/dist/internal/next/host/app-router-client.cjs.map +1 -1
  13. package/dist/internal/next/host/app-router-client.d.ts +3 -3
  14. package/dist/internal/next/host/app-router-client.js +64 -7
  15. package/dist/internal/next/host/app-router-client.js.map +1 -1
  16. package/dist/internal/next/remote/render-client.cjs +13 -3
  17. package/dist/internal/next/remote/render-client.cjs.map +1 -1
  18. package/dist/internal/next/remote/render-client.js +13 -3
  19. package/dist/internal/next/remote/render-client.js.map +1 -1
  20. package/dist/internal/next/remote/render-server.cjs +22 -3
  21. package/dist/internal/next/remote/render-server.cjs.map +1 -1
  22. package/dist/internal/next/remote/render-server.js +23 -4
  23. package/dist/internal/next/remote/render-server.js.map +1 -1
  24. package/dist/internal/shared/client/remote-component.cjs +134 -17
  25. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  26. package/dist/internal/shared/client/remote-component.d.ts +17 -3
  27. package/dist/internal/shared/client/remote-component.js +131 -17
  28. package/dist/internal/shared/client/remote-component.js.map +1 -1
  29. package/dist/internal/shared/error.cjs +50 -0
  30. package/dist/internal/shared/error.cjs.map +1 -0
  31. package/dist/internal/shared/error.d.ts +10 -0
  32. package/dist/internal/shared/error.js +24 -0
  33. package/dist/internal/shared/error.js.map +1 -0
  34. package/dist/internal/shared/ssr/dom-flight.cjs +24 -5
  35. package/dist/internal/shared/ssr/dom-flight.cjs.map +1 -1
  36. package/dist/internal/shared/ssr/dom-flight.d.ts +2 -1
  37. package/dist/internal/shared/ssr/dom-flight.js +24 -5
  38. package/dist/internal/shared/ssr/dom-flight.js.map +1 -1
  39. package/dist/internal/shared/ssr/fetch-remote-component.cjs +54 -7
  40. package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
  41. package/dist/internal/shared/ssr/fetch-remote-component.d.ts +2 -1
  42. package/dist/internal/shared/ssr/fetch-remote-component.js +58 -7
  43. package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
  44. package/dist/internal/webpack/next-client-pages-loader.cjs +3 -2
  45. package/dist/internal/webpack/next-client-pages-loader.cjs.map +1 -1
  46. package/dist/internal/webpack/next-client-pages-loader.js +3 -2
  47. package/dist/internal/webpack/next-client-pages-loader.js.map +1 -1
  48. package/dist/next/config.cjs +26 -9
  49. package/dist/next/config.cjs.map +1 -1
  50. package/dist/next/config.js +26 -9
  51. package/dist/next/config.js.map +1 -1
  52. package/dist/next/host/app-router-server.cjs +1 -0
  53. package/dist/next/host/app-router-server.cjs.map +1 -1
  54. package/dist/next/host/app-router-server.js +1 -0
  55. package/dist/next/host/app-router-server.js.map +1 -1
  56. package/dist/next/host/client/index.cjs +376 -130
  57. package/dist/next/host/client/index.cjs.map +1 -1
  58. package/dist/next/host/client/index.d.ts +1 -1
  59. package/dist/next/host/client/index.js +373 -129
  60. package/dist/next/host/client/index.js.map +1 -1
  61. package/dist/next/host/pages-router-client.cjs +1 -1
  62. package/dist/next/host/pages-router-client.cjs.map +1 -1
  63. package/dist/next/host/pages-router-client.js +1 -1
  64. package/dist/next/host/pages-router-client.js.map +1 -1
  65. package/dist/next/host/pages-router-server.cjs +4 -3
  66. package/dist/next/host/pages-router-server.cjs.map +1 -1
  67. package/dist/next/host/pages-router-server.js +4 -3
  68. package/dist/next/host/pages-router-server.js.map +1 -1
  69. package/dist/next/index.cjs +4 -2
  70. package/dist/next/index.cjs.map +1 -1
  71. package/dist/next/index.js +4 -2
  72. package/dist/next/index.js.map +1 -1
  73. package/dist/next/remote/pages-router.cjs +1 -1
  74. package/dist/next/remote/pages-router.cjs.map +1 -1
  75. package/dist/next/remote/pages-router.js +1 -1
  76. package/dist/next/remote/pages-router.js.map +1 -1
  77. package/dist/react/index.cjs +237 -112
  78. package/dist/react/index.cjs.map +1 -1
  79. package/dist/react/index.d.ts +2 -2
  80. package/dist/react/index.js +240 -111
  81. package/dist/react/index.js.map +1 -1
  82. package/dist/shared/host/app.cjs +36 -0
  83. package/dist/shared/host/app.cjs.map +1 -0
  84. package/dist/shared/host/app.d.ts +3 -0
  85. package/dist/shared/host/app.js +12 -0
  86. package/dist/shared/host/app.js.map +1 -0
  87. package/dist/shared/host/pages.cjs +36 -0
  88. package/dist/shared/host/pages.cjs.map +1 -0
  89. package/dist/shared/host/pages.d.ts +3 -0
  90. package/dist/shared/host/pages.js +12 -0
  91. package/dist/shared/host/pages.js.map +1 -0
  92. package/dist/shared/remote/app.cjs +32 -0
  93. package/dist/shared/remote/app.cjs.map +1 -0
  94. package/dist/shared/remote/app.d.ts +3 -0
  95. package/dist/shared/remote/app.js +8 -0
  96. package/dist/shared/remote/app.js.map +1 -0
  97. package/dist/shared/remote/pages.cjs +32 -0
  98. package/dist/shared/remote/pages.cjs.map +1 -0
  99. package/dist/shared/remote/pages.d.ts +3 -0
  100. package/dist/shared/remote/pages.js +8 -0
  101. package/dist/shared/remote/pages.js.map +1 -0
  102. package/dist/shared/remote/wrapper.cjs +48 -0
  103. package/dist/shared/remote/wrapper.cjs.map +1 -0
  104. package/dist/shared/remote/wrapper.d.ts +2 -0
  105. package/dist/shared/remote/wrapper.js +25 -0
  106. package/dist/shared/remote/wrapper.js.map +1 -0
  107. package/dist/{types-b8210fd3.d.ts → types-4e7dea94.d.ts} +2 -1
  108. package/dist/{types-280a3640.d.ts → types-cbf6c34f.d.ts} +2 -1
  109. package/package.json +44 -1
@@ -3,8 +3,9 @@ import * as react from 'react';
3
3
  interface RemoteComponentMetadata {
4
4
  bundle: string;
5
5
  route: string;
6
- runtime: 'webpack' | 'turbopack';
6
+ runtime: 'webpack' | 'turbopack' | 'script';
7
7
  id: string;
8
+ type: 'nextjs' | 'remote-component' | 'unknown';
8
9
  }
9
10
 
10
11
  interface RemoteComponentProps {
@@ -28,6 +29,7 @@ interface RemoteComponentProps {
28
29
  isolate?: boolean;
29
30
  mode?: 'open' | 'closed';
30
31
  reset?: boolean;
32
+ type?: RemoteComponentMetadata['type'];
31
33
  children: react.ReactNode;
32
34
  }
33
35
  interface GlobalScope {
@@ -46,7 +48,7 @@ interface GlobalScope {
46
48
  m?: Record<string | number, (module: {
47
49
  exports: unknown;
48
50
  }) => void>;
49
- type?: 'turbopack' | 'webpack';
51
+ type?: 'turbopack' | 'webpack' | 'script';
50
52
  }>;
51
53
  __webpack_require_type__?: RemoteComponentMetadata['runtime'];
52
54
  __remote_shared_modules__?: Record<string, Record<string, unknown>>;
@@ -60,6 +62,7 @@ interface LoaderResult {
60
62
  component: react.ReactNode;
61
63
  error?: Error;
62
64
  }
65
+ type MountOrUnmountFunction = (el?: ShadowRoot | DocumentFragment | HTMLElement | HTMLCollection | null) => Promise<void> | void;
63
66
 
64
67
  type LoadRemoteComponentProps = Pick<RemoteComponentProps, 'name' | 'bundle' | 'route' | 'runtime' | 'data' | 'nextData' | 'scripts'> & {
65
68
  url: URL;
@@ -73,4 +76,4 @@ type LoadRemoteComponentProps = Pick<RemoteComponentProps, 'name' | 'bundle' | '
73
76
  */
74
77
  declare function loadRemoteComponent({ url, name, rscName, bundle, route, runtime, data, nextData, scripts, shared, remoteShared, container, }: LoadRemoteComponentProps): Promise<LoaderResult>;
75
78
 
76
- export { GlobalScope as G, LoaderResult as L, RemoteComponentProps as R, LoadRemoteComponentProps as a, loadRemoteComponent as l };
79
+ export { GlobalScope as G, LoadRemoteComponentProps as L, MountOrUnmountFunction as M, RemoteComponentProps as R, LoaderResult as a, loadRemoteComponent as l };
@@ -62,6 +62,32 @@ var init_shared_modules = __esm({
62
62
  }
63
63
  });
64
64
 
65
+ // src/shared/error.ts
66
+ function multipleRemoteComponentsError(url) {
67
+ return new Error(
68
+ `Multiple Remote Components found at "${url}". When a page exposes multiple Remote Components you must specify the "name" prop to select which one to load.`
69
+ );
70
+ }
71
+ function failedToFetchRemoteComponentError(url, error) {
72
+ return new RemoteComponentsError(
73
+ `Failed to fetch Remote Component from "${url}". Is the URL correct and accessible?`,
74
+ { cause: error instanceof Error ? error : new Error(String(error)) }
75
+ );
76
+ }
77
+ var RemoteComponentsError;
78
+ var init_error = __esm({
79
+ "src/shared/error.ts"() {
80
+ "use strict";
81
+ RemoteComponentsError = class extends Error {
82
+ constructor(message, options) {
83
+ super(message, options);
84
+ this.code = "REMOTE_COMPONENTS_ERROR";
85
+ this.name = "RemoteComponentsError";
86
+ }
87
+ };
88
+ }
89
+ });
90
+
65
91
  // src/shared/webpack/next-client-pages-loader.ts
66
92
  function nextClientPagesLoader(bundle, route, styleContainer = document.head) {
67
93
  const self = globalThis;
@@ -100,8 +126,8 @@ function nextClientPagesLoader(bundle, route, styleContainer = document.head) {
100
126
  (key) => key.includes("/next/dist/client/page-loader.js")
101
127
  ) ?? ""] ?? -1;
102
128
  if (!(componentLoaderChunk && appLoaderChunk)) {
103
- throw new Error(
104
- `Next.js client pages loader not found in bundle "${bundle}"`
129
+ throw new RemoteComponentsError(
130
+ `Next.js client pages loader not found in bundle "${bundle}".`
105
131
  );
106
132
  }
107
133
  const __NEXT_P_ORIGINAL = self.__NEXT_P;
@@ -176,6 +202,7 @@ function nextClientPagesLoader(bundle, route, styleContainer = document.head) {
176
202
  var init_next_client_pages_loader = __esm({
177
203
  "src/shared/webpack/next-client-pages-loader.ts"() {
178
204
  "use strict";
205
+ init_error();
179
206
  }
180
207
  });
181
208
 
@@ -334,11 +361,11 @@ async function handleTurbopackChunk(code, bundle, url) {
334
361
  scriptResolve(void 0);
335
362
  script.remove();
336
363
  };
337
- script.onerror = (error) => {
364
+ script.onerror = () => {
338
365
  URL.revokeObjectURL(scriptUrl);
339
366
  scriptReject(
340
- new Error(
341
- `Failed to load script: ${error instanceof Error ? error.message : String(error)}`
367
+ new RemoteComponentsError(
368
+ `Failed to load <script src="${script.src}"> for Remote Component. Check the URL is correct.`
342
369
  )
343
370
  );
344
371
  script.remove();
@@ -380,11 +407,11 @@ function createModuleRequire(runtime) {
380
407
  if (bundle && moduleId) {
381
408
  return handleTurbopackModule(bundle, moduleId, id);
382
409
  }
383
- throw new Error(`Module ${id} not found`);
410
+ throw new Error(`Module "${id}" not found.`);
384
411
  } catch (requireError) {
385
412
  if (typeof self.__original_webpack_require__ !== "function") {
386
- throw new Error(
387
- `Module ${id} not found in remote component bundle ${bundle}`,
413
+ throw new RemoteComponentsError(
414
+ `Module "${id}" not found in remote component bundle "${bundle}".`,
388
415
  {
389
416
  cause: requireError instanceof Error ? requireError : void 0
390
417
  }
@@ -393,8 +420,8 @@ function createModuleRequire(runtime) {
393
420
  try {
394
421
  return self.__original_webpack_require__(id);
395
422
  } catch (originalError) {
396
- throw new Error(
397
- `Module ${id} not found in remote component bundle ${bundle}`,
423
+ throw new RemoteComponentsError(
424
+ `Module "${id}" not found in remote component bundle "${bundle}".`,
398
425
  { cause: originalError instanceof Error ? originalError : void 0 }
399
426
  );
400
427
  }
@@ -685,7 +712,9 @@ function handleTurbopackModule(bundle, moduleId, id) {
685
712
  return self.__webpack_chunk_load__?.(bundleUrl, bundle);
686
713
  }
687
714
  }
688
- throw new Error(`Failed to load chunk ${url} for module ${id}`);
715
+ throw new Error(
716
+ `Failed to load Turbopack chunk "${url}" for module "${id}". Check the URL is correct.`
717
+ );
689
718
  },
690
719
  // global
691
720
  g: self.__remote_components_turbopack_global__[bundle],
@@ -703,10 +732,111 @@ function handleTurbopackModule(bundle, moduleId, id) {
703
732
  var init_webpack_adapter = __esm({
704
733
  "src/shared/client/webpack-adapter.ts"() {
705
734
  "use strict";
735
+ init_error();
706
736
  init_const();
707
737
  }
708
738
  });
709
739
 
740
+ // src/shared/client/static-loader.ts
741
+ async function loadStaticRemoteComponent(scripts, url) {
742
+ const self = globalThis;
743
+ if (self.__remote_script_entrypoint_mount__?.[url.href]) {
744
+ self.__remote_script_entrypoint_mount__[url.href] = /* @__PURE__ */ new Set();
745
+ }
746
+ if (self.__remote_script_entrypoint_unmount__?.[url.href]) {
747
+ self.__remote_script_entrypoint_unmount__[url.href] = /* @__PURE__ */ new Set();
748
+ }
749
+ const mountUnmountSets = await Promise.all(
750
+ scripts.map(async (script) => {
751
+ try {
752
+ let src = typeof script.getAttribute === "function" ? script.getAttribute("src") ?? script.src : script.src;
753
+ if (!src && script.textContent) {
754
+ const blob = new Blob(
755
+ [
756
+ script.textContent.replace(
757
+ /import\.meta\.url/g,
758
+ JSON.stringify(url)
759
+ )
760
+ ],
761
+ {
762
+ type: "text/javascript"
763
+ }
764
+ );
765
+ src = URL.createObjectURL(blob);
766
+ }
767
+ const mod = await import(
768
+ /* @vite-ignore */
769
+ /* webpackIgnore: true */
770
+ new URL(src, url).href
771
+ );
772
+ if (src.startsWith("blob:")) {
773
+ URL.revokeObjectURL(src);
774
+ }
775
+ if (typeof mod.mount === "function" || typeof mod.default?.mount === "function") {
776
+ if (!self.__remote_script_entrypoint_mount__) {
777
+ self.__remote_script_entrypoint_mount__ = {};
778
+ }
779
+ if (!self.__remote_script_entrypoint_mount__[url.href]) {
780
+ self.__remote_script_entrypoint_mount__[url.href] = /* @__PURE__ */ new Set();
781
+ }
782
+ self.__remote_script_entrypoint_mount__[url.href]?.add(
783
+ mod.mount || mod.default?.mount || (() => {
784
+ })
785
+ );
786
+ }
787
+ if (typeof mod.unmount === "function" || typeof mod.default?.unmount === "function") {
788
+ if (!self.__remote_script_entrypoint_unmount__) {
789
+ self.__remote_script_entrypoint_unmount__ = {};
790
+ }
791
+ if (!self.__remote_script_entrypoint_unmount__[url.href]) {
792
+ self.__remote_script_entrypoint_unmount__[url.href] = /* @__PURE__ */ new Set();
793
+ }
794
+ self.__remote_script_entrypoint_unmount__[url.href]?.add(
795
+ mod.unmount || mod.default?.unmount || (() => {
796
+ })
797
+ );
798
+ }
799
+ return {
800
+ mount: mod.mount || mod.default?.mount,
801
+ unmount: mod.unmount || mod.default?.unmount
802
+ };
803
+ } catch (e) {
804
+ console.error(
805
+ new RemoteComponentsError(
806
+ `Error loading remote component script from "${script.src || url.href}".`,
807
+ { cause: e }
808
+ )
809
+ );
810
+ return {
811
+ mount: void 0,
812
+ unmount: void 0
813
+ };
814
+ }
815
+ })
816
+ );
817
+ return mountUnmountSets.reduce(
818
+ (acc, { mount, unmount }) => {
819
+ if (typeof mount === "function") {
820
+ acc.mount.add(mount);
821
+ }
822
+ if (typeof unmount === "function") {
823
+ acc.unmount.add(unmount);
824
+ }
825
+ return acc;
826
+ },
827
+ {
828
+ mount: /* @__PURE__ */ new Set(),
829
+ unmount: /* @__PURE__ */ new Set()
830
+ }
831
+ );
832
+ }
833
+ var init_static_loader = __esm({
834
+ "src/shared/client/static-loader.ts"() {
835
+ "use strict";
836
+ init_error();
837
+ }
838
+ });
839
+
710
840
  // src/shared/client/polyfill.tsx
711
841
  function applyBundleUrlToSrc(bundle, src) {
712
842
  const self = globalThis;
@@ -924,10 +1054,14 @@ async function webpackRuntime(bundle, shared, remoteShared) {
924
1054
  const remoteBundle = match?.groups?.bundle;
925
1055
  const id = match?.groups?.id;
926
1056
  if (!(id && remoteBundle)) {
927
- throw new Error(`Module not found: "${remoteId}"`);
1057
+ throw new RemoteComponentsError(
1058
+ `Remote Component module "${remoteId}" not found. Did you forget to wrap the Next.js config with \`withRemoteComponents\` on both host and remote?`
1059
+ );
928
1060
  }
929
1061
  if (typeof self.__remote_webpack_require__?.[remoteBundle] !== "function") {
930
- throw new Error(`Remote component loading error "${remoteBundle}"`);
1062
+ throw new RemoteComponentsError(
1063
+ `Remote Components are not available in "${remoteBundle}". Did you forget to wrap the Next.js config with \`withRemoteComponents\` on both host and remote?`
1064
+ );
931
1065
  }
932
1066
  return self.__remote_webpack_require__[remoteBundle](id);
933
1067
  };
@@ -949,8 +1083,8 @@ async function webpackRuntime(bundle, shared, remoteShared) {
949
1083
  };
950
1084
  newScript.onerror = () => {
951
1085
  reject(
952
- new Error(
953
- `Failed to load script ${script.src} for remote component`
1086
+ new RemoteComponentsError(
1087
+ `Failed to load <script src="${script.src}"> for Remote Component. Check the URL is correct.`
954
1088
  )
955
1089
  );
956
1090
  newScript.remove();
@@ -1010,6 +1144,7 @@ async function webpackRuntime(bundle, shared, remoteShared) {
1010
1144
  var init_webpack = __esm({
1011
1145
  "src/html/host/runtime/webpack.ts"() {
1012
1146
  "use strict";
1147
+ init_error();
1013
1148
  init_shared_modules();
1014
1149
  init_next_client_pages_loader();
1015
1150
  init_polyfill();
@@ -1070,6 +1205,31 @@ var init_turbopack = __esm({
1070
1205
  }
1071
1206
  });
1072
1207
 
1208
+ // src/html/host/runtime/script.ts
1209
+ var script_exports = {};
1210
+ __export(script_exports, {
1211
+ scriptRuntime: () => scriptRuntime
1212
+ });
1213
+ function scriptRuntime() {
1214
+ const self = globalThis;
1215
+ return {
1216
+ self,
1217
+ createFromReadableStream: () => Promise.resolve(null),
1218
+ applySharedModules: () => Promise.resolve(),
1219
+ nextClientPagesLoader: () => ({
1220
+ Component: null,
1221
+ App: null
1222
+ }),
1223
+ preloadScripts: loadStaticRemoteComponent
1224
+ };
1225
+ }
1226
+ var init_script = __esm({
1227
+ "src/html/host/runtime/script.ts"() {
1228
+ "use strict";
1229
+ init_static_loader();
1230
+ }
1231
+ });
1232
+
1073
1233
  // src/html/host/index.tsx
1074
1234
  var host_exports = {};
1075
1235
  __export(host_exports, {
@@ -1087,8 +1247,12 @@ var JSXDevRuntime = __toESM(require("react/jsx-dev-runtime"), 1);
1087
1247
  var JSXRuntime = __toESM(require("react/jsx-runtime"), 1);
1088
1248
  init_shared_modules();
1089
1249
  init_next_client_pages_loader();
1250
+ init_error();
1090
1251
  init_webpack_adapter();
1091
1252
 
1253
+ // src/shared/client/script-loader.ts
1254
+ init_error();
1255
+
1092
1256
  // src/shared/client/rsc.ts
1093
1257
  var import_web_streams_polyfill = require("web-streams-polyfill");
1094
1258
  function fixPayload(payload) {
@@ -1156,8 +1320,10 @@ function createRSCStream(rscName, data) {
1156
1320
  }
1157
1321
 
1158
1322
  // src/shared/client/remote-component.ts
1323
+ init_static_loader();
1159
1324
  init_webpack_adapter();
1160
1325
  init_const();
1326
+ init_error();
1161
1327
 
1162
1328
  // src/html/host/index.tsx
1163
1329
  init_utils();
@@ -1237,7 +1403,11 @@ function applyOriginToNodes(doc, url) {
1237
1403
  }
1238
1404
  }
1239
1405
 
1406
+ // src/html/host/index.tsx
1407
+ init_error();
1408
+
1240
1409
  // src/html/host/runtime/index.ts
1410
+ init_error();
1241
1411
  async function getRuntime(type, url, bundle, shared, remoteShared) {
1242
1412
  if (typeof globalThis.process === "undefined") {
1243
1413
  globalThis.process = {
@@ -1250,8 +1420,13 @@ async function getRuntime(type, url, bundle, shared, remoteShared) {
1250
1420
  } else if (type === "turbopack") {
1251
1421
  const { turbopackRuntime: turbopackRuntime2 } = await Promise.resolve().then(() => (init_turbopack(), turbopack_exports));
1252
1422
  return turbopackRuntime2(url, bundle, shared, remoteShared);
1423
+ } else if (type === "script") {
1424
+ const { scriptRuntime: scriptRuntime2 } = await Promise.resolve().then(() => (init_script(), script_exports));
1425
+ return scriptRuntime2();
1253
1426
  }
1254
- throw new Error(`Runtime ${type} is not supported`);
1427
+ throw new RemoteComponentsError(
1428
+ `Remote Components runtime "${type}" is not supported. Supported runtimes are "webpack", "turbopack", and "script".`
1429
+ );
1255
1430
  }
1256
1431
 
1257
1432
  // src/html/host/index.tsx
@@ -1263,6 +1438,7 @@ if (typeof HTMLElement !== "undefined") {
1263
1438
  this.__next = null;
1264
1439
  this.fouc = null;
1265
1440
  this.isLoading = false;
1441
+ this.prevIsRemoteComponent = false;
1266
1442
  this.root = null;
1267
1443
  }
1268
1444
  static get observedAttributes() {
@@ -1276,9 +1452,6 @@ if (typeof HTMLElement !== "undefined") {
1276
1452
  if (this.getAttribute("src")) {
1277
1453
  this.load().catch((e) => {
1278
1454
  console.error(e);
1279
- throw new Error(
1280
- `Failed to load remote component: ${this.bundle ?? this.name ?? this.getAttribute("src")}`
1281
- );
1282
1455
  });
1283
1456
  }
1284
1457
  } else if (name === "mode" && oldValue !== newValue && this.root) {
@@ -1290,7 +1463,7 @@ if (typeof HTMLElement !== "undefined") {
1290
1463
  });
1291
1464
  this.root = newRoot;
1292
1465
  this.load().catch((e) => {
1293
- throw new Error(`Failed to load remote component: ${e}`);
1466
+ console.error(e);
1294
1467
  });
1295
1468
  }
1296
1469
  }
@@ -1324,14 +1497,14 @@ if (typeof HTMLElement !== "undefined") {
1324
1497
  }
1325
1498
  if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
1326
1499
  this.load().catch((e) => {
1327
- throw new Error(`Failed to load remote component: ${e}`);
1500
+ console.error(e);
1328
1501
  });
1329
1502
  }
1330
1503
  this.isLoading = true;
1331
1504
  const src = this.getAttribute("src");
1332
1505
  const remoteComponentChild = this.querySelector("div#__REMOTE_COMPONENT__") || this.querySelector("div[data-bundle][data-route]");
1333
1506
  if (!src && !remoteComponentChild) {
1334
- throw new Error("src attribute is required");
1507
+ throw new RemoteComponentsError('"src" attribute is required');
1335
1508
  }
1336
1509
  let url = null;
1337
1510
  let html = this.innerHTML;
@@ -1349,26 +1522,57 @@ if (typeof HTMLElement !== "undefined") {
1349
1522
  };
1350
1523
  const res = await fetch(url, fetchInit);
1351
1524
  if (!res.ok) {
1352
- throw new Error(
1353
- `Failed to fetch remote component "${this.name}": ${res.status}`
1354
- );
1525
+ let error = failedToFetchRemoteComponentError(url.href, {
1526
+ cause: new Error(`${res.status} ${res.statusText}`)
1527
+ });
1528
+ try {
1529
+ const body = await res.text();
1530
+ const parser2 = new DOMParser();
1531
+ const doc2 = parser2.parseFromString(body, "text/html");
1532
+ const errorTemplate = doc2.querySelector(
1533
+ "template[data-next-error-message]"
1534
+ );
1535
+ const errorMessage = errorTemplate?.getAttribute(
1536
+ "data-next-error-message"
1537
+ );
1538
+ const errorStack = errorTemplate?.getAttribute(
1539
+ "data-next-error-stack"
1540
+ );
1541
+ if (errorMessage) {
1542
+ error = new RemoteComponentsError(errorMessage);
1543
+ if (errorStack) {
1544
+ error.stack = errorStack;
1545
+ }
1546
+ }
1547
+ } catch {
1548
+ }
1549
+ throw error;
1355
1550
  }
1356
1551
  html = await res.text();
1357
1552
  }
1358
1553
  const parser = new DOMParser();
1359
1554
  const doc = parser.parseFromString(html, "text/html");
1555
+ if (doc.querySelectorAll("div[data-bundle][data-route]").length > 1 && !doc.querySelector(
1556
+ `div[data-bundle][data-route][id^="${this.name}"]`
1557
+ ) || doc.querySelectorAll("remote-component").length > 1 && !doc.querySelector(`remote-component[name="${this.name}"]`)) {
1558
+ throw multipleRemoteComponentsError(
1559
+ url?.href ?? (this.getAttribute("src") || "unknown")
1560
+ );
1561
+ }
1360
1562
  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
1361
1563
  doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
1362
- doc.querySelector("div#__next");
1564
+ doc.querySelector("div#__next") ?? // fallback to a <remote-component> element
1565
+ doc.querySelector(`remote-component[name="${this.name}"]:not([src])`) ?? doc.querySelector("remote-component:not([src])");
1363
1566
  const nextData = JSON.parse(
1364
1567
  (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
1365
1568
  );
1569
+ const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
1366
1570
  if (nextData && nextData.buildId === "development" && !this.reactRoot) {
1367
1571
  this.fouc = document.createElement("style");
1368
1572
  this.fouc.textContent = `:host { display: none; }`;
1369
1573
  this.root.appendChild(this.fouc);
1370
1574
  }
1371
- this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : this.name);
1575
+ this.name = component?.getAttribute("id")?.replace(/_ssr$/, "") || isRemoteComponent && component.getAttribute("name") || (nextData ? "__next" : this.name);
1372
1576
  const rsc = doc.querySelector(`#${this.name}_rsc`);
1373
1577
  this.bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || this.bundle;
1374
1578
  if (url) {
@@ -1381,12 +1585,13 @@ if (typeof HTMLElement !== "undefined") {
1381
1585
  const metadata = document.createElement("script");
1382
1586
  metadata.type = "application/json";
1383
1587
  metadata.setAttribute("data-remote-component", "");
1384
- metadata.textContent = JSON.stringify({
1588
+ const metadataObj = {
1385
1589
  name: this.name,
1386
1590
  bundle: this.bundle,
1387
- route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
1388
- runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
1389
- });
1591
+ route: component?.getAttribute("data-route") ?? nextData?.page ?? url?.pathname ?? "/",
1592
+ runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime ?? "script"
1593
+ };
1594
+ metadata.textContent = JSON.stringify(metadataObj);
1390
1595
  if (this.previousElementSibling?.getAttribute("data-remote-component") !== null) {
1391
1596
  this.previousElementSibling?.remove();
1392
1597
  }
@@ -1396,9 +1601,43 @@ if (typeof HTMLElement !== "undefined") {
1396
1601
  );
1397
1602
  const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
1398
1603
  remoteSharedEl?.parentElement?.removeChild(remoteSharedEl);
1399
- if (!component || !(rsc || nextData)) {
1400
- throw new Error(`Failed to find component with id "${this.name}"`);
1604
+ if ("__remote_components_missing_shared__" in remoteShared) {
1605
+ throw new RemoteComponentsError(
1606
+ remoteShared.__remote_components_missing_shared__
1607
+ );
1608
+ }
1609
+ if (!component || !(rsc || nextData || isRemoteComponent)) {
1610
+ throw new RemoteComponentsError(
1611
+ `Remote Component not found on ${src}.${this.name !== "__vercel_remote_component" ? ` The name for the <RemoteComponent> is "${this.name}". Check <RemoteComponent> usage.` : ""} Did you forget to wrap the content in <RemoteComponent>?`
1612
+ );
1613
+ }
1614
+ if (this.prevIsRemoteComponent) {
1615
+ if (this.prevUrl) {
1616
+ const prevUrl = this.prevUrl;
1617
+ const self2 = globalThis;
1618
+ if (self2.__remote_script_entrypoint_unmount__?.[prevUrl.href]) {
1619
+ await Promise.all(
1620
+ Array.from(
1621
+ self2.__remote_script_entrypoint_unmount__[prevUrl.href] ?? []
1622
+ ).map(async (unmount) => {
1623
+ try {
1624
+ await unmount(this.root);
1625
+ } catch (e) {
1626
+ console.error(
1627
+ new RemoteComponentsError(
1628
+ `Error while calling unmount() for Remote Component from ${prevUrl.href}.`,
1629
+ { cause: e }
1630
+ )
1631
+ );
1632
+ }
1633
+ })
1634
+ );
1635
+ }
1636
+ }
1637
+ this.root.innerHTML = "";
1401
1638
  }
1639
+ this.prevUrl = url ?? new URL(location.href);
1640
+ this.prevIsRemoteComponent = isRemoteComponent;
1402
1641
  const removable = Array.from(this.childNodes);
1403
1642
  const links = doc.querySelectorAll("link[href]");
1404
1643
  const remoteComponentSrc = this.getAttribute("src");
@@ -1415,8 +1654,8 @@ if (typeof HTMLElement !== "undefined") {
1415
1654
  };
1416
1655
  newLink.onerror = () => {
1417
1656
  reject(
1418
- new Error(
1419
- `Failed to load link ${link.href} for remote component`
1657
+ new RemoteComponentsError(
1658
+ `Failed to load <link href="${link.href}"> for Remote Component. Check the URL is correct.`
1420
1659
  )
1421
1660
  );
1422
1661
  };
@@ -1464,7 +1703,35 @@ if (typeof HTMLElement !== "undefined") {
1464
1703
  applyOriginToNodes(doc, url ?? new URL(location.href));
1465
1704
  if (!this.reactRoot) {
1466
1705
  Array.from(component.children).forEach((el) => {
1467
- this.root?.appendChild(el);
1706
+ if (!isRemoteComponent && el.tagName.toLowerCase() === "script") {
1707
+ const newScript = document.createElement("script");
1708
+ for (const attr of el.attributes) {
1709
+ if (attr.name === "src") {
1710
+ newScript.setAttribute(
1711
+ attr.name,
1712
+ new URL(attr.value, url ?? location.origin).href
1713
+ );
1714
+ } else {
1715
+ newScript.setAttribute(attr.name, attr.value);
1716
+ }
1717
+ }
1718
+ newScript.textContent = el.textContent;
1719
+ if (remoteComponentSrc) {
1720
+ newScript.setAttribute(
1721
+ "data-remote-component-src",
1722
+ remoteComponentSrc
1723
+ );
1724
+ }
1725
+ this.root?.appendChild(newScript);
1726
+ } else {
1727
+ const newEl = el.cloneNode(true);
1728
+ for (const attr of el.attributes) {
1729
+ if (attr.name.startsWith("on")) {
1730
+ newEl.setAttribute(attr.name, attr.value);
1731
+ }
1732
+ }
1733
+ this.root?.appendChild(newEl);
1734
+ }
1468
1735
  });
1469
1736
  }
1470
1737
  for (const el of removable) {
@@ -1503,7 +1770,7 @@ if (typeof HTMLElement !== "undefined") {
1503
1770
  nextClientPagesLoader: nextClientPagesLoader2,
1504
1771
  preloadScripts
1505
1772
  } = await getRuntime(
1506
- component.getAttribute("data-runtime") ?? "webpack",
1773
+ metadataObj.runtime,
1507
1774
  url ?? new URL(location.href),
1508
1775
  this.bundle,
1509
1776
  {
@@ -1515,8 +1782,8 @@ if (typeof HTMLElement !== "undefined") {
1515
1782
  },
1516
1783
  remoteShared
1517
1784
  );
1518
- const scripts = doc.querySelectorAll(
1519
- "script[src],script[data-src]"
1785
+ const scripts = isRemoteComponent ? component.querySelectorAll("script") : doc.querySelectorAll(
1786
+ "script[src],script[data-src],script[data-remote-component-entrypoint]"
1520
1787
  );
1521
1788
  if (!url) {
1522
1789
  url = new URL(
@@ -1530,6 +1797,13 @@ if (typeof HTMLElement !== "undefined") {
1530
1797
  this.bundle ?? "default",
1531
1798
  this.name ?? "__vercel_remote_component"
1532
1799
  );
1800
+ if (isRemoteComponent) {
1801
+ Array.from(component.children).forEach((child) => {
1802
+ if (child.tagName === "SCRIPT") {
1803
+ child.remove();
1804
+ }
1805
+ });
1806
+ }
1533
1807
  const doCleanup = () => {
1534
1808
  if (this.root && remoteComponentSrc) {
1535
1809
  const selector = `[data-remote-component-src]:not([data-remote-component-src="${remoteComponentSrc}"])`;
@@ -1651,6 +1925,23 @@ if (typeof HTMLElement !== "undefined") {
1651
1925
  if (this.fouc) {
1652
1926
  this.root.removeChild(this.fouc);
1653
1927
  }
1928
+ } else if (self.__remote_script_entrypoint_mount__?.[url.href]) {
1929
+ await Promise.all(
1930
+ Array.from(
1931
+ self.__remote_script_entrypoint_mount__[url.href] ?? []
1932
+ ).map(async (mount) => {
1933
+ try {
1934
+ await mount(this.root);
1935
+ } catch (e) {
1936
+ console.error(
1937
+ new RemoteComponentsError(
1938
+ `Error while calling mount() for Remote Component from ${url.href}.`,
1939
+ { cause: e }
1940
+ )
1941
+ );
1942
+ }
1943
+ })
1944
+ );
1654
1945
  }
1655
1946
  this.isLoading = false;
1656
1947
  }