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.
- package/dist/{component-loader-26b1f55e.d.ts → component-loader-1838f572.d.ts} +62 -8
- package/dist/html/host.cjs +214 -76
- package/dist/html/host.cjs.map +1 -1
- package/dist/html/host.js +214 -76
- package/dist/html/host.js.map +1 -1
- package/dist/html/remote.cjs.map +1 -1
- package/dist/html/remote.js.map +1 -1
- package/dist/internal/next/host/app-router-client.cjs +6 -6
- package/dist/internal/next/host/app-router-client.cjs.map +1 -1
- package/dist/internal/next/host/app-router-client.d.ts +1 -1
- package/dist/internal/next/host/app-router-client.js +1 -1
- package/dist/internal/next/host/app-router-client.js.map +1 -1
- package/dist/internal/next/host/app-router-compat.cjs +5 -5
- package/dist/internal/next/host/app-router-compat.cjs.map +1 -1
- package/dist/internal/next/host/app-router-compat.js +1 -1
- package/dist/internal/next/host/app-router-compat.js.map +1 -1
- package/dist/internal/shared/client/polyfill.cjs +2 -2
- package/dist/internal/shared/client/polyfill.cjs.map +1 -1
- package/dist/internal/shared/client/polyfill.js +1 -1
- package/dist/internal/shared/client/polyfill.js.map +1 -1
- package/dist/internal/shared/client/remote-component.cjs +48 -1
- package/dist/internal/shared/client/remote-component.cjs.map +1 -1
- package/dist/internal/shared/client/remote-component.d.ts +2 -2
- package/dist/internal/shared/client/remote-component.js +48 -1
- package/dist/internal/shared/client/remote-component.js.map +1 -1
- package/dist/internal/shared/ssr/dom-flight.d.ts +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.cjs +1 -6
- package/dist/internal/shared/ssr/fetch-remote-component.cjs.map +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.d.ts +1 -1
- package/dist/internal/shared/ssr/fetch-remote-component.js +1 -6
- package/dist/internal/shared/ssr/fetch-remote-component.js.map +1 -1
- package/dist/internal/shared/ssr/fetch-with-hooks.cjs +22 -5
- package/dist/internal/shared/ssr/fetch-with-hooks.cjs.map +1 -1
- package/dist/internal/shared/ssr/fetch-with-hooks.d.ts +30 -14
- package/dist/internal/shared/ssr/fetch-with-hooks.js +22 -5
- package/dist/internal/shared/ssr/fetch-with-hooks.js.map +1 -1
- package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.cjs +62 -0
- package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.cjs.map +1 -0
- package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.d.ts +14 -0
- package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.js +37 -0
- package/dist/internal/shared/ssr/fetch-with-protected-rc-fallback.js.map +1 -0
- package/dist/internal/shared/utils/abort.cjs +38 -0
- package/dist/internal/shared/utils/abort.cjs.map +1 -0
- package/dist/internal/shared/utils/abort.d.ts +7 -0
- package/dist/internal/shared/utils/abort.js +14 -0
- package/dist/internal/shared/utils/abort.js.map +1 -0
- package/dist/internal/shared/{logger.cjs → utils/logger.cjs} +5 -0
- package/dist/internal/shared/utils/logger.cjs.map +1 -0
- package/dist/internal/shared/{logger.d.ts → utils/logger.d.ts} +3 -2
- package/dist/internal/shared/{logger.js → utils/logger.js} +4 -0
- package/dist/internal/shared/utils/logger.js.map +1 -0
- package/dist/internal/shared/utils.cjs +2 -9
- package/dist/internal/shared/utils.cjs.map +1 -1
- package/dist/internal/shared/utils.d.ts +0 -2
- package/dist/internal/shared/utils.js +1 -5
- package/dist/internal/shared/utils.js.map +1 -1
- package/dist/next/config.cjs +4 -2
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +4 -2
- package/dist/next/config.js.map +1 -1
- package/dist/next/host/app-router-server.d.ts +1 -1
- package/dist/next/host/client/index.cjs +91 -24
- package/dist/next/host/client/index.cjs.map +1 -1
- package/dist/next/host/client/index.d.ts +1 -1
- package/dist/next/host/client/index.js +91 -24
- package/dist/next/host/client/index.js.map +1 -1
- package/dist/next/host/pages-router-client.d.ts +1 -1
- package/dist/next/host/pages-router-server.d.ts +1 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/proxy.cjs +128 -19
- package/dist/next/proxy.cjs.map +1 -1
- package/dist/next/proxy.d.ts +34 -6
- package/dist/next/proxy.js +125 -18
- package/dist/next/proxy.js.map +1 -1
- package/dist/react/index.cjs +91 -24
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +91 -24
- package/dist/react/index.js.map +1 -1
- package/dist/shared/host/proxy.cjs +79 -0
- package/dist/shared/host/proxy.cjs.map +1 -0
- package/dist/shared/host/proxy.d.ts +29 -0
- package/dist/shared/host/proxy.js +54 -0
- package/dist/shared/host/proxy.js.map +1 -0
- package/dist/shared/remote/proxy.cjs +71 -0
- package/dist/shared/remote/proxy.cjs.map +1 -0
- package/dist/shared/remote/proxy.d.ts +38 -0
- package/dist/shared/remote/proxy.js +45 -0
- package/dist/shared/remote/proxy.js.map +1 -0
- package/dist/{types-6e4ba234.d.ts → types-cbe44b51.d.ts} +61 -7
- package/dist/webpack.cjs +274 -0
- package/dist/webpack.cjs.map +1 -0
- package/dist/webpack.d.ts +14 -0
- package/dist/webpack.js +247 -0
- package/dist/webpack.js.map +1 -0
- package/package.json +18 -1
- package/dist/internal/shared/logger.cjs.map +0 -1
- 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,
|
|
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,
|
|
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 };
|
package/dist/html/host.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
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
|
|
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(
|
|
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
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
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
|
|
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
|
-
|
|
2175
|
-
logError("HtmlHost", "Error attaching
|
|
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
|
-
|
|
2228
|
-
logError("HtmlHost", "Error attaching
|
|
2365
|
+
doAttachStyles().catch((e) => {
|
|
2366
|
+
logError("HtmlHost", "Error attaching styles.", e);
|
|
2229
2367
|
});
|
|
2230
2368
|
}
|
|
2231
2369
|
remoteComponent.isLoading = false;
|