remote-components 0.0.33 → 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 (50) hide show
  1. package/dist/{component-loader-28ad0083.d.ts → component-loader-8951c052.d.ts} +6 -4
  2. package/dist/html/host.cjs +227 -13
  3. package/dist/html/host.cjs.map +1 -1
  4. package/dist/html/host.js +227 -13
  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 +56 -4
  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 +58 -5
  15. package/dist/internal/next/host/app-router-client.js.map +1 -1
  16. package/dist/internal/shared/client/remote-component.cjs +99 -0
  17. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  18. package/dist/internal/shared/client/remote-component.d.ts +11 -4
  19. package/dist/internal/shared/client/remote-component.js +97 -0
  20. package/dist/internal/shared/client/remote-component.js.map +1 -1
  21. package/dist/internal/shared/error.cjs.map +1 -1
  22. package/dist/internal/shared/error.d.ts +1 -1
  23. package/dist/internal/shared/error.js.map +1 -1
  24. package/dist/internal/shared/ssr/dom-flight.cjs +17 -5
  25. package/dist/internal/shared/ssr/dom-flight.cjs.map +1 -1
  26. package/dist/internal/shared/ssr/dom-flight.d.ts +1 -1
  27. package/dist/internal/shared/ssr/dom-flight.js +17 -5
  28. package/dist/internal/shared/ssr/dom-flight.js.map +1 -1
  29. package/dist/internal/shared/ssr/fetch-remote-component.cjs +7 -3
  30. package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
  31. package/dist/internal/shared/ssr/fetch-remote-component.d.ts +2 -1
  32. package/dist/internal/shared/ssr/fetch-remote-component.js +7 -3
  33. package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
  34. package/dist/next/host/app-router-server.cjs +1 -0
  35. package/dist/next/host/app-router-server.cjs.map +1 -1
  36. package/dist/next/host/app-router-server.js +1 -0
  37. package/dist/next/host/app-router-server.js.map +1 -1
  38. package/dist/next/host/client/index.cjs +292 -103
  39. package/dist/next/host/client/index.cjs.map +1 -1
  40. package/dist/next/host/client/index.d.ts +1 -1
  41. package/dist/next/host/client/index.js +289 -102
  42. package/dist/next/host/client/index.js.map +1 -1
  43. package/dist/react/index.cjs +197 -103
  44. package/dist/react/index.cjs.map +1 -1
  45. package/dist/react/index.d.ts +2 -2
  46. package/dist/react/index.js +196 -102
  47. package/dist/react/index.js.map +1 -1
  48. package/dist/{types-7c207455.d.ts → types-4e7dea94.d.ts} +2 -1
  49. package/dist/{types-e4a3fa37.d.ts → types-cbf6c34f.d.ts} +2 -2
  50. package/package.json +8 -1
@@ -3,9 +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' | 'unknown';
8
+ type: 'nextjs' | 'remote-component' | 'unknown';
9
9
  }
10
10
 
11
11
  interface RemoteComponentProps {
@@ -29,6 +29,7 @@ interface RemoteComponentProps {
29
29
  isolate?: boolean;
30
30
  mode?: 'open' | 'closed';
31
31
  reset?: boolean;
32
+ type?: RemoteComponentMetadata['type'];
32
33
  children: react.ReactNode;
33
34
  }
34
35
  interface GlobalScope {
@@ -47,7 +48,7 @@ interface GlobalScope {
47
48
  m?: Record<string | number, (module: {
48
49
  exports: unknown;
49
50
  }) => void>;
50
- type?: 'turbopack' | 'webpack';
51
+ type?: 'turbopack' | 'webpack' | 'script';
51
52
  }>;
52
53
  __webpack_require_type__?: RemoteComponentMetadata['runtime'];
53
54
  __remote_shared_modules__?: Record<string, Record<string, unknown>>;
@@ -61,6 +62,7 @@ interface LoaderResult {
61
62
  component: react.ReactNode;
62
63
  error?: Error;
63
64
  }
65
+ type MountOrUnmountFunction = (el?: ShadowRoot | DocumentFragment | HTMLElement | HTMLCollection | null) => Promise<void> | void;
64
66
 
65
67
  type LoadRemoteComponentProps = Pick<RemoteComponentProps, 'name' | 'bundle' | 'route' | 'runtime' | 'data' | 'nextData' | 'scripts'> & {
66
68
  url: URL;
@@ -74,4 +76,4 @@ type LoadRemoteComponentProps = Pick<RemoteComponentProps, 'name' | 'bundle' | '
74
76
  */
75
77
  declare function loadRemoteComponent({ url, name, rscName, bundle, route, runtime, data, nextData, scripts, shared, remoteShared, container, }: LoadRemoteComponentProps): Promise<LoaderResult>;
76
78
 
77
- 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 };
@@ -737,6 +737,106 @@ var init_webpack_adapter = __esm({
737
737
  }
738
738
  });
739
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
+
740
840
  // src/shared/client/polyfill.tsx
741
841
  function applyBundleUrlToSrc(bundle, src) {
742
842
  const self = globalThis;
@@ -1105,6 +1205,31 @@ var init_turbopack = __esm({
1105
1205
  }
1106
1206
  });
1107
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
+
1108
1233
  // src/html/host/index.tsx
1109
1234
  var host_exports = {};
1110
1235
  __export(host_exports, {
@@ -1195,6 +1320,7 @@ function createRSCStream(rscName, data) {
1195
1320
  }
1196
1321
 
1197
1322
  // src/shared/client/remote-component.ts
1323
+ init_static_loader();
1198
1324
  init_webpack_adapter();
1199
1325
  init_const();
1200
1326
  init_error();
@@ -1294,9 +1420,12 @@ async function getRuntime(type, url, bundle, shared, remoteShared) {
1294
1420
  } else if (type === "turbopack") {
1295
1421
  const { turbopackRuntime: turbopackRuntime2 } = await Promise.resolve().then(() => (init_turbopack(), turbopack_exports));
1296
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();
1297
1426
  }
1298
1427
  throw new RemoteComponentsError(
1299
- `Remote Components runtime "${type}" is not supported. Supported runtimes are "webpack" and "turbopack".`
1428
+ `Remote Components runtime "${type}" is not supported. Supported runtimes are "webpack", "turbopack", and "script".`
1300
1429
  );
1301
1430
  }
1302
1431
 
@@ -1309,6 +1438,7 @@ if (typeof HTMLElement !== "undefined") {
1309
1438
  this.__next = null;
1310
1439
  this.fouc = null;
1311
1440
  this.isLoading = false;
1441
+ this.prevIsRemoteComponent = false;
1312
1442
  this.root = null;
1313
1443
  }
1314
1444
  static get observedAttributes() {
@@ -1422,23 +1552,27 @@ if (typeof HTMLElement !== "undefined") {
1422
1552
  }
1423
1553
  const parser = new DOMParser();
1424
1554
  const doc = parser.parseFromString(html, "text/html");
1425
- if (doc.querySelectorAll("div[data-bundle][data-route]").length > 1 && !doc.querySelector(`div[data-bundle][data-route][id^="${this.name}"]`)) {
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}"]`)) {
1426
1558
  throw multipleRemoteComponentsError(
1427
1559
  url?.href ?? (this.getAttribute("src") || "unknown")
1428
1560
  );
1429
1561
  }
1430
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
1431
1563
  doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
1432
- 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])");
1433
1566
  const nextData = JSON.parse(
1434
1567
  (doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
1435
1568
  );
1569
+ const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
1436
1570
  if (nextData && nextData.buildId === "development" && !this.reactRoot) {
1437
1571
  this.fouc = document.createElement("style");
1438
1572
  this.fouc.textContent = `:host { display: none; }`;
1439
1573
  this.root.appendChild(this.fouc);
1440
1574
  }
1441
- 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);
1442
1576
  const rsc = doc.querySelector(`#${this.name}_rsc`);
1443
1577
  this.bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || this.bundle;
1444
1578
  if (url) {
@@ -1451,12 +1585,13 @@ if (typeof HTMLElement !== "undefined") {
1451
1585
  const metadata = document.createElement("script");
1452
1586
  metadata.type = "application/json";
1453
1587
  metadata.setAttribute("data-remote-component", "");
1454
- metadata.textContent = JSON.stringify({
1588
+ const metadataObj = {
1455
1589
  name: this.name,
1456
1590
  bundle: this.bundle,
1457
- route: component?.getAttribute("data-route") ?? nextData?.page ?? "/",
1458
- runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime
1459
- });
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);
1460
1595
  if (this.previousElementSibling?.getAttribute("data-remote-component") !== null) {
1461
1596
  this.previousElementSibling?.remove();
1462
1597
  }
@@ -1471,11 +1606,38 @@ if (typeof HTMLElement !== "undefined") {
1471
1606
  remoteShared.__remote_components_missing_shared__
1472
1607
  );
1473
1608
  }
1474
- if (!component || !(rsc || nextData)) {
1609
+ if (!component || !(rsc || nextData || isRemoteComponent)) {
1475
1610
  throw new RemoteComponentsError(
1476
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>?`
1477
1612
  );
1478
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 = "";
1638
+ }
1639
+ this.prevUrl = url ?? new URL(location.href);
1640
+ this.prevIsRemoteComponent = isRemoteComponent;
1479
1641
  const removable = Array.from(this.childNodes);
1480
1642
  const links = doc.querySelectorAll("link[href]");
1481
1643
  const remoteComponentSrc = this.getAttribute("src");
@@ -1541,7 +1703,35 @@ if (typeof HTMLElement !== "undefined") {
1541
1703
  applyOriginToNodes(doc, url ?? new URL(location.href));
1542
1704
  if (!this.reactRoot) {
1543
1705
  Array.from(component.children).forEach((el) => {
1544
- 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
+ }
1545
1735
  });
1546
1736
  }
1547
1737
  for (const el of removable) {
@@ -1580,7 +1770,7 @@ if (typeof HTMLElement !== "undefined") {
1580
1770
  nextClientPagesLoader: nextClientPagesLoader2,
1581
1771
  preloadScripts
1582
1772
  } = await getRuntime(
1583
- component.getAttribute("data-runtime") ?? "webpack",
1773
+ metadataObj.runtime,
1584
1774
  url ?? new URL(location.href),
1585
1775
  this.bundle,
1586
1776
  {
@@ -1592,8 +1782,8 @@ if (typeof HTMLElement !== "undefined") {
1592
1782
  },
1593
1783
  remoteShared
1594
1784
  );
1595
- const scripts = doc.querySelectorAll(
1596
- "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]"
1597
1787
  );
1598
1788
  if (!url) {
1599
1789
  url = new URL(
@@ -1607,6 +1797,13 @@ if (typeof HTMLElement !== "undefined") {
1607
1797
  this.bundle ?? "default",
1608
1798
  this.name ?? "__vercel_remote_component"
1609
1799
  );
1800
+ if (isRemoteComponent) {
1801
+ Array.from(component.children).forEach((child) => {
1802
+ if (child.tagName === "SCRIPT") {
1803
+ child.remove();
1804
+ }
1805
+ });
1806
+ }
1610
1807
  const doCleanup = () => {
1611
1808
  if (this.root && remoteComponentSrc) {
1612
1809
  const selector = `[data-remote-component-src]:not([data-remote-component-src="${remoteComponentSrc}"])`;
@@ -1728,6 +1925,23 @@ if (typeof HTMLElement !== "undefined") {
1728
1925
  if (this.fouc) {
1729
1926
  this.root.removeChild(this.fouc);
1730
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
+ );
1731
1945
  }
1732
1946
  this.isLoading = false;
1733
1947
  }