remote-components 0.3.5 → 0.3.6
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/app-63L5THIQ.js +12 -0
- package/dist/app-63L5THIQ.js.map +1 -0
- package/dist/app-A5QE7XRH.cjs +12 -0
- package/dist/app-A5QE7XRH.cjs.map +1 -0
- package/dist/chunk-2VQGCACH.js +190 -0
- package/dist/chunk-2VQGCACH.js.map +1 -0
- package/dist/chunk-42N2ZLE2.js +703 -0
- package/dist/chunk-42N2ZLE2.js.map +1 -0
- package/dist/chunk-6IUP26UK.cjs +57 -0
- package/dist/chunk-6IUP26UK.cjs.map +1 -0
- package/dist/chunk-7MVFHOIP.cjs +60 -0
- package/dist/chunk-7MVFHOIP.cjs.map +1 -0
- package/dist/chunk-CREXMFMF.cjs +155 -0
- package/dist/chunk-CREXMFMF.cjs.map +1 -0
- package/dist/chunk-CTUJSWCM.js +215 -0
- package/dist/chunk-CTUJSWCM.js.map +1 -0
- package/dist/chunk-ENYGL5CO.js +11 -0
- package/dist/chunk-ENYGL5CO.js.map +1 -0
- package/dist/chunk-ER73O65F.cjs +703 -0
- package/dist/chunk-ER73O65F.cjs.map +1 -0
- package/dist/chunk-F44NODUS.cjs +709 -0
- package/dist/chunk-F44NODUS.cjs.map +1 -0
- package/dist/chunk-GAXJTFBV.js +20 -0
- package/dist/chunk-GAXJTFBV.js.map +1 -0
- package/dist/chunk-HNZVEIKN.js +358 -0
- package/dist/chunk-HNZVEIKN.js.map +1 -0
- package/dist/chunk-KE7QPAQ4.cjs +21 -0
- package/dist/chunk-KE7QPAQ4.cjs.map +1 -0
- package/dist/chunk-KEPHL25S.js +60 -0
- package/dist/chunk-KEPHL25S.js.map +1 -0
- package/dist/chunk-KKBEMQU7.cjs +670 -0
- package/dist/chunk-KKBEMQU7.cjs.map +1 -0
- package/dist/chunk-KYJWRZ2B.js +709 -0
- package/dist/chunk-KYJWRZ2B.js.map +1 -0
- package/dist/chunk-N5VQR2PW.cjs +215 -0
- package/dist/chunk-N5VQR2PW.cjs.map +1 -0
- package/dist/chunk-OO4AMJWO.js +155 -0
- package/dist/chunk-OO4AMJWO.js.map +1 -0
- package/dist/chunk-R4QFK5TN.cjs +358 -0
- package/dist/chunk-R4QFK5TN.cjs.map +1 -0
- package/dist/chunk-RUWR74XQ.cjs +152 -0
- package/dist/chunk-RUWR74XQ.cjs.map +1 -0
- package/dist/chunk-S2A4TFLS.js +152 -0
- package/dist/chunk-S2A4TFLS.js.map +1 -0
- package/dist/chunk-SHFJ5OQA.cjs +11 -0
- package/dist/chunk-SHFJ5OQA.cjs.map +1 -0
- package/dist/chunk-TCFLEBQM.cjs +20 -0
- package/dist/chunk-TCFLEBQM.cjs.map +1 -0
- package/dist/chunk-W5ESPGHH.js +670 -0
- package/dist/chunk-W5ESPGHH.js.map +1 -0
- package/dist/chunk-X6YKUJKH.js +21 -0
- package/dist/chunk-X6YKUJKH.js.map +1 -0
- package/dist/chunk-XCFYWSLD.cjs +190 -0
- package/dist/chunk-XCFYWSLD.cjs.map +1 -0
- package/dist/chunk-ZPMTZ3KJ.js +57 -0
- package/dist/chunk-ZPMTZ3KJ.js.map +1 -0
- package/dist/config/nextjs.cjs +76 -351
- package/dist/config/nextjs.cjs.map +1 -1
- package/dist/config/nextjs.js +26 -266
- package/dist/config/nextjs.js.map +1 -1
- package/dist/config/webpack.cjs +12 -240
- package/dist/config/webpack.cjs.map +1 -1
- package/dist/config/webpack.js +6 -207
- package/dist/config/webpack.js.map +1 -1
- package/dist/host/html.cjs +128 -2494
- package/dist/host/html.cjs.map +1 -1
- package/dist/host/html.js +45 -2382
- package/dist/host/html.js.map +1 -1
- package/dist/host/nextjs/app/client-only.cjs +53 -2939
- package/dist/host/nextjs/app/client-only.cjs.map +1 -1
- package/dist/host/nextjs/app/client-only.js +31 -2894
- package/dist/host/nextjs/app/client-only.js.map +1 -1
- package/dist/host/proxy/client.cjs +8 -38
- package/dist/host/proxy/client.cjs.map +1 -1
- package/dist/host/proxy/client.js +4 -7
- package/dist/host/proxy/client.js.map +1 -1
- package/dist/host/proxy.cjs +19 -56
- package/dist/host/proxy.cjs.map +1 -1
- package/dist/host/proxy.js +8 -20
- package/dist/host/proxy.js.map +1 -1
- package/dist/host/react.cjs +17 -2870
- package/dist/host/react.cjs.map +1 -1
- package/dist/host/react.js +13 -2837
- package/dist/host/react.js.map +1 -1
- package/dist/internal/host/server/fetch-remote-component.cjs +1 -18
- package/dist/internal/host/server/fetch-remote-component.cjs.map +1 -1
- package/dist/internal/host/server/fetch-remote-component.js +1 -18
- package/dist/internal/host/server/fetch-remote-component.js.map +1 -1
- package/dist/internal/runtime/loaders/component-loader.cjs +5 -2
- package/dist/internal/runtime/loaders/component-loader.cjs.map +1 -1
- package/dist/internal/runtime/loaders/component-loader.js +5 -2
- package/dist/internal/runtime/loaders/component-loader.js.map +1 -1
- package/dist/internal/runtime/turbopack/remote-scope.cjs +1 -5
- package/dist/internal/runtime/turbopack/remote-scope.cjs.map +1 -1
- package/dist/internal/runtime/turbopack/remote-scope.js +1 -5
- package/dist/internal/runtime/turbopack/remote-scope.js.map +1 -1
- package/dist/internal/utils.cjs +1 -1
- package/dist/internal/utils.cjs.map +1 -1
- package/dist/internal/utils.d.ts +5 -5
- package/dist/internal/utils.js +1 -1
- package/dist/internal/utils.js.map +1 -1
- package/dist/remote/html.cjs +15 -314
- package/dist/remote/html.cjs.map +1 -1
- package/dist/remote/html.js +7 -305
- package/dist/remote/html.js.map +1 -1
- package/dist/remote/middleware.cjs +16 -41
- package/dist/remote/middleware.cjs.map +1 -1
- package/dist/script-6W5JRBZK.cjs +26 -0
- package/dist/script-6W5JRBZK.cjs.map +1 -0
- package/dist/script-IFEBOLIA.js +26 -0
- package/dist/script-IFEBOLIA.js.map +1 -0
- package/dist/static-loader-X4TSF5KW.js +11 -0
- package/dist/static-loader-X4TSF5KW.js.map +1 -0
- package/dist/static-loader-ZYD5BO4D.cjs +11 -0
- package/dist/static-loader-ZYD5BO4D.cjs.map +1 -0
- package/dist/turbopack-NPGO3MWS.js +55 -0
- package/dist/turbopack-NPGO3MWS.js.map +1 -0
- package/dist/turbopack-WRMKPNN4.cjs +55 -0
- package/dist/turbopack-WRMKPNN4.cjs.map +1 -0
- package/dist/webpack-DUBHPYD6.js +92 -0
- package/dist/webpack-DUBHPYD6.js.map +1 -0
- package/dist/webpack-KSCMCL7M.cjs +92 -0
- package/dist/webpack-KSCMCL7M.cjs.map +1 -0
- package/package.json +9 -2
|
@@ -39,7 +39,6 @@ var import_get_client_src = require("#internal/host/server/get-client-src");
|
|
|
39
39
|
var import_get_ssr_relative_path_base_url = require("#internal/host/server/get-ssr-relative-path-base-url");
|
|
40
40
|
var import_metadata = require("#internal/runtime/metadata");
|
|
41
41
|
var import_rsc_imports = require("#internal/runtime/rsc-imports");
|
|
42
|
-
var import_utils = require("#internal/utils");
|
|
43
42
|
var import_error = require("#internal/utils/error");
|
|
44
43
|
async function buildRscComponent(rsc, serverUrl) {
|
|
45
44
|
const componentRSC = `0:${JSON.stringify(rsc)}
|
|
@@ -83,9 +82,6 @@ function buildSkeletonResponse(serverUrl, metadata, skeletonComponent) {
|
|
|
83
82
|
remoteShared: {}
|
|
84
83
|
};
|
|
85
84
|
}
|
|
86
|
-
function scopeChunkReferences(chunk, bundle, scopedName) {
|
|
87
|
-
return chunk.replaceAll(`[${bundle}]`, `[${scopedName}]`);
|
|
88
|
-
}
|
|
89
85
|
function visitFragment(fragment, serverUrl, remoteName) {
|
|
90
86
|
const scriptSrcSet = /* @__PURE__ */ new Set();
|
|
91
87
|
const scriptTextSet = /* @__PURE__ */ new Set();
|
|
@@ -100,7 +96,6 @@ function visitFragment(fragment, serverUrl, remoteName) {
|
|
|
100
96
|
let hasRSC = false;
|
|
101
97
|
let hasShared = false;
|
|
102
98
|
let error;
|
|
103
|
-
const isCrossOrigin = serverUrl.origin !== (0, import_get_ssr_relative_path_base_url.getSSRRelativePathBaseUrl)();
|
|
104
99
|
const rawRscChunks = [];
|
|
105
100
|
const rsc = (0, import_dom_flight.visit)(fragment, {
|
|
106
101
|
url: serverUrl,
|
|
@@ -159,19 +154,7 @@ function visitFragment(fragment, serverUrl, remoteName) {
|
|
|
159
154
|
}
|
|
160
155
|
}
|
|
161
156
|
});
|
|
162
|
-
|
|
163
|
-
const scopedName = (0, import_utils.computeScopedName)(metadata.bundle, {
|
|
164
|
-
remoteHost: serverUrl.host,
|
|
165
|
-
isCrossOrigin: true
|
|
166
|
-
});
|
|
167
|
-
for (const chunk of rawRscChunks) {
|
|
168
|
-
hydrationData.push(
|
|
169
|
-
scopeChunkReferences(chunk, metadata.bundle, scopedName)
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
} else {
|
|
173
|
-
hydrationData.push(...rawRscChunks);
|
|
174
|
-
}
|
|
157
|
+
hydrationData.push(...rawRscChunks);
|
|
175
158
|
if (error) {
|
|
176
159
|
throw error;
|
|
177
160
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/host/server/fetch-remote-component.ts"],"sourcesContent":["import { type DefaultTreeAdapterMap, Parser } from 'parse5';\nimport { type RSC, visit } from '#internal/host/nextjs/dom-flight';\nimport {\n getSkeletonHtml,\n getSkeletonMessage,\n} from '#internal/host/nextjs/skeleton';\nimport { fetchWithHooks } from '#internal/host/server/fetch-with-hooks';\nimport { getClientSrc } from '#internal/host/server/get-client-src';\nimport { getSSRRelativePathBaseUrl } from '#internal/host/server/get-ssr-relative-path-base-url';\nimport type {\n LinkDescriptor,\n ScriptDescriptor,\n} from '#internal/host/shared/asset-descriptors';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport {\n buildMetadata,\n type RawMetadataAttrs,\n type RemoteComponentMetadata,\n} from '#internal/runtime/metadata';\nimport { importRSCClientEdge } from '#internal/runtime/rsc-imports';\nimport { computeScopedName } from '#internal/utils';\nimport {\n failedToFetchRemoteComponentError,\n multipleRemoteComponentsError,\n RemoteComponentsError,\n} from '#internal/utils/error';\nimport type { FetchRemoteComponentResponse, NextData } from './types';\n\n/**\n * Converts RSC flight data into a React element tree using the edge streaming\n * runtime. The manifest tells React how to resolve module references back to\n * the remote origin.\n */\nasync function buildRscComponent(\n rsc: RSC | RSC[] | string | null,\n serverUrl: URL,\n): Promise<React.ReactNode> {\n const componentRSC = `0:${JSON.stringify(rsc)}\\n`;\n const { createFromReadableStream } = await importRSCClientEdge();\n return createFromReadableStream(\n new ReadableStream({\n type: 'bytes',\n start(controller) {\n const encoder = new TextEncoder();\n controller.enqueue(encoder.encode(componentRSC));\n controller.close();\n },\n }),\n {\n serverConsumerManifest: {\n moduleLoading: {\n prefix: serverUrl.origin,\n crossOrigin: true,\n },\n moduleMap: {},\n },\n },\n );\n}\n\nfunction buildSkeletonResponse(\n serverUrl: URL,\n metadata: RemoteComponentMetadata,\n skeletonComponent: React.ReactNode | undefined,\n): FetchRemoteComponentResponse {\n return {\n name: 'remote-component-skeleton',\n serverUrl,\n metadata: {\n ...metadata,\n type: 'remote-component',\n },\n rsc: getSkeletonMessage(),\n scripts: [],\n links: [],\n hydrationData: [],\n nextData: undefined,\n component: skeletonComponent,\n html: getSkeletonHtml(serverUrl.href),\n remoteShared: {},\n };\n}\n\n/**\n * Rewrites the bundle identifier in RSC flight data from the plain bundle\n * name to the origin-qualified scoped name. When multiple remotes share the\n * same bundle name (e.g. production and preview of the same app), this\n * makes each one unique so the client can look up the correct RemoteScope\n * by name alone.\n *\n * `[bundle] /path` → `[scopedName] /path`\n * `[bundle] 12345` → `[scopedName] 12345`\n *\n * Only applied for cross-origin remotes — same-origin chunks keep the\n * plain bundle name since there's no ambiguity.\n */\nfunction scopeChunkReferences(\n chunk: string,\n bundle: string,\n scopedName: string,\n): string {\n return chunk.replaceAll(`[${bundle}]`, `[${scopedName}]`);\n}\n\n/**\n * Walks the parsed HTML fragment and extracts all remote component data:\n * metadata, scripts, links, hydration data, Next.js data, shared deps, and HTML.\n */\nfunction visitFragment(\n fragment: DefaultTreeAdapterMap['documentFragment'],\n serverUrl: URL,\n remoteName: string | undefined,\n) {\n const scriptSrcSet = new Set<string>();\n const scriptTextSet = new Set<string>();\n const scripts: ScriptDescriptor[] = [];\n\n const linkKeySet = new Set<string>();\n const links: LinkDescriptor[] = [];\n\n const hydrationData: string[] = [];\n const htmlChunks = new Set<string>();\n\n let metadata: RemoteComponentMetadata | undefined;\n let nextData: NextData | undefined;\n let remoteShared: Record<string, string> = {};\n let hasRSC = false;\n let hasShared = false;\n let error: RemoteComponentsError | undefined;\n\n // For cross-origin remotes, rewrite bundle identifiers in RSC chunks to\n // the scoped name so the client dispatchers resolve the correct scope.\n // Chunks are collected raw during visit() and rewritten afterwards because\n // RSC script tags appear before the metadata element in the HTML.\n const isCrossOrigin = serverUrl.origin !== getSSRRelativePathBaseUrl();\n\n const rawRscChunks: string[] = [];\n\n const rsc = visit(fragment, {\n url: serverUrl,\n name: remoteName,\n onMetadata(attrs: RawMetadataAttrs) {\n const incoming = buildMetadata(attrs, serverUrl);\n // Skip multiple component detection for Pages Router (__next) since\n // it only supports one remote component per page\n if (\n !remoteName &&\n metadata &&\n metadata.id !== incoming.id &&\n incoming.id !== '__next' &&\n metadata.id !== '__next' &&\n !nextData\n ) {\n throw multipleRemoteComponentsError(serverUrl.href);\n }\n metadata = incoming;\n },\n onScript(attrs) {\n const clientSrc = getClientSrc(attrs.src, serverUrl.href);\n const textContent =\n typeof attrs.textContent === 'string' ? attrs.textContent : undefined;\n\n if (textContent) {\n if (!scriptTextSet.has(textContent)) {\n scriptTextSet.add(textContent);\n scripts.push({ src: '', textContent });\n }\n } else if (!scriptSrcSet.has(clientSrc)) {\n scriptSrcSet.add(clientSrc);\n scripts.push({ src: clientSrc });\n }\n },\n onLink(attrs) {\n const relativeAttrs = {\n ...attrs,\n href: getClientSrc(attrs.href, serverUrl.href),\n };\n const linkKey = `${relativeAttrs.href}::${attrs.rel}`;\n if (!linkKeySet.has(linkKey)) {\n linkKeySet.add(linkKey);\n links.push(relativeAttrs);\n }\n },\n onRSC(chunk) {\n rawRscChunks.push(chunk);\n hasRSC = true;\n },\n onNextData(data) {\n nextData = data;\n },\n onHTML(chunk) {\n if (!htmlChunks.has(chunk)) {\n htmlChunks.add(chunk);\n }\n },\n onShared(_shared) {\n remoteShared = _shared;\n hasShared = true;\n },\n onError(message, stack) {\n error = new RemoteComponentsError(message);\n if (stack) {\n error.stack = stack;\n }\n },\n });\n\n // Rewrite bundle identifiers in RSC chunk references to use the scoped name\n // so the client dispatchers can resolve the correct scope with a direct lookup.\n // This must happen after visit() because RSC script tags appear before the\n // metadata element in the HTML.\n if (isCrossOrigin && metadata?.bundle) {\n const scopedName = computeScopedName(metadata.bundle, {\n remoteHost: serverUrl.host,\n isCrossOrigin: true,\n });\n for (const chunk of rawRscChunks) {\n hydrationData.push(\n scopeChunkReferences(chunk, metadata.bundle, scopedName),\n );\n }\n } else {\n hydrationData.push(...rawRscChunks);\n }\n\n if (error) {\n throw error;\n }\n\n if (metadata) {\n if (!hasRSC && !nextData && metadata.type === 'nextjs') {\n throw new RemoteComponentsError(\n `The Remote Component at \"${serverUrl.href}\" seems to be a Next.js component but it does not contain any RSC flight data or Next.js props data. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n if (\n metadata.type === 'nextjs' &&\n !hasShared &&\n !nextData?.props.__REMOTE_COMPONENT__?.shared\n ) {\n throw new RemoteComponentsError(\n `No shared dependencies found for Remote Component at \"${serverUrl.href}\". Make sure the remote URL is correct and contains a Remote Component with shared dependencies.`,\n );\n }\n }\n\n const resolvedShared =\n nextData?.props.__REMOTE_COMPONENT__?.shared ?? remoteShared;\n\n return {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared: resolvedShared,\n html: Array.from(htmlChunks).join(''),\n };\n}\n\nexport async function fetchRemoteComponent(\n src: string | URL,\n options: {\n name?: string;\n rsc?: boolean;\n /** Whether this is being called from Next.js App Router. Used to enable skeleton fallback during SSG builds. */\n appRouter?: boolean;\n onRequest?: OnRequestHook;\n onResponse?: OnResponseHook;\n } = {},\n): Promise<FetchRemoteComponentResponse> {\n const ssrRelativePathBaseUrl = getSSRRelativePathBaseUrl();\n const serverUrl = new URL(src, ssrRelativePathBaseUrl);\n\n const tags = [\n '_vc_rc:fetch-remote-component',\n // the max size of a next cache tag is 256 characters\n serverUrl.host.slice(0, 256),\n // use the suffix so this tag is unique if multiple remote\n // components have the same host, but unique pathnames / query params\n (typeof src === 'string' ? src : src.href).slice(-256),\n ];\n if (options.name) {\n tags.push(options.name.slice(-256));\n }\n\n const fetchInit = {\n next: {\n tags,\n },\n };\n\n const res = await fetchWithHooks(serverUrl, fetchInit, {\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n });\n\n // If there is an error in the remote, parse and extract the remote error (except 404 and 401).\n if (!res.ok && !res.body) {\n throw failedToFetchRemoteComponentError(serverUrl.href, res);\n }\n\n if (res.status === 401) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'If you are using Deployment Protection, ensure the automation bypass environment variable secret in the host matches an automation bypass value in the remote. See https://remote-components-docs.vercel.sh/docs/concepts/cors-external-urls#deployment-protection for details.',\n );\n }\n\n if (res.status === 404) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'Check if you can open it in the browser.',\n );\n }\n\n // create a parser for the HTML response\n const parser = Parser.getFragmentParser<DefaultTreeAdapterMap>();\n\n if (!res.body) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `Response body is empty. Check if you can open it in the browser and you see the Remote Component content.`,\n );\n }\n\n const decoder = new TextDecoder();\n // read the response body as a stream and parse it using the parse5 fragment parser\n for await (const chunk of res.body as unknown as AsyncIterable<Uint8Array>) {\n parser.tokenizer.write(decoder.decode(chunk), false);\n }\n const fragment = parser.getFragment();\n\n const remoteName =\n options.name || (serverUrl.hash ? serverUrl.hash.substring(1) : undefined);\n\n const {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared,\n html,\n } = visitFragment(fragment, serverUrl, remoteName);\n\n if (!metadata) {\n // For microfrontend builds during run time, the host and remote build\n // may be happening concurrently. In this case, the request will 404.\n // We want to allow the build to continue with a placeholder remote\n // component. Once the build completes, vercel will automatically revalidate\n // ISR and fetch the built remote component.\n const isSSGBuild = process.env.NEXT_PHASE === 'phase-production-build';\n // If the remote component is part of a microfrontend, the src provided\n // will be relative.\n const isSSRRelativePathBase =\n serverUrl.host === new URL(ssrRelativePathBaseUrl).host;\n // Only want this skeleton behaviour in previews to unblock development.\n // For production, the remote component should already be built.\n const isPreview = process.env.VERCEL_TARGET_ENV === 'preview';\n\n if (isSSGBuild && isSSRRelativePathBase && isPreview && options.appRouter) {\n let skeletonComponent: React.ReactNode | undefined;\n if (options.rsc) {\n const { createElement } = await import('react');\n skeletonComponent = createElement('div', {\n dangerouslySetInnerHTML: {\n __html: getSkeletonHtml(serverUrl.href),\n },\n });\n }\n\n return buildSkeletonResponse(\n serverUrl,\n buildMetadata({}, serverUrl),\n skeletonComponent,\n );\n }\n\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `No Remote Component found. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n const name = remoteName || metadata.name;\n const component = options.rsc\n ? await buildRscComponent(rsc, serverUrl)\n : undefined;\n\n return {\n name,\n serverUrl,\n metadata,\n rsc,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n html,\n remoteShared,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/host/server/fetch-remote-component.ts"],"sourcesContent":["import { type DefaultTreeAdapterMap, Parser } from 'parse5';\nimport { type RSC, visit } from '#internal/host/nextjs/dom-flight';\nimport {\n getSkeletonHtml,\n getSkeletonMessage,\n} from '#internal/host/nextjs/skeleton';\nimport { fetchWithHooks } from '#internal/host/server/fetch-with-hooks';\nimport { getClientSrc } from '#internal/host/server/get-client-src';\nimport { getSSRRelativePathBaseUrl } from '#internal/host/server/get-ssr-relative-path-base-url';\nimport type {\n LinkDescriptor,\n ScriptDescriptor,\n} from '#internal/host/shared/asset-descriptors';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport {\n buildMetadata,\n type RawMetadataAttrs,\n type RemoteComponentMetadata,\n} from '#internal/runtime/metadata';\nimport { importRSCClientEdge } from '#internal/runtime/rsc-imports';\nimport {\n failedToFetchRemoteComponentError,\n multipleRemoteComponentsError,\n RemoteComponentsError,\n} from '#internal/utils/error';\nimport type { FetchRemoteComponentResponse, NextData } from './types';\n\n/**\n * Converts RSC flight data into a React element tree using the edge streaming\n * runtime. The manifest tells React how to resolve module references back to\n * the remote origin.\n */\nasync function buildRscComponent(\n rsc: RSC | RSC[] | string | null,\n serverUrl: URL,\n): Promise<React.ReactNode> {\n const componentRSC = `0:${JSON.stringify(rsc)}\\n`;\n const { createFromReadableStream } = await importRSCClientEdge();\n return createFromReadableStream(\n new ReadableStream({\n type: 'bytes',\n start(controller) {\n const encoder = new TextEncoder();\n controller.enqueue(encoder.encode(componentRSC));\n controller.close();\n },\n }),\n {\n serverConsumerManifest: {\n moduleLoading: {\n prefix: serverUrl.origin,\n crossOrigin: true,\n },\n moduleMap: {},\n },\n },\n );\n}\n\nfunction buildSkeletonResponse(\n serverUrl: URL,\n metadata: RemoteComponentMetadata,\n skeletonComponent: React.ReactNode | undefined,\n): FetchRemoteComponentResponse {\n return {\n name: 'remote-component-skeleton',\n serverUrl,\n metadata: {\n ...metadata,\n type: 'remote-component',\n },\n rsc: getSkeletonMessage(),\n scripts: [],\n links: [],\n hydrationData: [],\n nextData: undefined,\n component: skeletonComponent,\n html: getSkeletonHtml(serverUrl.href),\n remoteShared: {},\n };\n}\n\n/**\n * Walks the parsed HTML fragment and extracts all remote component data:\n * metadata, scripts, links, hydration data, Next.js data, shared deps, and HTML.\n */\nfunction visitFragment(\n fragment: DefaultTreeAdapterMap['documentFragment'],\n serverUrl: URL,\n remoteName: string | undefined,\n) {\n const scriptSrcSet = new Set<string>();\n const scriptTextSet = new Set<string>();\n const scripts: ScriptDescriptor[] = [];\n\n const linkKeySet = new Set<string>();\n const links: LinkDescriptor[] = [];\n\n const hydrationData: string[] = [];\n const htmlChunks = new Set<string>();\n\n let metadata: RemoteComponentMetadata | undefined;\n let nextData: NextData | undefined;\n let remoteShared: Record<string, string> = {};\n let hasRSC = false;\n let hasShared = false;\n let error: RemoteComponentsError | undefined;\n\n const rawRscChunks: string[] = [];\n\n const rsc = visit(fragment, {\n url: serverUrl,\n name: remoteName,\n onMetadata(attrs: RawMetadataAttrs) {\n const incoming = buildMetadata(attrs, serverUrl);\n // Skip multiple component detection for Pages Router (__next) since\n // it only supports one remote component per page\n if (\n !remoteName &&\n metadata &&\n metadata.id !== incoming.id &&\n incoming.id !== '__next' &&\n metadata.id !== '__next' &&\n !nextData\n ) {\n throw multipleRemoteComponentsError(serverUrl.href);\n }\n metadata = incoming;\n },\n onScript(attrs) {\n const clientSrc = getClientSrc(attrs.src, serverUrl.href);\n const textContent =\n typeof attrs.textContent === 'string' ? attrs.textContent : undefined;\n\n if (textContent) {\n if (!scriptTextSet.has(textContent)) {\n scriptTextSet.add(textContent);\n scripts.push({ src: '', textContent });\n }\n } else if (!scriptSrcSet.has(clientSrc)) {\n scriptSrcSet.add(clientSrc);\n scripts.push({ src: clientSrc });\n }\n },\n onLink(attrs) {\n const relativeAttrs = {\n ...attrs,\n href: getClientSrc(attrs.href, serverUrl.href),\n };\n const linkKey = `${relativeAttrs.href}::${attrs.rel}`;\n if (!linkKeySet.has(linkKey)) {\n linkKeySet.add(linkKey);\n links.push(relativeAttrs);\n }\n },\n onRSC(chunk) {\n rawRscChunks.push(chunk);\n hasRSC = true;\n },\n onNextData(data) {\n nextData = data;\n },\n onHTML(chunk) {\n if (!htmlChunks.has(chunk)) {\n htmlChunks.add(chunk);\n }\n },\n onShared(_shared) {\n remoteShared = _shared;\n hasShared = true;\n },\n onError(message, stack) {\n error = new RemoteComponentsError(message);\n if (stack) {\n error.stack = stack;\n }\n },\n });\n\n hydrationData.push(...rawRscChunks);\n\n if (error) {\n throw error;\n }\n\n if (metadata) {\n if (!hasRSC && !nextData && metadata.type === 'nextjs') {\n throw new RemoteComponentsError(\n `The Remote Component at \"${serverUrl.href}\" seems to be a Next.js component but it does not contain any RSC flight data or Next.js props data. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n if (\n metadata.type === 'nextjs' &&\n !hasShared &&\n !nextData?.props.__REMOTE_COMPONENT__?.shared\n ) {\n throw new RemoteComponentsError(\n `No shared dependencies found for Remote Component at \"${serverUrl.href}\". Make sure the remote URL is correct and contains a Remote Component with shared dependencies.`,\n );\n }\n }\n\n const resolvedShared =\n nextData?.props.__REMOTE_COMPONENT__?.shared ?? remoteShared;\n\n return {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared: resolvedShared,\n html: Array.from(htmlChunks).join(''),\n };\n}\n\nexport async function fetchRemoteComponent(\n src: string | URL,\n options: {\n name?: string;\n rsc?: boolean;\n /** Whether this is being called from Next.js App Router. Used to enable skeleton fallback during SSG builds. */\n appRouter?: boolean;\n onRequest?: OnRequestHook;\n onResponse?: OnResponseHook;\n } = {},\n): Promise<FetchRemoteComponentResponse> {\n const ssrRelativePathBaseUrl = getSSRRelativePathBaseUrl();\n const serverUrl = new URL(src, ssrRelativePathBaseUrl);\n\n const tags = [\n '_vc_rc:fetch-remote-component',\n // the max size of a next cache tag is 256 characters\n serverUrl.host.slice(0, 256),\n // use the suffix so this tag is unique if multiple remote\n // components have the same host, but unique pathnames / query params\n (typeof src === 'string' ? src : src.href).slice(-256),\n ];\n if (options.name) {\n tags.push(options.name.slice(-256));\n }\n\n const fetchInit = {\n next: {\n tags,\n },\n };\n\n const res = await fetchWithHooks(serverUrl, fetchInit, {\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n });\n\n // If there is an error in the remote, parse and extract the remote error (except 404 and 401).\n if (!res.ok && !res.body) {\n throw failedToFetchRemoteComponentError(serverUrl.href, res);\n }\n\n if (res.status === 401) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'If you are using Deployment Protection, ensure the automation bypass environment variable secret in the host matches an automation bypass value in the remote. See https://remote-components-docs.vercel.sh/docs/concepts/cors-external-urls#deployment-protection for details.',\n );\n }\n\n if (res.status === 404) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'Check if you can open it in the browser.',\n );\n }\n\n // create a parser for the HTML response\n const parser = Parser.getFragmentParser<DefaultTreeAdapterMap>();\n\n if (!res.body) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `Response body is empty. Check if you can open it in the browser and you see the Remote Component content.`,\n );\n }\n\n const decoder = new TextDecoder();\n // read the response body as a stream and parse it using the parse5 fragment parser\n for await (const chunk of res.body as unknown as AsyncIterable<Uint8Array>) {\n parser.tokenizer.write(decoder.decode(chunk), false);\n }\n const fragment = parser.getFragment();\n\n const remoteName =\n options.name || (serverUrl.hash ? serverUrl.hash.substring(1) : undefined);\n\n const {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared,\n html,\n } = visitFragment(fragment, serverUrl, remoteName);\n\n if (!metadata) {\n // For microfrontend builds during run time, the host and remote build\n // may be happening concurrently. In this case, the request will 404.\n // We want to allow the build to continue with a placeholder remote\n // component. Once the build completes, vercel will automatically revalidate\n // ISR and fetch the built remote component.\n const isSSGBuild = process.env.NEXT_PHASE === 'phase-production-build';\n // If the remote component is part of a microfrontend, the src provided\n // will be relative.\n const isSSRRelativePathBase =\n serverUrl.host === new URL(ssrRelativePathBaseUrl).host;\n // Only want this skeleton behaviour in previews to unblock development.\n // For production, the remote component should already be built.\n const isPreview = process.env.VERCEL_TARGET_ENV === 'preview';\n\n if (isSSGBuild && isSSRRelativePathBase && isPreview && options.appRouter) {\n let skeletonComponent: React.ReactNode | undefined;\n if (options.rsc) {\n const { createElement } = await import('react');\n skeletonComponent = createElement('div', {\n dangerouslySetInnerHTML: {\n __html: getSkeletonHtml(serverUrl.href),\n },\n });\n }\n\n return buildSkeletonResponse(\n serverUrl,\n buildMetadata({}, serverUrl),\n skeletonComponent,\n );\n }\n\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `No Remote Component found. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n const name = remoteName || metadata.name;\n const component = options.rsc\n ? await buildRscComponent(rsc, serverUrl)\n : undefined;\n\n return {\n name,\n serverUrl,\n metadata,\n rsc,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n html,\n remoteShared,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
buildMetadata
|
|
12
12
|
} from "#internal/runtime/metadata";
|
|
13
13
|
import { importRSCClientEdge } from "#internal/runtime/rsc-imports";
|
|
14
|
-
import { computeScopedName } from "#internal/utils";
|
|
15
14
|
import {
|
|
16
15
|
failedToFetchRemoteComponentError,
|
|
17
16
|
multipleRemoteComponentsError,
|
|
@@ -59,9 +58,6 @@ function buildSkeletonResponse(serverUrl, metadata, skeletonComponent) {
|
|
|
59
58
|
remoteShared: {}
|
|
60
59
|
};
|
|
61
60
|
}
|
|
62
|
-
function scopeChunkReferences(chunk, bundle, scopedName) {
|
|
63
|
-
return chunk.replaceAll(`[${bundle}]`, `[${scopedName}]`);
|
|
64
|
-
}
|
|
65
61
|
function visitFragment(fragment, serverUrl, remoteName) {
|
|
66
62
|
const scriptSrcSet = /* @__PURE__ */ new Set();
|
|
67
63
|
const scriptTextSet = /* @__PURE__ */ new Set();
|
|
@@ -76,7 +72,6 @@ function visitFragment(fragment, serverUrl, remoteName) {
|
|
|
76
72
|
let hasRSC = false;
|
|
77
73
|
let hasShared = false;
|
|
78
74
|
let error;
|
|
79
|
-
const isCrossOrigin = serverUrl.origin !== getSSRRelativePathBaseUrl();
|
|
80
75
|
const rawRscChunks = [];
|
|
81
76
|
const rsc = visit(fragment, {
|
|
82
77
|
url: serverUrl,
|
|
@@ -135,19 +130,7 @@ function visitFragment(fragment, serverUrl, remoteName) {
|
|
|
135
130
|
}
|
|
136
131
|
}
|
|
137
132
|
});
|
|
138
|
-
|
|
139
|
-
const scopedName = computeScopedName(metadata.bundle, {
|
|
140
|
-
remoteHost: serverUrl.host,
|
|
141
|
-
isCrossOrigin: true
|
|
142
|
-
});
|
|
143
|
-
for (const chunk of rawRscChunks) {
|
|
144
|
-
hydrationData.push(
|
|
145
|
-
scopeChunkReferences(chunk, metadata.bundle, scopedName)
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
hydrationData.push(...rawRscChunks);
|
|
150
|
-
}
|
|
133
|
+
hydrationData.push(...rawRscChunks);
|
|
151
134
|
if (error) {
|
|
152
135
|
throw error;
|
|
153
136
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/host/server/fetch-remote-component.ts"],"sourcesContent":["import { type DefaultTreeAdapterMap, Parser } from 'parse5';\nimport { type RSC, visit } from '#internal/host/nextjs/dom-flight';\nimport {\n getSkeletonHtml,\n getSkeletonMessage,\n} from '#internal/host/nextjs/skeleton';\nimport { fetchWithHooks } from '#internal/host/server/fetch-with-hooks';\nimport { getClientSrc } from '#internal/host/server/get-client-src';\nimport { getSSRRelativePathBaseUrl } from '#internal/host/server/get-ssr-relative-path-base-url';\nimport type {\n LinkDescriptor,\n ScriptDescriptor,\n} from '#internal/host/shared/asset-descriptors';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport {\n buildMetadata,\n type RawMetadataAttrs,\n type RemoteComponentMetadata,\n} from '#internal/runtime/metadata';\nimport { importRSCClientEdge } from '#internal/runtime/rsc-imports';\nimport { computeScopedName } from '#internal/utils';\nimport {\n failedToFetchRemoteComponentError,\n multipleRemoteComponentsError,\n RemoteComponentsError,\n} from '#internal/utils/error';\nimport type { FetchRemoteComponentResponse, NextData } from './types';\n\n/**\n * Converts RSC flight data into a React element tree using the edge streaming\n * runtime. The manifest tells React how to resolve module references back to\n * the remote origin.\n */\nasync function buildRscComponent(\n rsc: RSC | RSC[] | string | null,\n serverUrl: URL,\n): Promise<React.ReactNode> {\n const componentRSC = `0:${JSON.stringify(rsc)}\\n`;\n const { createFromReadableStream } = await importRSCClientEdge();\n return createFromReadableStream(\n new ReadableStream({\n type: 'bytes',\n start(controller) {\n const encoder = new TextEncoder();\n controller.enqueue(encoder.encode(componentRSC));\n controller.close();\n },\n }),\n {\n serverConsumerManifest: {\n moduleLoading: {\n prefix: serverUrl.origin,\n crossOrigin: true,\n },\n moduleMap: {},\n },\n },\n );\n}\n\nfunction buildSkeletonResponse(\n serverUrl: URL,\n metadata: RemoteComponentMetadata,\n skeletonComponent: React.ReactNode | undefined,\n): FetchRemoteComponentResponse {\n return {\n name: 'remote-component-skeleton',\n serverUrl,\n metadata: {\n ...metadata,\n type: 'remote-component',\n },\n rsc: getSkeletonMessage(),\n scripts: [],\n links: [],\n hydrationData: [],\n nextData: undefined,\n component: skeletonComponent,\n html: getSkeletonHtml(serverUrl.href),\n remoteShared: {},\n };\n}\n\n/**\n * Rewrites the bundle identifier in RSC flight data from the plain bundle\n * name to the origin-qualified scoped name. When multiple remotes share the\n * same bundle name (e.g. production and preview of the same app), this\n * makes each one unique so the client can look up the correct RemoteScope\n * by name alone.\n *\n * `[bundle] /path` → `[scopedName] /path`\n * `[bundle] 12345` → `[scopedName] 12345`\n *\n * Only applied for cross-origin remotes — same-origin chunks keep the\n * plain bundle name since there's no ambiguity.\n */\nfunction scopeChunkReferences(\n chunk: string,\n bundle: string,\n scopedName: string,\n): string {\n return chunk.replaceAll(`[${bundle}]`, `[${scopedName}]`);\n}\n\n/**\n * Walks the parsed HTML fragment and extracts all remote component data:\n * metadata, scripts, links, hydration data, Next.js data, shared deps, and HTML.\n */\nfunction visitFragment(\n fragment: DefaultTreeAdapterMap['documentFragment'],\n serverUrl: URL,\n remoteName: string | undefined,\n) {\n const scriptSrcSet = new Set<string>();\n const scriptTextSet = new Set<string>();\n const scripts: ScriptDescriptor[] = [];\n\n const linkKeySet = new Set<string>();\n const links: LinkDescriptor[] = [];\n\n const hydrationData: string[] = [];\n const htmlChunks = new Set<string>();\n\n let metadata: RemoteComponentMetadata | undefined;\n let nextData: NextData | undefined;\n let remoteShared: Record<string, string> = {};\n let hasRSC = false;\n let hasShared = false;\n let error: RemoteComponentsError | undefined;\n\n // For cross-origin remotes, rewrite bundle identifiers in RSC chunks to\n // the scoped name so the client dispatchers resolve the correct scope.\n // Chunks are collected raw during visit() and rewritten afterwards because\n // RSC script tags appear before the metadata element in the HTML.\n const isCrossOrigin = serverUrl.origin !== getSSRRelativePathBaseUrl();\n\n const rawRscChunks: string[] = [];\n\n const rsc = visit(fragment, {\n url: serverUrl,\n name: remoteName,\n onMetadata(attrs: RawMetadataAttrs) {\n const incoming = buildMetadata(attrs, serverUrl);\n // Skip multiple component detection for Pages Router (__next) since\n // it only supports one remote component per page\n if (\n !remoteName &&\n metadata &&\n metadata.id !== incoming.id &&\n incoming.id !== '__next' &&\n metadata.id !== '__next' &&\n !nextData\n ) {\n throw multipleRemoteComponentsError(serverUrl.href);\n }\n metadata = incoming;\n },\n onScript(attrs) {\n const clientSrc = getClientSrc(attrs.src, serverUrl.href);\n const textContent =\n typeof attrs.textContent === 'string' ? attrs.textContent : undefined;\n\n if (textContent) {\n if (!scriptTextSet.has(textContent)) {\n scriptTextSet.add(textContent);\n scripts.push({ src: '', textContent });\n }\n } else if (!scriptSrcSet.has(clientSrc)) {\n scriptSrcSet.add(clientSrc);\n scripts.push({ src: clientSrc });\n }\n },\n onLink(attrs) {\n const relativeAttrs = {\n ...attrs,\n href: getClientSrc(attrs.href, serverUrl.href),\n };\n const linkKey = `${relativeAttrs.href}::${attrs.rel}`;\n if (!linkKeySet.has(linkKey)) {\n linkKeySet.add(linkKey);\n links.push(relativeAttrs);\n }\n },\n onRSC(chunk) {\n rawRscChunks.push(chunk);\n hasRSC = true;\n },\n onNextData(data) {\n nextData = data;\n },\n onHTML(chunk) {\n if (!htmlChunks.has(chunk)) {\n htmlChunks.add(chunk);\n }\n },\n onShared(_shared) {\n remoteShared = _shared;\n hasShared = true;\n },\n onError(message, stack) {\n error = new RemoteComponentsError(message);\n if (stack) {\n error.stack = stack;\n }\n },\n });\n\n // Rewrite bundle identifiers in RSC chunk references to use the scoped name\n // so the client dispatchers can resolve the correct scope with a direct lookup.\n // This must happen after visit() because RSC script tags appear before the\n // metadata element in the HTML.\n if (isCrossOrigin && metadata?.bundle) {\n const scopedName = computeScopedName(metadata.bundle, {\n remoteHost: serverUrl.host,\n isCrossOrigin: true,\n });\n for (const chunk of rawRscChunks) {\n hydrationData.push(\n scopeChunkReferences(chunk, metadata.bundle, scopedName),\n );\n }\n } else {\n hydrationData.push(...rawRscChunks);\n }\n\n if (error) {\n throw error;\n }\n\n if (metadata) {\n if (!hasRSC && !nextData && metadata.type === 'nextjs') {\n throw new RemoteComponentsError(\n `The Remote Component at \"${serverUrl.href}\" seems to be a Next.js component but it does not contain any RSC flight data or Next.js props data. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n if (\n metadata.type === 'nextjs' &&\n !hasShared &&\n !nextData?.props.__REMOTE_COMPONENT__?.shared\n ) {\n throw new RemoteComponentsError(\n `No shared dependencies found for Remote Component at \"${serverUrl.href}\". Make sure the remote URL is correct and contains a Remote Component with shared dependencies.`,\n );\n }\n }\n\n const resolvedShared =\n nextData?.props.__REMOTE_COMPONENT__?.shared ?? remoteShared;\n\n return {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared: resolvedShared,\n html: Array.from(htmlChunks).join(''),\n };\n}\n\nexport async function fetchRemoteComponent(\n src: string | URL,\n options: {\n name?: string;\n rsc?: boolean;\n /** Whether this is being called from Next.js App Router. Used to enable skeleton fallback during SSG builds. */\n appRouter?: boolean;\n onRequest?: OnRequestHook;\n onResponse?: OnResponseHook;\n } = {},\n): Promise<FetchRemoteComponentResponse> {\n const ssrRelativePathBaseUrl = getSSRRelativePathBaseUrl();\n const serverUrl = new URL(src, ssrRelativePathBaseUrl);\n\n const tags = [\n '_vc_rc:fetch-remote-component',\n // the max size of a next cache tag is 256 characters\n serverUrl.host.slice(0, 256),\n // use the suffix so this tag is unique if multiple remote\n // components have the same host, but unique pathnames / query params\n (typeof src === 'string' ? src : src.href).slice(-256),\n ];\n if (options.name) {\n tags.push(options.name.slice(-256));\n }\n\n const fetchInit = {\n next: {\n tags,\n },\n };\n\n const res = await fetchWithHooks(serverUrl, fetchInit, {\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n });\n\n // If there is an error in the remote, parse and extract the remote error (except 404 and 401).\n if (!res.ok && !res.body) {\n throw failedToFetchRemoteComponentError(serverUrl.href, res);\n }\n\n if (res.status === 401) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'If you are using Deployment Protection, ensure the automation bypass environment variable secret in the host matches an automation bypass value in the remote. See https://remote-components-docs.vercel.sh/docs/concepts/cors-external-urls#deployment-protection for details.',\n );\n }\n\n if (res.status === 404) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'Check if you can open it in the browser.',\n );\n }\n\n // create a parser for the HTML response\n const parser = Parser.getFragmentParser<DefaultTreeAdapterMap>();\n\n if (!res.body) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `Response body is empty. Check if you can open it in the browser and you see the Remote Component content.`,\n );\n }\n\n const decoder = new TextDecoder();\n // read the response body as a stream and parse it using the parse5 fragment parser\n for await (const chunk of res.body as unknown as AsyncIterable<Uint8Array>) {\n parser.tokenizer.write(decoder.decode(chunk), false);\n }\n const fragment = parser.getFragment();\n\n const remoteName =\n options.name || (serverUrl.hash ? serverUrl.hash.substring(1) : undefined);\n\n const {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared,\n html,\n } = visitFragment(fragment, serverUrl, remoteName);\n\n if (!metadata) {\n // For microfrontend builds during run time, the host and remote build\n // may be happening concurrently. In this case, the request will 404.\n // We want to allow the build to continue with a placeholder remote\n // component. Once the build completes, vercel will automatically revalidate\n // ISR and fetch the built remote component.\n const isSSGBuild = process.env.NEXT_PHASE === 'phase-production-build';\n // If the remote component is part of a microfrontend, the src provided\n // will be relative.\n const isSSRRelativePathBase =\n serverUrl.host === new URL(ssrRelativePathBaseUrl).host;\n // Only want this skeleton behaviour in previews to unblock development.\n // For production, the remote component should already be built.\n const isPreview = process.env.VERCEL_TARGET_ENV === 'preview';\n\n if (isSSGBuild && isSSRRelativePathBase && isPreview && options.appRouter) {\n let skeletonComponent: React.ReactNode | undefined;\n if (options.rsc) {\n const { createElement } = await import('react');\n skeletonComponent = createElement('div', {\n dangerouslySetInnerHTML: {\n __html: getSkeletonHtml(serverUrl.href),\n },\n });\n }\n\n return buildSkeletonResponse(\n serverUrl,\n buildMetadata({}, serverUrl),\n skeletonComponent,\n );\n }\n\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `No Remote Component found. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n const name = remoteName || metadata.name;\n const component = options.rsc\n ? await buildRscComponent(rsc, serverUrl)\n : undefined;\n\n return {\n name,\n serverUrl,\n metadata,\n rsc,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n html,\n remoteShared,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/host/server/fetch-remote-component.ts"],"sourcesContent":["import { type DefaultTreeAdapterMap, Parser } from 'parse5';\nimport { type RSC, visit } from '#internal/host/nextjs/dom-flight';\nimport {\n getSkeletonHtml,\n getSkeletonMessage,\n} from '#internal/host/nextjs/skeleton';\nimport { fetchWithHooks } from '#internal/host/server/fetch-with-hooks';\nimport { getClientSrc } from '#internal/host/server/get-client-src';\nimport { getSSRRelativePathBaseUrl } from '#internal/host/server/get-ssr-relative-path-base-url';\nimport type {\n LinkDescriptor,\n ScriptDescriptor,\n} from '#internal/host/shared/asset-descriptors';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport {\n buildMetadata,\n type RawMetadataAttrs,\n type RemoteComponentMetadata,\n} from '#internal/runtime/metadata';\nimport { importRSCClientEdge } from '#internal/runtime/rsc-imports';\nimport {\n failedToFetchRemoteComponentError,\n multipleRemoteComponentsError,\n RemoteComponentsError,\n} from '#internal/utils/error';\nimport type { FetchRemoteComponentResponse, NextData } from './types';\n\n/**\n * Converts RSC flight data into a React element tree using the edge streaming\n * runtime. The manifest tells React how to resolve module references back to\n * the remote origin.\n */\nasync function buildRscComponent(\n rsc: RSC | RSC[] | string | null,\n serverUrl: URL,\n): Promise<React.ReactNode> {\n const componentRSC = `0:${JSON.stringify(rsc)}\\n`;\n const { createFromReadableStream } = await importRSCClientEdge();\n return createFromReadableStream(\n new ReadableStream({\n type: 'bytes',\n start(controller) {\n const encoder = new TextEncoder();\n controller.enqueue(encoder.encode(componentRSC));\n controller.close();\n },\n }),\n {\n serverConsumerManifest: {\n moduleLoading: {\n prefix: serverUrl.origin,\n crossOrigin: true,\n },\n moduleMap: {},\n },\n },\n );\n}\n\nfunction buildSkeletonResponse(\n serverUrl: URL,\n metadata: RemoteComponentMetadata,\n skeletonComponent: React.ReactNode | undefined,\n): FetchRemoteComponentResponse {\n return {\n name: 'remote-component-skeleton',\n serverUrl,\n metadata: {\n ...metadata,\n type: 'remote-component',\n },\n rsc: getSkeletonMessage(),\n scripts: [],\n links: [],\n hydrationData: [],\n nextData: undefined,\n component: skeletonComponent,\n html: getSkeletonHtml(serverUrl.href),\n remoteShared: {},\n };\n}\n\n/**\n * Walks the parsed HTML fragment and extracts all remote component data:\n * metadata, scripts, links, hydration data, Next.js data, shared deps, and HTML.\n */\nfunction visitFragment(\n fragment: DefaultTreeAdapterMap['documentFragment'],\n serverUrl: URL,\n remoteName: string | undefined,\n) {\n const scriptSrcSet = new Set<string>();\n const scriptTextSet = new Set<string>();\n const scripts: ScriptDescriptor[] = [];\n\n const linkKeySet = new Set<string>();\n const links: LinkDescriptor[] = [];\n\n const hydrationData: string[] = [];\n const htmlChunks = new Set<string>();\n\n let metadata: RemoteComponentMetadata | undefined;\n let nextData: NextData | undefined;\n let remoteShared: Record<string, string> = {};\n let hasRSC = false;\n let hasShared = false;\n let error: RemoteComponentsError | undefined;\n\n const rawRscChunks: string[] = [];\n\n const rsc = visit(fragment, {\n url: serverUrl,\n name: remoteName,\n onMetadata(attrs: RawMetadataAttrs) {\n const incoming = buildMetadata(attrs, serverUrl);\n // Skip multiple component detection for Pages Router (__next) since\n // it only supports one remote component per page\n if (\n !remoteName &&\n metadata &&\n metadata.id !== incoming.id &&\n incoming.id !== '__next' &&\n metadata.id !== '__next' &&\n !nextData\n ) {\n throw multipleRemoteComponentsError(serverUrl.href);\n }\n metadata = incoming;\n },\n onScript(attrs) {\n const clientSrc = getClientSrc(attrs.src, serverUrl.href);\n const textContent =\n typeof attrs.textContent === 'string' ? attrs.textContent : undefined;\n\n if (textContent) {\n if (!scriptTextSet.has(textContent)) {\n scriptTextSet.add(textContent);\n scripts.push({ src: '', textContent });\n }\n } else if (!scriptSrcSet.has(clientSrc)) {\n scriptSrcSet.add(clientSrc);\n scripts.push({ src: clientSrc });\n }\n },\n onLink(attrs) {\n const relativeAttrs = {\n ...attrs,\n href: getClientSrc(attrs.href, serverUrl.href),\n };\n const linkKey = `${relativeAttrs.href}::${attrs.rel}`;\n if (!linkKeySet.has(linkKey)) {\n linkKeySet.add(linkKey);\n links.push(relativeAttrs);\n }\n },\n onRSC(chunk) {\n rawRscChunks.push(chunk);\n hasRSC = true;\n },\n onNextData(data) {\n nextData = data;\n },\n onHTML(chunk) {\n if (!htmlChunks.has(chunk)) {\n htmlChunks.add(chunk);\n }\n },\n onShared(_shared) {\n remoteShared = _shared;\n hasShared = true;\n },\n onError(message, stack) {\n error = new RemoteComponentsError(message);\n if (stack) {\n error.stack = stack;\n }\n },\n });\n\n hydrationData.push(...rawRscChunks);\n\n if (error) {\n throw error;\n }\n\n if (metadata) {\n if (!hasRSC && !nextData && metadata.type === 'nextjs') {\n throw new RemoteComponentsError(\n `The Remote Component at \"${serverUrl.href}\" seems to be a Next.js component but it does not contain any RSC flight data or Next.js props data. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n if (\n metadata.type === 'nextjs' &&\n !hasShared &&\n !nextData?.props.__REMOTE_COMPONENT__?.shared\n ) {\n throw new RemoteComponentsError(\n `No shared dependencies found for Remote Component at \"${serverUrl.href}\". Make sure the remote URL is correct and contains a Remote Component with shared dependencies.`,\n );\n }\n }\n\n const resolvedShared =\n nextData?.props.__REMOTE_COMPONENT__?.shared ?? remoteShared;\n\n return {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared: resolvedShared,\n html: Array.from(htmlChunks).join(''),\n };\n}\n\nexport async function fetchRemoteComponent(\n src: string | URL,\n options: {\n name?: string;\n rsc?: boolean;\n /** Whether this is being called from Next.js App Router. Used to enable skeleton fallback during SSG builds. */\n appRouter?: boolean;\n onRequest?: OnRequestHook;\n onResponse?: OnResponseHook;\n } = {},\n): Promise<FetchRemoteComponentResponse> {\n const ssrRelativePathBaseUrl = getSSRRelativePathBaseUrl();\n const serverUrl = new URL(src, ssrRelativePathBaseUrl);\n\n const tags = [\n '_vc_rc:fetch-remote-component',\n // the max size of a next cache tag is 256 characters\n serverUrl.host.slice(0, 256),\n // use the suffix so this tag is unique if multiple remote\n // components have the same host, but unique pathnames / query params\n (typeof src === 'string' ? src : src.href).slice(-256),\n ];\n if (options.name) {\n tags.push(options.name.slice(-256));\n }\n\n const fetchInit = {\n next: {\n tags,\n },\n };\n\n const res = await fetchWithHooks(serverUrl, fetchInit, {\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n });\n\n // If there is an error in the remote, parse and extract the remote error (except 404 and 401).\n if (!res.ok && !res.body) {\n throw failedToFetchRemoteComponentError(serverUrl.href, res);\n }\n\n if (res.status === 401) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'If you are using Deployment Protection, ensure the automation bypass environment variable secret in the host matches an automation bypass value in the remote. See https://remote-components-docs.vercel.sh/docs/concepts/cors-external-urls#deployment-protection for details.',\n );\n }\n\n if (res.status === 404) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n 'Check if you can open it in the browser.',\n );\n }\n\n // create a parser for the HTML response\n const parser = Parser.getFragmentParser<DefaultTreeAdapterMap>();\n\n if (!res.body) {\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `Response body is empty. Check if you can open it in the browser and you see the Remote Component content.`,\n );\n }\n\n const decoder = new TextDecoder();\n // read the response body as a stream and parse it using the parse5 fragment parser\n for await (const chunk of res.body as unknown as AsyncIterable<Uint8Array>) {\n parser.tokenizer.write(decoder.decode(chunk), false);\n }\n const fragment = parser.getFragment();\n\n const remoteName =\n options.name || (serverUrl.hash ? serverUrl.hash.substring(1) : undefined);\n\n const {\n rsc,\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n remoteShared,\n html,\n } = visitFragment(fragment, serverUrl, remoteName);\n\n if (!metadata) {\n // For microfrontend builds during run time, the host and remote build\n // may be happening concurrently. In this case, the request will 404.\n // We want to allow the build to continue with a placeholder remote\n // component. Once the build completes, vercel will automatically revalidate\n // ISR and fetch the built remote component.\n const isSSGBuild = process.env.NEXT_PHASE === 'phase-production-build';\n // If the remote component is part of a microfrontend, the src provided\n // will be relative.\n const isSSRRelativePathBase =\n serverUrl.host === new URL(ssrRelativePathBaseUrl).host;\n // Only want this skeleton behaviour in previews to unblock development.\n // For production, the remote component should already be built.\n const isPreview = process.env.VERCEL_TARGET_ENV === 'preview';\n\n if (isSSGBuild && isSSRRelativePathBase && isPreview && options.appRouter) {\n let skeletonComponent: React.ReactNode | undefined;\n if (options.rsc) {\n const { createElement } = await import('react');\n skeletonComponent = createElement('div', {\n dangerouslySetInnerHTML: {\n __html: getSkeletonHtml(serverUrl.href),\n },\n });\n }\n\n return buildSkeletonResponse(\n serverUrl,\n buildMetadata({}, serverUrl),\n skeletonComponent,\n );\n }\n\n throw failedToFetchRemoteComponentError(\n serverUrl.href,\n res,\n `No Remote Component found. Make sure the remote URL is correct and contains a Remote Component.`,\n );\n }\n\n const name = remoteName || metadata.name;\n const component = options.rsc\n ? await buildRscComponent(rsc, serverUrl)\n : undefined;\n\n return {\n name,\n serverUrl,\n metadata,\n rsc,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n html,\n remoteShared,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -118,8 +118,11 @@ async function loadRemoteComponent({
|
|
|
118
118
|
"No bundle specified, skipping shared module setup"
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const scopedData = data.map(
|
|
122
|
+
(chunk) => chunk.replaceAll(`[${bundle}]`, `[${scope.scopedName}]`)
|
|
123
|
+
);
|
|
124
|
+
if (scopedData.length > 0) {
|
|
125
|
+
return await loadRSCComponent(rscName ?? name, scopedData);
|
|
123
126
|
} else if (nextData) {
|
|
124
127
|
return loadNextPagesComponent(bundle, route, nextData, name, container);
|
|
125
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/runtime/loaders/component-loader.ts"],"sourcesContent":["import * as React from 'react';\nimport * as JSXDevRuntime from 'react/jsx-dev-runtime';\nimport * as JSXRuntime from 'react/jsx-runtime';\nimport * as ReactDOM from 'react-dom';\nimport * as ReactDOMClient from 'react-dom/client';\nimport { applySharedModules } from '#internal/config/webpack/apply-shared-modules';\nimport { nextClientPagesLoader } from '#internal/config/webpack/next-client-pages-loader';\nimport type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport {\n buildCoreShared,\n buildWebpackResolve,\n} from '#internal/host/shared/shared-module-resolver';\nimport { createRSCStream } from '#internal/runtime/rsc';\nimport { importRSCClientBrowser } from '#internal/runtime/rsc-imports';\nimport { setupRemoteScope } from '#internal/runtime/turbopack/remote-scope-setup';\nimport { initializeSharedModules } from '#internal/runtime/turbopack/shared-modules';\nimport type { GlobalScope, LoaderResult } from '#internal/runtime/types';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { logDebug, logWarn } from '#internal/utils/logger';\nimport { loadScripts } from './script-loader';\n\n/**\n * Props accepted by {@link loadRemoteComponent}.\n *\n * Extends {@link ConsumeLoaderPayload} (the SSR-resolved fields needed for\n * hydration) with loader-specific fields (`url`, `shared`, `container`, etc.).\n * `remoteShared` is narrowed from optional to required (defaults to `{}` at\n * the call site).\n */\nexport interface ConsumeLoaderProps extends ConsumeLoaderPayload {\n url: URL;\n shared:\n | Promise<Record<string, (bundle?: string) => Promise<unknown>>>\n | Record<string, (bundle?: string) => Promise<unknown>>;\n remoteShared: Record<string, string>;\n container?: HTMLHeadElement | ShadowRoot | null;\n rscName?: string;\n resolveClientUrl?: InternalResolveClientUrl;\n}\n\n/**\n * Main loader function that orchestrates the component loading process\n */\nexport async function loadRemoteComponent({\n url,\n name,\n rscName,\n bundle,\n route = '/',\n runtime = 'webpack',\n data,\n nextData,\n scripts = [],\n shared = Promise.resolve({}),\n remoteShared = {},\n container,\n resolveClientUrl,\n}: ConsumeLoaderProps): Promise<LoaderResult> {\n try {\n // Load scripts if using webpack runtime\n if (runtime === 'webpack') {\n const self = globalThis as GlobalScope;\n // disable webpack entrypoint execution for the remote\n if (!self.__DISABLE_WEBPACK_EXEC__) {\n self.__DISABLE_WEBPACK_EXEC__ = {};\n }\n // disable webpack entrypoint execution for the current remote bundle\n self.__DISABLE_WEBPACK_EXEC__[bundle] = true;\n await loadScripts(scripts, resolveClientUrl);\n }\n\n const hostShared = await shared;\n logDebug(\n 'ComponentLoader',\n `loadRemoteComponent: bundle=\"${bundle}\", name=\"${name}\"`,\n );\n logDebug(\n 'ComponentLoader',\n `Host shared modules available: ${Object.keys(hostShared)}`,\n );\n logDebug(\n 'ComponentLoader',\n `Remote shared modules requested: ${JSON.stringify(remoteShared)}`,\n );\n\n // Setup remote scope and load turbopack chunks\n const scope = await setupRemoteScope(\n runtime,\n scripts,\n url,\n bundle,\n resolveClientUrl,\n );\n\n // Initialize turbopack shared modules (React, etc.) now that chunks are loaded\n if (runtime === 'turbopack') {\n await initializeSharedModules(\n scope,\n buildCoreShared(hostShared),\n remoteShared,\n );\n }\n\n // Setup shared modules\n if (bundle) {\n const resolve = await buildWebpackResolve(\n hostShared,\n remoteShared,\n bundle,\n {\n '/react/index.js': React,\n '/react/jsx-dev-runtime.js': JSXDevRuntime,\n '/react/jsx-runtime.js': JSXRuntime,\n '/react-dom/index.js': ReactDOM,\n '/react-dom/client.js': ReactDOMClient,\n },\n 'ComponentLoader',\n );\n applySharedModules(bundle, resolve);\n } else {\n logWarn(\n 'ComponentLoader',\n 'No bundle specified, skipping shared module setup',\n );\n }\n\n // Load component based on data type\n if (
|
|
1
|
+
{"version":3,"sources":["../../../../src/runtime/loaders/component-loader.ts"],"sourcesContent":["import * as React from 'react';\nimport * as JSXDevRuntime from 'react/jsx-dev-runtime';\nimport * as JSXRuntime from 'react/jsx-runtime';\nimport * as ReactDOM from 'react-dom';\nimport * as ReactDOMClient from 'react-dom/client';\nimport { applySharedModules } from '#internal/config/webpack/apply-shared-modules';\nimport { nextClientPagesLoader } from '#internal/config/webpack/next-client-pages-loader';\nimport type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport {\n buildCoreShared,\n buildWebpackResolve,\n} from '#internal/host/shared/shared-module-resolver';\nimport { createRSCStream } from '#internal/runtime/rsc';\nimport { importRSCClientBrowser } from '#internal/runtime/rsc-imports';\nimport { setupRemoteScope } from '#internal/runtime/turbopack/remote-scope-setup';\nimport { initializeSharedModules } from '#internal/runtime/turbopack/shared-modules';\nimport type { GlobalScope, LoaderResult } from '#internal/runtime/types';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { logDebug, logWarn } from '#internal/utils/logger';\nimport { loadScripts } from './script-loader';\n\n/**\n * Props accepted by {@link loadRemoteComponent}.\n *\n * Extends {@link ConsumeLoaderPayload} (the SSR-resolved fields needed for\n * hydration) with loader-specific fields (`url`, `shared`, `container`, etc.).\n * `remoteShared` is narrowed from optional to required (defaults to `{}` at\n * the call site).\n */\nexport interface ConsumeLoaderProps extends ConsumeLoaderPayload {\n url: URL;\n shared:\n | Promise<Record<string, (bundle?: string) => Promise<unknown>>>\n | Record<string, (bundle?: string) => Promise<unknown>>;\n remoteShared: Record<string, string>;\n container?: HTMLHeadElement | ShadowRoot | null;\n rscName?: string;\n resolveClientUrl?: InternalResolveClientUrl;\n}\n\n/**\n * Main loader function that orchestrates the component loading process\n */\nexport async function loadRemoteComponent({\n url,\n name,\n rscName,\n bundle,\n route = '/',\n runtime = 'webpack',\n data,\n nextData,\n scripts = [],\n shared = Promise.resolve({}),\n remoteShared = {},\n container,\n resolveClientUrl,\n}: ConsumeLoaderProps): Promise<LoaderResult> {\n try {\n // Load scripts if using webpack runtime\n if (runtime === 'webpack') {\n const self = globalThis as GlobalScope;\n // disable webpack entrypoint execution for the remote\n if (!self.__DISABLE_WEBPACK_EXEC__) {\n self.__DISABLE_WEBPACK_EXEC__ = {};\n }\n // disable webpack entrypoint execution for the current remote bundle\n self.__DISABLE_WEBPACK_EXEC__[bundle] = true;\n await loadScripts(scripts, resolveClientUrl);\n }\n\n const hostShared = await shared;\n logDebug(\n 'ComponentLoader',\n `loadRemoteComponent: bundle=\"${bundle}\", name=\"${name}\"`,\n );\n logDebug(\n 'ComponentLoader',\n `Host shared modules available: ${Object.keys(hostShared)}`,\n );\n logDebug(\n 'ComponentLoader',\n `Remote shared modules requested: ${JSON.stringify(remoteShared)}`,\n );\n\n // Setup remote scope and load turbopack chunks\n const scope = await setupRemoteScope(\n runtime,\n scripts,\n url,\n bundle,\n resolveClientUrl,\n );\n\n // Initialize turbopack shared modules (React, etc.) now that chunks are loaded\n if (runtime === 'turbopack') {\n await initializeSharedModules(\n scope,\n buildCoreShared(hostShared),\n remoteShared,\n );\n }\n\n // Setup shared modules\n if (bundle) {\n const resolve = await buildWebpackResolve(\n hostShared,\n remoteShared,\n bundle,\n {\n '/react/index.js': React,\n '/react/jsx-dev-runtime.js': JSXDevRuntime,\n '/react/jsx-runtime.js': JSXRuntime,\n '/react-dom/index.js': ReactDOM,\n '/react-dom/client.js': ReactDOMClient,\n },\n 'ComponentLoader',\n );\n applySharedModules(bundle, resolve);\n } else {\n logWarn(\n 'ComponentLoader',\n 'No bundle specified, skipping shared module setup',\n );\n }\n\n // Rewrite plain bundle references in RSC data to the scoped name so\n // the client dispatchers resolve the correct scope.\n const scopedData = data.map((chunk) =>\n chunk.replaceAll(`[${bundle}]`, `[${scope.scopedName}]`),\n );\n\n // Load component based on data type\n if (scopedData.length > 0) {\n return await loadRSCComponent(rscName ?? name, scopedData);\n } else if (nextData) {\n return loadNextPagesComponent(bundle, route, nextData, name, container);\n }\n\n return loadRSCComponent(rscName ?? name, [`0:[null]\\n`]); // Fallback to empty RSC payload\n } catch (error) {\n return {\n component: null,\n error: new RemoteComponentsError(\n `Failed to load remote component \"${name}\".`,\n {\n cause: error instanceof Error ? error : new Error(String(error)),\n },\n ),\n };\n }\n}\n\n/**\n * Loads RSC (React Server Components) based component\n */\nasync function loadRSCComponent(\n rscName: string,\n data: string[],\n): Promise<LoaderResult> {\n const { createFromReadableStream } = await importRSCClientBrowser();\n if (typeof createFromReadableStream !== 'function') {\n throw new RemoteComponentsError(\n 'Failed to import \"react-server-dom-webpack\". Is Next.js installed correctly?',\n );\n }\n\n const stream = createRSCStream(rscName, data);\n const component = createFromReadableStream(stream);\n\n return { component };\n}\n\n/**\n * Loads Next.js Pages Router based component\n */\nfunction loadNextPagesComponent(\n bundle: string,\n route: string,\n nextData: NonNullable<ConsumeLoaderPayload['nextData']>,\n name: string,\n container?: HTMLHeadElement | ShadowRoot | null,\n): LoaderResult {\n const { Component, App } = nextClientPagesLoader(bundle, route, container);\n\n if (!Component) {\n throw new RemoteComponentsError(\n `Remote Component \"${name}\" is trying to load the component for route \"${route}\" but it is not available.`,\n );\n }\n\n // error tolerance when app component is not found\n const component = App\n ? React.createElement(App, { Component, ...nextData.props })\n : React.createElement(Component, nextData.props);\n\n return { component };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -88,8 +88,11 @@ async function loadRemoteComponent({
|
|
|
88
88
|
"No bundle specified, skipping shared module setup"
|
|
89
89
|
);
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
const scopedData = data.map(
|
|
92
|
+
(chunk) => chunk.replaceAll(`[${bundle}]`, `[${scope.scopedName}]`)
|
|
93
|
+
);
|
|
94
|
+
if (scopedData.length > 0) {
|
|
95
|
+
return await loadRSCComponent(rscName ?? name, scopedData);
|
|
93
96
|
} else if (nextData) {
|
|
94
97
|
return loadNextPagesComponent(bundle, route, nextData, name, container);
|
|
95
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/runtime/loaders/component-loader.ts"],"sourcesContent":["import * as React from 'react';\nimport * as JSXDevRuntime from 'react/jsx-dev-runtime';\nimport * as JSXRuntime from 'react/jsx-runtime';\nimport * as ReactDOM from 'react-dom';\nimport * as ReactDOMClient from 'react-dom/client';\nimport { applySharedModules } from '#internal/config/webpack/apply-shared-modules';\nimport { nextClientPagesLoader } from '#internal/config/webpack/next-client-pages-loader';\nimport type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport {\n buildCoreShared,\n buildWebpackResolve,\n} from '#internal/host/shared/shared-module-resolver';\nimport { createRSCStream } from '#internal/runtime/rsc';\nimport { importRSCClientBrowser } from '#internal/runtime/rsc-imports';\nimport { setupRemoteScope } from '#internal/runtime/turbopack/remote-scope-setup';\nimport { initializeSharedModules } from '#internal/runtime/turbopack/shared-modules';\nimport type { GlobalScope, LoaderResult } from '#internal/runtime/types';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { logDebug, logWarn } from '#internal/utils/logger';\nimport { loadScripts } from './script-loader';\n\n/**\n * Props accepted by {@link loadRemoteComponent}.\n *\n * Extends {@link ConsumeLoaderPayload} (the SSR-resolved fields needed for\n * hydration) with loader-specific fields (`url`, `shared`, `container`, etc.).\n * `remoteShared` is narrowed from optional to required (defaults to `{}` at\n * the call site).\n */\nexport interface ConsumeLoaderProps extends ConsumeLoaderPayload {\n url: URL;\n shared:\n | Promise<Record<string, (bundle?: string) => Promise<unknown>>>\n | Record<string, (bundle?: string) => Promise<unknown>>;\n remoteShared: Record<string, string>;\n container?: HTMLHeadElement | ShadowRoot | null;\n rscName?: string;\n resolveClientUrl?: InternalResolveClientUrl;\n}\n\n/**\n * Main loader function that orchestrates the component loading process\n */\nexport async function loadRemoteComponent({\n url,\n name,\n rscName,\n bundle,\n route = '/',\n runtime = 'webpack',\n data,\n nextData,\n scripts = [],\n shared = Promise.resolve({}),\n remoteShared = {},\n container,\n resolveClientUrl,\n}: ConsumeLoaderProps): Promise<LoaderResult> {\n try {\n // Load scripts if using webpack runtime\n if (runtime === 'webpack') {\n const self = globalThis as GlobalScope;\n // disable webpack entrypoint execution for the remote\n if (!self.__DISABLE_WEBPACK_EXEC__) {\n self.__DISABLE_WEBPACK_EXEC__ = {};\n }\n // disable webpack entrypoint execution for the current remote bundle\n self.__DISABLE_WEBPACK_EXEC__[bundle] = true;\n await loadScripts(scripts, resolveClientUrl);\n }\n\n const hostShared = await shared;\n logDebug(\n 'ComponentLoader',\n `loadRemoteComponent: bundle=\"${bundle}\", name=\"${name}\"`,\n );\n logDebug(\n 'ComponentLoader',\n `Host shared modules available: ${Object.keys(hostShared)}`,\n );\n logDebug(\n 'ComponentLoader',\n `Remote shared modules requested: ${JSON.stringify(remoteShared)}`,\n );\n\n // Setup remote scope and load turbopack chunks\n const scope = await setupRemoteScope(\n runtime,\n scripts,\n url,\n bundle,\n resolveClientUrl,\n );\n\n // Initialize turbopack shared modules (React, etc.) now that chunks are loaded\n if (runtime === 'turbopack') {\n await initializeSharedModules(\n scope,\n buildCoreShared(hostShared),\n remoteShared,\n );\n }\n\n // Setup shared modules\n if (bundle) {\n const resolve = await buildWebpackResolve(\n hostShared,\n remoteShared,\n bundle,\n {\n '/react/index.js': React,\n '/react/jsx-dev-runtime.js': JSXDevRuntime,\n '/react/jsx-runtime.js': JSXRuntime,\n '/react-dom/index.js': ReactDOM,\n '/react-dom/client.js': ReactDOMClient,\n },\n 'ComponentLoader',\n );\n applySharedModules(bundle, resolve);\n } else {\n logWarn(\n 'ComponentLoader',\n 'No bundle specified, skipping shared module setup',\n );\n }\n\n // Load component based on data type\n if (
|
|
1
|
+
{"version":3,"sources":["../../../../src/runtime/loaders/component-loader.ts"],"sourcesContent":["import * as React from 'react';\nimport * as JSXDevRuntime from 'react/jsx-dev-runtime';\nimport * as JSXRuntime from 'react/jsx-runtime';\nimport * as ReactDOM from 'react-dom';\nimport * as ReactDOMClient from 'react-dom/client';\nimport { applySharedModules } from '#internal/config/webpack/apply-shared-modules';\nimport { nextClientPagesLoader } from '#internal/config/webpack/next-client-pages-loader';\nimport type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport type { ConsumeLoaderPayload } from '#internal/host/shared/server-handoff';\nimport {\n buildCoreShared,\n buildWebpackResolve,\n} from '#internal/host/shared/shared-module-resolver';\nimport { createRSCStream } from '#internal/runtime/rsc';\nimport { importRSCClientBrowser } from '#internal/runtime/rsc-imports';\nimport { setupRemoteScope } from '#internal/runtime/turbopack/remote-scope-setup';\nimport { initializeSharedModules } from '#internal/runtime/turbopack/shared-modules';\nimport type { GlobalScope, LoaderResult } from '#internal/runtime/types';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { logDebug, logWarn } from '#internal/utils/logger';\nimport { loadScripts } from './script-loader';\n\n/**\n * Props accepted by {@link loadRemoteComponent}.\n *\n * Extends {@link ConsumeLoaderPayload} (the SSR-resolved fields needed for\n * hydration) with loader-specific fields (`url`, `shared`, `container`, etc.).\n * `remoteShared` is narrowed from optional to required (defaults to `{}` at\n * the call site).\n */\nexport interface ConsumeLoaderProps extends ConsumeLoaderPayload {\n url: URL;\n shared:\n | Promise<Record<string, (bundle?: string) => Promise<unknown>>>\n | Record<string, (bundle?: string) => Promise<unknown>>;\n remoteShared: Record<string, string>;\n container?: HTMLHeadElement | ShadowRoot | null;\n rscName?: string;\n resolveClientUrl?: InternalResolveClientUrl;\n}\n\n/**\n * Main loader function that orchestrates the component loading process\n */\nexport async function loadRemoteComponent({\n url,\n name,\n rscName,\n bundle,\n route = '/',\n runtime = 'webpack',\n data,\n nextData,\n scripts = [],\n shared = Promise.resolve({}),\n remoteShared = {},\n container,\n resolveClientUrl,\n}: ConsumeLoaderProps): Promise<LoaderResult> {\n try {\n // Load scripts if using webpack runtime\n if (runtime === 'webpack') {\n const self = globalThis as GlobalScope;\n // disable webpack entrypoint execution for the remote\n if (!self.__DISABLE_WEBPACK_EXEC__) {\n self.__DISABLE_WEBPACK_EXEC__ = {};\n }\n // disable webpack entrypoint execution for the current remote bundle\n self.__DISABLE_WEBPACK_EXEC__[bundle] = true;\n await loadScripts(scripts, resolveClientUrl);\n }\n\n const hostShared = await shared;\n logDebug(\n 'ComponentLoader',\n `loadRemoteComponent: bundle=\"${bundle}\", name=\"${name}\"`,\n );\n logDebug(\n 'ComponentLoader',\n `Host shared modules available: ${Object.keys(hostShared)}`,\n );\n logDebug(\n 'ComponentLoader',\n `Remote shared modules requested: ${JSON.stringify(remoteShared)}`,\n );\n\n // Setup remote scope and load turbopack chunks\n const scope = await setupRemoteScope(\n runtime,\n scripts,\n url,\n bundle,\n resolveClientUrl,\n );\n\n // Initialize turbopack shared modules (React, etc.) now that chunks are loaded\n if (runtime === 'turbopack') {\n await initializeSharedModules(\n scope,\n buildCoreShared(hostShared),\n remoteShared,\n );\n }\n\n // Setup shared modules\n if (bundle) {\n const resolve = await buildWebpackResolve(\n hostShared,\n remoteShared,\n bundle,\n {\n '/react/index.js': React,\n '/react/jsx-dev-runtime.js': JSXDevRuntime,\n '/react/jsx-runtime.js': JSXRuntime,\n '/react-dom/index.js': ReactDOM,\n '/react-dom/client.js': ReactDOMClient,\n },\n 'ComponentLoader',\n );\n applySharedModules(bundle, resolve);\n } else {\n logWarn(\n 'ComponentLoader',\n 'No bundle specified, skipping shared module setup',\n );\n }\n\n // Rewrite plain bundle references in RSC data to the scoped name so\n // the client dispatchers resolve the correct scope.\n const scopedData = data.map((chunk) =>\n chunk.replaceAll(`[${bundle}]`, `[${scope.scopedName}]`),\n );\n\n // Load component based on data type\n if (scopedData.length > 0) {\n return await loadRSCComponent(rscName ?? name, scopedData);\n } else if (nextData) {\n return loadNextPagesComponent(bundle, route, nextData, name, container);\n }\n\n return loadRSCComponent(rscName ?? name, [`0:[null]\\n`]); // Fallback to empty RSC payload\n } catch (error) {\n return {\n component: null,\n error: new RemoteComponentsError(\n `Failed to load remote component \"${name}\".`,\n {\n cause: error instanceof Error ? error : new Error(String(error)),\n },\n ),\n };\n }\n}\n\n/**\n * Loads RSC (React Server Components) based component\n */\nasync function loadRSCComponent(\n rscName: string,\n data: string[],\n): Promise<LoaderResult> {\n const { createFromReadableStream } = await importRSCClientBrowser();\n if (typeof createFromReadableStream !== 'function') {\n throw new RemoteComponentsError(\n 'Failed to import \"react-server-dom-webpack\". Is Next.js installed correctly?',\n );\n }\n\n const stream = createRSCStream(rscName, data);\n const component = createFromReadableStream(stream);\n\n return { component };\n}\n\n/**\n * Loads Next.js Pages Router based component\n */\nfunction loadNextPagesComponent(\n bundle: string,\n route: string,\n nextData: NonNullable<ConsumeLoaderPayload['nextData']>,\n name: string,\n container?: HTMLHeadElement | ShadowRoot | null,\n): LoaderResult {\n const { Component, App } = nextClientPagesLoader(bundle, route, container);\n\n if (!Component) {\n throw new RemoteComponentsError(\n `Remote Component \"${name}\" is trying to load the component for route \"${route}\" but it is not available.`,\n );\n }\n\n // error tolerance when app component is not found\n const component = App\n ? React.createElement(App, { Component, ...nextData.props })\n : React.createElement(Component, nextData.props);\n\n return { component };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -34,11 +34,7 @@ function getRegistry() {
|
|
|
34
34
|
return (0, import_namespace.getNamespace)().scopes;
|
|
35
35
|
}
|
|
36
36
|
function createScope(name, url, runtime, resolveClientUrl) {
|
|
37
|
-
const
|
|
38
|
-
const scopedName = (0, import_utils.computeScopedName)(name, {
|
|
39
|
-
remoteHost: url.host,
|
|
40
|
-
isCrossOrigin
|
|
41
|
-
});
|
|
37
|
+
const scopedName = (0, import_utils.computeScopedName)(name, { remoteHost: url.host });
|
|
42
38
|
const globalKey = (0, import_constants.getBundleKey)(scopedName);
|
|
43
39
|
return {
|
|
44
40
|
name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/runtime/turbopack/remote-scope.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport { getBundleKey, type Runtime } from '#internal/runtime/constants';\nimport { getNamespace } from '#internal/runtime/namespace';\nimport { REMOTE_COMPONENT_REGEX } from '#internal/runtime/patterns';\nimport { computeScopedName } from '#internal/utils';\nimport { logDebug, logWarn } from '#internal/utils/logger';\n\n/**\n * Encapsulates all per-remote state so that two remotes sharing the same\n * bundle name but served from different origins never collide.\n *\n * A scope is created once per `setupRemoteScope` call and threaded\n * directly through internal code paths (chunk loading, module resolution,\n * shared modules). Global dispatchers (`__webpack_require__`,\n * `__webpack_chunk_load__`) only exist for external callers (RSC runtime)\n * and resolve the correct scope via the registry.\n */\nexport interface RemoteScope {\n /** Plain bundle name (e.g. \"remote-component-registry\") */\n name: string;\n /** Origin-qualified key — unique even when two remotes share a name */\n scopedName: string;\n /** Escaped key used as suffix for TURBOPACK_ globals */\n globalKey: string;\n /** Base URL for resolving relative chunk paths */\n url: URL;\n /** Bundler runtime type */\n runtime: Runtime;\n /** Proxy callback for routing chunks through the host */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Per-scope cache of executed Turbopack module exports */\n moduleCache: Record<string, unknown>;\n /** Per-scope shared modules provided by the host (React, etc.) */\n sharedModules: Record<string, unknown>;\n /** Per-scope globalThis substitute passed to module initializers as `g` */\n moduleGlobal: Record<string, unknown>;\n /**\n * Webpack's bundle-scoped require function, populated from\n * `__remote_webpack_require__[bundleName]` for webpack remotes.\n * Undefined for turbopack remotes.\n */\n webpackRequire?: ((id: string | number) => unknown) & {\n m?: Record<string | number, (module: { exports: unknown }) => void>;\n type?: string;\n };\n /**\n * Flat array of captured turbopack module entries: [scriptEl, id, factory, ...].\n * Populated by the push interceptor in handleTurbopackChunk. This is the\n * primary source of truth for getTurbopackModules — immune to the turbopack\n * runtime replacing the TURBOPACK global (canary builds use a deferred-loading\n * pattern that swaps the array for an immediate-processing dispatcher).\n */\n turbopackModules: unknown[];\n}\n\nfunction getRegistry(): Map<string, RemoteScope> {\n return getNamespace().scopes;\n}\n\nexport function createScope(\n name: string,\n url: URL,\n runtime: Runtime,\n resolveClientUrl?: InternalResolveClientUrl,\n): RemoteScope {\n const
|
|
1
|
+
{"version":3,"sources":["../../../../src/runtime/turbopack/remote-scope.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport { getBundleKey, type Runtime } from '#internal/runtime/constants';\nimport { getNamespace } from '#internal/runtime/namespace';\nimport { REMOTE_COMPONENT_REGEX } from '#internal/runtime/patterns';\nimport { computeScopedName } from '#internal/utils';\nimport { logDebug, logWarn } from '#internal/utils/logger';\n\n/**\n * Encapsulates all per-remote state so that two remotes sharing the same\n * bundle name but served from different origins never collide.\n *\n * A scope is created once per `setupRemoteScope` call and threaded\n * directly through internal code paths (chunk loading, module resolution,\n * shared modules). Global dispatchers (`__webpack_require__`,\n * `__webpack_chunk_load__`) only exist for external callers (RSC runtime)\n * and resolve the correct scope via the registry.\n */\nexport interface RemoteScope {\n /** Plain bundle name (e.g. \"remote-component-registry\") */\n name: string;\n /** Origin-qualified key — unique even when two remotes share a name */\n scopedName: string;\n /** Escaped key used as suffix for TURBOPACK_ globals */\n globalKey: string;\n /** Base URL for resolving relative chunk paths */\n url: URL;\n /** Bundler runtime type */\n runtime: Runtime;\n /** Proxy callback for routing chunks through the host */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Per-scope cache of executed Turbopack module exports */\n moduleCache: Record<string, unknown>;\n /** Per-scope shared modules provided by the host (React, etc.) */\n sharedModules: Record<string, unknown>;\n /** Per-scope globalThis substitute passed to module initializers as `g` */\n moduleGlobal: Record<string, unknown>;\n /**\n * Webpack's bundle-scoped require function, populated from\n * `__remote_webpack_require__[bundleName]` for webpack remotes.\n * Undefined for turbopack remotes.\n */\n webpackRequire?: ((id: string | number) => unknown) & {\n m?: Record<string | number, (module: { exports: unknown }) => void>;\n type?: string;\n };\n /**\n * Flat array of captured turbopack module entries: [scriptEl, id, factory, ...].\n * Populated by the push interceptor in handleTurbopackChunk. This is the\n * primary source of truth for getTurbopackModules — immune to the turbopack\n * runtime replacing the TURBOPACK global (canary builds use a deferred-loading\n * pattern that swaps the array for an immediate-processing dispatcher).\n */\n turbopackModules: unknown[];\n}\n\nfunction getRegistry(): Map<string, RemoteScope> {\n return getNamespace().scopes;\n}\n\nexport function createScope(\n name: string,\n url: URL,\n runtime: Runtime,\n resolveClientUrl?: InternalResolveClientUrl,\n): RemoteScope {\n const scopedName = computeScopedName(name, { remoteHost: url.host });\n const globalKey = getBundleKey(scopedName);\n return {\n name,\n scopedName,\n globalKey,\n url,\n runtime,\n resolveClientUrl,\n moduleCache: {},\n sharedModules: {},\n moduleGlobal: {},\n turbopackModules: [],\n };\n}\n\nexport function registerScope(scope: RemoteScope): void {\n const registry = getRegistry();\n registry.set(scope.scopedName, scope);\n\n // Also register under the plain name so static/HTML hosts (which don't\n // rewrite RSC chunk IDs) can look up scopes by the unrewritten bundle name.\n if (scope.scopedName !== scope.name) {\n const existing = registry.get(scope.name);\n if (existing && existing.scopedName !== scope.scopedName) {\n logWarn(\n 'RemoteScope',\n `Plain name \"${scope.name}\" already registered by scope \"${existing.scopedName}\" — ` +\n `overwriting with \"${scope.scopedName}\". Static hosts will only resolve the latest one.`,\n );\n }\n registry.set(scope.name, scope);\n }\n\n logDebug(\n 'RemoteScope',\n `Registered scope \"${scope.scopedName}\" (${registry.size} total)`,\n );\n}\n\n/**\n * Resolves a scope by name. Accepts either the scoped name (used by Next.js\n * hosts that rewrite RSC data server-side) or the plain bundle name (used by\n * static/HTML hosts where chunks arrive unrewritten).\n */\nexport function getScope(name: string): RemoteScope | undefined {\n return getRegistry().get(name);\n}\n\n/** Formats a `[scopedName] path` string for use in chunk/module IDs. */\nexport function formatRemoteId(scope: RemoteScope, path: string): string {\n return `[${scope.scopedName}] ${path}`;\n}\n\n/**\n * Parses the `[bundle] path` format used in chunk/module IDs.\n * Uses REMOTE_COMPONENT_REGEX (the same pattern used by the module dispatcher\n * and script loader) so the two parsing paths can never diverge.\n */\nexport function parseRemoteId(id: string): {\n bundle: string;\n path: string;\n prefix: string;\n} {\n const groups = REMOTE_COMPONENT_REGEX.exec(id)?.groups;\n if (groups?.bundle && groups.id) {\n return {\n bundle: groups.bundle,\n path: groups.id,\n prefix: groups.prefix ?? '',\n };\n }\n return { bundle: 'default', path: id, prefix: '' };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,uBAA2C;AAC3C,uBAA6B;AAC7B,sBAAuC;AACvC,mBAAkC;AAClC,oBAAkC;AAkDlC,SAAS,cAAwC;AAC/C,aAAO,+BAAa,EAAE;AACxB;AAEO,SAAS,YACd,MACA,KACA,SACA,kBACa;AACb,QAAM,iBAAa,gCAAkB,MAAM,EAAE,YAAY,IAAI,KAAK,CAAC;AACnE,QAAM,gBAAY,+BAAa,UAAU;AACzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,CAAC;AAAA,IACd,eAAe,CAAC;AAAA,IAChB,cAAc,CAAC;AAAA,IACf,kBAAkB,CAAC;AAAA,EACrB;AACF;AAEO,SAAS,cAAc,OAA0B;AACtD,QAAM,WAAW,YAAY;AAC7B,WAAS,IAAI,MAAM,YAAY,KAAK;AAIpC,MAAI,MAAM,eAAe,MAAM,MAAM;AACnC,UAAM,WAAW,SAAS,IAAI,MAAM,IAAI;AACxC,QAAI,YAAY,SAAS,eAAe,MAAM,YAAY;AACxD;AAAA,QACE;AAAA,QACA,eAAe,MAAM,sCAAsC,SAAS,wCAC7C,MAAM;AAAA,MAC/B;AAAA,IACF;AACA,aAAS,IAAI,MAAM,MAAM,KAAK;AAAA,EAChC;AAEA;AAAA,IACE;AAAA,IACA,qBAAqB,MAAM,gBAAgB,SAAS;AAAA,EACtD;AACF;AAOO,SAAS,SAAS,MAAuC;AAC9D,SAAO,YAAY,EAAE,IAAI,IAAI;AAC/B;AAGO,SAAS,eAAe,OAAoB,MAAsB;AACvE,SAAO,IAAI,MAAM,eAAe;AAClC;AAOO,SAAS,cAAc,IAI5B;AACA,QAAM,SAAS,uCAAuB,KAAK,EAAE,GAAG;AAChD,MAAI,QAAQ,UAAU,OAAO,IAAI;AAC/B,WAAO;AAAA,MACL,QAAQ,OAAO;AAAA,MACf,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO,UAAU;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,WAAW,MAAM,IAAI,QAAQ,GAAG;AACnD;","names":[]}
|
|
@@ -7,11 +7,7 @@ function getRegistry() {
|
|
|
7
7
|
return getNamespace().scopes;
|
|
8
8
|
}
|
|
9
9
|
function createScope(name, url, runtime, resolveClientUrl) {
|
|
10
|
-
const
|
|
11
|
-
const scopedName = computeScopedName(name, {
|
|
12
|
-
remoteHost: url.host,
|
|
13
|
-
isCrossOrigin
|
|
14
|
-
});
|
|
10
|
+
const scopedName = computeScopedName(name, { remoteHost: url.host });
|
|
15
11
|
const globalKey = getBundleKey(scopedName);
|
|
16
12
|
return {
|
|
17
13
|
name,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/runtime/turbopack/remote-scope.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport { getBundleKey, type Runtime } from '#internal/runtime/constants';\nimport { getNamespace } from '#internal/runtime/namespace';\nimport { REMOTE_COMPONENT_REGEX } from '#internal/runtime/patterns';\nimport { computeScopedName } from '#internal/utils';\nimport { logDebug, logWarn } from '#internal/utils/logger';\n\n/**\n * Encapsulates all per-remote state so that two remotes sharing the same\n * bundle name but served from different origins never collide.\n *\n * A scope is created once per `setupRemoteScope` call and threaded\n * directly through internal code paths (chunk loading, module resolution,\n * shared modules). Global dispatchers (`__webpack_require__`,\n * `__webpack_chunk_load__`) only exist for external callers (RSC runtime)\n * and resolve the correct scope via the registry.\n */\nexport interface RemoteScope {\n /** Plain bundle name (e.g. \"remote-component-registry\") */\n name: string;\n /** Origin-qualified key — unique even when two remotes share a name */\n scopedName: string;\n /** Escaped key used as suffix for TURBOPACK_ globals */\n globalKey: string;\n /** Base URL for resolving relative chunk paths */\n url: URL;\n /** Bundler runtime type */\n runtime: Runtime;\n /** Proxy callback for routing chunks through the host */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Per-scope cache of executed Turbopack module exports */\n moduleCache: Record<string, unknown>;\n /** Per-scope shared modules provided by the host (React, etc.) */\n sharedModules: Record<string, unknown>;\n /** Per-scope globalThis substitute passed to module initializers as `g` */\n moduleGlobal: Record<string, unknown>;\n /**\n * Webpack's bundle-scoped require function, populated from\n * `__remote_webpack_require__[bundleName]` for webpack remotes.\n * Undefined for turbopack remotes.\n */\n webpackRequire?: ((id: string | number) => unknown) & {\n m?: Record<string | number, (module: { exports: unknown }) => void>;\n type?: string;\n };\n /**\n * Flat array of captured turbopack module entries: [scriptEl, id, factory, ...].\n * Populated by the push interceptor in handleTurbopackChunk. This is the\n * primary source of truth for getTurbopackModules — immune to the turbopack\n * runtime replacing the TURBOPACK global (canary builds use a deferred-loading\n * pattern that swaps the array for an immediate-processing dispatcher).\n */\n turbopackModules: unknown[];\n}\n\nfunction getRegistry(): Map<string, RemoteScope> {\n return getNamespace().scopes;\n}\n\nexport function createScope(\n name: string,\n url: URL,\n runtime: Runtime,\n resolveClientUrl?: InternalResolveClientUrl,\n): RemoteScope {\n const
|
|
1
|
+
{"version":3,"sources":["../../../../src/runtime/turbopack/remote-scope.ts"],"sourcesContent":["import type { InternalResolveClientUrl } from '#internal/host/server/types';\nimport { getBundleKey, type Runtime } from '#internal/runtime/constants';\nimport { getNamespace } from '#internal/runtime/namespace';\nimport { REMOTE_COMPONENT_REGEX } from '#internal/runtime/patterns';\nimport { computeScopedName } from '#internal/utils';\nimport { logDebug, logWarn } from '#internal/utils/logger';\n\n/**\n * Encapsulates all per-remote state so that two remotes sharing the same\n * bundle name but served from different origins never collide.\n *\n * A scope is created once per `setupRemoteScope` call and threaded\n * directly through internal code paths (chunk loading, module resolution,\n * shared modules). Global dispatchers (`__webpack_require__`,\n * `__webpack_chunk_load__`) only exist for external callers (RSC runtime)\n * and resolve the correct scope via the registry.\n */\nexport interface RemoteScope {\n /** Plain bundle name (e.g. \"remote-component-registry\") */\n name: string;\n /** Origin-qualified key — unique even when two remotes share a name */\n scopedName: string;\n /** Escaped key used as suffix for TURBOPACK_ globals */\n globalKey: string;\n /** Base URL for resolving relative chunk paths */\n url: URL;\n /** Bundler runtime type */\n runtime: Runtime;\n /** Proxy callback for routing chunks through the host */\n resolveClientUrl?: InternalResolveClientUrl;\n /** Per-scope cache of executed Turbopack module exports */\n moduleCache: Record<string, unknown>;\n /** Per-scope shared modules provided by the host (React, etc.) */\n sharedModules: Record<string, unknown>;\n /** Per-scope globalThis substitute passed to module initializers as `g` */\n moduleGlobal: Record<string, unknown>;\n /**\n * Webpack's bundle-scoped require function, populated from\n * `__remote_webpack_require__[bundleName]` for webpack remotes.\n * Undefined for turbopack remotes.\n */\n webpackRequire?: ((id: string | number) => unknown) & {\n m?: Record<string | number, (module: { exports: unknown }) => void>;\n type?: string;\n };\n /**\n * Flat array of captured turbopack module entries: [scriptEl, id, factory, ...].\n * Populated by the push interceptor in handleTurbopackChunk. This is the\n * primary source of truth for getTurbopackModules — immune to the turbopack\n * runtime replacing the TURBOPACK global (canary builds use a deferred-loading\n * pattern that swaps the array for an immediate-processing dispatcher).\n */\n turbopackModules: unknown[];\n}\n\nfunction getRegistry(): Map<string, RemoteScope> {\n return getNamespace().scopes;\n}\n\nexport function createScope(\n name: string,\n url: URL,\n runtime: Runtime,\n resolveClientUrl?: InternalResolveClientUrl,\n): RemoteScope {\n const scopedName = computeScopedName(name, { remoteHost: url.host });\n const globalKey = getBundleKey(scopedName);\n return {\n name,\n scopedName,\n globalKey,\n url,\n runtime,\n resolveClientUrl,\n moduleCache: {},\n sharedModules: {},\n moduleGlobal: {},\n turbopackModules: [],\n };\n}\n\nexport function registerScope(scope: RemoteScope): void {\n const registry = getRegistry();\n registry.set(scope.scopedName, scope);\n\n // Also register under the plain name so static/HTML hosts (which don't\n // rewrite RSC chunk IDs) can look up scopes by the unrewritten bundle name.\n if (scope.scopedName !== scope.name) {\n const existing = registry.get(scope.name);\n if (existing && existing.scopedName !== scope.scopedName) {\n logWarn(\n 'RemoteScope',\n `Plain name \"${scope.name}\" already registered by scope \"${existing.scopedName}\" — ` +\n `overwriting with \"${scope.scopedName}\". Static hosts will only resolve the latest one.`,\n );\n }\n registry.set(scope.name, scope);\n }\n\n logDebug(\n 'RemoteScope',\n `Registered scope \"${scope.scopedName}\" (${registry.size} total)`,\n );\n}\n\n/**\n * Resolves a scope by name. Accepts either the scoped name (used by Next.js\n * hosts that rewrite RSC data server-side) or the plain bundle name (used by\n * static/HTML hosts where chunks arrive unrewritten).\n */\nexport function getScope(name: string): RemoteScope | undefined {\n return getRegistry().get(name);\n}\n\n/** Formats a `[scopedName] path` string for use in chunk/module IDs. */\nexport function formatRemoteId(scope: RemoteScope, path: string): string {\n return `[${scope.scopedName}] ${path}`;\n}\n\n/**\n * Parses the `[bundle] path` format used in chunk/module IDs.\n * Uses REMOTE_COMPONENT_REGEX (the same pattern used by the module dispatcher\n * and script loader) so the two parsing paths can never diverge.\n */\nexport function parseRemoteId(id: string): {\n bundle: string;\n path: string;\n prefix: string;\n} {\n const groups = REMOTE_COMPONENT_REGEX.exec(id)?.groups;\n if (groups?.bundle && groups.id) {\n return {\n bundle: groups.bundle,\n path: groups.id,\n prefix: groups.prefix ?? '',\n };\n }\n return { bundle: 'default', path: id, prefix: '' };\n}\n"],"mappings":"AACA,SAAS,oBAAkC;AAC3C,SAAS,oBAAoB;AAC7B,SAAS,8BAA8B;AACvC,SAAS,yBAAyB;AAClC,SAAS,UAAU,eAAe;AAkDlC,SAAS,cAAwC;AAC/C,SAAO,aAAa,EAAE;AACxB;AAEO,SAAS,YACd,MACA,KACA,SACA,kBACa;AACb,QAAM,aAAa,kBAAkB,MAAM,EAAE,YAAY,IAAI,KAAK,CAAC;AACnE,QAAM,YAAY,aAAa,UAAU;AACzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,CAAC;AAAA,IACd,eAAe,CAAC;AAAA,IAChB,cAAc,CAAC;AAAA,IACf,kBAAkB,CAAC;AAAA,EACrB;AACF;AAEO,SAAS,cAAc,OAA0B;AACtD,QAAM,WAAW,YAAY;AAC7B,WAAS,IAAI,MAAM,YAAY,KAAK;AAIpC,MAAI,MAAM,eAAe,MAAM,MAAM;AACnC,UAAM,WAAW,SAAS,IAAI,MAAM,IAAI;AACxC,QAAI,YAAY,SAAS,eAAe,MAAM,YAAY;AACxD;AAAA,QACE;AAAA,QACA,eAAe,MAAM,sCAAsC,SAAS,wCAC7C,MAAM;AAAA,MAC/B;AAAA,IACF;AACA,aAAS,IAAI,MAAM,MAAM,KAAK;AAAA,EAChC;AAEA;AAAA,IACE;AAAA,IACA,qBAAqB,MAAM,gBAAgB,SAAS;AAAA,EACtD;AACF;AAOO,SAAS,SAAS,MAAuC;AAC9D,SAAO,YAAY,EAAE,IAAI,IAAI;AAC/B;AAGO,SAAS,eAAe,OAAoB,MAAsB;AACvE,SAAO,IAAI,MAAM,eAAe;AAClC;AAOO,SAAS,cAAc,IAI5B;AACA,QAAM,SAAS,uBAAuB,KAAK,EAAE,GAAG;AAChD,MAAI,QAAQ,UAAU,OAAO,IAAI;AAC/B,WAAO;AAAA,MACL,QAAQ,OAAO;AAAA,MACf,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO,UAAU;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,WAAW,MAAM,IAAI,QAAQ,GAAG;AACnD;","names":[]}
|
package/dist/internal/utils.cjs
CHANGED
|
@@ -27,7 +27,7 @@ function escapeString(str) {
|
|
|
27
27
|
return str.replace(/[^a-z0-9]/g, "_");
|
|
28
28
|
}
|
|
29
29
|
function computeScopedName(name, options) {
|
|
30
|
-
return
|
|
30
|
+
return `${name}_${escapeString(options.remoteHost.toLowerCase())}`;
|
|
31
31
|
}
|
|
32
32
|
const attrToProp = {
|
|
33
33
|
fetchpriority: "fetchPriority",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export function escapeString(str: string) {\n return str.replace(/[^a-z0-9]/g, '_');\n}\n\n/**\n * Computes the origin-qualified scoped name for a bundle.
|
|
1
|
+
{"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export function escapeString(str: string) {\n return str.replace(/[^a-z0-9]/g, '_');\n}\n\n/**\n * Computes the origin-qualified scoped name for a bundle by appending\n * the escaped host (hostname + port). This ensures the server and client\n * always agree on the scoped name — the server's cross-origin detection\n * (based on deployment URL) can differ from the client's (based on\n * `location.origin`), so the name must not depend on that distinction.\n *\n * Used on both the server (to rewrite RSC flight data) and the client\n * (to create and look up RemoteScopes). Both sides must produce the\n * same value for a given remote.\n */\nexport function computeScopedName(\n name: string,\n options: { remoteHost: string },\n): string {\n return `${name}_${escapeString(options.remoteHost.toLowerCase())}`;\n}\n\nexport const attrToProp = {\n fetchpriority: 'fetchPriority',\n crossorigin: 'crossOrigin',\n imagesrcset: 'imageSrcSet',\n imagesizes: 'imageSizes',\n srcset: 'srcSet',\n} as Record<string, string>;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,aAAa,KAAa;AACxC,SAAO,IAAI,QAAQ,cAAc,GAAG;AACtC;AAaO,SAAS,kBACd,MACA,SACQ;AACR,SAAO,GAAG,QAAQ,aAAa,QAAQ,WAAW,YAAY,CAAC;AACjE;AAEO,MAAM,aAAa;AAAA,EACxB,eAAe;AAAA,EACf,aAAa;AAAA,EACb,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,QAAQ;AACV;","names":[]}
|
package/dist/internal/utils.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
declare function escapeString(str: string): string;
|
|
2
2
|
/**
|
|
3
|
-
* Computes the origin-qualified scoped name for a bundle
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* Computes the origin-qualified scoped name for a bundle by appending
|
|
4
|
+
* the escaped host (hostname + port). This ensures the server and client
|
|
5
|
+
* always agree on the scoped name — the server's cross-origin detection
|
|
6
|
+
* (based on deployment URL) can differ from the client's (based on
|
|
7
|
+
* `location.origin`), so the name must not depend on that distinction.
|
|
7
8
|
*
|
|
8
9
|
* Used on both the server (to rewrite RSC flight data) and the client
|
|
9
10
|
* (to create and look up RemoteScopes). Both sides must produce the
|
|
@@ -11,7 +12,6 @@ declare function escapeString(str: string): string;
|
|
|
11
12
|
*/
|
|
12
13
|
declare function computeScopedName(name: string, options: {
|
|
13
14
|
remoteHost: string;
|
|
14
|
-
isCrossOrigin: boolean;
|
|
15
15
|
}): string;
|
|
16
16
|
declare const attrToProp: Record<string, string>;
|
|
17
17
|
|
package/dist/internal/utils.js
CHANGED
|
@@ -2,7 +2,7 @@ function escapeString(str) {
|
|
|
2
2
|
return str.replace(/[^a-z0-9]/g, "_");
|
|
3
3
|
}
|
|
4
4
|
function computeScopedName(name, options) {
|
|
5
|
-
return
|
|
5
|
+
return `${name}_${escapeString(options.remoteHost.toLowerCase())}`;
|
|
6
6
|
}
|
|
7
7
|
const attrToProp = {
|
|
8
8
|
fetchpriority: "fetchPriority",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export function escapeString(str: string) {\n return str.replace(/[^a-z0-9]/g, '_');\n}\n\n/**\n * Computes the origin-qualified scoped name for a bundle.
|
|
1
|
+
{"version":3,"sources":["../../src/utils/index.ts"],"sourcesContent":["export function escapeString(str: string) {\n return str.replace(/[^a-z0-9]/g, '_');\n}\n\n/**\n * Computes the origin-qualified scoped name for a bundle by appending\n * the escaped host (hostname + port). This ensures the server and client\n * always agree on the scoped name — the server's cross-origin detection\n * (based on deployment URL) can differ from the client's (based on\n * `location.origin`), so the name must not depend on that distinction.\n *\n * Used on both the server (to rewrite RSC flight data) and the client\n * (to create and look up RemoteScopes). Both sides must produce the\n * same value for a given remote.\n */\nexport function computeScopedName(\n name: string,\n options: { remoteHost: string },\n): string {\n return `${name}_${escapeString(options.remoteHost.toLowerCase())}`;\n}\n\nexport const attrToProp = {\n fetchpriority: 'fetchPriority',\n crossorigin: 'crossOrigin',\n imagesrcset: 'imageSrcSet',\n imagesizes: 'imageSizes',\n srcset: 'srcSet',\n} as Record<string, string>;\n"],"mappings":"AAAO,SAAS,aAAa,KAAa;AACxC,SAAO,IAAI,QAAQ,cAAc,GAAG;AACtC;AAaO,SAAS,kBACd,MACA,SACQ;AACR,SAAO,GAAG,QAAQ,aAAa,QAAQ,WAAW,YAAY,CAAC;AACjE;AAEO,MAAM,aAAa;AAAA,EACxB,eAAe;AAAA,EACf,aAAa;AAAA,EACb,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,QAAQ;AACV;","names":[]}
|