remote-components 0.0.46 → 0.0.48

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 (98) hide show
  1. package/dist/{component-loader-26b1f55e.d.ts → component-loader-1838f572.d.ts} +62 -8
  2. package/dist/html/host.cjs +214 -76
  3. package/dist/html/host.cjs.map +1 -1
  4. package/dist/html/host.js +214 -76
  5. package/dist/html/host.js.map +1 -1
  6. package/dist/html/remote.cjs.map +1 -1
  7. package/dist/html/remote.js.map +1 -1
  8. package/dist/internal/next/host/app-router-client.cjs +6 -6
  9. package/dist/internal/next/host/app-router-client.cjs.map +1 -1
  10. package/dist/internal/next/host/app-router-client.d.ts +1 -1
  11. package/dist/internal/next/host/app-router-client.js +1 -1
  12. package/dist/internal/next/host/app-router-client.js.map +1 -1
  13. package/dist/internal/next/host/app-router-compat.cjs +5 -5
  14. package/dist/internal/next/host/app-router-compat.cjs.map +1 -1
  15. package/dist/internal/next/host/app-router-compat.js +1 -1
  16. package/dist/internal/next/host/app-router-compat.js.map +1 -1
  17. package/dist/internal/shared/client/polyfill.cjs +2 -2
  18. package/dist/internal/shared/client/polyfill.cjs.map +1 -1
  19. package/dist/internal/shared/client/polyfill.js +1 -1
  20. package/dist/internal/shared/client/polyfill.js.map +1 -1
  21. package/dist/internal/shared/client/remote-component.cjs +48 -1
  22. package/dist/internal/shared/client/remote-component.cjs.map +1 -1
  23. package/dist/internal/shared/client/remote-component.d.ts +2 -2
  24. package/dist/internal/shared/client/remote-component.js +48 -1
  25. package/dist/internal/shared/client/remote-component.js.map +1 -1
  26. package/dist/internal/shared/ssr/dom-flight.d.ts +1 -1
  27. package/dist/internal/shared/ssr/fetch-remote-component.cjs +1 -6
  28. package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
  29. package/dist/internal/shared/ssr/fetch-remote-component.d.ts +1 -1
  30. package/dist/internal/shared/ssr/fetch-remote-component.js +1 -6
  31. package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
  32. package/dist/internal/shared/ssr/fetch-with-hooks.cjs +22 -5
  33. package/dist/internal/shared/ssr/fetch-with-hooks.cjs.map +1 -1
  34. package/dist/internal/shared/ssr/fetch-with-hooks.d.ts +30 -14
  35. package/dist/internal/shared/ssr/fetch-with-hooks.js +22 -5
  36. package/dist/internal/shared/ssr/fetch-with-hooks.js.map +1 -1
  37. package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.cjs +62 -0
  38. package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.cjs.map +1 -0
  39. package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.d.ts +14 -0
  40. package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.js +37 -0
  41. package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.js.map +1 -0
  42. package/dist/internal/shared/utils/abort.cjs +38 -0
  43. package/dist/internal/shared/utils/abort.cjs.map +1 -0
  44. package/dist/internal/shared/utils/abort.d.ts +7 -0
  45. package/dist/internal/shared/utils/abort.js +14 -0
  46. package/dist/internal/shared/utils/abort.js.map +1 -0
  47. package/dist/internal/shared/{logger.cjs → utils/logger.cjs} +5 -0
  48. package/dist/internal/shared/utils/logger.cjs.map +1 -0
  49. package/dist/internal/shared/{logger.d.ts → utils/logger.d.ts} +3 -2
  50. package/dist/internal/shared/{logger.js → utils/logger.js} +4 -0
  51. package/dist/internal/shared/utils/logger.js.map +1 -0
  52. package/dist/internal/shared/utils.cjs +2 -9
  53. package/dist/internal/shared/utils.cjs.map +1 -1
  54. package/dist/internal/shared/utils.d.ts +0 -2
  55. package/dist/internal/shared/utils.js +1 -5
  56. package/dist/internal/shared/utils.js.map +1 -1
  57. package/dist/next/config.cjs +4 -2
  58. package/dist/next/config.cjs.map +1 -1
  59. package/dist/next/config.js +4 -2
  60. package/dist/next/config.js.map +1 -1
  61. package/dist/next/host/app-router-server.d.ts +1 -1
  62. package/dist/next/host/client/index.cjs +91 -24
  63. package/dist/next/host/client/index.cjs.map +1 -1
  64. package/dist/next/host/client/index.d.ts +1 -1
  65. package/dist/next/host/client/index.js +91 -24
  66. package/dist/next/host/client/index.js.map +1 -1
  67. package/dist/next/host/pages-router-client.d.ts +1 -1
  68. package/dist/next/host/pages-router-server.d.ts +1 -1
  69. package/dist/next/index.d.ts +1 -1
  70. package/dist/next/proxy.cjs +128 -19
  71. package/dist/next/proxy.cjs.map +1 -1
  72. package/dist/next/proxy.d.ts +34 -6
  73. package/dist/next/proxy.js +125 -18
  74. package/dist/next/proxy.js.map +1 -1
  75. package/dist/react/index.cjs +91 -24
  76. package/dist/react/index.cjs.map +1 -1
  77. package/dist/react/index.d.ts +2 -1
  78. package/dist/react/index.js +91 -24
  79. package/dist/react/index.js.map +1 -1
  80. package/dist/shared/host/proxy.cjs +79 -0
  81. package/dist/shared/host/proxy.cjs.map +1 -0
  82. package/dist/shared/host/proxy.d.ts +29 -0
  83. package/dist/shared/host/proxy.js +54 -0
  84. package/dist/shared/host/proxy.js.map +1 -0
  85. package/dist/shared/remote/proxy.cjs +71 -0
  86. package/dist/shared/remote/proxy.cjs.map +1 -0
  87. package/dist/shared/remote/proxy.d.ts +38 -0
  88. package/dist/shared/remote/proxy.js +45 -0
  89. package/dist/shared/remote/proxy.js.map +1 -0
  90. package/dist/{types-6e4ba234.d.ts → types-cbe44b51.d.ts} +61 -7
  91. package/dist/webpack.cjs +274 -0
  92. package/dist/webpack.cjs.map +1 -0
  93. package/dist/webpack.d.ts +14 -0
  94. package/dist/webpack.js +247 -0
  95. package/dist/webpack.js.map +1 -0
  96. package/package.json +18 -1
  97. package/dist/internal/shared/logger.cjs.map +0 -1
  98. package/dist/internal/shared/logger.js.map +0 -1
@@ -7,17 +7,51 @@ interface RemoteComponentMetadata {
7
7
  id: string;
8
8
  type: 'nextjs' | 'remote-component' | 'unknown';
9
9
  }
10
+ /**
11
+ * Options object passed to hook functions containing abort capabilities.
12
+ * Uses standard AbortController/AbortSignal for compatibility with Web APIs.
13
+ *
14
+ * @example
15
+ * // Abort on redirect
16
+ * component.onResponse = (url, response, { signal, abort }) => {
17
+ * if (response.redirected) {
18
+ * abort();
19
+ * }
20
+ * };
21
+ *
22
+ * @example
23
+ * // Check if already aborted
24
+ * component.onRequest = (url, init, { signal }) => {
25
+ * if (signal.aborted) return;
26
+ * // ...
27
+ * };
28
+ *
29
+ * @example
30
+ * // Pass signal to fetch or other APIs
31
+ * component.onRequest = async (url, init, { signal }) => {
32
+ * const data = await fetch('/api/check', { signal });
33
+ * // ...
34
+ * };
35
+ */
36
+ interface HookOptions {
37
+ /** Standard AbortSignal - can be passed to fetch and other Web APIs */
38
+ signal: AbortSignal;
39
+ /** Abort loading - prevents further processing and DOM attachment */
40
+ abort(reason?: unknown): void;
41
+ }
10
42
  /**
11
43
  * Hook function that intercepts remote component fetch requests.
12
- * Can be used to modify request options, provide a custom response, or inspect the request.
44
+ * Can be used to modify request options, provide a custom response, inspect the request,
45
+ * or abort loading.
13
46
  *
14
47
  * @param url - The URL being fetched
15
48
  * @param init - The fetch init options being used
49
+ * @param options - Options object containing the abort signal
16
50
  * @returns Optional Response to use instead of fetching, or void/undefined to proceed with normal fetch
17
51
  *
18
52
  * @example
19
53
  * // Log all remote component requests
20
- * const onRequest = async (url, init) => {
54
+ * const onRequest = async (url, init, { abort }) => {
21
55
  * console.log('Fetching remote component from:', url.href);
22
56
  * };
23
57
  *
@@ -35,21 +69,32 @@ interface RemoteComponentMetadata {
35
69
  * return new Response(cached);
36
70
  * }
37
71
  * };
72
+ *
73
+ * @example
74
+ * // Block certain domains
75
+ * const onRequest = async (url, init, { abort }) => {
76
+ * if (isBlockedDomain(url)) {
77
+ * abort('Domain is blocked');
78
+ * }
79
+ * };
38
80
  */
39
- type OnRequestHook = (url: URL, init: RequestInit) => Promise<Response | undefined> | Response | undefined;
81
+ type OnRequestHook = (url: URL, init: RequestInit, options: HookOptions) => Promise<Response | undefined> | Response | undefined;
40
82
  /**
41
83
  * Hook function that is called after a remote component fetch completes.
42
- * Can be used to inspect the response, check for redirects, or transform the response.
84
+ * Can be used to inspect the response, check for redirects, transform the response,
85
+ * or abort loading.
43
86
  *
44
87
  * @param url - The original URL that was requested
45
88
  * @param response - The Response object from the fetch
89
+ * @param options - Options object containing the abort signal
46
90
  * @returns Optional Response to use instead of the original, or void/undefined to use the original response
47
91
  *
48
92
  * @example
49
- * // Check for redirects
50
- * const onResponse = async (url, response) => {
93
+ * // Check for redirects and abort
94
+ * const onResponse = async (url, response, { abort }) => {
51
95
  * if (response.redirected) {
52
96
  * console.log(`Redirected from ${url.href} to ${response.url}`);
97
+ * abort();
53
98
  * }
54
99
  * };
55
100
  *
@@ -67,8 +112,17 @@ type OnRequestHook = (url: URL, init: RequestInit) => Promise<Response | undefin
67
112
  * const modified = text.replace(/foo/g, 'bar');
68
113
  * return new Response(modified, response);
69
114
  * };
115
+ *
116
+ * @example
117
+ * // Abort on redirect to legacy routes
118
+ * const onResponse = async (url, response, { abort }) => {
119
+ * if (response.redirected && isLegacyRoute(response.url)) {
120
+ * window.location.href = toLegacyUrl(response.url);
121
+ * abort(); // Abort rendering - no flash!
122
+ * }
123
+ * };
70
124
  */
71
- type OnResponseHook = (url: URL, response: Response) => Promise<Response | undefined> | Response | undefined;
125
+ type OnResponseHook = (url: URL, response: Response, options: HookOptions) => Promise<Response | undefined> | Response | undefined;
72
126
 
73
127
  interface RemoteComponentProps {
74
128
  /** The src provided to the `<RemoteComponent>` component. May be relative or absolute URL. */
@@ -141,4 +195,4 @@ type LoadRemoteComponentProps = Pick<RemoteComponentProps, 'name' | 'bundle' | '
141
195
  */
142
196
  declare function loadRemoteComponent({ url, name, rscName, bundle, route, runtime, data, nextData, scripts, shared, remoteShared, container, }: LoadRemoteComponentProps): Promise<LoaderResult>;
143
197
 
144
- export { GlobalScope as G, LoadRemoteComponentProps as L, MountOrUnmountFunction as M, OnRequestHook as O, RemoteComponentProps as R, OnResponseHook as a, LoaderResult as b, loadRemoteComponent as l };
198
+ export { GlobalScope as G, HookOptions as H, LoadRemoteComponentProps as L, MountOrUnmountFunction as M, OnRequestHook as O, RemoteComponentProps as R, OnResponseHook as a, LoaderResult as b, loadRemoteComponent as l };
@@ -62,6 +62,9 @@ function logDebug(location2, message) {
62
62
  console.debug(`[${PREFIX}:${location2}]: ${message}`);
63
63
  }
64
64
  }
65
+ function logInfo(location2, message) {
66
+ console.info(`[${PREFIX}:${location2}]: ${message}`);
67
+ }
65
68
  function logWarn(location2, message) {
66
69
  console.warn(`[${PREFIX}:${location2}]: ${message}`);
67
70
  }
@@ -267,6 +270,63 @@ var init_shared_modules = __esm({
267
270
  }
268
271
  });
269
272
 
273
+ // src/shared/utils/abort.ts
274
+ function isAbortError(error) {
275
+ if (error instanceof DOMException && error.name === "AbortError") {
276
+ return true;
277
+ }
278
+ if (error !== null && typeof error === "object" && "name" in error && error.name === "AbortError" && "message" in error && typeof error.message === "string") {
279
+ const e = error;
280
+ return typeof e.code === "number" || e.constructor?.name === "DOMException";
281
+ }
282
+ return false;
283
+ }
284
+ var init_abort = __esm({
285
+ "src/shared/utils/abort.ts"() {
286
+ "use strict";
287
+ }
288
+ });
289
+
290
+ // src/shared/ssr/fetch-with-protected-rc-fallback.ts
291
+ async function fetchWithProtectedRcFallback(url, init) {
292
+ try {
293
+ const res = await fetch(url, init);
294
+ return res;
295
+ } catch (error) {
296
+ if (isAbortError(error)) {
297
+ throw error;
298
+ }
299
+ if (typeof document === "object" && typeof document.location === "object" && document.location.origin !== new URL(url).origin) {
300
+ logInfo(
301
+ "FetchRemoteComponent",
302
+ "Request failed due to CORS, attempting to fetch it via the withRemoteComponentsHost proxy."
303
+ );
304
+ const proxiedRes = await fetch(
305
+ `${RC_PROTECTED_REMOTE_FETCH_PATHNAME}?url=${url}`,
306
+ init?.signal ? { signal: init.signal } : void 0
307
+ );
308
+ if (proxiedRes.status === 200) {
309
+ return proxiedRes;
310
+ } else {
311
+ logError(
312
+ "FetchRemoteComponent",
313
+ `Could not proxy remote: [response status ${proxiedRes.status}] ${await proxiedRes.text()}`
314
+ );
315
+ }
316
+ }
317
+ throw error;
318
+ }
319
+ }
320
+ var RC_PROTECTED_REMOTE_FETCH_PATHNAME;
321
+ var init_fetch_with_protected_rc_fallback = __esm({
322
+ "src/shared/ssr/fetch-with-protected-rc-fallback.ts"() {
323
+ "use strict";
324
+ init_abort();
325
+ init_logger();
326
+ RC_PROTECTED_REMOTE_FETCH_PATHNAME = "/rc-fetch-protected-remote";
327
+ }
328
+ });
329
+
270
330
  // src/shared/utils/index.ts
271
331
  function escapeString(str) {
272
332
  return str.replace(/[^a-z0-9]/g, "_");
@@ -274,7 +334,6 @@ function escapeString(str) {
274
334
  var init_utils = __esm({
275
335
  "src/shared/utils/index.ts"() {
276
336
  "use strict";
277
- init_logger();
278
337
  }
279
338
  });
280
339
 
@@ -336,7 +395,7 @@ function createChunkLoader(runtime) {
336
395
  }
337
396
  logDebug("ChunkLoader", `Fetching chunk from: "${url}"`);
338
397
  self.__remote_components_turbopack_chunk_loader_promise__[url] = new Promise((resolve, reject) => {
339
- fetch(url).then((res) => res.text()).then((code) => {
398
+ fetchWithProtectedRcFallback(url).then((res) => res.text()).then((code) => {
340
399
  const hasTurbopack = code.includes("globalThis.TURBOPACK") || code.includes("self.TURBOPACK");
341
400
  if (hasTurbopack) {
342
401
  return handleTurbopackChunk(code, bundle ?? "", url);
@@ -489,6 +548,7 @@ var init_chunk_loader = __esm({
489
548
  "src/shared/client/chunk-loader.ts"() {
490
549
  "use strict";
491
550
  init_error();
551
+ init_fetch_with_protected_rc_fallback();
492
552
  init_logger();
493
553
  init_const();
494
554
  }
@@ -1258,7 +1318,7 @@ var import_jsx_runtime, imageImpl;
1258
1318
  var init_polyfill = __esm({
1259
1319
  "src/shared/client/polyfill.tsx"() {
1260
1320
  "use strict";
1261
- init_utils();
1321
+ init_logger();
1262
1322
  // eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
1263
1323
  import_jsx_runtime = require("react/jsx-runtime");
1264
1324
  imageImpl = (bundle) => function RemoteImage({
@@ -1663,13 +1723,29 @@ function remoteFetchHeaders() {
1663
1723
  }
1664
1724
 
1665
1725
  // src/shared/ssr/fetch-with-hooks.ts
1666
- async function fetchWithHooks(url, init, options = {}) {
1667
- const { onRequest, onResponse } = options;
1668
- let res = await onRequest?.(url, init);
1726
+ init_fetch_with_protected_rc_fallback();
1727
+ async function fetchWithHooks(url, additionalInit, options = {}) {
1728
+ const {
1729
+ onRequest,
1730
+ onResponse,
1731
+ abortController = new AbortController()
1732
+ } = options;
1733
+ const signal = abortController.signal;
1734
+ const hookOptions = {
1735
+ signal,
1736
+ abort: (reason) => abortController.abort(reason)
1737
+ };
1738
+ const init = {
1739
+ method: "GET",
1740
+ headers: remoteFetchHeaders(),
1741
+ signal,
1742
+ ...additionalInit
1743
+ };
1744
+ let res = await onRequest?.(url, init, hookOptions);
1669
1745
  if (!res) {
1670
- res = await fetch(url, init);
1746
+ res = await fetchWithProtectedRcFallback(url, init);
1671
1747
  }
1672
- const transformedRes = await onResponse?.(url, res);
1748
+ const transformedRes = await onResponse?.(url, res, hookOptions);
1673
1749
  if (transformedRes) {
1674
1750
  res = transformedRes;
1675
1751
  }
@@ -1678,6 +1754,86 @@ async function fetchWithHooks(url, init, options = {}) {
1678
1754
 
1679
1755
  // src/html/host/index.tsx
1680
1756
  init_utils();
1757
+ init_abort();
1758
+ init_logger();
1759
+
1760
+ // src/html/host/attach-styles.ts
1761
+ init_error();
1762
+ async function attachStyles({
1763
+ doc,
1764
+ component,
1765
+ links,
1766
+ signal,
1767
+ baseUrl,
1768
+ remoteComponentSrc,
1769
+ root
1770
+ }) {
1771
+ const appendedLinks = [];
1772
+ let abortReject = null;
1773
+ const abortPromise = new Promise((_, reject) => {
1774
+ abortReject = reject;
1775
+ });
1776
+ const abortHandler = () => {
1777
+ for (const link of appendedLinks) {
1778
+ link.onload = null;
1779
+ link.onerror = null;
1780
+ link.remove();
1781
+ }
1782
+ abortReject?.(new DOMException("Aborted", "AbortError"));
1783
+ };
1784
+ signal?.addEventListener("abort", abortHandler, { once: true });
1785
+ try {
1786
+ await Promise.all(
1787
+ Array.from(links).filter((link) => !component.contains(link)).map((link) => {
1788
+ const newLink = document.createElement("link");
1789
+ appendedLinks.push(newLink);
1790
+ const loadPromise = new Promise((resolve, reject) => {
1791
+ if (link.rel === "stylesheet") {
1792
+ newLink.onload = () => resolve();
1793
+ newLink.onerror = () => reject(
1794
+ new RemoteComponentsError(
1795
+ `Failed to load <link href="${link.href}"> for Remote Component. Check the URL is correct.`
1796
+ )
1797
+ );
1798
+ } else {
1799
+ resolve();
1800
+ }
1801
+ });
1802
+ for (const attr of link.attributes) {
1803
+ if (attr.name === "href") {
1804
+ newLink.setAttribute(
1805
+ attr.name,
1806
+ new URL(attr.value, baseUrl ?? location.origin).href
1807
+ );
1808
+ } else {
1809
+ newLink.setAttribute(attr.name, attr.value);
1810
+ }
1811
+ }
1812
+ if (remoteComponentSrc) {
1813
+ newLink.setAttribute(
1814
+ "data-remote-component-src",
1815
+ remoteComponentSrc
1816
+ );
1817
+ }
1818
+ root?.appendChild(newLink);
1819
+ return Promise.race([loadPromise, abortPromise]);
1820
+ })
1821
+ );
1822
+ } finally {
1823
+ signal?.removeEventListener("abort", abortHandler);
1824
+ }
1825
+ const styles = doc.querySelectorAll("style");
1826
+ for (const style of styles) {
1827
+ if (style.parentElement?.tagName.toLowerCase() === "head") {
1828
+ const newStyle = document.createElement("style");
1829
+ newStyle.textContent = style.textContent;
1830
+ if (remoteComponentSrc) {
1831
+ newStyle.setAttribute("data-remote-component-src", remoteComponentSrc);
1832
+ }
1833
+ root?.appendChild(newStyle);
1834
+ }
1835
+ }
1836
+ }
1681
1837
 
1682
1838
  // src/html/host/runtime/index.ts
1683
1839
  init_error();
@@ -1720,6 +1876,8 @@ if (typeof HTMLElement !== "undefined") {
1720
1876
  reactRoot;
1721
1877
  onRequest;
1722
1878
  onResponse;
1879
+ /** Current AbortController for the loading operation - can be used to cancel loading via controller.abort() */
1880
+ abortController;
1723
1881
  static get observedAttributes() {
1724
1882
  return ["src", "name", "mode"];
1725
1883
  }
@@ -1730,6 +1888,10 @@ if (typeof HTMLElement !== "undefined") {
1730
1888
  if ((name === "src" || name === "name") && oldValue !== newValue) {
1731
1889
  if (this.getAttribute("src")) {
1732
1890
  this.load().catch((e) => {
1891
+ if (isAbortError(e)) {
1892
+ this.isLoading = false;
1893
+ return;
1894
+ }
1733
1895
  logError("HtmlHost", "Error loading remote component.", e);
1734
1896
  const errorEvent = new Event("error", {
1735
1897
  bubbles: true,
@@ -1752,6 +1914,10 @@ if (typeof HTMLElement !== "undefined") {
1752
1914
  });
1753
1915
  this.root = newRoot;
1754
1916
  this.load().catch((e) => {
1917
+ if (isAbortError(e)) {
1918
+ this.isLoading = false;
1919
+ return;
1920
+ }
1755
1921
  logError("HtmlHost", "Error reloading remote component.", e);
1756
1922
  const errorEvent = new Event("error", {
1757
1923
  bubbles: true,
@@ -1785,6 +1951,10 @@ if (typeof HTMLElement !== "undefined") {
1785
1951
  this.bundle = "default";
1786
1952
  if (this.hasAttribute("src") || this.querySelector("div#__REMOTE_COMPONENT__") || this.hasAttribute("data-ssr")) {
1787
1953
  this.load().catch((e) => {
1954
+ if (isAbortError(e)) {
1955
+ this.isLoading = false;
1956
+ return;
1957
+ }
1788
1958
  logError("HtmlHost", "Error loading remote component.", e);
1789
1959
  const errorEvent = new Event("error", {
1790
1960
  bubbles: true,
@@ -1799,6 +1969,8 @@ if (typeof HTMLElement !== "undefined") {
1799
1969
  }
1800
1970
  this.isLoading = true;
1801
1971
  const src = this.getAttribute("src");
1972
+ this.abortController = new AbortController();
1973
+ const signal = this.abortController.signal;
1802
1974
  const beforeLoadEvent = new Event("beforeload", {
1803
1975
  bubbles: true,
1804
1976
  composed: true
@@ -1819,18 +1991,20 @@ if (typeof HTMLElement !== "undefined") {
1819
1991
  }
1820
1992
  if (!remoteComponentChild && url) {
1821
1993
  const fetchInit = {
1822
- method: "GET",
1823
- headers: remoteFetchHeaders(),
1824
1994
  credentials: this.getAttribute("credentials") || "same-origin"
1825
1995
  };
1826
1996
  const res = await fetchWithHooks(url, fetchInit, {
1827
1997
  onRequest: this.onRequest,
1828
- onResponse: this.onResponse
1998
+ onResponse: this.onResponse,
1999
+ abortController: this.abortController
1829
2000
  });
1830
- if (!res.ok) {
1831
- let error = failedToFetchRemoteComponentError(url.href, res);
2001
+ if (!res || !res.ok) {
2002
+ let error = failedToFetchRemoteComponentError(
2003
+ url.href,
2004
+ res ?? new Response(null, { status: 0 })
2005
+ );
1832
2006
  try {
1833
- const body = await res.text();
2007
+ const body = res ? await res.text() : "";
1834
2008
  const parser2 = new DOMParser();
1835
2009
  const doc2 = parser2.parseFromString(body, "text/html");
1836
2010
  const errorTemplate = doc2.querySelector(
@@ -1848,7 +2022,9 @@ if (typeof HTMLElement !== "undefined") {
1848
2022
  error.stack = errorStack;
1849
2023
  }
1850
2024
  }
1851
- } catch {
2025
+ } catch (parseError) {
2026
+ if (isAbortError(parseError))
2027
+ throw parseError;
1852
2028
  }
1853
2029
  throw error;
1854
2030
  }
@@ -1959,64 +2135,26 @@ if (typeof HTMLElement !== "undefined") {
1959
2135
  const removable = Array.from(this.childNodes);
1960
2136
  const links = doc.querySelectorAll("link[href]");
1961
2137
  const remoteComponentSrc = this.getAttribute("src");
1962
- const attachLinks = async () => {
1963
- await Promise.all(
1964
- Array.from(links).filter((link) => {
1965
- return !component.contains(link);
1966
- }).map((link) => {
1967
- return new Promise((resolve, reject) => {
1968
- const newLink = document.createElement("link");
1969
- if (link.rel === "stylesheet") {
1970
- newLink.onload = () => {
1971
- resolve();
1972
- };
1973
- newLink.onerror = () => {
1974
- reject(
1975
- new RemoteComponentsError(
1976
- `Failed to load <link href="${link.href}"> for Remote Component. Check the URL is correct.`
1977
- )
1978
- );
1979
- };
1980
- } else {
1981
- resolve();
1982
- }
1983
- for (const attr of link.attributes) {
1984
- if (attr.name === "href") {
1985
- newLink.setAttribute(
1986
- attr.name,
1987
- new URL(attr.value, url ?? location.origin).href
1988
- );
1989
- } else {
1990
- newLink.setAttribute(attr.name, attr.value);
1991
- }
1992
- }
1993
- if (remoteComponentSrc) {
1994
- newLink.setAttribute(
1995
- "data-remote-component-src",
1996
- remoteComponentSrc
1997
- );
1998
- }
1999
- this.root?.appendChild(newLink);
2000
- });
2001
- })
2002
- );
2003
- const styles = doc.querySelectorAll("style");
2004
- styles.forEach((style) => {
2005
- if (style.parentElement?.tagName.toLowerCase() === "head") {
2006
- const newStyle = document.createElement("style");
2007
- newStyle.textContent = style.textContent;
2008
- if (remoteComponentSrc) {
2009
- newStyle.setAttribute(
2010
- "data-remote-component-src",
2011
- remoteComponentSrc
2012
- );
2013
- }
2014
- this.root?.appendChild(newStyle);
2015
- }
2016
- });
2017
- };
2138
+ const doAttachStyles = () => attachStyles({
2139
+ doc,
2140
+ component,
2141
+ links,
2142
+ signal: void 0,
2143
+ // Effects run after load, no abort needed
2144
+ baseUrl: url?.href,
2145
+ remoteComponentSrc,
2146
+ root: this.root ?? null
2147
+ });
2018
2148
  if (!this.reactRoot) {
2019
- await attachLinks();
2149
+ await attachStyles({
2150
+ doc,
2151
+ component,
2152
+ links,
2153
+ signal,
2154
+ baseUrl: url?.href,
2155
+ remoteComponentSrc,
2156
+ root: this.root
2157
+ });
2020
2158
  }
2021
2159
  applyOriginToNodes(doc, url ?? new URL(location.href));
2022
2160
  if (!this.reactRoot) {
@@ -2171,8 +2309,8 @@ if (typeof HTMLElement !== "undefined") {
2171
2309
  doCleanup();
2172
2310
  applyReset();
2173
2311
  if (!initial) {
2174
- attachLinks().catch((e) => {
2175
- logError("HtmlHost", "Error attaching links.", e);
2312
+ doAttachStyles().catch((e) => {
2313
+ logError("HtmlHost", "Error attaching styles.", e);
2176
2314
  });
2177
2315
  }
2178
2316
  this.isLoading = false;
@@ -2224,8 +2362,8 @@ if (typeof HTMLElement !== "undefined") {
2224
2362
  doCleanup();
2225
2363
  if (!initial) {
2226
2364
  applyReset();
2227
- attachLinks().catch((e) => {
2228
- logError("HtmlHost", "Error attaching links.", e);
2365
+ doAttachStyles().catch((e) => {
2366
+ logError("HtmlHost", "Error attaching styles.", e);
2229
2367
  });
2230
2368
  }
2231
2369
  remoteComponent.isLoading = false;