remote-components 0.2.2 → 0.3.0
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/config/nextjs.cjs +2 -4
- package/dist/config/nextjs.cjs.map +1 -1
- package/dist/config/nextjs.d.ts +1 -1
- package/dist/config/nextjs.js +2 -4
- package/dist/config/nextjs.js.map +1 -1
- package/dist/host/html.cjs +40 -59
- package/dist/host/html.cjs.map +1 -1
- package/dist/host/html.js +40 -62
- package/dist/host/html.js.map +1 -1
- package/dist/host/nextjs/app/client-only.cjs +169 -237
- package/dist/host/nextjs/app/client-only.cjs.map +1 -1
- package/dist/host/nextjs/app/client-only.js +170 -238
- package/dist/host/nextjs/app/client-only.js.map +1 -1
- package/dist/host/nextjs/pages.cjs +1 -8
- package/dist/host/nextjs/pages.cjs.map +1 -1
- package/dist/host/nextjs/pages.js +2 -9
- package/dist/host/nextjs/pages.js.map +1 -1
- package/dist/host/react.cjs +37 -71
- package/dist/host/react.cjs.map +1 -1
- package/dist/host/react.js +37 -71
- package/dist/host/react.js.map +1 -1
- package/dist/internal/host/nextjs/app-client.cjs +3 -8
- package/dist/internal/host/nextjs/app-client.cjs.map +1 -1
- package/dist/internal/host/nextjs/app-client.js +4 -9
- package/dist/internal/host/nextjs/app-client.js.map +1 -1
- package/dist/internal/host/nextjs/image-shared.cjs +25 -15
- package/dist/internal/host/nextjs/image-shared.cjs.map +1 -1
- package/dist/internal/host/nextjs/image-shared.d.ts +19 -6
- package/dist/internal/host/nextjs/image-shared.js +24 -14
- package/dist/internal/host/nextjs/image-shared.js.map +1 -1
- package/dist/internal/host/react/hooks/use-resolve-client-url.cjs +1 -5
- package/dist/internal/host/react/hooks/use-resolve-client-url.cjs.map +1 -1
- package/dist/internal/host/react/hooks/use-resolve-client-url.d.ts +1 -4
- package/dist/internal/host/react/hooks/use-resolve-client-url.js +1 -5
- package/dist/internal/host/react/hooks/use-resolve-client-url.js.map +1 -1
- package/dist/internal/host/shared/polyfill.cjs +10 -65
- package/dist/internal/host/shared/polyfill.cjs.map +1 -1
- package/dist/internal/host/shared/polyfill.d.ts +1 -3
- package/dist/internal/host/shared/polyfill.js +9 -63
- package/dist/internal/host/shared/polyfill.js.map +1 -1
- package/dist/internal/host/shared/remote-image-loader.cjs +53 -0
- package/dist/internal/host/shared/remote-image-loader.cjs.map +1 -0
- package/dist/internal/host/shared/remote-image-loader.d.ts +30 -0
- package/dist/internal/host/shared/remote-image-loader.js +29 -0
- package/dist/internal/host/shared/remote-image-loader.js.map +1 -0
- package/package.json +1 -1
- package/dist/internal/host/nextjs/image-impl.cjs +0 -64
- package/dist/internal/host/nextjs/image-impl.cjs.map +0 -1
- package/dist/internal/host/nextjs/image-impl.d.ts +0 -10
- package/dist/internal/host/nextjs/image-impl.js +0 -40
- package/dist/internal/host/nextjs/image-impl.js.map +0 -1
|
@@ -35,13 +35,11 @@ module.exports = __toCommonJS(pages_exports);
|
|
|
35
35
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
36
|
var import_wrapper = require("remote-components/remote/defaults/wrapper");
|
|
37
37
|
var Form = __toESM(require("next/form"), 1);
|
|
38
|
-
var Image = __toESM(require("next/image"), 1);
|
|
39
38
|
var Link = __toESM(require("next/link"), 1);
|
|
40
39
|
var Router = __toESM(require("next/router"), 1);
|
|
41
40
|
var Script = __toESM(require("next/script"), 1);
|
|
42
41
|
var import_react = require("react");
|
|
43
42
|
var import_react2 = require("remote-components/host/react");
|
|
44
|
-
var import_image_impl = require("#internal/host/nextjs/image-impl");
|
|
45
43
|
var import_image_shared = require("#internal/host/nextjs/image-shared");
|
|
46
44
|
var import_fetch_remote_component = require("#internal/host/server/fetch-remote-component");
|
|
47
45
|
var import_error = require("#internal/utils/error");
|
|
@@ -63,7 +61,6 @@ const shared = (bundle, resolveClientUrl) => {
|
|
|
63
61
|
return sharedCache.get(bundle);
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
|
-
const ImageComponent = Image.default.default ?? Image.default;
|
|
67
64
|
const result = {
|
|
68
65
|
// polyfill Next.js App Router client API (minimal)
|
|
69
66
|
// some API methods are not available when using a Next.js Pages Router application as host
|
|
@@ -77,11 +74,7 @@ const shared = (bundle, resolveClientUrl) => {
|
|
|
77
74
|
"next/script": () => Promise.resolve(Script.default),
|
|
78
75
|
"next/router": () => Promise.resolve(Router),
|
|
79
76
|
...import_pages.shared,
|
|
80
|
-
|
|
81
|
-
...(0, import_image_shared.createNextImageSharedEntries)(
|
|
82
|
-
() => (0, import_image_impl.imageImpl)(ImageComponent, bundle, resolveClientUrl, true),
|
|
83
|
-
{ getImageProps: Image.getImageProps }
|
|
84
|
-
)
|
|
77
|
+
...(0, import_image_shared.createImageLoaderSharedEntries)({ unbound: resolveClientUrl })
|
|
85
78
|
};
|
|
86
79
|
if (!resolveClientUrl) {
|
|
87
80
|
sharedCache.set(bundle, result);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/host/nextjs/pages.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport * as Form from 'next/form';\nimport * as Image from 'next/image';\nimport * as Link from 'next/link';\nimport * as Router from 'next/router';\nimport * as Script from 'next/script';\nimport { useEffect } from 'react';\nimport { ConsumeRemoteComponent as ConsumeRemoteComponentReact } from 'remote-components/host/react';\nimport { imageImpl } from '#internal/host/nextjs/image-impl';\nimport { createNextImageSharedEntries } from '#internal/host/nextjs/image-shared';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeRemoteComponentConfig } from '#internal/host/shared/config';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport type { ResolveClientUrl } from '#internal/runtime/url/resolve-client-url';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { shared as _shared } from '#remote-components/host/defaults/pages';\n\nconst navigationImpl = {\n useRouter: () => Router.useRouter(),\n useSearchParams: () => {\n const router = Router.useRouter();\n return {\n get: (key: string) => router.query[key],\n has: (key: string) => key in router.query,\n };\n },\n};\n\nconst sharedCache = new Map<string, Record<string, () => Promise<unknown>>>();\nconst shared = (bundle: string, resolveClientUrl?: ResolveClientUrl) => {\n // Skip cache when resolveClientUrl is provided — different resolver instances\n // must not share a cache entry, since imageImpl closes over the resolver.\n if (!resolveClientUrl) {\n if (sharedCache.has(bundle)) {\n return sharedCache.get(bundle);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ImageComponent: typeof Image.default =\n (Image.default as any).default ?? Image.default;\n const result = {\n // polyfill Next.js App Router client API (minimal)\n // some API methods are not available when using a Next.js Pages Router application as host\n 'next/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/components/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/app-dir/link': () =>\n Promise.resolve(Link.default) as Promise<unknown>,\n 'next/link': () => Promise.resolve(Link.default) as Promise<unknown>,\n 'next/dist/client/app-dir/form': () =>\n Promise.resolve(Form.default) as Promise<unknown>,\n 'next/form': () => Promise.resolve(Form.default) as Promise<unknown>,\n 'next/dist/client/script': () =>\n Promise.resolve(Script.default) as Promise<unknown>,\n 'next/script': () => Promise.resolve(Script.default) as Promise<unknown>,\n 'next/router': () => Promise.resolve(Router) as Promise<unknown>,\n ..._shared,\n // Always override Next.js image modules to use the bundle URL rewriter.\n ...createNextImageSharedEntries(\n () => imageImpl(ImageComponent, bundle, resolveClientUrl, true),\n { getImageProps: Image.getImageProps },\n ),\n };\n\n if (!resolveClientUrl) {\n sharedCache.set(bundle, result);\n }\n\n return result;\n};\n\n// internal symbols to access global store\nconst REMOTE_COMPONENT_STORE = Symbol('REMOTE_COMPONENT_STORE');\nconst REMOTE_COMPONENT_KEY = '__REMOTE_COMPONENT_KEY__';\n\n// temporary global store for remote component HTML\n// the store is used to save the HTML of remote components for SSR without sending the content to the client\nconst self = globalThis as typeof globalThis & {\n [REMOTE_COMPONENT_STORE]?: Map<string, React.ReactNode>;\n};\n\nfunction getKey({\n bundle,\n route,\n name,\n}: {\n bundle?: string;\n route?: string;\n name?: string;\n}): string {\n return `${bundle ?? '__next'}:${route ?? '/'}:${\n name ?? '__vercel_remote_component'\n }__${crypto.randomUUID()}`;\n}\n\nfunction setComponent(key: string, component: React.ReactNode): void {\n if (!self[REMOTE_COMPONENT_STORE]) {\n self[REMOTE_COMPONENT_STORE] = new Map();\n }\n self[REMOTE_COMPONENT_STORE].set(key, component);\n}\n\nfunction getComponent(key: string): React.ReactNode | undefined {\n const component = self[REMOTE_COMPONENT_STORE]?.get(key);\n // remove the component from the store after retrieving it to prevent memory leaks\n // storing the HTML in the global store is only needed for SSR and it's temporary only used for a single render\n self[REMOTE_COMPONENT_STORE]?.delete(key);\n return component;\n}\n\n/**\n * Props for the Next.js Pages Router remote component host.\n *\n * Extends {@link ConsumeRemoteComponentConfig} with Pages Router–specific `bundle` and\n * `route` props used for SSR hydration.\n */\nexport interface ConsumeRemoteComponentProps\n extends ConsumeRemoteComponentConfig {\n /** The source URL of the remote component. Required for server rendering. */\n src: string | URL;\n /** The Webpack bundle name for the remote component. */\n bundle?: string;\n /** The page route of the remote component. */\n route?: string;\n /** Loading fallback content displayed while the remote component is being fetched. */\n children?: React.ReactNode;\n [REMOTE_COMPONENT_KEY]?: string;\n}\n\n/**\n * This component handles the rendering of remote microfrontends.\n *\n * @param props - The properties for the remote component.\n * @returns A React component that renders the remote component.\n */\nexport function ConsumeRemoteComponent(props: ConsumeRemoteComponentProps) {\n const remoteComponent =\n typeof document !== 'undefined'\n ? null\n : // retrieve the HTML from the global store\n getComponent(\n props[REMOTE_COMPONENT_KEY] ?? '__vercel_remote_component',\n );\n\n const sharedResult = shared(\n props.bundle ?? 'default',\n props.resolveClientUrl,\n );\n\n useEffect(() => {\n const clientSelf = globalThis as typeof globalThis & {\n __remote_component_shared__?: Record<string, () => Promise<unknown>>;\n };\n // eslint-disable-next-line camelcase\n clientSelf.__remote_component_shared__ = sharedResult;\n }, [sharedResult]);\n\n if (!props[REMOTE_COMPONENT_KEY]) {\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {props.children}\n </ConsumeRemoteComponentReact>\n );\n }\n\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {remoteComponent}\n </ConsumeRemoteComponentReact>\n );\n}\n\n/**\n * Fetches the remote component properties from the server. You need to pass these properties to the `<ConsumeRemoteComponent>` component to render the fetched remote component.\n *\n * @param src - The source URL of the remote component. When using the Vercel Microfrontends solution, you can use relative paths, e.g. `/nextjs-app-remote/components/header`. Absolute URLs are also supported.\n * @param headers - The HTTP headers used for supporting the Vercel Microfrontends proxy.\n * @returns The properties of the remote component.\n *\n * @example\n *\n * ```tsx\n * import { getRemoteComponentProps } from 'remote-components/next/host/pages';\n * import type { GetServerSideProps } from 'next';\n *\n * export const getServerSideProps: GetServerSideProps<PageProps> = async function getServerSideProps({ req }) {\n * const myRemoteComponent = await getConsumeRemoteComponentProps(\n * '/nextjs-app-remote/components/header',\n * req.headers,\n * );\n * return {\n * props: {\n * remoteComponents: {\n * myRemoteComponent,\n * },\n * },\n * };\n * }\n * ```\n */\nexport async function getConsumeRemoteComponentProps(\n src: string,\n options?: {\n /**\n * Called when a fetch request is made to retrieve the remote component payload.\n * Can be used to intercept requests, modify headers, or provide a custom response.\n */\n onRequest?: OnRequestHook;\n /**\n * Called after a fetch completes to retrieve the remote component payload.\n * Can be used to inspect the response (e.g., check for redirects) or transform it.\n */\n onResponse?: OnResponseHook;\n /**\n * The name of the exposed remote component. Used to identify the remote component\n * when multiple remote components are exposed on a page.\n */\n name?: string;\n },\n): Promise<ConsumeRemoteComponentProps> {\n if (typeof document !== 'undefined') {\n throw new RemoteComponentsError(\n '`getConsumeRemoteComponentProps()` can only be used on the server side.',\n );\n }\n\n const {\n metadata: { bundle, route },\n name,\n links,\n component,\n nextData,\n remoteShared,\n } = await fetchRemoteComponent(src, {\n rsc: true,\n ...options,\n });\n\n const props: ConsumeRemoteComponentProps = {\n src,\n bundle,\n name,\n route,\n };\n\n const key = getKey(props);\n\n // do not render the HTML in development mode when remote is using Next.js Pages Router\n // this behavior is emulating the Next.js Pages Router FOUC as the styles are only applied on the client when running in development mode\n if (nextData?.buildId !== 'development') {\n // store the HTML in a global store\n setComponent(\n key,\n <>\n <script\n data-remote-components-shared=\"\"\n id={`${name}_shared`}\n type=\"application/json\"\n >\n {JSON.stringify(remoteShared)}\n </script>\n {links.map((link) => (\n <link\n key={`${link.as}_${link.href}`}\n {...link}\n precedence={undefined}\n />\n ))}\n {component}\n </>,\n );\n }\n\n return {\n ...props,\n // add remote component key to the props\n [REMOTE_COMPONENT_KEY]: key,\n };\n}\n"],"mappings":"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","names":["import_react","_shared","ConsumeRemoteComponentReact"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/host/nextjs/pages.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport * as Form from 'next/form';\nimport * as Link from 'next/link';\nimport * as Router from 'next/router';\nimport * as Script from 'next/script';\nimport { useEffect } from 'react';\nimport { ConsumeRemoteComponent as ConsumeRemoteComponentReact } from 'remote-components/host/react';\nimport { createImageLoaderSharedEntries } from '#internal/host/nextjs/image-shared';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeRemoteComponentConfig } from '#internal/host/shared/config';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport type { ResolveClientUrl } from '#internal/runtime/url/resolve-client-url';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { shared as _shared } from '#remote-components/host/defaults/pages';\n\nconst navigationImpl = {\n useRouter: () => Router.useRouter(),\n useSearchParams: () => {\n const router = Router.useRouter();\n return {\n get: (key: string) => router.query[key],\n has: (key: string) => key in router.query,\n };\n },\n};\n\nconst sharedCache = new Map<string, Record<string, () => Promise<unknown>>>();\nconst shared = (bundle: string, resolveClientUrl?: ResolveClientUrl) => {\n // Skip cache when resolveClientUrl is provided — different resolver instances\n // must not share a cache entry, since the image loader closes over the resolver.\n if (!resolveClientUrl) {\n if (sharedCache.has(bundle)) {\n return sharedCache.get(bundle);\n }\n }\n\n const result = {\n // polyfill Next.js App Router client API (minimal)\n // some API methods are not available when using a Next.js Pages Router application as host\n 'next/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/components/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/app-dir/link': () =>\n Promise.resolve(Link.default) as Promise<unknown>,\n 'next/link': () => Promise.resolve(Link.default) as Promise<unknown>,\n 'next/dist/client/app-dir/form': () =>\n Promise.resolve(Form.default) as Promise<unknown>,\n 'next/form': () => Promise.resolve(Form.default) as Promise<unknown>,\n 'next/dist/client/script': () =>\n Promise.resolve(Script.default) as Promise<unknown>,\n 'next/script': () => Promise.resolve(Script.default) as Promise<unknown>,\n 'next/router': () => Promise.resolve(Router) as Promise<unknown>,\n ..._shared,\n ...createImageLoaderSharedEntries({ unbound: resolveClientUrl }),\n };\n\n if (!resolveClientUrl) {\n sharedCache.set(bundle, result);\n }\n\n return result;\n};\n\n// internal symbols to access global store\nconst REMOTE_COMPONENT_STORE = Symbol('REMOTE_COMPONENT_STORE');\nconst REMOTE_COMPONENT_KEY = '__REMOTE_COMPONENT_KEY__';\n\n// temporary global store for remote component HTML\n// the store is used to save the HTML of remote components for SSR without sending the content to the client\nconst self = globalThis as typeof globalThis & {\n [REMOTE_COMPONENT_STORE]?: Map<string, React.ReactNode>;\n};\n\nfunction getKey({\n bundle,\n route,\n name,\n}: {\n bundle?: string;\n route?: string;\n name?: string;\n}): string {\n return `${bundle ?? '__next'}:${route ?? '/'}:${\n name ?? '__vercel_remote_component'\n }__${crypto.randomUUID()}`;\n}\n\nfunction setComponent(key: string, component: React.ReactNode): void {\n if (!self[REMOTE_COMPONENT_STORE]) {\n self[REMOTE_COMPONENT_STORE] = new Map();\n }\n self[REMOTE_COMPONENT_STORE].set(key, component);\n}\n\nfunction getComponent(key: string): React.ReactNode | undefined {\n const component = self[REMOTE_COMPONENT_STORE]?.get(key);\n // remove the component from the store after retrieving it to prevent memory leaks\n // storing the HTML in the global store is only needed for SSR and it's temporary only used for a single render\n self[REMOTE_COMPONENT_STORE]?.delete(key);\n return component;\n}\n\n/**\n * Props for the Next.js Pages Router remote component host.\n *\n * Extends {@link ConsumeRemoteComponentConfig} with Pages Router–specific `bundle` and\n * `route` props used for SSR hydration.\n */\nexport interface ConsumeRemoteComponentProps\n extends ConsumeRemoteComponentConfig {\n /** The source URL of the remote component. Required for server rendering. */\n src: string | URL;\n /** The Webpack bundle name for the remote component. */\n bundle?: string;\n /** The page route of the remote component. */\n route?: string;\n /** Loading fallback content displayed while the remote component is being fetched. */\n children?: React.ReactNode;\n [REMOTE_COMPONENT_KEY]?: string;\n}\n\n/**\n * This component handles the rendering of remote microfrontends.\n *\n * @param props - The properties for the remote component.\n * @returns A React component that renders the remote component.\n */\nexport function ConsumeRemoteComponent(props: ConsumeRemoteComponentProps) {\n const remoteComponent =\n typeof document !== 'undefined'\n ? null\n : // retrieve the HTML from the global store\n getComponent(\n props[REMOTE_COMPONENT_KEY] ?? '__vercel_remote_component',\n );\n\n const sharedResult = shared(\n props.bundle ?? 'default',\n props.resolveClientUrl,\n );\n\n useEffect(() => {\n const clientSelf = globalThis as typeof globalThis & {\n __remote_component_shared__?: Record<string, () => Promise<unknown>>;\n };\n // eslint-disable-next-line camelcase\n clientSelf.__remote_component_shared__ = sharedResult;\n }, [sharedResult]);\n\n if (!props[REMOTE_COMPONENT_KEY]) {\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {props.children}\n </ConsumeRemoteComponentReact>\n );\n }\n\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {remoteComponent}\n </ConsumeRemoteComponentReact>\n );\n}\n\n/**\n * Fetches the remote component properties from the server. You need to pass these properties to the `<ConsumeRemoteComponent>` component to render the fetched remote component.\n *\n * @param src - The source URL of the remote component. When using the Vercel Microfrontends solution, you can use relative paths, e.g. `/nextjs-app-remote/components/header`. Absolute URLs are also supported.\n * @param headers - The HTTP headers used for supporting the Vercel Microfrontends proxy.\n * @returns The properties of the remote component.\n *\n * @example\n *\n * ```tsx\n * import { getRemoteComponentProps } from 'remote-components/next/host/pages';\n * import type { GetServerSideProps } from 'next';\n *\n * export const getServerSideProps: GetServerSideProps<PageProps> = async function getServerSideProps({ req }) {\n * const myRemoteComponent = await getConsumeRemoteComponentProps(\n * '/nextjs-app-remote/components/header',\n * req.headers,\n * );\n * return {\n * props: {\n * remoteComponents: {\n * myRemoteComponent,\n * },\n * },\n * };\n * }\n * ```\n */\nexport async function getConsumeRemoteComponentProps(\n src: string,\n options?: {\n /**\n * Called when a fetch request is made to retrieve the remote component payload.\n * Can be used to intercept requests, modify headers, or provide a custom response.\n */\n onRequest?: OnRequestHook;\n /**\n * Called after a fetch completes to retrieve the remote component payload.\n * Can be used to inspect the response (e.g., check for redirects) or transform it.\n */\n onResponse?: OnResponseHook;\n /**\n * The name of the exposed remote component. Used to identify the remote component\n * when multiple remote components are exposed on a page.\n */\n name?: string;\n },\n): Promise<ConsumeRemoteComponentProps> {\n if (typeof document !== 'undefined') {\n throw new RemoteComponentsError(\n '`getConsumeRemoteComponentProps()` can only be used on the server side.',\n );\n }\n\n const {\n metadata: { bundle, route },\n name,\n links,\n component,\n nextData,\n remoteShared,\n } = await fetchRemoteComponent(src, {\n rsc: true,\n ...options,\n });\n\n const props: ConsumeRemoteComponentProps = {\n src,\n bundle,\n name,\n route,\n };\n\n const key = getKey(props);\n\n // do not render the HTML in development mode when remote is using Next.js Pages Router\n // this behavior is emulating the Next.js Pages Router FOUC as the styles are only applied on the client when running in development mode\n if (nextData?.buildId !== 'development') {\n // store the HTML in a global store\n setComponent(\n key,\n <>\n <script\n data-remote-components-shared=\"\"\n id={`${name}_shared`}\n type=\"application/json\"\n >\n {JSON.stringify(remoteShared)}\n </script>\n {links.map((link) => (\n <link\n key={`${link.as}_${link.href}`}\n {...link}\n precedence={undefined}\n />\n ))}\n {component}\n </>,\n );\n }\n\n return {\n ...props,\n // add remote component key to the props\n [REMOTE_COMPONENT_KEY]: key,\n };\n}\n"],"mappings":"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","names":["import_react","_shared","ConsumeRemoteComponentReact"]}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import "remote-components/remote/defaults/wrapper";
|
|
3
3
|
import * as Form from "next/form";
|
|
4
|
-
import * as Image from "next/image";
|
|
5
4
|
import * as Link from "next/link";
|
|
6
5
|
import * as Router from "next/router";
|
|
7
6
|
import * as Script from "next/script";
|
|
8
7
|
import { useEffect } from "react";
|
|
9
8
|
import { ConsumeRemoteComponent as ConsumeRemoteComponentReact } from "remote-components/host/react";
|
|
10
|
-
import {
|
|
11
|
-
import { createNextImageSharedEntries } from "#internal/host/nextjs/image-shared";
|
|
9
|
+
import { createImageLoaderSharedEntries } from "#internal/host/nextjs/image-shared";
|
|
12
10
|
import { fetchRemoteComponent } from "#internal/host/server/fetch-remote-component";
|
|
13
11
|
import { RemoteComponentsError } from "#internal/utils/error";
|
|
14
12
|
import { shared as _shared } from "#remote-components/host/defaults/pages";
|
|
@@ -29,7 +27,6 @@ const shared = (bundle, resolveClientUrl) => {
|
|
|
29
27
|
return sharedCache.get(bundle);
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
|
-
const ImageComponent = Image.default.default ?? Image.default;
|
|
33
30
|
const result = {
|
|
34
31
|
// polyfill Next.js App Router client API (minimal)
|
|
35
32
|
// some API methods are not available when using a Next.js Pages Router application as host
|
|
@@ -43,11 +40,7 @@ const shared = (bundle, resolveClientUrl) => {
|
|
|
43
40
|
"next/script": () => Promise.resolve(Script.default),
|
|
44
41
|
"next/router": () => Promise.resolve(Router),
|
|
45
42
|
..._shared,
|
|
46
|
-
|
|
47
|
-
...createNextImageSharedEntries(
|
|
48
|
-
() => imageImpl(ImageComponent, bundle, resolveClientUrl, true),
|
|
49
|
-
{ getImageProps: Image.getImageProps }
|
|
50
|
-
)
|
|
43
|
+
...createImageLoaderSharedEntries({ unbound: resolveClientUrl })
|
|
51
44
|
};
|
|
52
45
|
if (!resolveClientUrl) {
|
|
53
46
|
sharedCache.set(bundle, result);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/host/nextjs/pages.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport * as Form from 'next/form';\nimport * as Image from 'next/image';\nimport * as Link from 'next/link';\nimport * as Router from 'next/router';\nimport * as Script from 'next/script';\nimport { useEffect } from 'react';\nimport { ConsumeRemoteComponent as ConsumeRemoteComponentReact } from 'remote-components/host/react';\nimport { imageImpl } from '#internal/host/nextjs/image-impl';\nimport { createNextImageSharedEntries } from '#internal/host/nextjs/image-shared';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeRemoteComponentConfig } from '#internal/host/shared/config';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport type { ResolveClientUrl } from '#internal/runtime/url/resolve-client-url';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { shared as _shared } from '#remote-components/host/defaults/pages';\n\nconst navigationImpl = {\n useRouter: () => Router.useRouter(),\n useSearchParams: () => {\n const router = Router.useRouter();\n return {\n get: (key: string) => router.query[key],\n has: (key: string) => key in router.query,\n };\n },\n};\n\nconst sharedCache = new Map<string, Record<string, () => Promise<unknown>>>();\nconst shared = (bundle: string, resolveClientUrl?: ResolveClientUrl) => {\n // Skip cache when resolveClientUrl is provided — different resolver instances\n // must not share a cache entry, since imageImpl closes over the resolver.\n if (!resolveClientUrl) {\n if (sharedCache.has(bundle)) {\n return sharedCache.get(bundle);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const ImageComponent: typeof Image.default =\n (Image.default as any).default ?? Image.default;\n const result = {\n // polyfill Next.js App Router client API (minimal)\n // some API methods are not available when using a Next.js Pages Router application as host\n 'next/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/components/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/app-dir/link': () =>\n Promise.resolve(Link.default) as Promise<unknown>,\n 'next/link': () => Promise.resolve(Link.default) as Promise<unknown>,\n 'next/dist/client/app-dir/form': () =>\n Promise.resolve(Form.default) as Promise<unknown>,\n 'next/form': () => Promise.resolve(Form.default) as Promise<unknown>,\n 'next/dist/client/script': () =>\n Promise.resolve(Script.default) as Promise<unknown>,\n 'next/script': () => Promise.resolve(Script.default) as Promise<unknown>,\n 'next/router': () => Promise.resolve(Router) as Promise<unknown>,\n ..._shared,\n // Always override Next.js image modules to use the bundle URL rewriter.\n ...createNextImageSharedEntries(\n () => imageImpl(ImageComponent, bundle, resolveClientUrl, true),\n { getImageProps: Image.getImageProps },\n ),\n };\n\n if (!resolveClientUrl) {\n sharedCache.set(bundle, result);\n }\n\n return result;\n};\n\n// internal symbols to access global store\nconst REMOTE_COMPONENT_STORE = Symbol('REMOTE_COMPONENT_STORE');\nconst REMOTE_COMPONENT_KEY = '__REMOTE_COMPONENT_KEY__';\n\n// temporary global store for remote component HTML\n// the store is used to save the HTML of remote components for SSR without sending the content to the client\nconst self = globalThis as typeof globalThis & {\n [REMOTE_COMPONENT_STORE]?: Map<string, React.ReactNode>;\n};\n\nfunction getKey({\n bundle,\n route,\n name,\n}: {\n bundle?: string;\n route?: string;\n name?: string;\n}): string {\n return `${bundle ?? '__next'}:${route ?? '/'}:${\n name ?? '__vercel_remote_component'\n }__${crypto.randomUUID()}`;\n}\n\nfunction setComponent(key: string, component: React.ReactNode): void {\n if (!self[REMOTE_COMPONENT_STORE]) {\n self[REMOTE_COMPONENT_STORE] = new Map();\n }\n self[REMOTE_COMPONENT_STORE].set(key, component);\n}\n\nfunction getComponent(key: string): React.ReactNode | undefined {\n const component = self[REMOTE_COMPONENT_STORE]?.get(key);\n // remove the component from the store after retrieving it to prevent memory leaks\n // storing the HTML in the global store is only needed for SSR and it's temporary only used for a single render\n self[REMOTE_COMPONENT_STORE]?.delete(key);\n return component;\n}\n\n/**\n * Props for the Next.js Pages Router remote component host.\n *\n * Extends {@link ConsumeRemoteComponentConfig} with Pages Router–specific `bundle` and\n * `route` props used for SSR hydration.\n */\nexport interface ConsumeRemoteComponentProps\n extends ConsumeRemoteComponentConfig {\n /** The source URL of the remote component. Required for server rendering. */\n src: string | URL;\n /** The Webpack bundle name for the remote component. */\n bundle?: string;\n /** The page route of the remote component. */\n route?: string;\n /** Loading fallback content displayed while the remote component is being fetched. */\n children?: React.ReactNode;\n [REMOTE_COMPONENT_KEY]?: string;\n}\n\n/**\n * This component handles the rendering of remote microfrontends.\n *\n * @param props - The properties for the remote component.\n * @returns A React component that renders the remote component.\n */\nexport function ConsumeRemoteComponent(props: ConsumeRemoteComponentProps) {\n const remoteComponent =\n typeof document !== 'undefined'\n ? null\n : // retrieve the HTML from the global store\n getComponent(\n props[REMOTE_COMPONENT_KEY] ?? '__vercel_remote_component',\n );\n\n const sharedResult = shared(\n props.bundle ?? 'default',\n props.resolveClientUrl,\n );\n\n useEffect(() => {\n const clientSelf = globalThis as typeof globalThis & {\n __remote_component_shared__?: Record<string, () => Promise<unknown>>;\n };\n // eslint-disable-next-line camelcase\n clientSelf.__remote_component_shared__ = sharedResult;\n }, [sharedResult]);\n\n if (!props[REMOTE_COMPONENT_KEY]) {\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {props.children}\n </ConsumeRemoteComponentReact>\n );\n }\n\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {remoteComponent}\n </ConsumeRemoteComponentReact>\n );\n}\n\n/**\n * Fetches the remote component properties from the server. You need to pass these properties to the `<ConsumeRemoteComponent>` component to render the fetched remote component.\n *\n * @param src - The source URL of the remote component. When using the Vercel Microfrontends solution, you can use relative paths, e.g. `/nextjs-app-remote/components/header`. Absolute URLs are also supported.\n * @param headers - The HTTP headers used for supporting the Vercel Microfrontends proxy.\n * @returns The properties of the remote component.\n *\n * @example\n *\n * ```tsx\n * import { getRemoteComponentProps } from 'remote-components/next/host/pages';\n * import type { GetServerSideProps } from 'next';\n *\n * export const getServerSideProps: GetServerSideProps<PageProps> = async function getServerSideProps({ req }) {\n * const myRemoteComponent = await getConsumeRemoteComponentProps(\n * '/nextjs-app-remote/components/header',\n * req.headers,\n * );\n * return {\n * props: {\n * remoteComponents: {\n * myRemoteComponent,\n * },\n * },\n * };\n * }\n * ```\n */\nexport async function getConsumeRemoteComponentProps(\n src: string,\n options?: {\n /**\n * Called when a fetch request is made to retrieve the remote component payload.\n * Can be used to intercept requests, modify headers, or provide a custom response.\n */\n onRequest?: OnRequestHook;\n /**\n * Called after a fetch completes to retrieve the remote component payload.\n * Can be used to inspect the response (e.g., check for redirects) or transform it.\n */\n onResponse?: OnResponseHook;\n /**\n * The name of the exposed remote component. Used to identify the remote component\n * when multiple remote components are exposed on a page.\n */\n name?: string;\n },\n): Promise<ConsumeRemoteComponentProps> {\n if (typeof document !== 'undefined') {\n throw new RemoteComponentsError(\n '`getConsumeRemoteComponentProps()` can only be used on the server side.',\n );\n }\n\n const {\n metadata: { bundle, route },\n name,\n links,\n component,\n nextData,\n remoteShared,\n } = await fetchRemoteComponent(src, {\n rsc: true,\n ...options,\n });\n\n const props: ConsumeRemoteComponentProps = {\n src,\n bundle,\n name,\n route,\n };\n\n const key = getKey(props);\n\n // do not render the HTML in development mode when remote is using Next.js Pages Router\n // this behavior is emulating the Next.js Pages Router FOUC as the styles are only applied on the client when running in development mode\n if (nextData?.buildId !== 'development') {\n // store the HTML in a global store\n setComponent(\n key,\n <>\n <script\n data-remote-components-shared=\"\"\n id={`${name}_shared`}\n type=\"application/json\"\n >\n {JSON.stringify(remoteShared)}\n </script>\n {links.map((link) => (\n <link\n key={`${link.as}_${link.href}`}\n {...link}\n precedence={undefined}\n />\n ))}\n {component}\n </>,\n );\n }\n\n return {\n ...props,\n // add remote component key to the props\n [REMOTE_COMPONENT_KEY]: key,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/host/nextjs/pages.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport * as Form from 'next/form';\nimport * as Link from 'next/link';\nimport * as Router from 'next/router';\nimport * as Script from 'next/script';\nimport { useEffect } from 'react';\nimport { ConsumeRemoteComponent as ConsumeRemoteComponentReact } from 'remote-components/host/react';\nimport { createImageLoaderSharedEntries } from '#internal/host/nextjs/image-shared';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeRemoteComponentConfig } from '#internal/host/shared/config';\nimport type {\n OnRequestHook,\n OnResponseHook,\n} from '#internal/host/shared/fetch-interceptors';\nimport type { ResolveClientUrl } from '#internal/runtime/url/resolve-client-url';\nimport { RemoteComponentsError } from '#internal/utils/error';\nimport { shared as _shared } from '#remote-components/host/defaults/pages';\n\nconst navigationImpl = {\n useRouter: () => Router.useRouter(),\n useSearchParams: () => {\n const router = Router.useRouter();\n return {\n get: (key: string) => router.query[key],\n has: (key: string) => key in router.query,\n };\n },\n};\n\nconst sharedCache = new Map<string, Record<string, () => Promise<unknown>>>();\nconst shared = (bundle: string, resolveClientUrl?: ResolveClientUrl) => {\n // Skip cache when resolveClientUrl is provided — different resolver instances\n // must not share a cache entry, since the image loader closes over the resolver.\n if (!resolveClientUrl) {\n if (sharedCache.has(bundle)) {\n return sharedCache.get(bundle);\n }\n }\n\n const result = {\n // polyfill Next.js App Router client API (minimal)\n // some API methods are not available when using a Next.js Pages Router application as host\n 'next/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/components/navigation': () =>\n Promise.resolve(navigationImpl) as Promise<unknown>,\n 'next/dist/client/app-dir/link': () =>\n Promise.resolve(Link.default) as Promise<unknown>,\n 'next/link': () => Promise.resolve(Link.default) as Promise<unknown>,\n 'next/dist/client/app-dir/form': () =>\n Promise.resolve(Form.default) as Promise<unknown>,\n 'next/form': () => Promise.resolve(Form.default) as Promise<unknown>,\n 'next/dist/client/script': () =>\n Promise.resolve(Script.default) as Promise<unknown>,\n 'next/script': () => Promise.resolve(Script.default) as Promise<unknown>,\n 'next/router': () => Promise.resolve(Router) as Promise<unknown>,\n ..._shared,\n ...createImageLoaderSharedEntries({ unbound: resolveClientUrl }),\n };\n\n if (!resolveClientUrl) {\n sharedCache.set(bundle, result);\n }\n\n return result;\n};\n\n// internal symbols to access global store\nconst REMOTE_COMPONENT_STORE = Symbol('REMOTE_COMPONENT_STORE');\nconst REMOTE_COMPONENT_KEY = '__REMOTE_COMPONENT_KEY__';\n\n// temporary global store for remote component HTML\n// the store is used to save the HTML of remote components for SSR without sending the content to the client\nconst self = globalThis as typeof globalThis & {\n [REMOTE_COMPONENT_STORE]?: Map<string, React.ReactNode>;\n};\n\nfunction getKey({\n bundle,\n route,\n name,\n}: {\n bundle?: string;\n route?: string;\n name?: string;\n}): string {\n return `${bundle ?? '__next'}:${route ?? '/'}:${\n name ?? '__vercel_remote_component'\n }__${crypto.randomUUID()}`;\n}\n\nfunction setComponent(key: string, component: React.ReactNode): void {\n if (!self[REMOTE_COMPONENT_STORE]) {\n self[REMOTE_COMPONENT_STORE] = new Map();\n }\n self[REMOTE_COMPONENT_STORE].set(key, component);\n}\n\nfunction getComponent(key: string): React.ReactNode | undefined {\n const component = self[REMOTE_COMPONENT_STORE]?.get(key);\n // remove the component from the store after retrieving it to prevent memory leaks\n // storing the HTML in the global store is only needed for SSR and it's temporary only used for a single render\n self[REMOTE_COMPONENT_STORE]?.delete(key);\n return component;\n}\n\n/**\n * Props for the Next.js Pages Router remote component host.\n *\n * Extends {@link ConsumeRemoteComponentConfig} with Pages Router–specific `bundle` and\n * `route` props used for SSR hydration.\n */\nexport interface ConsumeRemoteComponentProps\n extends ConsumeRemoteComponentConfig {\n /** The source URL of the remote component. Required for server rendering. */\n src: string | URL;\n /** The Webpack bundle name for the remote component. */\n bundle?: string;\n /** The page route of the remote component. */\n route?: string;\n /** Loading fallback content displayed while the remote component is being fetched. */\n children?: React.ReactNode;\n [REMOTE_COMPONENT_KEY]?: string;\n}\n\n/**\n * This component handles the rendering of remote microfrontends.\n *\n * @param props - The properties for the remote component.\n * @returns A React component that renders the remote component.\n */\nexport function ConsumeRemoteComponent(props: ConsumeRemoteComponentProps) {\n const remoteComponent =\n typeof document !== 'undefined'\n ? null\n : // retrieve the HTML from the global store\n getComponent(\n props[REMOTE_COMPONENT_KEY] ?? '__vercel_remote_component',\n );\n\n const sharedResult = shared(\n props.bundle ?? 'default',\n props.resolveClientUrl,\n );\n\n useEffect(() => {\n const clientSelf = globalThis as typeof globalThis & {\n __remote_component_shared__?: Record<string, () => Promise<unknown>>;\n };\n // eslint-disable-next-line camelcase\n clientSelf.__remote_component_shared__ = sharedResult;\n }, [sharedResult]);\n\n if (!props[REMOTE_COMPONENT_KEY]) {\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {props.children}\n </ConsumeRemoteComponentReact>\n );\n }\n\n return (\n <ConsumeRemoteComponentReact\n isolate={props.isolate}\n mode={props.mode}\n name={props.name}\n onBeforeLoad={props.onBeforeLoad}\n onChange={props.onChange}\n onError={props.onError}\n onLoad={props.onLoad}\n onRequest={props.onRequest}\n onResponse={props.onResponse}\n resolveClientUrl={props.resolveClientUrl}\n reset={props.reset}\n shared={sharedResult}\n src={props.src}\n >\n {remoteComponent}\n </ConsumeRemoteComponentReact>\n );\n}\n\n/**\n * Fetches the remote component properties from the server. You need to pass these properties to the `<ConsumeRemoteComponent>` component to render the fetched remote component.\n *\n * @param src - The source URL of the remote component. When using the Vercel Microfrontends solution, you can use relative paths, e.g. `/nextjs-app-remote/components/header`. Absolute URLs are also supported.\n * @param headers - The HTTP headers used for supporting the Vercel Microfrontends proxy.\n * @returns The properties of the remote component.\n *\n * @example\n *\n * ```tsx\n * import { getRemoteComponentProps } from 'remote-components/next/host/pages';\n * import type { GetServerSideProps } from 'next';\n *\n * export const getServerSideProps: GetServerSideProps<PageProps> = async function getServerSideProps({ req }) {\n * const myRemoteComponent = await getConsumeRemoteComponentProps(\n * '/nextjs-app-remote/components/header',\n * req.headers,\n * );\n * return {\n * props: {\n * remoteComponents: {\n * myRemoteComponent,\n * },\n * },\n * };\n * }\n * ```\n */\nexport async function getConsumeRemoteComponentProps(\n src: string,\n options?: {\n /**\n * Called when a fetch request is made to retrieve the remote component payload.\n * Can be used to intercept requests, modify headers, or provide a custom response.\n */\n onRequest?: OnRequestHook;\n /**\n * Called after a fetch completes to retrieve the remote component payload.\n * Can be used to inspect the response (e.g., check for redirects) or transform it.\n */\n onResponse?: OnResponseHook;\n /**\n * The name of the exposed remote component. Used to identify the remote component\n * when multiple remote components are exposed on a page.\n */\n name?: string;\n },\n): Promise<ConsumeRemoteComponentProps> {\n if (typeof document !== 'undefined') {\n throw new RemoteComponentsError(\n '`getConsumeRemoteComponentProps()` can only be used on the server side.',\n );\n }\n\n const {\n metadata: { bundle, route },\n name,\n links,\n component,\n nextData,\n remoteShared,\n } = await fetchRemoteComponent(src, {\n rsc: true,\n ...options,\n });\n\n const props: ConsumeRemoteComponentProps = {\n src,\n bundle,\n name,\n route,\n };\n\n const key = getKey(props);\n\n // do not render the HTML in development mode when remote is using Next.js Pages Router\n // this behavior is emulating the Next.js Pages Router FOUC as the styles are only applied on the client when running in development mode\n if (nextData?.buildId !== 'development') {\n // store the HTML in a global store\n setComponent(\n key,\n <>\n <script\n data-remote-components-shared=\"\"\n id={`${name}_shared`}\n type=\"application/json\"\n >\n {JSON.stringify(remoteShared)}\n </script>\n {links.map((link) => (\n <link\n key={`${link.as}_${link.href}`}\n {...link}\n precedence={undefined}\n />\n ))}\n {component}\n </>,\n );\n }\n\n return {\n ...props,\n // add remote component key to the props\n [REMOTE_COMPONENT_KEY]: key,\n };\n}\n"],"mappings":"AA2JM,SA0HA,UA1HA,KA0HA,YA1HA;AA3JN,OAAO;AACP,YAAY,UAAU;AACtB,YAAY,UAAU;AACtB,YAAY,YAAY;AACxB,YAAY,YAAY;AACxB,SAAS,iBAAiB;AAC1B,SAAS,0BAA0B,mCAAmC;AACtE,SAAS,sCAAsC;AAC/C,SAAS,4BAA4B;AAOrC,SAAS,6BAA6B;AACtC,SAAS,UAAU,eAAe;AAElC,MAAM,iBAAiB;AAAA,EACrB,WAAW,MAAM,OAAO,UAAU;AAAA,EAClC,iBAAiB,MAAM;AACrB,UAAM,SAAS,OAAO,UAAU;AAChC,WAAO;AAAA,MACL,KAAK,CAAC,QAAgB,OAAO,MAAM,GAAG;AAAA,MACtC,KAAK,CAAC,QAAgB,OAAO,OAAO;AAAA,IACtC;AAAA,EACF;AACF;AAEA,MAAM,cAAc,oBAAI,IAAoD;AAC5E,MAAM,SAAS,CAAC,QAAgB,qBAAwC;AAGtE,MAAI,CAAC,kBAAkB;AACrB,QAAI,YAAY,IAAI,MAAM,GAAG;AAC3B,aAAO,YAAY,IAAI,MAAM;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,SAAS;AAAA;AAAA;AAAA,IAGb,mBAAmB,MACjB,QAAQ,QAAQ,cAAc;AAAA,IAChC,0CAA0C,MACxC,QAAQ,QAAQ,cAAc;AAAA,IAChC,iCAAiC,MAC/B,QAAQ,QAAQ,KAAK,OAAO;AAAA,IAC9B,aAAa,MAAM,QAAQ,QAAQ,KAAK,OAAO;AAAA,IAC/C,iCAAiC,MAC/B,QAAQ,QAAQ,KAAK,OAAO;AAAA,IAC9B,aAAa,MAAM,QAAQ,QAAQ,KAAK,OAAO;AAAA,IAC/C,2BAA2B,MACzB,QAAQ,QAAQ,OAAO,OAAO;AAAA,IAChC,eAAe,MAAM,QAAQ,QAAQ,OAAO,OAAO;AAAA,IACnD,eAAe,MAAM,QAAQ,QAAQ,MAAM;AAAA,IAC3C,GAAG;AAAA,IACH,GAAG,+BAA+B,EAAE,SAAS,iBAAiB,CAAC;AAAA,EACjE;AAEA,MAAI,CAAC,kBAAkB;AACrB,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AAEA,SAAO;AACT;AAGA,MAAM,yBAAyB,OAAO,wBAAwB;AAC9D,MAAM,uBAAuB;AAI7B,MAAM,OAAO;AAIb,SAAS,OAAO;AAAA,EACd;AAAA,EACA;AAAA,EACA;AACF,GAIW;AACT,SAAO,GAAG,UAAU,YAAY,SAAS,OACvC,QAAQ,gCACL,OAAO,WAAW;AACzB;AAEA,SAAS,aAAa,KAAa,WAAkC;AACnE,MAAI,CAAC,KAAK,sBAAsB,GAAG;AACjC,SAAK,sBAAsB,IAAI,oBAAI,IAAI;AAAA,EACzC;AACA,OAAK,sBAAsB,EAAE,IAAI,KAAK,SAAS;AACjD;AAEA,SAAS,aAAa,KAA0C;AAC9D,QAAM,YAAY,KAAK,sBAAsB,GAAG,IAAI,GAAG;AAGvD,OAAK,sBAAsB,GAAG,OAAO,GAAG;AACxC,SAAO;AACT;AA2BO,SAAS,uBAAuB,OAAoC;AACzE,QAAM,kBACJ,OAAO,aAAa,cAChB;AAAA;AAAA,IAEA;AAAA,MACE,MAAM,oBAAoB,KAAK;AAAA,IACjC;AAAA;AAEN,QAAM,eAAe;AAAA,IACnB,MAAM,UAAU;AAAA,IAChB,MAAM;AAAA,EACR;AAEA,YAAU,MAAM;AACd,UAAM,aAAa;AAInB,eAAW,8BAA8B;AAAA,EAC3C,GAAG,CAAC,YAAY,CAAC;AAEjB,MAAI,CAAC,MAAM,oBAAoB,GAAG;AAChC,WACE;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,MAAM;AAAA,QACf,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,cAAc,MAAM;AAAA,QACpB,UAAU,MAAM;AAAA,QAChB,SAAS,MAAM;AAAA,QACf,QAAQ,MAAM;AAAA,QACd,WAAW,MAAM;AAAA,QACjB,YAAY,MAAM;AAAA,QAClB,kBAAkB,MAAM;AAAA,QACxB,OAAO,MAAM;AAAA,QACb,QAAQ;AAAA,QACR,KAAK,MAAM;AAAA,QAEV,gBAAM;AAAA;AAAA,IACT;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,cAAc,MAAM;AAAA,MACpB,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,MACf,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,kBAAkB,MAAM;AAAA,MACxB,OAAO,MAAM;AAAA,MACb,QAAQ;AAAA,MACR,KAAK,MAAM;AAAA,MAEV;AAAA;AAAA,EACH;AAEJ;AA8BA,eAAsB,+BACpB,KACA,SAiBsC;AACtC,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM;AAAA,IACJ,UAAU,EAAE,QAAQ,MAAM;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,MAAM,qBAAqB,KAAK;AAAA,IAClC,KAAK;AAAA,IACL,GAAG;AAAA,EACL,CAAC;AAED,QAAM,QAAqC;AAAA,IACzC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,MAAM,OAAO,KAAK;AAIxB,MAAI,UAAU,YAAY,eAAe;AAEvC;AAAA,MACE;AAAA,MACA,iCACE;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,iCAA8B;AAAA,YAC9B,IAAI,GAAG;AAAA,YACP,MAAK;AAAA,YAEJ,eAAK,UAAU,YAAY;AAAA;AAAA,QAC9B;AAAA,QACC,MAAM,IAAI,CAAC,SACV;AAAA,UAAC;AAAA;AAAA,YAEE,GAAG;AAAA,YACJ,YAAY;AAAA;AAAA,UAFP,GAAG,KAAK,MAAM,KAAK;AAAA,QAG1B,CACD;AAAA,QACA;AAAA,SACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,GAAG;AAAA;AAAA,IAEH,CAAC,oBAAoB,GAAG;AAAA,EAC1B;AACF;","names":[]}
|
package/dist/host/react.cjs
CHANGED
|
@@ -237,58 +237,35 @@ function getClientOrServerUrl(src, serverFallback) {
|
|
|
237
237
|
return typeof src === "string" ? new URL(src, fallback) : src;
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
// src/host/shared/
|
|
241
|
-
|
|
242
|
-
// eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
|
|
243
|
-
require("react/jsx-runtime")
|
|
244
|
-
);
|
|
245
|
-
function applyBundleUrlToSrc(bundle, src) {
|
|
240
|
+
// src/host/shared/remote-image-loader.ts
|
|
241
|
+
function getRemoteBundleOrigin(bundle) {
|
|
246
242
|
const self = globalThis;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
priority: _priority,
|
|
268
|
-
loading: _loading,
|
|
269
|
-
placeholder: _placeholder,
|
|
270
|
-
blurDataURL: _blurDataURL,
|
|
271
|
-
unoptimized: _unoptimized,
|
|
272
|
-
overrideSrc: _overrideSrc,
|
|
273
|
-
src,
|
|
274
|
-
...props
|
|
275
|
-
}) {
|
|
276
|
-
const newSrc = applyBundleUrlToImagePropsSrc(
|
|
277
|
-
bundle,
|
|
278
|
-
typeof src === "string" ? src : src.src
|
|
279
|
-
);
|
|
280
|
-
const proxiedSrc = resolveClientUrl?.(newSrc) ?? newSrc;
|
|
281
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
282
|
-
"img",
|
|
283
|
-
{
|
|
284
|
-
decoding: "async",
|
|
285
|
-
style: { color: "transparent" },
|
|
286
|
-
...props,
|
|
287
|
-
src: proxiedSrc,
|
|
288
|
-
suppressHydrationWarning: true
|
|
289
|
-
}
|
|
243
|
+
return self.__remote_bundle_url__?.[bundle]?.origin ?? "";
|
|
244
|
+
}
|
|
245
|
+
function createRemoteImageLoader(bundle, resolveClientUrl) {
|
|
246
|
+
const loader = Object.assign(
|
|
247
|
+
({
|
|
248
|
+
config,
|
|
249
|
+
src,
|
|
250
|
+
width,
|
|
251
|
+
quality
|
|
252
|
+
}) => {
|
|
253
|
+
const q = quality ?? 75;
|
|
254
|
+
const remoteOrigin = getRemoteBundleOrigin(bundle);
|
|
255
|
+
const isCrossOrigin = remoteOrigin && remoteOrigin !== location.origin;
|
|
256
|
+
const basePath = isCrossOrigin ? `${remoteOrigin}${config.path ?? "/_next/image"}` : config.path ?? `${remoteOrigin}/_next/image`;
|
|
257
|
+
const url = `${basePath}?url=${encodeURIComponent(src)}&w=${width}&q=${q}`;
|
|
258
|
+
return resolveClientUrl?.(url) ?? url;
|
|
259
|
+
},
|
|
260
|
+
// Signals to getImgProps that this is a default loader (not a user-defined
|
|
261
|
+
// one), enabling srcSet generation with device/image sizes from the config.
|
|
262
|
+
{ __next_img_default: true }
|
|
290
263
|
);
|
|
291
|
-
|
|
264
|
+
return loader;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/host/shared/polyfill.tsx
|
|
268
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
292
269
|
function sharedPolyfills(shared, resolveClientUrl) {
|
|
293
270
|
const self = globalThis;
|
|
294
271
|
const polyfill = {
|
|
@@ -379,17 +356,13 @@ function sharedPolyfills(shared, resolveClientUrl) {
|
|
|
379
356
|
},
|
|
380
357
|
__esModule: true
|
|
381
358
|
})),
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
throw new Error(
|
|
390
|
-
"Next.js getImageProps() is not implemented in remote components"
|
|
391
|
-
);
|
|
392
|
-
},
|
|
359
|
+
// Instead of replacing next/image entirely, we let the real Next.js Image
|
|
360
|
+
// component load from the remote bundle and only replace its default loader.
|
|
361
|
+
// This gives us full next/image fidelity (fill, priority, srcSet, blur
|
|
362
|
+
// placeholders, error handling) while routing image optimization through the
|
|
363
|
+
// remote app's /_next/image endpoint.
|
|
364
|
+
"next/dist/shared/lib/image-loader": self.__remote_component_host_shared_modules__?.["next/dist/shared/lib/image-loader"] ?? shared?.["next/dist/shared/lib/image-loader"] ?? ((bundle) => Promise.resolve({
|
|
365
|
+
default: createRemoteImageLoader(bundle, resolveClientUrl),
|
|
393
366
|
__esModule: true
|
|
394
367
|
})),
|
|
395
368
|
"next/dist/client/script": self.__remote_component_host_shared_modules__?.["next/script"] ?? shared?.["next/script"] ?? (() => Promise.resolve({
|
|
@@ -429,7 +402,7 @@ function sharedPolyfills(shared, resolveClientUrl) {
|
|
|
429
402
|
polyfill["next/navigation"] = polyfill["next/dist/client/components/navigation"];
|
|
430
403
|
polyfill["next/link"] = polyfill["next/dist/client/app-dir/link"];
|
|
431
404
|
polyfill["next/form"] = polyfill["next/dist/client/app-dir/form"];
|
|
432
|
-
polyfill["next/dist/
|
|
405
|
+
polyfill["next/dist/esm/shared/lib/image-loader"] = polyfill["next/dist/shared/lib/image-loader"];
|
|
433
406
|
polyfill["next/script"] = polyfill["next/dist/client/script"];
|
|
434
407
|
return polyfill;
|
|
435
408
|
}
|
|
@@ -1941,11 +1914,7 @@ function bindResolveClientUrl(prop, remoteSrc) {
|
|
|
1941
1914
|
function useResolveClientUrl(prop, urlHref) {
|
|
1942
1915
|
const { resolveClientUrl: contextValue } = (0, import_context.useRemoteComponentsContext)();
|
|
1943
1916
|
const raw = prop ?? contextValue;
|
|
1944
|
-
|
|
1945
|
-
() => bindResolveClientUrl(raw, urlHref),
|
|
1946
|
-
[raw, urlHref]
|
|
1947
|
-
);
|
|
1948
|
-
return { bound, raw };
|
|
1917
|
+
return (0, import_react.useMemo)(() => bindResolveClientUrl(raw, urlHref), [raw, urlHref]);
|
|
1949
1918
|
}
|
|
1950
1919
|
|
|
1951
1920
|
// src/host/react/hooks/use-shadow-root.ts
|
|
@@ -2054,10 +2023,7 @@ function ConsumeRemoteComponent({
|
|
|
2054
2023
|
null
|
|
2055
2024
|
);
|
|
2056
2025
|
const url = (0, import_react3.useMemo)(() => getClientOrServerUrl(src, DUMMY_FALLBACK), [src]);
|
|
2057
|
-
const
|
|
2058
|
-
resolveClientUrlProp,
|
|
2059
|
-
url.href
|
|
2060
|
-
);
|
|
2026
|
+
const resolveClientUrl = useResolveClientUrl(resolveClientUrlProp, url.href);
|
|
2061
2027
|
const id = url.origin === (typeof location !== "undefined" ? location.origin : DUMMY_FALLBACK) ? url.pathname : url.href;
|
|
2062
2028
|
const keySuffix = `${escapeString(id)}_${escapeString(
|
|
2063
2029
|
data?.name ?? name
|