remote-components 0.1.0 → 0.1.2
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-76eb1b8b.d.ts → component-loader-21865da3.d.ts} +140 -16
- package/dist/host-config-58cdccea.d.ts +87 -0
- package/dist/html/host.cjs +294 -162
- package/dist/html/host.cjs.map +1 -1
- package/dist/html/host.js +294 -162
- package/dist/html/host.js.map +1 -1
- package/dist/internal/next/host/app-router-client.cjs +9 -7
- package/dist/internal/next/host/app-router-client.cjs.map +1 -1
- package/dist/internal/next/host/app-router-client.d.ts +32 -19
- package/dist/internal/next/host/app-router-client.js +9 -7
- package/dist/internal/next/host/app-router-client.js.map +1 -1
- package/dist/internal/next/remote/render-server.cjs.map +1 -1
- package/dist/internal/next/remote/render-server.d.ts +13 -14
- package/dist/internal/next/remote/render-server.js.map +1 -1
- package/dist/internal/shared/client/proxy-through-host.cjs +15 -1
- package/dist/internal/shared/client/proxy-through-host.cjs.map +1 -1
- package/dist/internal/shared/client/proxy-through-host.d.ts +5 -0
- package/dist/internal/shared/client/proxy-through-host.js +15 -1
- package/dist/internal/shared/client/proxy-through-host.js.map +1 -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.map +1 -1
- package/dist/internal/shared/contract/host-state.cjs +38 -0
- package/dist/internal/shared/contract/host-state.cjs.map +1 -0
- package/dist/internal/shared/contract/host-state.d.ts +53 -0
- package/dist/internal/shared/contract/host-state.js +14 -0
- package/dist/internal/shared/contract/host-state.js.map +1 -0
- package/dist/internal/shared/contract/resolve-name-from-src.cjs +40 -0
- package/dist/internal/shared/contract/resolve-name-from-src.cjs.map +1 -0
- package/dist/internal/shared/contract/resolve-name-from-src.d.ts +13 -0
- package/dist/internal/shared/contract/resolve-name-from-src.js +16 -0
- package/dist/internal/shared/contract/resolve-name-from-src.js.map +1 -0
- package/dist/internal/shared/ssr/dom-flight.d.ts +1 -1
- 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.map +1 -1
- package/dist/internal/shared/ssr/fetch-with-hooks.d.ts +1 -1
- package/dist/next/host/app-router-server.cjs.map +1 -1
- package/dist/next/host/app-router-server.d.ts +11 -41
- package/dist/next/host/app-router-server.js.map +1 -1
- package/dist/next/host/client/index.cjs +203 -95
- 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 +203 -95
- package/dist/next/host/client/index.js.map +1 -1
- package/dist/next/host/pages-router-client.cjs.map +1 -1
- package/dist/next/host/pages-router-client.d.ts +13 -36
- package/dist/next/host/pages-router-client.js.map +1 -1
- package/dist/next/host/pages-router-server.cjs.map +1 -1
- package/dist/next/host/pages-router-server.d.ts +17 -42
- package/dist/next/host/pages-router-server.js.map +1 -1
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.ts +13 -39
- package/dist/next/index.js.map +1 -1
- package/dist/next/remote/server.d.ts +4 -0
- package/dist/react/index.cjs +203 -95
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +12 -49
- package/dist/react/index.js +203 -95
- package/dist/react/index.js.map +1 -1
- package/dist/{types-cbe44b51.d.ts → types-2b26a246.d.ts} +23 -6
- package/package.json +1 -1
package/dist/react/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { R as ResolveClientUrl } from '../proxy-through-host-a676a522.js';
|
|
3
3
|
export { p as proxyClientRequestsThroughHost } from '../proxy-through-host-a676a522.js';
|
|
4
|
-
import {
|
|
5
|
-
export {
|
|
4
|
+
import { H as HostConfig, C as ClientHostConfig, a as HostLifecycleCallbacks, L as LoadRemoteComponentProps } from '../component-loader-21865da3.js';
|
|
5
|
+
export { b as HookOptions, O as OnRequestHook, c as OnResponseHook } from '../component-loader-21865da3.js';
|
|
6
6
|
import 'react';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -32,55 +32,18 @@ declare module 'react/jsx-runtime' {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
reset?: boolean;
|
|
44
|
-
/** The credentials to use for the fetch request. Defaults to `same-origin`. */
|
|
45
|
-
credentials?: RequestCredentials;
|
|
46
|
-
name?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Props for the React remote component host.
|
|
37
|
+
*
|
|
38
|
+
* Extends {@link HostConfig}, {@link ClientHostConfig}, and
|
|
39
|
+
* {@link HostLifecycleCallbacks}. Adds `shared` for module sharing and
|
|
40
|
+
* `children` for loading fallback content.
|
|
41
|
+
*/
|
|
42
|
+
interface RemoteComponentProps extends HostConfig, ClientHostConfig, HostLifecycleCallbacks {
|
|
47
43
|
/** Shared modules to include in the remote component's context. */
|
|
48
44
|
shared?: LoadRemoteComponentProps['shared'];
|
|
49
|
-
/**
|
|
45
|
+
/** Loading fallback content displayed while the remote component is being fetched. */
|
|
50
46
|
children?: React.ReactNode;
|
|
51
|
-
/** Called right before a new remote component load starts. */
|
|
52
|
-
onBeforeLoad?: (src: string | URL) => void;
|
|
53
|
-
/** Called when the remote component has been successfully loaded and mounted. */
|
|
54
|
-
onLoad?: (src: string | URL) => void;
|
|
55
|
-
/** Called when an error occurs while loading or mounting the remote component. */
|
|
56
|
-
onError?: (error: unknown) => void;
|
|
57
|
-
/** Called when a different remote component is loaded into the same wrapper. */
|
|
58
|
-
onChange?: (info: {
|
|
59
|
-
previousSrc: string | URL | null;
|
|
60
|
-
nextSrc: string | URL | null;
|
|
61
|
-
previousName: string | undefined;
|
|
62
|
-
nextName: string | undefined;
|
|
63
|
-
}) => void;
|
|
64
|
-
/**
|
|
65
|
-
* Called when a fetch request is made to retrieve the remote component payload.
|
|
66
|
-
* Can be used to intercept requests, modify headers, or provide a custom response.
|
|
67
|
-
*/
|
|
68
|
-
onRequest?: OnRequestHook;
|
|
69
|
-
/**
|
|
70
|
-
* Called after a fetch completes to retrieve the remote component payload.
|
|
71
|
-
* Can be used to inspect the response (e.g., check for redirects) or transform it.
|
|
72
|
-
*/
|
|
73
|
-
onResponse?: OnResponseHook;
|
|
74
|
-
/**
|
|
75
|
-
* Called before each client-side asset (script, stylesheet, chunk, module, image) is fetched.
|
|
76
|
-
* Return a new URL string to redirect the request (e.g., through a proxy),
|
|
77
|
-
* or `undefined` to use the original URL.
|
|
78
|
-
*
|
|
79
|
-
* Pass `proxyClientRequestsThroughHost` to proxy cross-origin assets through
|
|
80
|
-
* the host on Vercel preview deployments. Requires `withRemoteComponentsHost`
|
|
81
|
-
* middleware on the host to handle the proxied requests.
|
|
82
|
-
*/
|
|
83
|
-
resolveClientUrl?: ResolveClientUrl;
|
|
84
47
|
}
|
|
85
48
|
/**
|
|
86
49
|
* RemoteComponent is a React component that fetches and renders a remote component.
|
|
@@ -120,4 +83,4 @@ interface RemoteComponentProps {
|
|
|
120
83
|
*/
|
|
121
84
|
declare function RemoteComponent({ src, isolate, mode, reset, credentials, name: nameProp, shared, children, onBeforeLoad, onLoad, onError, onChange, onRequest, onResponse, resolveClientUrl: _resolveClientUrl, }: RemoteComponentProps): react_jsx_runtime.JSX.Element;
|
|
122
85
|
|
|
123
|
-
export {
|
|
86
|
+
export { RemoteComponent, RemoteComponentProps, RemoteComponentsProvider, ResolveClientUrl };
|
package/dist/react/index.js
CHANGED
|
@@ -183,6 +183,122 @@ Docs: ${CORS_DOCS_URL}`
|
|
|
183
183
|
);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
// src/shared/utils/index.ts
|
|
187
|
+
function escapeString(str) {
|
|
188
|
+
return str.replace(/[^a-z0-9]/g, "_");
|
|
189
|
+
}
|
|
190
|
+
var attrToProp = {
|
|
191
|
+
fetchpriority: "fetchPriority",
|
|
192
|
+
crossorigin: "crossOrigin",
|
|
193
|
+
imagesrcset: "imageSrcSet",
|
|
194
|
+
imagesizes: "imageSizes",
|
|
195
|
+
srcset: "srcSet"
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// src/shared/client/const.ts
|
|
199
|
+
var DEFAULT_ROUTE = "/";
|
|
200
|
+
var RUNTIME_WEBPACK = "webpack";
|
|
201
|
+
var RUNTIME_TURBOPACK = "turbopack";
|
|
202
|
+
var RUNTIME_SCRIPT = "script";
|
|
203
|
+
var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
|
|
204
|
+
function getBundleKey(bundle) {
|
|
205
|
+
return escapeString(bundle);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/shared/client/parse-remote-html.ts
|
|
209
|
+
function validateSingleComponent(doc, name, url) {
|
|
210
|
+
if (doc.querySelectorAll("div[data-bundle][data-route]").length > 1 && !doc.querySelector(`div[data-bundle][data-route][id^="${name}"]`) || doc.querySelectorAll("remote-component:not([src])").length > 1 && !doc.querySelector(`remote-component[name="${name}"]`)) {
|
|
211
|
+
throw multipleRemoteComponentsError(url);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function findComponentElement(doc, name) {
|
|
215
|
+
return doc.querySelector(`div[data-bundle][data-route][id^="${name}"]`) ?? doc.querySelector("div[data-bundle][data-route]") ?? doc.querySelector("div#__next") ?? doc.querySelector(`remote-component[name="${name}"]:not([src])`) ?? doc.querySelector("remote-component:not([src])");
|
|
216
|
+
}
|
|
217
|
+
function parseNextData(doc) {
|
|
218
|
+
return JSON.parse(
|
|
219
|
+
(doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
function resolveComponentName(component, nextData, fallbackName) {
|
|
223
|
+
const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
|
|
224
|
+
const name = component?.getAttribute("id")?.replace(/_ssr$/, "") || isRemoteComponent && component?.getAttribute("name") || (nextData ? "__next" : fallbackName);
|
|
225
|
+
return { name, isRemoteComponent };
|
|
226
|
+
}
|
|
227
|
+
function extractComponentMetadata(component, nextData, name, url) {
|
|
228
|
+
return {
|
|
229
|
+
name,
|
|
230
|
+
bundle: component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || "default",
|
|
231
|
+
route: component?.getAttribute("data-route") ?? nextData?.page ?? (url.pathname || DEFAULT_ROUTE),
|
|
232
|
+
runtime: component?.getAttribute("data-runtime") ?? (nextData?.props.__REMOTE_COMPONENT__?.runtime || RUNTIME_SCRIPT)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function extractRemoteShared(doc, name, nextData) {
|
|
236
|
+
const remoteSharedEl = doc.querySelector(
|
|
237
|
+
`#${name}_shared[data-remote-components-shared]`
|
|
238
|
+
);
|
|
239
|
+
const remoteShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? (JSON.parse(remoteSharedEl?.textContent ?? "{}") ?? {});
|
|
240
|
+
remoteSharedEl?.remove();
|
|
241
|
+
return remoteShared;
|
|
242
|
+
}
|
|
243
|
+
function validateComponentFound(component, rsc, nextData, isRemoteComponent, url, name) {
|
|
244
|
+
if (!component || !(rsc || nextData || isRemoteComponent)) {
|
|
245
|
+
throw new RemoteComponentsError(
|
|
246
|
+
`Remote Component not found on ${url}.${name !== "__vercel_remote_component" ? ` The name for the <RemoteComponent> is "${name}". Check <RemoteComponent> usage.` : ""} Did you forget to wrap the content in <RemoteComponent>?`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function extractLinks(doc, component) {
|
|
251
|
+
return Array.from(doc.querySelectorAll("link[href]")).filter(
|
|
252
|
+
(link) => !component.contains(link)
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
function extractScripts(doc, component, isRemoteComponent) {
|
|
256
|
+
return Array.from(
|
|
257
|
+
(isRemoteComponent ? component : doc).querySelectorAll(
|
|
258
|
+
"script[src],script[data-src]"
|
|
259
|
+
)
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
function parseRemoteComponentDocument(doc, name, url) {
|
|
263
|
+
validateSingleComponent(doc, name, url.href);
|
|
264
|
+
const component = findComponentElement(doc, name);
|
|
265
|
+
const nextData = parseNextData(doc);
|
|
266
|
+
const { name: resolvedName, isRemoteComponent } = resolveComponentName(
|
|
267
|
+
component,
|
|
268
|
+
nextData,
|
|
269
|
+
name
|
|
270
|
+
);
|
|
271
|
+
const rsc = doc.querySelector(`#${resolvedName}_rsc`);
|
|
272
|
+
const metadata = extractComponentMetadata(
|
|
273
|
+
component,
|
|
274
|
+
nextData,
|
|
275
|
+
resolvedName,
|
|
276
|
+
url
|
|
277
|
+
);
|
|
278
|
+
const remoteShared = extractRemoteShared(doc, resolvedName, nextData);
|
|
279
|
+
validateComponentFound(
|
|
280
|
+
component,
|
|
281
|
+
rsc,
|
|
282
|
+
nextData,
|
|
283
|
+
isRemoteComponent,
|
|
284
|
+
url.href,
|
|
285
|
+
resolvedName
|
|
286
|
+
);
|
|
287
|
+
const links = extractLinks(doc, component);
|
|
288
|
+
const scripts = extractScripts(doc, component, isRemoteComponent);
|
|
289
|
+
return {
|
|
290
|
+
component,
|
|
291
|
+
name: resolvedName,
|
|
292
|
+
isRemoteComponent,
|
|
293
|
+
metadata,
|
|
294
|
+
nextData,
|
|
295
|
+
rsc,
|
|
296
|
+
remoteShared,
|
|
297
|
+
links,
|
|
298
|
+
scripts
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
186
302
|
// src/shared/utils/logger.ts
|
|
187
303
|
var PREFIX = "remote-components";
|
|
188
304
|
var DEBUG = typeof window !== "undefined" && localStorage.getItem("RC_DEBUG") === "true";
|
|
@@ -698,28 +814,6 @@ async function loadScripts(scripts, resolveClientUrl) {
|
|
|
698
814
|
);
|
|
699
815
|
}
|
|
700
816
|
|
|
701
|
-
// src/shared/utils/index.ts
|
|
702
|
-
function escapeString(str) {
|
|
703
|
-
return str.replace(/[^a-z0-9]/g, "_");
|
|
704
|
-
}
|
|
705
|
-
var attrToProp = {
|
|
706
|
-
fetchpriority: "fetchPriority",
|
|
707
|
-
crossorigin: "crossOrigin",
|
|
708
|
-
imagesrcset: "imageSrcSet",
|
|
709
|
-
imagesizes: "imageSizes",
|
|
710
|
-
srcset: "srcSet"
|
|
711
|
-
};
|
|
712
|
-
|
|
713
|
-
// src/shared/client/const.ts
|
|
714
|
-
var DEFAULT_ROUTE = "/";
|
|
715
|
-
var RUNTIME_WEBPACK = "webpack";
|
|
716
|
-
var RUNTIME_TURBOPACK = "turbopack";
|
|
717
|
-
var RUNTIME_SCRIPT = "script";
|
|
718
|
-
var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
|
|
719
|
-
function getBundleKey(bundle) {
|
|
720
|
-
return escapeString(bundle);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
817
|
// src/shared/client/turbopack-patterns.ts
|
|
724
818
|
var REMOTE_SHARED_MARKER_RE = /(?:self|[a-z])\.TURBOPACK_REMOTE_SHARED/;
|
|
725
819
|
var REMOTE_SHARED_ASSIGNMENT_RE = /\.TURBOPACK_REMOTE_SHARED=await (?:__turbopack_context__|e)\.A\((?<sharedModuleId>[0-9]+)\)/;
|
|
@@ -1520,7 +1614,21 @@ function loadNextPagesComponent(bundle, route, nextData, name, container) {
|
|
|
1520
1614
|
|
|
1521
1615
|
// src/shared/client/proxy-through-host.ts
|
|
1522
1616
|
function withRemoteSrc(resolveClientUrl, remoteSrc) {
|
|
1523
|
-
|
|
1617
|
+
const remoteOrigin = parseOrigin(remoteSrc);
|
|
1618
|
+
return (url) => {
|
|
1619
|
+
const urlOrigin = parseOrigin(url);
|
|
1620
|
+
if (remoteOrigin && urlOrigin && urlOrigin !== remoteOrigin) {
|
|
1621
|
+
return void 0;
|
|
1622
|
+
}
|
|
1623
|
+
return resolveClientUrl(remoteSrc, url);
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
function parseOrigin(url) {
|
|
1627
|
+
try {
|
|
1628
|
+
return new URL(url).origin;
|
|
1629
|
+
} catch {
|
|
1630
|
+
return void 0;
|
|
1631
|
+
}
|
|
1524
1632
|
}
|
|
1525
1633
|
var proxyClientRequestsThroughHost = (remoteSrc, url) => {
|
|
1526
1634
|
if (typeof location === "undefined") {
|
|
@@ -1732,6 +1840,32 @@ async function loadStaticRemoteComponent(scripts, url, resolveClientUrl) {
|
|
|
1732
1840
|
);
|
|
1733
1841
|
}
|
|
1734
1842
|
|
|
1843
|
+
// src/shared/contract/host-state.ts
|
|
1844
|
+
function createHostState() {
|
|
1845
|
+
return {
|
|
1846
|
+
stage: "idle",
|
|
1847
|
+
prevSrc: void 0,
|
|
1848
|
+
prevUrl: void 0,
|
|
1849
|
+
prevName: void 0,
|
|
1850
|
+
prevIsRemoteComponent: false,
|
|
1851
|
+
abortController: void 0
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
// src/shared/contract/resolve-name-from-src.ts
|
|
1856
|
+
function resolveNameFromSrc(src, defaultName) {
|
|
1857
|
+
if (!src) {
|
|
1858
|
+
return defaultName;
|
|
1859
|
+
}
|
|
1860
|
+
const hash = typeof src === "string" ? src : src.hash;
|
|
1861
|
+
const hashIndex = hash.indexOf("#");
|
|
1862
|
+
if (hashIndex < 0) {
|
|
1863
|
+
return defaultName;
|
|
1864
|
+
}
|
|
1865
|
+
const name = hash.slice(hashIndex + 1);
|
|
1866
|
+
return name || defaultName;
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1735
1869
|
// src/shared/ssr/fetch-headers.ts
|
|
1736
1870
|
function remoteFetchHeaders() {
|
|
1737
1871
|
return {
|
|
@@ -1859,7 +1993,7 @@ function useShadowRoot({
|
|
|
1859
1993
|
return { shadowRoot, shadowRootContainerRef };
|
|
1860
1994
|
}
|
|
1861
1995
|
|
|
1862
|
-
// src/react/utils/
|
|
1996
|
+
// src/react/utils/extract-remote-html.ts
|
|
1863
1997
|
var DUMMY_FALLBACK = "http://remote-components-dummy-fallback";
|
|
1864
1998
|
function getRemoteComponentHtml(html) {
|
|
1865
1999
|
if (typeof document === "undefined")
|
|
@@ -1903,20 +2037,10 @@ function RemoteComponent({
|
|
|
1903
2037
|
resolveClientUrl: _resolveClientUrl
|
|
1904
2038
|
}) {
|
|
1905
2039
|
const instanceId = useId();
|
|
1906
|
-
const name = useMemo2(
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
typeof document !== "undefined" ? location.href : DUMMY_FALLBACK
|
|
1911
|
-
);
|
|
1912
|
-
if (url2.hash) {
|
|
1913
|
-
return url2.hash.slice(1);
|
|
1914
|
-
}
|
|
1915
|
-
} else if (typeof src === "object" && "hash" in src && src.hash) {
|
|
1916
|
-
return src.hash.slice(1) || nameProp;
|
|
1917
|
-
}
|
|
1918
|
-
return nameProp;
|
|
1919
|
-
}, [src, nameProp]);
|
|
2040
|
+
const name = useMemo2(
|
|
2041
|
+
() => resolveNameFromSrc(src, nameProp),
|
|
2042
|
+
[src, nameProp]
|
|
2043
|
+
);
|
|
1920
2044
|
const [data, setData] = useState2(null);
|
|
1921
2045
|
const url = useMemo2(() => getClientOrServerUrl(src, DUMMY_FALLBACK), [src]);
|
|
1922
2046
|
const resolveClientUrl = useResolveClientUrl(_resolveClientUrl, url.href);
|
|
@@ -1949,13 +2073,10 @@ function RemoteComponent({
|
|
|
1949
2073
|
return elements;
|
|
1950
2074
|
})() : []
|
|
1951
2075
|
);
|
|
1952
|
-
const
|
|
2076
|
+
const hostStateRef = useRef2(createHostState());
|
|
1953
2077
|
const componentHydrationHtml = useRef2(null);
|
|
1954
|
-
const prevIsRemoteComponentRef = useRef2(false);
|
|
1955
|
-
const prevUrlRef = useRef2(null);
|
|
1956
2078
|
const prevRemoteComponentContainerRef = useRef2(null);
|
|
1957
2079
|
const unmountRef = useRef2(null);
|
|
1958
|
-
const prevNameRef = useRef2(void 0);
|
|
1959
2080
|
useLayoutEffect2(() => {
|
|
1960
2081
|
const shadowRootKey = `__remote_components_shadowroot_${keySuffix}`;
|
|
1961
2082
|
return () => {
|
|
@@ -1994,14 +2115,18 @@ function RemoteComponent({
|
|
|
1994
2115
|
}
|
|
1995
2116
|
}, [shadowRoot, remoteComponent, name]);
|
|
1996
2117
|
useEffect(() => {
|
|
1997
|
-
if (src && src !==
|
|
1998
|
-
const previousSrc =
|
|
1999
|
-
const previousName =
|
|
2000
|
-
|
|
2118
|
+
if (src && src !== hostStateRef.current.prevSrc) {
|
|
2119
|
+
const previousSrc = hostStateRef.current.prevSrc;
|
|
2120
|
+
const previousName = hostStateRef.current.prevName;
|
|
2121
|
+
hostStateRef.current.prevSrc = src;
|
|
2001
2122
|
if (previousSrc !== null) {
|
|
2002
2123
|
htmlRef.current = null;
|
|
2003
2124
|
}
|
|
2125
|
+
hostStateRef.current.abortController?.abort();
|
|
2126
|
+
hostStateRef.current.abortController = new AbortController();
|
|
2127
|
+
const { signal } = hostStateRef.current.abortController;
|
|
2004
2128
|
onBeforeLoad?.(src);
|
|
2129
|
+
hostStateRef.current.stage = "loading";
|
|
2005
2130
|
startTransition(async () => {
|
|
2006
2131
|
try {
|
|
2007
2132
|
let html = getRemoteComponentHtml(
|
|
@@ -2015,59 +2140,41 @@ function RemoteComponent({
|
|
|
2015
2140
|
resolveClientUrl?.(url.href) ?? url.href,
|
|
2016
2141
|
location.href
|
|
2017
2142
|
);
|
|
2018
|
-
const abortController = new AbortController();
|
|
2019
2143
|
const res = await fetchWithHooks(resolvedUrl, fetchInit, {
|
|
2020
2144
|
onRequest,
|
|
2021
2145
|
onResponse,
|
|
2022
|
-
abortController
|
|
2146
|
+
abortController: hostStateRef.current.abortController
|
|
2023
2147
|
});
|
|
2024
2148
|
if (!res || !res.ok) {
|
|
2025
2149
|
throw await errorFromFailedFetch(url.href, resolvedUrl, res);
|
|
2026
2150
|
}
|
|
2027
2151
|
const remoteHtml = await res.text();
|
|
2152
|
+
if (signal.aborted)
|
|
2153
|
+
return;
|
|
2028
2154
|
htmlRef.current = remoteHtml;
|
|
2029
2155
|
html = getRemoteComponentHtml(remoteHtml);
|
|
2030
2156
|
}
|
|
2157
|
+
if (signal.aborted)
|
|
2158
|
+
return;
|
|
2031
2159
|
const parser = new DOMParser();
|
|
2032
2160
|
const doc = parser.parseFromString(html, "text/html");
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
) || doc.querySelectorAll("remote-component:not([src])").length > 1 && !doc.querySelector(`remote-component[name="${name}"]`)) {
|
|
2036
|
-
throw multipleRemoteComponentsError(url.href);
|
|
2037
|
-
}
|
|
2038
|
-
const component = doc.querySelector(`div[data-bundle][data-route][id^="${name}"]`) ?? // fallback to the first element with the data-bundle and data-route attributes when not using a named remote component
|
|
2039
|
-
doc.querySelector("div[data-bundle][data-route]") ?? // fallback to Next.js Pages Router
|
|
2040
|
-
doc.querySelector("div#__next") ?? // fallback to the remote-component web component
|
|
2041
|
-
doc.querySelector(`remote-component[name="${name}"]:not([src])`) ?? doc.querySelector("remote-component:not([src])");
|
|
2042
|
-
const nextData = JSON.parse(
|
|
2043
|
-
(doc.querySelector("#__NEXT_DATA__") ?? doc.querySelector("#__REMOTE_NEXT_DATA__"))?.textContent ?? "null"
|
|
2044
|
-
);
|
|
2045
|
-
const remoteName = component?.getAttribute("id")?.replace(/_ssr$/, "") || (nextData ? "__next" : name);
|
|
2046
|
-
const rsc = doc.querySelector(`#${remoteName}_rsc`);
|
|
2047
|
-
const bundle = component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || "default";
|
|
2048
|
-
const isRemoteComponent = component?.tagName.toLowerCase() === "remote-component";
|
|
2049
|
-
const metadata = {
|
|
2161
|
+
const {
|
|
2162
|
+
component,
|
|
2050
2163
|
name: remoteName,
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
if (!component || !(rsc || nextData || isRemoteComponent)) {
|
|
2061
|
-
throw new RemoteComponentsError(
|
|
2062
|
-
`Remote Component not found on ${url.href}.${remoteName !== "__vercel_remote_component" ? `The name for the <RemoteComponent> is "${remoteName}". Check <RemoteComponent> usage.` : ""} Did you forget to wrap the content in <RemoteComponent>?`
|
|
2063
|
-
);
|
|
2064
|
-
}
|
|
2065
|
-
if (prevIsRemoteComponentRef.current) {
|
|
2164
|
+
isRemoteComponent,
|
|
2165
|
+
metadata,
|
|
2166
|
+
nextData,
|
|
2167
|
+
rsc,
|
|
2168
|
+
remoteShared,
|
|
2169
|
+
links: linkElements,
|
|
2170
|
+
scripts: scriptElements
|
|
2171
|
+
} = parseRemoteComponentDocument(doc, name, url);
|
|
2172
|
+
if (hostStateRef.current.prevIsRemoteComponent) {
|
|
2066
2173
|
if (shadowRoot) {
|
|
2067
2174
|
shadowRoot.innerHTML = "";
|
|
2068
2175
|
}
|
|
2069
2176
|
const self = globalThis;
|
|
2070
|
-
const prevUrl =
|
|
2177
|
+
const prevUrl = hostStateRef.current.prevUrl;
|
|
2071
2178
|
if (prevUrl && self.__remote_script_entrypoint_unmount__?.[prevUrl.href]) {
|
|
2072
2179
|
const unmountPromises = Promise.all(
|
|
2073
2180
|
Array.from(unmountRef.current ?? []).map(
|
|
@@ -2080,15 +2187,11 @@ function RemoteComponent({
|
|
|
2080
2187
|
await unmountPromises;
|
|
2081
2188
|
}
|
|
2082
2189
|
}
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2190
|
+
hostStateRef.current.prevIsRemoteComponent = isRemoteComponent;
|
|
2191
|
+
hostStateRef.current.prevUrl = url;
|
|
2192
|
+
hostStateRef.current.prevName = remoteName;
|
|
2086
2193
|
applyOriginToNodes(doc, url, resolveClientUrl);
|
|
2087
|
-
const links =
|
|
2088
|
-
doc.querySelectorAll("link[href]")
|
|
2089
|
-
).filter((link) => {
|
|
2090
|
-
return !component.contains(link);
|
|
2091
|
-
}).map((link) => ({
|
|
2194
|
+
const links = linkElements.map((link) => ({
|
|
2092
2195
|
href: new URL(link.getAttribute("href") ?? link.href, url).href,
|
|
2093
2196
|
...link.getAttributeNames().reduce((acc, key) => {
|
|
2094
2197
|
if (key !== "href") {
|
|
@@ -2097,7 +2200,7 @@ function RemoteComponent({
|
|
|
2097
2200
|
return acc;
|
|
2098
2201
|
}, {})
|
|
2099
2202
|
}));
|
|
2100
|
-
const scripts =
|
|
2203
|
+
const scripts = scriptElements;
|
|
2101
2204
|
const inlineScripts = (isRemoteComponent ? component : doc).querySelectorAll(
|
|
2102
2205
|
"script:not([src]):not([data-src]):not([id*='_rsc']):not([id='__NEXT_DATA__']):not([id='__REMOTE_NEXT_DATA__'])"
|
|
2103
2206
|
);
|
|
@@ -2188,7 +2291,7 @@ function RemoteComponent({
|
|
|
2188
2291
|
);
|
|
2189
2292
|
}
|
|
2190
2293
|
if (isRemoteComponent) {
|
|
2191
|
-
if (previousSrc !==
|
|
2294
|
+
if (previousSrc !== void 0) {
|
|
2192
2295
|
onChange?.({
|
|
2193
2296
|
previousSrc,
|
|
2194
2297
|
nextSrc: src,
|
|
@@ -2240,12 +2343,13 @@ function RemoteComponent({
|
|
|
2240
2343
|
);
|
|
2241
2344
|
onLoad?.(src);
|
|
2242
2345
|
}
|
|
2346
|
+
hostStateRef.current.stage = "loaded";
|
|
2243
2347
|
} else {
|
|
2244
2348
|
const result = await loadRemoteComponent({
|
|
2245
2349
|
url,
|
|
2246
2350
|
name: remoteName,
|
|
2247
2351
|
rscName,
|
|
2248
|
-
bundle,
|
|
2352
|
+
bundle: metadata.bundle,
|
|
2249
2353
|
route: metadata.route,
|
|
2250
2354
|
runtime: metadata.runtime,
|
|
2251
2355
|
data: newData.data,
|
|
@@ -2280,7 +2384,7 @@ function RemoteComponent({
|
|
|
2280
2384
|
rsc.remove();
|
|
2281
2385
|
}
|
|
2282
2386
|
setData(newData);
|
|
2283
|
-
if (previousSrc !==
|
|
2387
|
+
if (previousSrc !== void 0) {
|
|
2284
2388
|
onChange?.({
|
|
2285
2389
|
previousSrc,
|
|
2286
2390
|
nextSrc: src,
|
|
@@ -2289,17 +2393,21 @@ function RemoteComponent({
|
|
|
2289
2393
|
});
|
|
2290
2394
|
}
|
|
2291
2395
|
if (result.error) {
|
|
2396
|
+
hostStateRef.current.stage = "error";
|
|
2292
2397
|
setRemoteComponent(result.error);
|
|
2293
2398
|
onError?.(result.error);
|
|
2294
2399
|
} else {
|
|
2400
|
+
hostStateRef.current.stage = "loaded";
|
|
2295
2401
|
setRemoteComponent(result.component);
|
|
2296
2402
|
onLoad?.(src);
|
|
2297
2403
|
}
|
|
2298
2404
|
}
|
|
2299
2405
|
} catch (error) {
|
|
2300
2406
|
if (isAbortError(error)) {
|
|
2407
|
+
hostStateRef.current.stage = "idle";
|
|
2301
2408
|
return;
|
|
2302
2409
|
}
|
|
2410
|
+
hostStateRef.current.stage = "error";
|
|
2303
2411
|
setRemoteComponent(error);
|
|
2304
2412
|
onError?.(error);
|
|
2305
2413
|
}
|
|
@@ -2330,7 +2438,7 @@ function RemoteComponent({
|
|
|
2330
2438
|
name: data?.name || name,
|
|
2331
2439
|
bundle: data?.bundle || "default",
|
|
2332
2440
|
route: data?.route || DEFAULT_ROUTE,
|
|
2333
|
-
runtime:
|
|
2441
|
+
runtime: hostStateRef.current.prevIsRemoteComponent ? RUNTIME_SCRIPT : data?.runtime || RUNTIME_WEBPACK
|
|
2334
2442
|
}) });
|
|
2335
2443
|
const resetStyle = reset ? /* @__PURE__ */ jsx2("style", { "data-remote-components-reset": "react", children: `:host { all: initial; }` }) : null;
|
|
2336
2444
|
const linksToRender = data?.links?.map((link) => /* @__PURE__ */ createElement2(
|
|
@@ -2349,7 +2457,7 @@ function RemoteComponent({
|
|
|
2349
2457
|
if (componentHydrationHtml.current && shadowRoot && !shadowRoot.innerHTML) {
|
|
2350
2458
|
shadowRoot.innerHTML = componentHydrationHtml.current;
|
|
2351
2459
|
componentHydrationHtml.current = null;
|
|
2352
|
-
if (
|
|
2460
|
+
if (hostStateRef.current.prevIsRemoteComponent) {
|
|
2353
2461
|
loadStaticRemoteComponent(
|
|
2354
2462
|
Array.from(shadowRoot.querySelectorAll("script")),
|
|
2355
2463
|
url,
|