remote-components 0.3.0 → 0.3.1
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/host/html.cjs +88 -53
- package/dist/host/html.cjs.map +1 -1
- package/dist/host/html.js +88 -53
- package/dist/host/html.js.map +1 -1
- package/dist/host/nextjs/app/client-only.cjs +64 -22
- package/dist/host/nextjs/app/client-only.cjs.map +1 -1
- package/dist/host/nextjs/app/client-only.js +64 -22
- package/dist/host/nextjs/app/client-only.js.map +1 -1
- package/dist/host/nextjs/app.cjs +5 -6
- package/dist/host/nextjs/app.cjs.map +1 -1
- package/dist/host/nextjs/app.js +5 -6
- package/dist/host/nextjs/app.js.map +1 -1
- package/dist/host/nextjs/pages.cjs +6 -11
- package/dist/host/nextjs/pages.cjs.map +1 -1
- package/dist/host/nextjs/pages.js +9 -11
- package/dist/host/nextjs/pages.js.map +1 -1
- package/dist/host/react.cjs +64 -22
- package/dist/host/react.cjs.map +1 -1
- package/dist/host/react.js +64 -22
- package/dist/host/react.js.map +1 -1
- package/dist/internal/host/nextjs/dom-flight.cjs +16 -7
- package/dist/internal/host/nextjs/dom-flight.cjs.map +1 -1
- package/dist/internal/host/nextjs/dom-flight.d.ts +2 -2
- package/dist/internal/host/nextjs/dom-flight.js +16 -7
- package/dist/internal/host/nextjs/dom-flight.js.map +1 -1
- package/dist/internal/host/server/fetch-remote-component.cjs +164 -149
- package/dist/internal/host/server/fetch-remote-component.cjs.map +1 -1
- package/dist/internal/host/server/fetch-remote-component.js +166 -149
- package/dist/internal/host/server/fetch-remote-component.js.map +1 -1
- package/dist/internal/runtime/constants.cjs +6 -6
- package/dist/internal/runtime/constants.cjs.map +1 -1
- package/dist/internal/runtime/constants.d.ts +3 -3
- package/dist/internal/runtime/constants.js +4 -4
- package/dist/internal/runtime/constants.js.map +1 -1
- package/dist/internal/runtime/html/parse-remote-html.cjs +11 -15
- package/dist/internal/runtime/html/parse-remote-html.cjs.map +1 -1
- package/dist/internal/runtime/html/parse-remote-html.d.ts +2 -12
- package/dist/internal/runtime/html/parse-remote-html.js +17 -15
- package/dist/internal/runtime/html/parse-remote-html.js.map +1 -1
- package/dist/internal/runtime/loaders/script-loader.cjs +2 -2
- package/dist/internal/runtime/loaders/script-loader.cjs.map +1 -1
- package/dist/internal/runtime/loaders/script-loader.js +1 -1
- package/dist/internal/runtime/loaders/script-loader.js.map +1 -1
- package/dist/internal/runtime/metadata.cjs +42 -0
- package/dist/internal/runtime/metadata.cjs.map +1 -1
- package/dist/internal/runtime/metadata.d.ts +21 -1
- package/dist/internal/runtime/metadata.js +38 -0
- package/dist/internal/runtime/metadata.js.map +1 -1
- package/dist/internal/runtime/patterns.cjs +38 -0
- package/dist/internal/runtime/patterns.cjs.map +1 -0
- package/dist/internal/runtime/patterns.d.ts +5 -0
- package/dist/internal/runtime/patterns.js +12 -0
- package/dist/internal/runtime/patterns.js.map +1 -0
- package/dist/internal/runtime/turbopack/chunk-loader.cjs +4 -3
- package/dist/internal/runtime/turbopack/chunk-loader.cjs.map +1 -1
- package/dist/internal/runtime/turbopack/chunk-loader.js +1 -1
- package/dist/internal/runtime/turbopack/chunk-loader.js.map +1 -1
- package/dist/internal/runtime/turbopack/webpack-runtime.cjs +11 -2
- package/dist/internal/runtime/turbopack/webpack-runtime.cjs.map +1 -1
- package/dist/internal/runtime/turbopack/webpack-runtime.js +10 -2
- package/dist/internal/runtime/turbopack/webpack-runtime.js.map +1 -1
- package/dist/remote/nextjs/app.cjs +2 -1
- package/dist/remote/nextjs/app.cjs.map +1 -1
- package/dist/remote/nextjs/app.js +2 -1
- package/dist/remote/nextjs/app.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/host/server/fetch-remote-component.ts"],"sourcesContent":["import { type DefaultTreeAdapterMap, Parser } from 'parse5';\nimport { 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 type { RemoteComponentMetadata } from '#internal/runtime/metadata';\nimport {\n failedToFetchRemoteComponentError,\n multipleRemoteComponentsError,\n RemoteComponentsError,\n} from '#internal/utils/error';\nimport type { FetchRemoteComponentResponse, NextData } from './types';\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\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 rsc: false,\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 let metadata: RemoteComponentMetadata = {\n bundle: CURRENT_ZONE ?? '__vercel_remote_component',\n route: '/',\n runtime: 'webpack',\n id: '__vercel_remote_component',\n type: 'unknown',\n };\n let remoteShared: Record<string, string> = {};\n const scripts: ScriptDescriptor[] = [];\n const links: LinkDescriptor[] = [];\n const hydrationData: string[] = [];\n let nextData: NextData | undefined;\n let html = '';\n\n const remoteName =\n options.name || (serverUrl.hash ? serverUrl.hash.substring(1) : undefined);\n // convert the parsed HTML fragment into an RSC flight data\n // and extract the metadata, scripts, links and remote component RSC flight data\n let hasRemoteComponent = false;\n let hasRSC = false;\n let hasShared = false;\n let hasMultipleRemoteComponents = false;\n let error: RemoteComponentsError | undefined;\n const rsc = visit(fragment, {\n url: serverUrl,\n name: remoteName,\n onMetadata(_metadata) {\n // Skip multiple component detection for Pages Router (__next) since it only supports one remote component per page\n if (\n hasRemoteComponent &&\n metadata.id !== _metadata.id &&\n _metadata.id !== '__next' &&\n metadata.id !== '__next' &&\n !nextData\n ) {\n hasMultipleRemoteComponents = true;\n }\n metadata = _metadata;\n hasRemoteComponent = true;\n },\n onScript(attrs) {\n const clientSrc = getClientSrc(attrs.src, serverUrl.href);\n if (\n !scripts.find(\n (it) =>\n it.src === clientSrc ||\n (attrs.textContent && it.textContent === attrs.textContent),\n )\n ) {\n scripts.push(\n typeof attrs.textContent === 'string'\n ? {\n src: '',\n textContent: attrs.textContent,\n }\n : {\n src: clientSrc,\n },\n );\n }\n },\n onLink(attrs) {\n const relativeAttrs = {\n ...attrs,\n href: getClientSrc(attrs.href, serverUrl.href),\n };\n if (\n !links.find(\n (it) => it.href === relativeAttrs.href && it.rel === attrs.rel,\n )\n ) {\n links.push(relativeAttrs);\n }\n },\n onRSC(chunk) {\n hydrationData.push(chunk);\n hasRSC = true;\n },\n onNextData(data) {\n nextData = data;\n\n // use the Next.js Pages Router props data to extract remote component metadata\n if (data.props.__REMOTE_COMPONENT__) {\n Object.assign(metadata, data.props.__REMOTE_COMPONENT__);\n // only a singleton remote component is supported per page when using the Next.js Pages Router\n metadata.id = '__next';\n metadata.route = data.page ?? '/';\n }\n },\n onHTML(_html) {\n if (!html.includes(_html)) {\n html += _html;\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 if (error) {\n throw error;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!hasRemoteComponent) {\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 const skeletonMessage = getSkeletonMessage();\n const skeletonHtml = getSkeletonHtml(serverUrl.href);\n\n let skeletonComponent: React.ReactNode | undefined;\n if (options.rsc) {\n const { createElement } = await import('react');\n skeletonComponent = createElement('div', {\n dangerouslySetInnerHTML: { __html: skeletonHtml },\n });\n }\n\n return {\n name: 'remote-component-skeleton',\n serverUrl,\n metadata: {\n ...metadata,\n type: 'remote-component',\n },\n rsc: skeletonMessage,\n scripts: [],\n links: [],\n hydrationData: [],\n nextData: undefined,\n component: skeletonComponent,\n html: skeletonHtml,\n remoteShared: {},\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 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (hasMultipleRemoteComponents && !remoteName) {\n throw multipleRemoteComponentsError(serverUrl.href);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\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 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\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 let component: React.ReactNode | undefined;\n\n // only create a React component if requested\n if (options.rsc) {\n // RSC flight data for the static HTML in a single RSC line\n const componentRSC = `0:${JSON.stringify(rsc)}\\n`;\n\n const { createFromReadableStream } = await import(\n 'next/dist/compiled/react-server-dom-webpack/client.edge'\n );\n\n // create a React tree from the RSC flight data\n component = await 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\n return {\n name: remoteName || metadata.id.replace(/_ssr$/, ''),\n serverUrl,\n metadata,\n rsc,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n html,\n remoteShared: nextData?.props.__REMOTE_COMPONENT__?.shared ?? 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 {\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 import(\n 'next/dist/compiled/react-server-dom-webpack/client.edge'\n );\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 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 hydrationData.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 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":[]}
|
|
@@ -7,15 +7,155 @@ import {
|
|
|
7
7
|
import { fetchWithHooks } from "#internal/host/server/fetch-with-hooks";
|
|
8
8
|
import { getClientSrc } from "#internal/host/server/get-client-src";
|
|
9
9
|
import { getSSRRelativePathBaseUrl } from "#internal/host/server/get-ssr-relative-path-base-url";
|
|
10
|
+
import {
|
|
11
|
+
buildMetadata
|
|
12
|
+
} from "#internal/runtime/metadata";
|
|
10
13
|
import {
|
|
11
14
|
failedToFetchRemoteComponentError,
|
|
12
15
|
multipleRemoteComponentsError,
|
|
13
16
|
RemoteComponentsError
|
|
14
17
|
} from "#internal/utils/error";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
})
|
|
18
|
+
async function buildRscComponent(rsc, serverUrl) {
|
|
19
|
+
const componentRSC = `0:${JSON.stringify(rsc)}
|
|
20
|
+
`;
|
|
21
|
+
const { createFromReadableStream } = await import("next/dist/compiled/react-server-dom-webpack/client.edge");
|
|
22
|
+
return createFromReadableStream(
|
|
23
|
+
new ReadableStream({
|
|
24
|
+
type: "bytes",
|
|
25
|
+
start(controller) {
|
|
26
|
+
const encoder = new TextEncoder();
|
|
27
|
+
controller.enqueue(encoder.encode(componentRSC));
|
|
28
|
+
controller.close();
|
|
29
|
+
}
|
|
30
|
+
}),
|
|
31
|
+
{
|
|
32
|
+
serverConsumerManifest: {
|
|
33
|
+
moduleLoading: {
|
|
34
|
+
prefix: serverUrl.origin,
|
|
35
|
+
crossOrigin: true
|
|
36
|
+
},
|
|
37
|
+
moduleMap: {}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function buildSkeletonResponse(serverUrl, metadata, skeletonComponent) {
|
|
43
|
+
return {
|
|
44
|
+
name: "remote-component-skeleton",
|
|
45
|
+
serverUrl,
|
|
46
|
+
metadata: {
|
|
47
|
+
...metadata,
|
|
48
|
+
type: "remote-component"
|
|
49
|
+
},
|
|
50
|
+
rsc: getSkeletonMessage(),
|
|
51
|
+
scripts: [],
|
|
52
|
+
links: [],
|
|
53
|
+
hydrationData: [],
|
|
54
|
+
nextData: void 0,
|
|
55
|
+
component: skeletonComponent,
|
|
56
|
+
html: getSkeletonHtml(serverUrl.href),
|
|
57
|
+
remoteShared: {}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function visitFragment(fragment, serverUrl, remoteName) {
|
|
61
|
+
const scriptSrcSet = /* @__PURE__ */ new Set();
|
|
62
|
+
const scriptTextSet = /* @__PURE__ */ new Set();
|
|
63
|
+
const scripts = [];
|
|
64
|
+
const linkKeySet = /* @__PURE__ */ new Set();
|
|
65
|
+
const links = [];
|
|
66
|
+
const hydrationData = [];
|
|
67
|
+
const htmlChunks = /* @__PURE__ */ new Set();
|
|
68
|
+
let metadata;
|
|
69
|
+
let nextData;
|
|
70
|
+
let remoteShared = {};
|
|
71
|
+
let hasRSC = false;
|
|
72
|
+
let hasShared = false;
|
|
73
|
+
let error;
|
|
74
|
+
const rsc = visit(fragment, {
|
|
75
|
+
url: serverUrl,
|
|
76
|
+
name: remoteName,
|
|
77
|
+
onMetadata(attrs) {
|
|
78
|
+
const incoming = buildMetadata(attrs, serverUrl);
|
|
79
|
+
if (!remoteName && metadata && metadata.id !== incoming.id && incoming.id !== "__next" && metadata.id !== "__next" && !nextData) {
|
|
80
|
+
throw multipleRemoteComponentsError(serverUrl.href);
|
|
81
|
+
}
|
|
82
|
+
metadata = incoming;
|
|
83
|
+
},
|
|
84
|
+
onScript(attrs) {
|
|
85
|
+
const clientSrc = getClientSrc(attrs.src, serverUrl.href);
|
|
86
|
+
const textContent = typeof attrs.textContent === "string" ? attrs.textContent : void 0;
|
|
87
|
+
if (textContent) {
|
|
88
|
+
if (!scriptTextSet.has(textContent)) {
|
|
89
|
+
scriptTextSet.add(textContent);
|
|
90
|
+
scripts.push({ src: "", textContent });
|
|
91
|
+
}
|
|
92
|
+
} else if (!scriptSrcSet.has(clientSrc)) {
|
|
93
|
+
scriptSrcSet.add(clientSrc);
|
|
94
|
+
scripts.push({ src: clientSrc });
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
onLink(attrs) {
|
|
98
|
+
const relativeAttrs = {
|
|
99
|
+
...attrs,
|
|
100
|
+
href: getClientSrc(attrs.href, serverUrl.href)
|
|
101
|
+
};
|
|
102
|
+
const linkKey = `${relativeAttrs.href}::${attrs.rel}`;
|
|
103
|
+
if (!linkKeySet.has(linkKey)) {
|
|
104
|
+
linkKeySet.add(linkKey);
|
|
105
|
+
links.push(relativeAttrs);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
onRSC(chunk) {
|
|
109
|
+
hydrationData.push(chunk);
|
|
110
|
+
hasRSC = true;
|
|
111
|
+
},
|
|
112
|
+
onNextData(data) {
|
|
113
|
+
nextData = data;
|
|
114
|
+
},
|
|
115
|
+
onHTML(chunk) {
|
|
116
|
+
if (!htmlChunks.has(chunk)) {
|
|
117
|
+
htmlChunks.add(chunk);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
onShared(_shared) {
|
|
121
|
+
remoteShared = _shared;
|
|
122
|
+
hasShared = true;
|
|
123
|
+
},
|
|
124
|
+
onError(message, stack) {
|
|
125
|
+
error = new RemoteComponentsError(message);
|
|
126
|
+
if (stack) {
|
|
127
|
+
error.stack = stack;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
if (error) {
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
if (metadata) {
|
|
135
|
+
if (!hasRSC && !nextData && metadata.type === "nextjs") {
|
|
136
|
+
throw new RemoteComponentsError(
|
|
137
|
+
`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.`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
if (metadata.type === "nextjs" && !hasShared && !nextData?.props.__REMOTE_COMPONENT__?.shared) {
|
|
141
|
+
throw new RemoteComponentsError(
|
|
142
|
+
`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.`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const resolvedShared = nextData?.props.__REMOTE_COMPONENT__?.shared ?? remoteShared;
|
|
147
|
+
return {
|
|
148
|
+
rsc,
|
|
149
|
+
metadata,
|
|
150
|
+
scripts,
|
|
151
|
+
links,
|
|
152
|
+
hydrationData,
|
|
153
|
+
nextData,
|
|
154
|
+
remoteShared: resolvedShared,
|
|
155
|
+
html: Array.from(htmlChunks).join("")
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async function fetchRemoteComponent(src, options = {}) {
|
|
19
159
|
const ssrRelativePathBaseUrl = getSSRRelativePathBaseUrl();
|
|
20
160
|
const serverUrl = new URL(src, ssrRelativePathBaseUrl);
|
|
21
161
|
const tags = [
|
|
@@ -68,122 +208,36 @@ async function fetchRemoteComponent(src, options = {
|
|
|
68
208
|
parser.tokenizer.write(decoder.decode(chunk), false);
|
|
69
209
|
}
|
|
70
210
|
const fragment = parser.getFragment();
|
|
71
|
-
let metadata = {
|
|
72
|
-
bundle: CURRENT_ZONE ?? "__vercel_remote_component",
|
|
73
|
-
route: "/",
|
|
74
|
-
runtime: "webpack",
|
|
75
|
-
id: "__vercel_remote_component",
|
|
76
|
-
type: "unknown"
|
|
77
|
-
};
|
|
78
|
-
let remoteShared = {};
|
|
79
|
-
const scripts = [];
|
|
80
|
-
const links = [];
|
|
81
|
-
const hydrationData = [];
|
|
82
|
-
let nextData;
|
|
83
|
-
let html = "";
|
|
84
211
|
const remoteName = options.name || (serverUrl.hash ? serverUrl.hash.substring(1) : void 0);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
metadata = _metadata;
|
|
98
|
-
hasRemoteComponent = true;
|
|
99
|
-
},
|
|
100
|
-
onScript(attrs) {
|
|
101
|
-
const clientSrc = getClientSrc(attrs.src, serverUrl.href);
|
|
102
|
-
if (!scripts.find(
|
|
103
|
-
(it) => it.src === clientSrc || attrs.textContent && it.textContent === attrs.textContent
|
|
104
|
-
)) {
|
|
105
|
-
scripts.push(
|
|
106
|
-
typeof attrs.textContent === "string" ? {
|
|
107
|
-
src: "",
|
|
108
|
-
textContent: attrs.textContent
|
|
109
|
-
} : {
|
|
110
|
-
src: clientSrc
|
|
111
|
-
}
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
onLink(attrs) {
|
|
116
|
-
const relativeAttrs = {
|
|
117
|
-
...attrs,
|
|
118
|
-
href: getClientSrc(attrs.href, serverUrl.href)
|
|
119
|
-
};
|
|
120
|
-
if (!links.find(
|
|
121
|
-
(it) => it.href === relativeAttrs.href && it.rel === attrs.rel
|
|
122
|
-
)) {
|
|
123
|
-
links.push(relativeAttrs);
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
onRSC(chunk) {
|
|
127
|
-
hydrationData.push(chunk);
|
|
128
|
-
hasRSC = true;
|
|
129
|
-
},
|
|
130
|
-
onNextData(data) {
|
|
131
|
-
nextData = data;
|
|
132
|
-
if (data.props.__REMOTE_COMPONENT__) {
|
|
133
|
-
Object.assign(metadata, data.props.__REMOTE_COMPONENT__);
|
|
134
|
-
metadata.id = "__next";
|
|
135
|
-
metadata.route = data.page ?? "/";
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
onHTML(_html) {
|
|
139
|
-
if (!html.includes(_html)) {
|
|
140
|
-
html += _html;
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
onShared(_shared) {
|
|
144
|
-
remoteShared = _shared;
|
|
145
|
-
hasShared = true;
|
|
146
|
-
},
|
|
147
|
-
onError(message, stack) {
|
|
148
|
-
error = new RemoteComponentsError(message);
|
|
149
|
-
if (stack) {
|
|
150
|
-
error.stack = stack;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
if (error) {
|
|
155
|
-
throw error;
|
|
156
|
-
}
|
|
157
|
-
if (!hasRemoteComponent) {
|
|
212
|
+
const {
|
|
213
|
+
rsc,
|
|
214
|
+
metadata,
|
|
215
|
+
scripts,
|
|
216
|
+
links,
|
|
217
|
+
hydrationData,
|
|
218
|
+
nextData,
|
|
219
|
+
remoteShared,
|
|
220
|
+
html
|
|
221
|
+
} = visitFragment(fragment, serverUrl, remoteName);
|
|
222
|
+
if (!metadata) {
|
|
158
223
|
const isSSGBuild = process.env.NEXT_PHASE === "phase-production-build";
|
|
159
224
|
const isSSRRelativePathBase = serverUrl.host === new URL(ssrRelativePathBaseUrl).host;
|
|
160
225
|
const isPreview = process.env.VERCEL_TARGET_ENV === "preview";
|
|
161
226
|
if (isSSGBuild && isSSRRelativePathBase && isPreview && options.appRouter) {
|
|
162
|
-
const skeletonMessage = getSkeletonMessage();
|
|
163
|
-
const skeletonHtml = getSkeletonHtml(serverUrl.href);
|
|
164
227
|
let skeletonComponent;
|
|
165
228
|
if (options.rsc) {
|
|
166
229
|
const { createElement } = await import("react");
|
|
167
230
|
skeletonComponent = createElement("div", {
|
|
168
|
-
dangerouslySetInnerHTML: {
|
|
231
|
+
dangerouslySetInnerHTML: {
|
|
232
|
+
__html: getSkeletonHtml(serverUrl.href)
|
|
233
|
+
}
|
|
169
234
|
});
|
|
170
235
|
}
|
|
171
|
-
return
|
|
172
|
-
name: "remote-component-skeleton",
|
|
236
|
+
return buildSkeletonResponse(
|
|
173
237
|
serverUrl,
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
},
|
|
178
|
-
rsc: skeletonMessage,
|
|
179
|
-
scripts: [],
|
|
180
|
-
links: [],
|
|
181
|
-
hydrationData: [],
|
|
182
|
-
nextData: void 0,
|
|
183
|
-
component: skeletonComponent,
|
|
184
|
-
html: skeletonHtml,
|
|
185
|
-
remoteShared: {}
|
|
186
|
-
};
|
|
238
|
+
buildMetadata({}, serverUrl),
|
|
239
|
+
skeletonComponent
|
|
240
|
+
);
|
|
187
241
|
}
|
|
188
242
|
throw failedToFetchRemoteComponentError(
|
|
189
243
|
serverUrl.href,
|
|
@@ -191,47 +245,10 @@ async function fetchRemoteComponent(src, options = {
|
|
|
191
245
|
`No Remote Component found. Make sure the remote URL is correct and contains a Remote Component.`
|
|
192
246
|
);
|
|
193
247
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
if (!hasRSC && !nextData && metadata.type === "nextjs") {
|
|
198
|
-
throw new RemoteComponentsError(
|
|
199
|
-
`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.`
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
if (metadata.type === "nextjs" && // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
203
|
-
!hasShared && !nextData?.props.__REMOTE_COMPONENT__?.shared) {
|
|
204
|
-
throw new RemoteComponentsError(
|
|
205
|
-
`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.`
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
let component;
|
|
209
|
-
if (options.rsc) {
|
|
210
|
-
const componentRSC = `0:${JSON.stringify(rsc)}
|
|
211
|
-
`;
|
|
212
|
-
const { createFromReadableStream } = await import("next/dist/compiled/react-server-dom-webpack/client.edge");
|
|
213
|
-
component = await createFromReadableStream(
|
|
214
|
-
new ReadableStream({
|
|
215
|
-
type: "bytes",
|
|
216
|
-
start(controller) {
|
|
217
|
-
const encoder = new TextEncoder();
|
|
218
|
-
controller.enqueue(encoder.encode(componentRSC));
|
|
219
|
-
controller.close();
|
|
220
|
-
}
|
|
221
|
-
}),
|
|
222
|
-
{
|
|
223
|
-
serverConsumerManifest: {
|
|
224
|
-
moduleLoading: {
|
|
225
|
-
prefix: serverUrl.origin,
|
|
226
|
-
crossOrigin: true
|
|
227
|
-
},
|
|
228
|
-
moduleMap: {}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
);
|
|
232
|
-
}
|
|
248
|
+
const name = remoteName || metadata.name;
|
|
249
|
+
const component = options.rsc ? await buildRscComponent(rsc, serverUrl) : void 0;
|
|
233
250
|
return {
|
|
234
|
-
name
|
|
251
|
+
name,
|
|
235
252
|
serverUrl,
|
|
236
253
|
metadata,
|
|
237
254
|
rsc,
|
|
@@ -241,7 +258,7 @@ async function fetchRemoteComponent(src, options = {
|
|
|
241
258
|
nextData,
|
|
242
259
|
component,
|
|
243
260
|
html,
|
|
244
|
-
remoteShared
|
|
261
|
+
remoteShared
|
|
245
262
|
};
|
|
246
263
|
}
|
|
247
264
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/host/server/fetch-remote-component.ts"],"sourcesContent":["import { type DefaultTreeAdapterMap, Parser } from 'parse5';\nimport { 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 type { RemoteComponentMetadata } from '#internal/runtime/metadata';\nimport {\n failedToFetchRemoteComponentError,\n multipleRemoteComponentsError,\n RemoteComponentsError,\n} from '#internal/utils/error';\nimport type { FetchRemoteComponentResponse, NextData } from './types';\n\nconst CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;\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 rsc: false,\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 let metadata: RemoteComponentMetadata = {\n bundle: CURRENT_ZONE ?? '__vercel_remote_component',\n route: '/',\n runtime: 'webpack',\n id: '__vercel_remote_component',\n type: 'unknown',\n };\n let remoteShared: Record<string, string> = {};\n const scripts: ScriptDescriptor[] = [];\n const links: LinkDescriptor[] = [];\n const hydrationData: string[] = [];\n let nextData: NextData | undefined;\n let html = '';\n\n const remoteName =\n options.name || (serverUrl.hash ? serverUrl.hash.substring(1) : undefined);\n // convert the parsed HTML fragment into an RSC flight data\n // and extract the metadata, scripts, links and remote component RSC flight data\n let hasRemoteComponent = false;\n let hasRSC = false;\n let hasShared = false;\n let hasMultipleRemoteComponents = false;\n let error: RemoteComponentsError | undefined;\n const rsc = visit(fragment, {\n url: serverUrl,\n name: remoteName,\n onMetadata(_metadata) {\n // Skip multiple component detection for Pages Router (__next) since it only supports one remote component per page\n if (\n hasRemoteComponent &&\n metadata.id !== _metadata.id &&\n _metadata.id !== '__next' &&\n metadata.id !== '__next' &&\n !nextData\n ) {\n hasMultipleRemoteComponents = true;\n }\n metadata = _metadata;\n hasRemoteComponent = true;\n },\n onScript(attrs) {\n const clientSrc = getClientSrc(attrs.src, serverUrl.href);\n if (\n !scripts.find(\n (it) =>\n it.src === clientSrc ||\n (attrs.textContent && it.textContent === attrs.textContent),\n )\n ) {\n scripts.push(\n typeof attrs.textContent === 'string'\n ? {\n src: '',\n textContent: attrs.textContent,\n }\n : {\n src: clientSrc,\n },\n );\n }\n },\n onLink(attrs) {\n const relativeAttrs = {\n ...attrs,\n href: getClientSrc(attrs.href, serverUrl.href),\n };\n if (\n !links.find(\n (it) => it.href === relativeAttrs.href && it.rel === attrs.rel,\n )\n ) {\n links.push(relativeAttrs);\n }\n },\n onRSC(chunk) {\n hydrationData.push(chunk);\n hasRSC = true;\n },\n onNextData(data) {\n nextData = data;\n\n // use the Next.js Pages Router props data to extract remote component metadata\n if (data.props.__REMOTE_COMPONENT__) {\n Object.assign(metadata, data.props.__REMOTE_COMPONENT__);\n // only a singleton remote component is supported per page when using the Next.js Pages Router\n metadata.id = '__next';\n metadata.route = data.page ?? '/';\n }\n },\n onHTML(_html) {\n if (!html.includes(_html)) {\n html += _html;\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 if (error) {\n throw error;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!hasRemoteComponent) {\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 const skeletonMessage = getSkeletonMessage();\n const skeletonHtml = getSkeletonHtml(serverUrl.href);\n\n let skeletonComponent: React.ReactNode | undefined;\n if (options.rsc) {\n const { createElement } = await import('react');\n skeletonComponent = createElement('div', {\n dangerouslySetInnerHTML: { __html: skeletonHtml },\n });\n }\n\n return {\n name: 'remote-component-skeleton',\n serverUrl,\n metadata: {\n ...metadata,\n type: 'remote-component',\n },\n rsc: skeletonMessage,\n scripts: [],\n links: [],\n hydrationData: [],\n nextData: undefined,\n component: skeletonComponent,\n html: skeletonHtml,\n remoteShared: {},\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 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (hasMultipleRemoteComponents && !remoteName) {\n throw multipleRemoteComponentsError(serverUrl.href);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\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 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\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 let component: React.ReactNode | undefined;\n\n // only create a React component if requested\n if (options.rsc) {\n // RSC flight data for the static HTML in a single RSC line\n const componentRSC = `0:${JSON.stringify(rsc)}\\n`;\n\n const { createFromReadableStream } = await import(\n 'next/dist/compiled/react-server-dom-webpack/client.edge'\n );\n\n // create a React tree from the RSC flight data\n component = await 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\n return {\n name: remoteName || metadata.id.replace(/_ssr$/, ''),\n serverUrl,\n metadata,\n rsc,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n html,\n remoteShared: nextData?.props.__REMOTE_COMPONENT__?.shared ?? 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 {\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 import(\n 'next/dist/compiled/react-server-dom-webpack/client.edge'\n );\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 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 hydrationData.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 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":[]}
|
|
@@ -18,9 +18,9 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var constants_exports = {};
|
|
20
20
|
__export(constants_exports, {
|
|
21
|
+
DEFAULT_BUNDLE_NAME: () => DEFAULT_BUNDLE_NAME,
|
|
22
|
+
DEFAULT_COMPONENT_NAME: () => DEFAULT_COMPONENT_NAME,
|
|
21
23
|
DEFAULT_ROUTE: () => DEFAULT_ROUTE,
|
|
22
|
-
NEXT_BUNDLE_PATH_RE: () => NEXT_BUNDLE_PATH_RE,
|
|
23
|
-
REMOTE_COMPONENT_REGEX: () => REMOTE_COMPONENT_REGEX,
|
|
24
24
|
RUNTIME_SCRIPT: () => RUNTIME_SCRIPT,
|
|
25
25
|
RUNTIME_TURBOPACK: () => RUNTIME_TURBOPACK,
|
|
26
26
|
RUNTIME_WEBPACK: () => RUNTIME_WEBPACK,
|
|
@@ -28,20 +28,20 @@ __export(constants_exports, {
|
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(constants_exports);
|
|
30
30
|
var import_utils = require("#internal/utils");
|
|
31
|
+
const DEFAULT_BUNDLE_NAME = "__vercel_remote_bundle";
|
|
32
|
+
const DEFAULT_COMPONENT_NAME = "__vercel_remote_component";
|
|
31
33
|
const DEFAULT_ROUTE = "/";
|
|
32
34
|
const RUNTIME_WEBPACK = "webpack";
|
|
33
35
|
const RUNTIME_TURBOPACK = "turbopack";
|
|
34
36
|
const RUNTIME_SCRIPT = "script";
|
|
35
|
-
const REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
|
|
36
|
-
const NEXT_BUNDLE_PATH_RE = /\/_next\/\[.+\](?:%20| )/;
|
|
37
37
|
function getBundleKey(bundle) {
|
|
38
38
|
return (0, import_utils.escapeString)(bundle);
|
|
39
39
|
}
|
|
40
40
|
// Annotate the CommonJS export names for ESM import in node:
|
|
41
41
|
0 && (module.exports = {
|
|
42
|
+
DEFAULT_BUNDLE_NAME,
|
|
43
|
+
DEFAULT_COMPONENT_NAME,
|
|
42
44
|
DEFAULT_ROUTE,
|
|
43
|
-
NEXT_BUNDLE_PATH_RE,
|
|
44
|
-
REMOTE_COMPONENT_REGEX,
|
|
45
45
|
RUNTIME_SCRIPT,
|
|
46
46
|
RUNTIME_TURBOPACK,
|
|
47
47
|
RUNTIME_WEBPACK,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/runtime/constants.ts"],"sourcesContent":["import { escapeString } from '#internal/utils';\n\nexport const
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/constants.ts"],"sourcesContent":["import { escapeString } from '#internal/utils';\n\nexport const DEFAULT_BUNDLE_NAME = '__vercel_remote_bundle';\nexport const DEFAULT_COMPONENT_NAME = '__vercel_remote_component';\nexport const DEFAULT_ROUTE = '/';\n\nexport const RUNTIME_WEBPACK = 'webpack';\nexport const RUNTIME_TURBOPACK = 'turbopack';\nexport const RUNTIME_SCRIPT = 'script';\n\nexport function getBundleKey(bundle: string): string {\n return escapeString(bundle);\n}\n\nexport type Runtime =\n | typeof RUNTIME_WEBPACK\n | typeof RUNTIME_TURBOPACK\n | typeof RUNTIME_SCRIPT;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6B;AAEtB,MAAM,sBAAsB;AAC5B,MAAM,yBAAyB;AAC/B,MAAM,gBAAgB;AAEtB,MAAM,kBAAkB;AACxB,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AAEvB,SAAS,aAAa,QAAwB;AACnD,aAAO,2BAAa,MAAM;AAC5B;","names":[]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
declare const DEFAULT_BUNDLE_NAME = "__vercel_remote_bundle";
|
|
2
|
+
declare const DEFAULT_COMPONENT_NAME = "__vercel_remote_component";
|
|
1
3
|
declare const DEFAULT_ROUTE = "/";
|
|
2
4
|
declare const RUNTIME_WEBPACK = "webpack";
|
|
3
5
|
declare const RUNTIME_TURBOPACK = "turbopack";
|
|
4
6
|
declare const RUNTIME_SCRIPT = "script";
|
|
5
|
-
declare const REMOTE_COMPONENT_REGEX: RegExp;
|
|
6
|
-
declare const NEXT_BUNDLE_PATH_RE: RegExp;
|
|
7
7
|
declare function getBundleKey(bundle: string): string;
|
|
8
8
|
type Runtime = typeof RUNTIME_WEBPACK | typeof RUNTIME_TURBOPACK | typeof RUNTIME_SCRIPT;
|
|
9
9
|
|
|
10
|
-
export {
|
|
10
|
+
export { DEFAULT_BUNDLE_NAME, DEFAULT_COMPONENT_NAME, DEFAULT_ROUTE, RUNTIME_SCRIPT, RUNTIME_TURBOPACK, RUNTIME_WEBPACK, Runtime, getBundleKey };
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { escapeString } from "#internal/utils";
|
|
2
|
+
const DEFAULT_BUNDLE_NAME = "__vercel_remote_bundle";
|
|
3
|
+
const DEFAULT_COMPONENT_NAME = "__vercel_remote_component";
|
|
2
4
|
const DEFAULT_ROUTE = "/";
|
|
3
5
|
const RUNTIME_WEBPACK = "webpack";
|
|
4
6
|
const RUNTIME_TURBOPACK = "turbopack";
|
|
5
7
|
const RUNTIME_SCRIPT = "script";
|
|
6
|
-
const REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
|
|
7
|
-
const NEXT_BUNDLE_PATH_RE = /\/_next\/\[.+\](?:%20| )/;
|
|
8
8
|
function getBundleKey(bundle) {
|
|
9
9
|
return escapeString(bundle);
|
|
10
10
|
}
|
|
11
11
|
export {
|
|
12
|
+
DEFAULT_BUNDLE_NAME,
|
|
13
|
+
DEFAULT_COMPONENT_NAME,
|
|
12
14
|
DEFAULT_ROUTE,
|
|
13
|
-
NEXT_BUNDLE_PATH_RE,
|
|
14
|
-
REMOTE_COMPONENT_REGEX,
|
|
15
15
|
RUNTIME_SCRIPT,
|
|
16
16
|
RUNTIME_TURBOPACK,
|
|
17
17
|
RUNTIME_WEBPACK,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/runtime/constants.ts"],"sourcesContent":["import { escapeString } from '#internal/utils';\n\nexport const
|
|
1
|
+
{"version":3,"sources":["../../../src/runtime/constants.ts"],"sourcesContent":["import { escapeString } from '#internal/utils';\n\nexport const DEFAULT_BUNDLE_NAME = '__vercel_remote_bundle';\nexport const DEFAULT_COMPONENT_NAME = '__vercel_remote_component';\nexport const DEFAULT_ROUTE = '/';\n\nexport const RUNTIME_WEBPACK = 'webpack';\nexport const RUNTIME_TURBOPACK = 'turbopack';\nexport const RUNTIME_SCRIPT = 'script';\n\nexport function getBundleKey(bundle: string): string {\n return escapeString(bundle);\n}\n\nexport type Runtime =\n | typeof RUNTIME_WEBPACK\n | typeof RUNTIME_TURBOPACK\n | typeof RUNTIME_SCRIPT;\n"],"mappings":"AAAA,SAAS,oBAAoB;AAEtB,MAAM,sBAAsB;AAC5B,MAAM,yBAAyB;AAC/B,MAAM,gBAAgB;AAEtB,MAAM,kBAAkB;AACxB,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AAEvB,SAAS,aAAa,QAAwB;AACnD,SAAO,aAAa,MAAM;AAC5B;","names":[]}
|