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
package/dist/host/nextjs/app.cjs
CHANGED
|
@@ -26,7 +26,6 @@ var import_wrapper = require("remote-components/remote/defaults/wrapper");
|
|
|
26
26
|
var import_react = require("react");
|
|
27
27
|
var import_app_client = require("#internal/host/nextjs/app-client");
|
|
28
28
|
var import_fetch_remote_component = require("#internal/host/server/fetch-remote-component");
|
|
29
|
-
const CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;
|
|
30
29
|
async function ConsumeRemoteComponent({
|
|
31
30
|
src,
|
|
32
31
|
name: nameProp,
|
|
@@ -53,11 +52,11 @@ async function ConsumeRemoteComponent({
|
|
|
53
52
|
onRequest,
|
|
54
53
|
onResponse
|
|
55
54
|
});
|
|
56
|
-
const name = metadata
|
|
55
|
+
const { name, bundle, route, runtime, type } = metadata;
|
|
57
56
|
const remoteComponentClient = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
58
57
|
import_app_client.ConsumeRemoteComponentClient,
|
|
59
58
|
{
|
|
60
|
-
bundle
|
|
59
|
+
bundle,
|
|
61
60
|
data: hydrationData,
|
|
62
61
|
isolate,
|
|
63
62
|
links,
|
|
@@ -66,10 +65,10 @@ async function ConsumeRemoteComponent({
|
|
|
66
65
|
nextData,
|
|
67
66
|
remoteShared,
|
|
68
67
|
reset,
|
|
69
|
-
route
|
|
70
|
-
runtime
|
|
68
|
+
route,
|
|
69
|
+
runtime,
|
|
71
70
|
scripts,
|
|
72
|
-
type
|
|
71
|
+
type,
|
|
73
72
|
src: typeof src === "string" ? src : src.href,
|
|
74
73
|
serverUrl: serverUrl.href,
|
|
75
74
|
children: component
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/host/nextjs/app.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport { Children, Suspense } from 'react';\nimport { ConsumeRemoteComponentClient } from '#internal/host/nextjs/app-client';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeServerConfig } from '#internal/host/shared/config';\n\
|
|
1
|
+
{"version":3,"sources":["../../../src/host/nextjs/app.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport { Children, Suspense } from 'react';\nimport { ConsumeRemoteComponentClient } from '#internal/host/nextjs/app-client';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeServerConfig } from '#internal/host/shared/config';\n\n/**\n * Props for the Next.js App Router remote component host (server component).\n */\nexport interface ConsumeRemoteComponentProps extends ConsumeServerConfig {\n /** The source URL of the remote component. Required for server rendering. */\n src: string | URL;\n /** Loading fallback content to display while the remote component is being fetched. */\n children?: React.ReactNode;\n}\n\n/**\n * Next.js App Router server component that fetches and renders a remote component.\n * Props are documented on {@link ConsumeRemoteComponentProps} (extends {@link ConsumeServerConfig}).\n *\n * @example\n * ```tsx\n * import { ConsumeRemoteComponent } from 'remote-components/host/nextjs/app';\n *\n * export default function MyPage() {\n * return <ConsumeRemoteComponent src=\"/nextjs-app-remote/components/header\" />;\n * }\n * ```\n */\nexport async function ConsumeRemoteComponent({\n src,\n name: nameProp,\n isolate,\n mode,\n reset,\n children,\n onRequest,\n onResponse,\n}: ConsumeRemoteComponentProps): Promise<React.ReactElement> {\n const {\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n remoteShared,\n serverUrl,\n } = await fetchRemoteComponent(src, {\n name: nameProp,\n rsc: true,\n appRouter: true,\n onRequest,\n onResponse,\n });\n\n const { name, bundle, route, runtime, type } = metadata;\n const remoteComponentClient = (\n <ConsumeRemoteComponentClient\n bundle={bundle}\n data={hydrationData}\n isolate={isolate}\n links={links}\n mode={mode}\n name={name}\n nextData={nextData}\n remoteShared={remoteShared}\n reset={reset}\n route={route}\n runtime={runtime}\n scripts={scripts}\n type={type}\n src={typeof src === 'string' ? src : src.href}\n serverUrl={serverUrl.href}\n >\n {component}\n </ConsumeRemoteComponentClient>\n );\n\n if (Children.count(children) > 0) {\n // if there are children, render them inside the remote component\n return <Suspense fallback={children}>{remoteComponentClient}</Suspense>;\n }\n\n return remoteComponentClient;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0DI;AA1DJ,qBAAO;AACP,mBAAmC;AACnC,wBAA6C;AAC7C,oCAAqC;AA0BrC,eAAsB,uBAAuB;AAAA,EAC3C;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6D;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,UAAM,oDAAqB,KAAK;AAAA,IAClC,MAAM;AAAA,IACN,KAAK;AAAA,IACL,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,EAAE,MAAM,QAAQ,OAAO,SAAS,KAAK,IAAI;AAC/C,QAAM,wBACJ;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI;AAAA,MACzC,WAAW,UAAU;AAAA,MAEpB;AAAA;AAAA,EACH;AAGF,MAAI,sBAAS,MAAM,QAAQ,IAAI,GAAG;AAEhC,WAAO,4CAAC,yBAAS,UAAU,UAAW,iCAAsB;AAAA,EAC9D;AAEA,SAAO;AACT;","names":[]}
|
package/dist/host/nextjs/app.js
CHANGED
|
@@ -3,7 +3,6 @@ import "remote-components/remote/defaults/wrapper";
|
|
|
3
3
|
import { Children, Suspense } from "react";
|
|
4
4
|
import { ConsumeRemoteComponentClient } from "#internal/host/nextjs/app-client";
|
|
5
5
|
import { fetchRemoteComponent } from "#internal/host/server/fetch-remote-component";
|
|
6
|
-
const CURRENT_ZONE = process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION;
|
|
7
6
|
async function ConsumeRemoteComponent({
|
|
8
7
|
src,
|
|
9
8
|
name: nameProp,
|
|
@@ -30,11 +29,11 @@ async function ConsumeRemoteComponent({
|
|
|
30
29
|
onRequest,
|
|
31
30
|
onResponse
|
|
32
31
|
});
|
|
33
|
-
const name = metadata
|
|
32
|
+
const { name, bundle, route, runtime, type } = metadata;
|
|
34
33
|
const remoteComponentClient = /* @__PURE__ */ jsx(
|
|
35
34
|
ConsumeRemoteComponentClient,
|
|
36
35
|
{
|
|
37
|
-
bundle
|
|
36
|
+
bundle,
|
|
38
37
|
data: hydrationData,
|
|
39
38
|
isolate,
|
|
40
39
|
links,
|
|
@@ -43,10 +42,10 @@ async function ConsumeRemoteComponent({
|
|
|
43
42
|
nextData,
|
|
44
43
|
remoteShared,
|
|
45
44
|
reset,
|
|
46
|
-
route
|
|
47
|
-
runtime
|
|
45
|
+
route,
|
|
46
|
+
runtime,
|
|
48
47
|
scripts,
|
|
49
|
-
type
|
|
48
|
+
type,
|
|
50
49
|
src: typeof src === "string" ? src : src.href,
|
|
51
50
|
serverUrl: serverUrl.href,
|
|
52
51
|
children: component
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/host/nextjs/app.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport { Children, Suspense } from 'react';\nimport { ConsumeRemoteComponentClient } from '#internal/host/nextjs/app-client';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeServerConfig } from '#internal/host/shared/config';\n\
|
|
1
|
+
{"version":3,"sources":["../../../src/host/nextjs/app.tsx"],"sourcesContent":["import 'remote-components/remote/defaults/wrapper';\nimport { Children, Suspense } from 'react';\nimport { ConsumeRemoteComponentClient } from '#internal/host/nextjs/app-client';\nimport { fetchRemoteComponent } from '#internal/host/server/fetch-remote-component';\nimport type { ConsumeServerConfig } from '#internal/host/shared/config';\n\n/**\n * Props for the Next.js App Router remote component host (server component).\n */\nexport interface ConsumeRemoteComponentProps extends ConsumeServerConfig {\n /** The source URL of the remote component. Required for server rendering. */\n src: string | URL;\n /** Loading fallback content to display while the remote component is being fetched. */\n children?: React.ReactNode;\n}\n\n/**\n * Next.js App Router server component that fetches and renders a remote component.\n * Props are documented on {@link ConsumeRemoteComponentProps} (extends {@link ConsumeServerConfig}).\n *\n * @example\n * ```tsx\n * import { ConsumeRemoteComponent } from 'remote-components/host/nextjs/app';\n *\n * export default function MyPage() {\n * return <ConsumeRemoteComponent src=\"/nextjs-app-remote/components/header\" />;\n * }\n * ```\n */\nexport async function ConsumeRemoteComponent({\n src,\n name: nameProp,\n isolate,\n mode,\n reset,\n children,\n onRequest,\n onResponse,\n}: ConsumeRemoteComponentProps): Promise<React.ReactElement> {\n const {\n metadata,\n scripts,\n links,\n hydrationData,\n nextData,\n component,\n remoteShared,\n serverUrl,\n } = await fetchRemoteComponent(src, {\n name: nameProp,\n rsc: true,\n appRouter: true,\n onRequest,\n onResponse,\n });\n\n const { name, bundle, route, runtime, type } = metadata;\n const remoteComponentClient = (\n <ConsumeRemoteComponentClient\n bundle={bundle}\n data={hydrationData}\n isolate={isolate}\n links={links}\n mode={mode}\n name={name}\n nextData={nextData}\n remoteShared={remoteShared}\n reset={reset}\n route={route}\n runtime={runtime}\n scripts={scripts}\n type={type}\n src={typeof src === 'string' ? src : src.href}\n serverUrl={serverUrl.href}\n >\n {component}\n </ConsumeRemoteComponentClient>\n );\n\n if (Children.count(children) > 0) {\n // if there are children, render them inside the remote component\n return <Suspense fallback={children}>{remoteComponentClient}</Suspense>;\n }\n\n return remoteComponentClient;\n}\n"],"mappings":"AA0DI;AA1DJ,OAAO;AACP,SAAS,UAAU,gBAAgB;AACnC,SAAS,oCAAoC;AAC7C,SAAS,4BAA4B;AA0BrC,eAAsB,uBAAuB;AAAA,EAC3C;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6D;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,MAAM,qBAAqB,KAAK;AAAA,IAClC,MAAM;AAAA,IACN,KAAK;AAAA,IACL,WAAW;AAAA,IACX;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,EAAE,MAAM,QAAQ,OAAO,SAAS,KAAK,IAAI;AAC/C,QAAM,wBACJ;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI;AAAA,MACzC,WAAW,UAAU;AAAA,MAEpB;AAAA;AAAA,EACH;AAGF,MAAI,SAAS,MAAM,QAAQ,IAAI,GAAG;AAEhC,WAAO,oBAAC,YAAS,UAAU,UAAW,iCAAsB;AAAA,EAC9D;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -42,6 +42,7 @@ var import_react = require("react");
|
|
|
42
42
|
var import_react2 = require("remote-components/host/react");
|
|
43
43
|
var import_image_shared = require("#internal/host/nextjs/image-shared");
|
|
44
44
|
var import_fetch_remote_component = require("#internal/host/server/fetch-remote-component");
|
|
45
|
+
var import_constants = require("#internal/runtime/constants");
|
|
45
46
|
var import_error = require("#internal/utils/error");
|
|
46
47
|
var import_pages = require("#remote-components/host/defaults/pages");
|
|
47
48
|
const navigationImpl = {
|
|
@@ -84,12 +85,8 @@ const shared = (bundle, resolveClientUrl) => {
|
|
|
84
85
|
const REMOTE_COMPONENT_STORE = Symbol("REMOTE_COMPONENT_STORE");
|
|
85
86
|
const REMOTE_COMPONENT_KEY = "__REMOTE_COMPONENT_KEY__";
|
|
86
87
|
const self = globalThis;
|
|
87
|
-
function getKey({
|
|
88
|
-
bundle
|
|
89
|
-
route,
|
|
90
|
-
name
|
|
91
|
-
}) {
|
|
92
|
-
return `${bundle ?? "__next"}:${route ?? "/"}:${name ?? "__vercel_remote_component"}__${crypto.randomUUID()}`;
|
|
88
|
+
function getKey(bundle, route, name) {
|
|
89
|
+
return `${bundle}:${route}:${name}__${crypto.randomUUID()}`;
|
|
93
90
|
}
|
|
94
91
|
function setComponent(key, component) {
|
|
95
92
|
if (!self[REMOTE_COMPONENT_STORE]) {
|
|
@@ -105,12 +102,10 @@ function getComponent(key) {
|
|
|
105
102
|
function ConsumeRemoteComponent(props) {
|
|
106
103
|
const remoteComponent = typeof document !== "undefined" ? null : (
|
|
107
104
|
// retrieve the HTML from the global store
|
|
108
|
-
getComponent(
|
|
109
|
-
props[REMOTE_COMPONENT_KEY] ?? "__vercel_remote_component"
|
|
110
|
-
)
|
|
105
|
+
getComponent(props[REMOTE_COMPONENT_KEY] ?? import_constants.DEFAULT_COMPONENT_NAME)
|
|
111
106
|
);
|
|
112
107
|
const sharedResult = shared(
|
|
113
|
-
props.bundle ??
|
|
108
|
+
props.bundle ?? import_constants.DEFAULT_BUNDLE_NAME,
|
|
114
109
|
props.resolveClientUrl
|
|
115
110
|
);
|
|
116
111
|
(0, import_react.useEffect)(() => {
|
|
@@ -181,7 +176,7 @@ async function getConsumeRemoteComponentProps(src, options) {
|
|
|
181
176
|
name,
|
|
182
177
|
route
|
|
183
178
|
};
|
|
184
|
-
const key = getKey(
|
|
179
|
+
const key = getKey(bundle, route, name);
|
|
185
180
|
if (nextData?.buildId !== "development") {
|
|
186
181
|
setComponent(
|
|
187
182
|
key,
|
|
@@ -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 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
|
+
{"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 {\n DEFAULT_BUNDLE_NAME,\n DEFAULT_COMPONENT_NAME,\n} from '#internal/runtime/constants';\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(bundle: string, route: string, name: string): string {\n return `${bundle}:${route}:${name}__${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(props[REMOTE_COMPONENT_KEY] ?? DEFAULT_COMPONENT_NAME);\n\n const sharedResult = shared(\n props.bundle ?? DEFAULT_BUNDLE_NAME,\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(bundle, route, name);\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmJM;AAnJN,qBAAO;AACP,WAAsB;AACtB,WAAsB;AACtB,aAAwB;AACxB,aAAwB;AACxB,mBAA0B;AAC1B,IAAAA,gBAAsE;AACtE,0BAA+C;AAC/C,oCAAqC;AAMrC,uBAGO;AAEP,mBAAsC;AACtC,mBAAkC;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,aAAAC;AAAA,IACH,OAAG,oDAA+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,QAAgB,OAAe,MAAsB;AACnE,SAAO,GAAG,UAAU,SAAS,SAAS,OAAO,WAAW;AAC1D;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,MAAM,oBAAoB,KAAK,uCAAsB;AAAA;AAExE,QAAM,eAAe;AAAA,IACnB,MAAM,UAAU;AAAA,IAChB,MAAM;AAAA,EACR;AAEA,8BAAU,MAAM;AACd,UAAM,aAAa;AAInB,eAAW,8BAA8B;AAAA,EAC3C,GAAG,CAAC,YAAY,CAAC;AAEjB,MAAI,CAAC,MAAM,oBAAoB,GAAG;AAChC,WACE;AAAA,MAAC,cAAAC;AAAA,MAAA;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,cAAAA;AAAA,IAAA;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,UAAM,oDAAqB,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,QAAQ,OAAO,IAAI;AAItC,MAAI,UAAU,YAAY,eAAe;AAEvC;AAAA,MACE;AAAA,MACA,4EACE;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":["import_react","_shared","ConsumeRemoteComponentReact"]}
|
|
@@ -8,6 +8,10 @@ import { useEffect } from "react";
|
|
|
8
8
|
import { ConsumeRemoteComponent as ConsumeRemoteComponentReact } from "remote-components/host/react";
|
|
9
9
|
import { createImageLoaderSharedEntries } from "#internal/host/nextjs/image-shared";
|
|
10
10
|
import { fetchRemoteComponent } from "#internal/host/server/fetch-remote-component";
|
|
11
|
+
import {
|
|
12
|
+
DEFAULT_BUNDLE_NAME,
|
|
13
|
+
DEFAULT_COMPONENT_NAME
|
|
14
|
+
} from "#internal/runtime/constants";
|
|
11
15
|
import { RemoteComponentsError } from "#internal/utils/error";
|
|
12
16
|
import { shared as _shared } from "#remote-components/host/defaults/pages";
|
|
13
17
|
const navigationImpl = {
|
|
@@ -50,12 +54,8 @@ const shared = (bundle, resolveClientUrl) => {
|
|
|
50
54
|
const REMOTE_COMPONENT_STORE = Symbol("REMOTE_COMPONENT_STORE");
|
|
51
55
|
const REMOTE_COMPONENT_KEY = "__REMOTE_COMPONENT_KEY__";
|
|
52
56
|
const self = globalThis;
|
|
53
|
-
function getKey({
|
|
54
|
-
bundle
|
|
55
|
-
route,
|
|
56
|
-
name
|
|
57
|
-
}) {
|
|
58
|
-
return `${bundle ?? "__next"}:${route ?? "/"}:${name ?? "__vercel_remote_component"}__${crypto.randomUUID()}`;
|
|
57
|
+
function getKey(bundle, route, name) {
|
|
58
|
+
return `${bundle}:${route}:${name}__${crypto.randomUUID()}`;
|
|
59
59
|
}
|
|
60
60
|
function setComponent(key, component) {
|
|
61
61
|
if (!self[REMOTE_COMPONENT_STORE]) {
|
|
@@ -71,12 +71,10 @@ function getComponent(key) {
|
|
|
71
71
|
function ConsumeRemoteComponent(props) {
|
|
72
72
|
const remoteComponent = typeof document !== "undefined" ? null : (
|
|
73
73
|
// retrieve the HTML from the global store
|
|
74
|
-
getComponent(
|
|
75
|
-
props[REMOTE_COMPONENT_KEY] ?? "__vercel_remote_component"
|
|
76
|
-
)
|
|
74
|
+
getComponent(props[REMOTE_COMPONENT_KEY] ?? DEFAULT_COMPONENT_NAME)
|
|
77
75
|
);
|
|
78
76
|
const sharedResult = shared(
|
|
79
|
-
props.bundle ??
|
|
77
|
+
props.bundle ?? DEFAULT_BUNDLE_NAME,
|
|
80
78
|
props.resolveClientUrl
|
|
81
79
|
);
|
|
82
80
|
useEffect(() => {
|
|
@@ -147,7 +145,7 @@ async function getConsumeRemoteComponentProps(src, options) {
|
|
|
147
145
|
name,
|
|
148
146
|
route
|
|
149
147
|
};
|
|
150
|
-
const key = getKey(
|
|
148
|
+
const key = getKey(bundle, route, name);
|
|
151
149
|
if (nextData?.buildId !== "development") {
|
|
152
150
|
setComponent(
|
|
153
151
|
key,
|
|
@@ -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 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":[]}
|
|
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 {\n DEFAULT_BUNDLE_NAME,\n DEFAULT_COMPONENT_NAME,\n} from '#internal/runtime/constants';\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(bundle: string, route: string, name: string): string {\n return `${bundle}:${route}:${name}__${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(props[REMOTE_COMPONENT_KEY] ?? DEFAULT_COMPONENT_NAME);\n\n const sharedResult = shared(\n props.bundle ?? DEFAULT_BUNDLE_NAME,\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(bundle, route, name);\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":[]}
|
package/dist/host/react.cjs
CHANGED
|
@@ -446,12 +446,12 @@ var attrToProp = {
|
|
|
446
446
|
};
|
|
447
447
|
|
|
448
448
|
// src/runtime/constants.ts
|
|
449
|
+
var DEFAULT_BUNDLE_NAME = "__vercel_remote_bundle";
|
|
450
|
+
var DEFAULT_COMPONENT_NAME = "__vercel_remote_component";
|
|
449
451
|
var DEFAULT_ROUTE = "/";
|
|
450
452
|
var RUNTIME_WEBPACK = "webpack";
|
|
451
453
|
var RUNTIME_TURBOPACK = "turbopack";
|
|
452
454
|
var RUNTIME_SCRIPT = "script";
|
|
453
|
-
var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
|
|
454
|
-
var NEXT_BUNDLE_PATH_RE = /\/_next\/\[.+\](?:%20| )/;
|
|
455
455
|
function getBundleKey(bundle) {
|
|
456
456
|
return escapeString(bundle);
|
|
457
457
|
}
|
|
@@ -518,6 +518,38 @@ function applyOriginToNodes(doc, url, resolveClientUrl) {
|
|
|
518
518
|
}
|
|
519
519
|
}
|
|
520
520
|
|
|
521
|
+
// src/runtime/metadata.ts
|
|
522
|
+
var VALID_RUNTIMES = /* @__PURE__ */ new Set(["webpack", "turbopack", "script"]);
|
|
523
|
+
var VALID_TYPES = /* @__PURE__ */ new Set([
|
|
524
|
+
"nextjs",
|
|
525
|
+
"remote-component",
|
|
526
|
+
"unknown"
|
|
527
|
+
]);
|
|
528
|
+
function isRuntime(value) {
|
|
529
|
+
return VALID_RUNTIMES.has(value);
|
|
530
|
+
}
|
|
531
|
+
function isComponentType(value) {
|
|
532
|
+
return VALID_TYPES.has(value);
|
|
533
|
+
}
|
|
534
|
+
function toRuntime(value) {
|
|
535
|
+
return value && isRuntime(value) ? value : "webpack";
|
|
536
|
+
}
|
|
537
|
+
function toComponentType(value) {
|
|
538
|
+
return value && isComponentType(value) ? value : "unknown";
|
|
539
|
+
}
|
|
540
|
+
function buildMetadata(attrs, url) {
|
|
541
|
+
const id = attrs.id || DEFAULT_COMPONENT_NAME;
|
|
542
|
+
const bundle = attrs.bundle || process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION || DEFAULT_BUNDLE_NAME;
|
|
543
|
+
return {
|
|
544
|
+
name: attrs.name || id.replace(/_ssr$/, ""),
|
|
545
|
+
bundle,
|
|
546
|
+
route: attrs.route || url.pathname || DEFAULT_ROUTE,
|
|
547
|
+
runtime: toRuntime(attrs.runtime),
|
|
548
|
+
id,
|
|
549
|
+
type: toComponentType(attrs.type)
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
|
|
521
553
|
// src/runtime/html/parse-remote-html.ts
|
|
522
554
|
function validateSingleComponent(doc, name, url) {
|
|
523
555
|
if (doc.querySelectorAll("div[data-bundle][data-route]").length > 1 && !doc.querySelector(`div[data-bundle][data-route][id^="${name}"]`) || doc.querySelectorAll("remote-component:not([src])").length > 1 && !doc.querySelector(`remote-component[name="${name}"]`)) {
|
|
@@ -537,14 +569,6 @@ function resolveComponentName(component, nextData, fallbackName) {
|
|
|
537
569
|
const name = component?.getAttribute("id")?.replace(/_ssr$/, "") || isRemoteComponent && component?.getAttribute("name") || (nextData ? "__next" : fallbackName);
|
|
538
570
|
return { name, isRemoteComponent };
|
|
539
571
|
}
|
|
540
|
-
function extractComponentMetadata(component, nextData, name, url) {
|
|
541
|
-
return {
|
|
542
|
-
name,
|
|
543
|
-
bundle: component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle || "default",
|
|
544
|
-
route: component?.getAttribute("data-route") ?? nextData?.page ?? (url.pathname || DEFAULT_ROUTE),
|
|
545
|
-
runtime: component?.getAttribute("data-runtime") ?? (nextData?.props.__REMOTE_COMPONENT__?.runtime || RUNTIME_SCRIPT)
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
572
|
function extractRemoteShared(doc, name, nextData) {
|
|
549
573
|
const remoteSharedEl = doc.querySelector(
|
|
550
574
|
`#${name}_shared[data-remote-components-shared]`
|
|
@@ -556,7 +580,7 @@ function extractRemoteShared(doc, name, nextData) {
|
|
|
556
580
|
function validateComponentFound(component, rsc, nextData, isRemoteComponent, url, name) {
|
|
557
581
|
if (!component || !(rsc || nextData || isRemoteComponent)) {
|
|
558
582
|
throw new RemoteComponentsError(
|
|
559
|
-
`Remote Component not found on ${url}.${name !==
|
|
583
|
+
`Remote Component not found on ${url}.${name !== DEFAULT_COMPONENT_NAME ? ` The name for the <RemoteComponent> is "${name}". Check <RemoteComponent> usage.` : ""} Did you forget to wrap the content in <RemoteComponent>?`
|
|
560
584
|
);
|
|
561
585
|
}
|
|
562
586
|
}
|
|
@@ -582,10 +606,15 @@ function parseRemoteComponentDocument(doc, name, url) {
|
|
|
582
606
|
name
|
|
583
607
|
);
|
|
584
608
|
const rsc = doc.querySelector(`#${resolvedName}_rsc`);
|
|
585
|
-
const metadata =
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
609
|
+
const metadata = buildMetadata(
|
|
610
|
+
{
|
|
611
|
+
name: resolvedName,
|
|
612
|
+
bundle: component?.getAttribute("data-bundle") || nextData?.props.__REMOTE_COMPONENT__?.bundle,
|
|
613
|
+
route: component?.getAttribute("data-route") ?? nextData?.page,
|
|
614
|
+
runtime: component?.getAttribute("data-runtime") ?? nextData?.props.__REMOTE_COMPONENT__?.runtime ?? RUNTIME_SCRIPT,
|
|
615
|
+
id: component?.getAttribute("id"),
|
|
616
|
+
type: component?.getAttribute("data-type")
|
|
617
|
+
},
|
|
589
618
|
url
|
|
590
619
|
);
|
|
591
620
|
const remoteShared = extractRemoteShared(doc, resolvedName, nextData);
|
|
@@ -901,6 +930,14 @@ function createRSCStream(rscName, data) {
|
|
|
901
930
|
});
|
|
902
931
|
}
|
|
903
932
|
|
|
933
|
+
// src/runtime/patterns.ts
|
|
934
|
+
var REMOTE_COMPONENT_REGEX = /(?<prefix>.*?)\[(?<bundle>[^\]]+)\](?:%20| )(?<id>.+)/;
|
|
935
|
+
var NEXT_BUNDLE_PATH_RE = /\/_next\/\[.+\](?:%20| )/;
|
|
936
|
+
var DOUBLE_SLASH_RE = /(?<!:)\/\//g;
|
|
937
|
+
function collapseDoubleSlashes(path) {
|
|
938
|
+
return path.replace(DOUBLE_SLASH_RE, "/");
|
|
939
|
+
}
|
|
940
|
+
|
|
904
941
|
// src/runtime/turbopack/patterns.ts
|
|
905
942
|
var REMOTE_SHARED_MARKER_RE = /(?:self|[a-z])\.TURBOPACK_REMOTE_SHARED/;
|
|
906
943
|
var REMOTE_SHARED_ASSIGNMENT_RE = /\.TURBOPACK_REMOTE_SHARED=await (?:__turbopack_context__|[a-z])\.A\((?<sharedModuleId>[0-9]+)\)/;
|
|
@@ -1490,7 +1527,7 @@ async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location
|
|
|
1490
1527
|
}
|
|
1491
1528
|
}
|
|
1492
1529
|
if (runtime === RUNTIME_TURBOPACK) {
|
|
1493
|
-
await Promise.
|
|
1530
|
+
const results = await Promise.allSettled(
|
|
1494
1531
|
scripts.map((script) => {
|
|
1495
1532
|
if (script.src) {
|
|
1496
1533
|
return self.__webpack_chunk_load__?.(script.src, bundle);
|
|
@@ -1498,6 +1535,14 @@ async function setupWebpackRuntime(runtime, scripts = [], url = new URL(location
|
|
|
1498
1535
|
return Promise.resolve(void 0);
|
|
1499
1536
|
})
|
|
1500
1537
|
);
|
|
1538
|
+
for (const result of results) {
|
|
1539
|
+
if (result.status === "rejected") {
|
|
1540
|
+
logWarn(
|
|
1541
|
+
"WebpackRuntime",
|
|
1542
|
+
`Initial chunk load failed: ${String(result.reason)}`
|
|
1543
|
+
);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1501
1546
|
}
|
|
1502
1547
|
const coreShared = {
|
|
1503
1548
|
react: async () => (await import("react")).default,
|
|
@@ -1980,7 +2025,7 @@ function getRemoteComponentHtml(html) {
|
|
|
1980
2025
|
return ssrRemoteComponentContainer.innerHTML;
|
|
1981
2026
|
}
|
|
1982
2027
|
const remoteComponentContainer = temp.querySelectorAll(
|
|
1983
|
-
`div[data-bundle][data-route][data-runtime][id^="
|
|
2028
|
+
`div[data-bundle][data-route][data-runtime][id^="${DEFAULT_COMPONENT_NAME}"],div[data-bundle][data-route],div#__next,remote-component:not([src])`
|
|
1984
2029
|
);
|
|
1985
2030
|
if (remoteComponentContainer.length > 0) {
|
|
1986
2031
|
return `${Array.from(temp.querySelectorAll("link,script")).map((link) => link.outerHTML).join("")}${Array.from(remoteComponentContainer).map((container) => container.outerHTML).join("")}`;
|
|
@@ -2000,7 +2045,7 @@ function ConsumeRemoteComponent({
|
|
|
2000
2045
|
mode = "open",
|
|
2001
2046
|
reset,
|
|
2002
2047
|
credentials: credentialsProp,
|
|
2003
|
-
name: nameProp =
|
|
2048
|
+
name: nameProp = DEFAULT_COMPONENT_NAME,
|
|
2004
2049
|
shared: sharedProp,
|
|
2005
2050
|
children,
|
|
2006
2051
|
onBeforeLoad,
|
|
@@ -2339,10 +2384,7 @@ function ConsumeRemoteComponent({
|
|
|
2339
2384
|
};
|
|
2340
2385
|
return {
|
|
2341
2386
|
src: new URL(
|
|
2342
|
-
`${prefix ?? ""}${path}
|
|
2343
|
-
/(?<char>[^:])(?<double>\/\/)/g,
|
|
2344
|
-
"$1/"
|
|
2345
|
-
),
|
|
2387
|
+
collapseDoubleSlashes(`${prefix ?? ""}${path}`),
|
|
2346
2388
|
url
|
|
2347
2389
|
).href
|
|
2348
2390
|
};
|