@vercel/microfrontends 1.1.0 → 1.1.1-canary.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/bin/cli.cjs +120 -27
- package/dist/config.cjs +80 -16
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.js +80 -16
- package/dist/config.js.map +1 -1
- package/dist/experimental/sveltekit.cjs +108 -23
- package/dist/experimental/sveltekit.cjs.map +1 -1
- package/dist/experimental/sveltekit.js +108 -23
- package/dist/experimental/sveltekit.js.map +1 -1
- package/dist/experimental/vite.cjs +108 -23
- package/dist/experimental/vite.cjs.map +1 -1
- package/dist/experimental/vite.js +108 -23
- package/dist/experimental/vite.js.map +1 -1
- package/dist/{index-2b59c627.d.ts → index-7e69650e.d.ts} +11 -5
- package/dist/microfrontends/server.cjs +108 -23
- package/dist/microfrontends/server.cjs.map +1 -1
- package/dist/microfrontends/server.d.ts +4 -4
- package/dist/microfrontends/server.js +108 -23
- package/dist/microfrontends/server.js.map +1 -1
- package/dist/microfrontends.cjs +80 -16
- package/dist/microfrontends.cjs.map +1 -1
- package/dist/microfrontends.d.ts +4 -4
- package/dist/microfrontends.js +80 -16
- package/dist/microfrontends.js.map +1 -1
- package/dist/next/config.cjs +125 -30
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +125 -30
- package/dist/next/config.js.map +1 -1
- package/dist/next/endpoints.cjs +9 -0
- package/dist/next/endpoints.cjs.map +1 -1
- package/dist/next/endpoints.d.ts +36 -4
- package/dist/next/endpoints.js +8 -0
- package/dist/next/endpoints.js.map +1 -1
- package/dist/next/middleware.cjs +90 -16
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.js +90 -16
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +84 -21
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.d.ts +4 -4
- package/dist/next/testing.js +84 -21
- package/dist/next/testing.js.map +1 -1
- package/dist/overrides.d.ts +3 -3
- package/dist/schema.cjs +23 -0
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.ts +7 -1
- package/dist/schema.js +13 -0
- package/dist/schema.js.map +1 -1
- package/dist/{index-2f78c0ca.d.ts → types-6ee19ccc.d.ts} +40 -9
- package/dist/{types-b6d38aea.d.ts → types-73527280.d.ts} +1 -1
- package/dist/{types-4ef2bddb.d.ts → types-74e3336c.d.ts} +1 -1
- package/dist/utils/mfe-port.cjs +108 -23
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.js +108 -23
- package/dist/utils/mfe-port.js.map +1 -1
- package/dist/validation.cjs +28 -7
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +28 -7
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
- package/schema/schema.json +28 -7
package/dist/next/endpoints.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/next/endpoints/index.ts
|
|
21
21
|
var endpoints_exports = {};
|
|
22
22
|
__export(endpoints_exports, {
|
|
23
|
+
handleClientConfigForPagesRouter: () => handleClientConfigForPagesRouter,
|
|
23
24
|
wellKnownNextjsClientConfigAppRoute: () => wellKnownNextjsClientConfigAppRoute
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(endpoints_exports);
|
|
@@ -134,8 +135,16 @@ async function wellKnownNextjsClientConfigAppRoute(flagValues) {
|
|
|
134
135
|
)
|
|
135
136
|
);
|
|
136
137
|
}
|
|
138
|
+
async function handleClientConfigForPagesRouter(res, flagValues) {
|
|
139
|
+
const clientData = await getWellKnownClientData(
|
|
140
|
+
process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,
|
|
141
|
+
flagValues
|
|
142
|
+
);
|
|
143
|
+
res.status(200).json(clientData);
|
|
144
|
+
}
|
|
137
145
|
// Annotate the CommonJS export names for ESM import in node:
|
|
138
146
|
0 && (module.exports = {
|
|
147
|
+
handleClientConfigForPagesRouter,
|
|
139
148
|
wellKnownNextjsClientConfigAppRoute
|
|
140
149
|
});
|
|
141
150
|
//# sourceMappingURL=endpoints.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/next/endpoints/index.ts","../../src/config/microfrontends-config/client/index.ts","../../src/config/well-known/endpoints.ts"],"sourcesContent":["import { NextResponse } from 'next/server';\nimport { getWellKnownClientData } from '../../config/well-known/endpoints';\nimport type { WellKnownClientData } from '../../config/well-known/types';\n\n/**\n * A Next.js App Router API handler to export the
|
|
1
|
+
{"version":3,"sources":["../../src/next/endpoints/index.ts","../../src/config/microfrontends-config/client/index.ts","../../src/config/well-known/endpoints.ts"],"sourcesContent":["import type { NextApiResponse } from 'next';\nimport { NextResponse } from 'next/server';\nimport { getWellKnownClientData } from '../../config/well-known/endpoints';\nimport type { WellKnownClientData } from '../../config/well-known/types';\n\n/**\n * A Next.js App Router API handler to export the microfrontends client config\n * data.\n *\n * @example In the `app/.well-known/vercel/microfrontends/client-config/route.ts` file,\n * add this code:\n * ```\n * export { wellKnownNextjsClientConfigAppRoute as GET } from '@vercel/microfrontends/next/endpoints';\n * ```\n */\nexport async function wellKnownNextjsClientConfigAppRoute(\n flagValues: Record<string, () => Promise<boolean>>,\n): Promise<NextResponse> {\n return NextResponse.json<WellKnownClientData>(\n await getWellKnownClientData(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n flagValues,\n ),\n );\n}\n\n/**\n * A Next.js Pages Router API to export the microfrontends client config data to the client.\n *\n * @example In the `pages/api/.well-known/vercel/microfrontends/client-config/index.ts` file,\n * add this code:\n * ```\n * import { handleClientConfigForPagesRouter } from '@vercel/microfrontends/next/endpoints';\n * import type { NextApiResponse } from 'next';\n *\n * async function handler(\n * _,\n * res: NextApiResponse,\n * ): Promise<void> {\n * await handleClientConfigForPagesRouter(res, {\n * flagValue: () => Promise.resolve(true)\n * });\n * }\n * ```\n *\n * Then also make sure to add the following rewrite rule to your `next.config.js` file:\n * ```\n * rewrites: () =>\n * Promise.resolve([\n * {\n * source: '/.well-known/vercel/microfrontends/client-config',\n * destination: '/api/.well-known/vercel/microfrontends/client-config',\n * },\n * ]),\n * ```\n */\nexport async function handleClientConfigForPagesRouter(\n res: NextApiResponse,\n flagValues: Record<string, () => Promise<boolean>>,\n): Promise<void> {\n const clientData = await getWellKnownClientData(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n flagValues,\n );\n res.status(200).json(clientData);\n}\n\nexport type { WellKnownClientData };\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error('No microfrontends configuration found');\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = pathToRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import { MicrofrontendConfigClient } from '../microfrontends-config/client';\nimport type { WellKnownClientData } from './types';\n\n/**\n * Returns data used by the client to ensure that navigations across\n * microfrontend boundaries are routed and prefetched correctly. The client\n * configuration is safe to expose to users.\n *\n * This data should be exposed in a `.well-known/vercel/microfrontends/client-config`\n * endpoint.\n */\nexport async function getWellKnownClientData(\n clientConfig: string | undefined,\n flagValues: Record<string, () => Promise<boolean>> = {},\n): Promise<WellKnownClientData> {\n const config = MicrofrontendConfigClient.fromEnv(clientConfig);\n for (const [applicationName, application] of Object.entries(\n config.applications,\n )) {\n if (!application.routing) {\n continue;\n }\n const newRoutingMatches = [];\n for (const pathGroup of application.routing) {\n if (pathGroup.flag) {\n const flagName = pathGroup.flag;\n const flagFn = flagValues[flagName];\n if (!flagFn) {\n throw new Error(\n `Flag \"${flagName}\" was specified to control routing for path group \"${pathGroup.group}\" in application ${applicationName} but not found in provided flag values.`,\n );\n }\n // eslint-disable-next-line no-await-in-loop\n const flagEnabled = await flagFn();\n if (flagEnabled) {\n newRoutingMatches.push(pathGroup);\n }\n } else {\n newRoutingMatches.push(pathGroup);\n }\n }\n application.routing = newRoutingMatches;\n }\n\n return {\n config: config.serialize(),\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/next/endpoints.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { NextApiResponse } from 'next';
|
|
1
2
|
import { NextResponse } from 'next/server';
|
|
2
|
-
import { C as ClientConfig } from '../types-
|
|
3
|
-
import '../
|
|
3
|
+
import { C as ClientConfig } from '../types-74e3336c.js';
|
|
4
|
+
import '../types-6ee19ccc.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Data that is returned from the `.well-known/vercel/microfrontends/client-config`
|
|
@@ -12,7 +13,7 @@ interface WellKnownClientData {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
|
-
* A Next.js App Router API handler to export the
|
|
16
|
+
* A Next.js App Router API handler to export the microfrontends client config
|
|
16
17
|
* data.
|
|
17
18
|
*
|
|
18
19
|
* @example In the `app/.well-known/vercel/microfrontends/client-config/route.ts` file,
|
|
@@ -22,5 +23,36 @@ interface WellKnownClientData {
|
|
|
22
23
|
* ```
|
|
23
24
|
*/
|
|
24
25
|
declare function wellKnownNextjsClientConfigAppRoute(flagValues: Record<string, () => Promise<boolean>>): Promise<NextResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* A Next.js Pages Router API to export the microfrontends client config data to the client.
|
|
28
|
+
*
|
|
29
|
+
* @example In the `pages/api/.well-known/vercel/microfrontends/client-config/index.ts` file,
|
|
30
|
+
* add this code:
|
|
31
|
+
* ```
|
|
32
|
+
* import { handleClientConfigForPagesRouter } from '@vercel/microfrontends/next/endpoints';
|
|
33
|
+
* import type { NextApiResponse } from 'next';
|
|
34
|
+
*
|
|
35
|
+
* async function handler(
|
|
36
|
+
* _,
|
|
37
|
+
* res: NextApiResponse,
|
|
38
|
+
* ): Promise<void> {
|
|
39
|
+
* await handleClientConfigForPagesRouter(res, {
|
|
40
|
+
* flagValue: () => Promise.resolve(true)
|
|
41
|
+
* });
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* Then also make sure to add the following rewrite rule to your `next.config.js` file:
|
|
46
|
+
* ```
|
|
47
|
+
* rewrites: () =>
|
|
48
|
+
* Promise.resolve([
|
|
49
|
+
* {
|
|
50
|
+
* source: '/.well-known/vercel/microfrontends/client-config',
|
|
51
|
+
* destination: '/api/.well-known/vercel/microfrontends/client-config',
|
|
52
|
+
* },
|
|
53
|
+
* ]),
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
declare function handleClientConfigForPagesRouter(res: NextApiResponse, flagValues: Record<string, () => Promise<boolean>>): Promise<void>;
|
|
25
57
|
|
|
26
|
-
export { WellKnownClientData, wellKnownNextjsClientConfigAppRoute };
|
|
58
|
+
export { WellKnownClientData, handleClientConfigForPagesRouter, wellKnownNextjsClientConfigAppRoute };
|
package/dist/next/endpoints.js
CHANGED
|
@@ -110,7 +110,15 @@ async function wellKnownNextjsClientConfigAppRoute(flagValues) {
|
|
|
110
110
|
)
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
|
+
async function handleClientConfigForPagesRouter(res, flagValues) {
|
|
114
|
+
const clientData = await getWellKnownClientData(
|
|
115
|
+
process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,
|
|
116
|
+
flagValues
|
|
117
|
+
);
|
|
118
|
+
res.status(200).json(clientData);
|
|
119
|
+
}
|
|
113
120
|
export {
|
|
121
|
+
handleClientConfigForPagesRouter,
|
|
114
122
|
wellKnownNextjsClientConfigAppRoute
|
|
115
123
|
};
|
|
116
124
|
//# sourceMappingURL=endpoints.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/next/endpoints/index.ts","../../src/config/microfrontends-config/client/index.ts","../../src/config/well-known/endpoints.ts"],"sourcesContent":["import { NextResponse } from 'next/server';\nimport { getWellKnownClientData } from '../../config/well-known/endpoints';\nimport type { WellKnownClientData } from '../../config/well-known/types';\n\n/**\n * A Next.js App Router API handler to export the
|
|
1
|
+
{"version":3,"sources":["../../src/next/endpoints/index.ts","../../src/config/microfrontends-config/client/index.ts","../../src/config/well-known/endpoints.ts"],"sourcesContent":["import type { NextApiResponse } from 'next';\nimport { NextResponse } from 'next/server';\nimport { getWellKnownClientData } from '../../config/well-known/endpoints';\nimport type { WellKnownClientData } from '../../config/well-known/types';\n\n/**\n * A Next.js App Router API handler to export the microfrontends client config\n * data.\n *\n * @example In the `app/.well-known/vercel/microfrontends/client-config/route.ts` file,\n * add this code:\n * ```\n * export { wellKnownNextjsClientConfigAppRoute as GET } from '@vercel/microfrontends/next/endpoints';\n * ```\n */\nexport async function wellKnownNextjsClientConfigAppRoute(\n flagValues: Record<string, () => Promise<boolean>>,\n): Promise<NextResponse> {\n return NextResponse.json<WellKnownClientData>(\n await getWellKnownClientData(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n flagValues,\n ),\n );\n}\n\n/**\n * A Next.js Pages Router API to export the microfrontends client config data to the client.\n *\n * @example In the `pages/api/.well-known/vercel/microfrontends/client-config/index.ts` file,\n * add this code:\n * ```\n * import { handleClientConfigForPagesRouter } from '@vercel/microfrontends/next/endpoints';\n * import type { NextApiResponse } from 'next';\n *\n * async function handler(\n * _,\n * res: NextApiResponse,\n * ): Promise<void> {\n * await handleClientConfigForPagesRouter(res, {\n * flagValue: () => Promise.resolve(true)\n * });\n * }\n * ```\n *\n * Then also make sure to add the following rewrite rule to your `next.config.js` file:\n * ```\n * rewrites: () =>\n * Promise.resolve([\n * {\n * source: '/.well-known/vercel/microfrontends/client-config',\n * destination: '/api/.well-known/vercel/microfrontends/client-config',\n * },\n * ]),\n * ```\n */\nexport async function handleClientConfigForPagesRouter(\n res: NextApiResponse,\n flagValues: Record<string, () => Promise<boolean>>,\n): Promise<void> {\n const clientData = await getWellKnownClientData(\n process.env.NEXT_PUBLIC_MFE_CLIENT_CONFIG,\n flagValues,\n );\n res.status(200).json(clientData);\n}\n\nexport type { WellKnownClientData };\n","import { pathToRegexp } from 'path-to-regexp';\nimport type { ClientConfig } from './types';\n\ninterface MicrofrontendConfigClientOptions {\n removeFlaggedPaths?: boolean;\n}\n\nexport class MicrofrontendConfigClient {\n applications: ClientConfig['applications'];\n pathCache: Record<string, string> = {};\n private readonly serialized: ClientConfig;\n\n constructor(config: ClientConfig, opts?: MicrofrontendConfigClientOptions) {\n this.serialized = config;\n if (opts?.removeFlaggedPaths) {\n for (const app of Object.values(config.applications)) {\n if (app.routing) {\n app.routing = app.routing.filter((match) => !match.flag);\n }\n }\n }\n this.applications = config.applications;\n }\n\n /**\n * Create a new `MicrofrontendConfigClient` from a JSON string.\n * Config must be passed in to remain framework agnostic\n */\n static fromEnv(\n config: string | undefined,\n opts?: MicrofrontendConfigClientOptions,\n ): MicrofrontendConfigClient {\n if (!config) {\n throw new Error('No microfrontends configuration found');\n }\n return new MicrofrontendConfigClient(\n JSON.parse(config) as ClientConfig,\n opts,\n );\n }\n\n isEqual(other: MicrofrontendConfigClient): boolean {\n return (\n JSON.stringify(this.applications) === JSON.stringify(other.applications)\n );\n }\n\n getApplicationNameForPath(path: string): string | null {\n if (!path.startsWith('/')) {\n throw new Error(`Path must start with a /`);\n }\n\n if (this.pathCache[path]) {\n return this.pathCache[path];\n }\n\n const pathname = new URL(path, 'https://example.com').pathname;\n for (const [name, application] of Object.entries(this.applications)) {\n if (application.routing) {\n for (const group of application.routing) {\n for (const childPath of group.paths) {\n const regexp = pathToRegexp(childPath);\n if (regexp.test(pathname)) {\n this.pathCache[path] = name;\n return name;\n }\n }\n }\n }\n }\n const defaultApplication = Object.entries(this.applications).find(\n ([, application]) => application.default,\n );\n if (!defaultApplication) {\n return null;\n }\n\n this.pathCache[path] = defaultApplication[0];\n return defaultApplication[0];\n }\n\n serialize(): ClientConfig {\n return this.serialized;\n }\n}\n","import { MicrofrontendConfigClient } from '../microfrontends-config/client';\nimport type { WellKnownClientData } from './types';\n\n/**\n * Returns data used by the client to ensure that navigations across\n * microfrontend boundaries are routed and prefetched correctly. The client\n * configuration is safe to expose to users.\n *\n * This data should be exposed in a `.well-known/vercel/microfrontends/client-config`\n * endpoint.\n */\nexport async function getWellKnownClientData(\n clientConfig: string | undefined,\n flagValues: Record<string, () => Promise<boolean>> = {},\n): Promise<WellKnownClientData> {\n const config = MicrofrontendConfigClient.fromEnv(clientConfig);\n for (const [applicationName, application] of Object.entries(\n config.applications,\n )) {\n if (!application.routing) {\n continue;\n }\n const newRoutingMatches = [];\n for (const pathGroup of application.routing) {\n if (pathGroup.flag) {\n const flagName = pathGroup.flag;\n const flagFn = flagValues[flagName];\n if (!flagFn) {\n throw new Error(\n `Flag \"${flagName}\" was specified to control routing for path group \"${pathGroup.group}\" in application ${applicationName} but not found in provided flag values.`,\n );\n }\n // eslint-disable-next-line no-await-in-loop\n const flagEnabled = await flagFn();\n if (flagEnabled) {\n newRoutingMatches.push(pathGroup);\n }\n } else {\n newRoutingMatches.push(pathGroup);\n }\n }\n application.routing = newRoutingMatches;\n }\n\n return {\n config: config.serialize(),\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/next/middleware.cjs
CHANGED
|
@@ -305,10 +305,13 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
305
305
|
}
|
|
306
306
|
}
|
|
307
307
|
if (errors.length) {
|
|
308
|
-
throw new MicrofrontendError(
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
throw new MicrofrontendError(
|
|
309
|
+
`Invalid paths: ${errors.join(", ")}. See supported paths in the documentation https://vercel.com/docs/microfrontends/path-routing#supported-path-expressions.`,
|
|
310
|
+
{
|
|
311
|
+
type: "config",
|
|
312
|
+
subtype: "conflicting_paths"
|
|
313
|
+
}
|
|
314
|
+
);
|
|
312
315
|
}
|
|
313
316
|
};
|
|
314
317
|
var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
|
|
@@ -423,9 +426,40 @@ var validateDeprecatedFields = (config) => {
|
|
|
423
426
|
`Application '${applicationId}' cannot contain deprecated field 'production'. Use 'development.fallback' instead.`
|
|
424
427
|
);
|
|
425
428
|
}
|
|
426
|
-
if (application.development?.
|
|
429
|
+
if (application.development?.localPort) {
|
|
430
|
+
errors.push(
|
|
431
|
+
`Application '${applicationId}' cannot contain deprecated field 'development.localPort'. Use 'developement.local' instead.`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
if (application.development?.fallback && typeof application.development.fallback !== "string") {
|
|
435
|
+
const fallback = application.development.fallback;
|
|
436
|
+
let asString = fallback.host;
|
|
437
|
+
if (fallback.protocol) {
|
|
438
|
+
asString = `${fallback.protocol}://${asString}`;
|
|
439
|
+
}
|
|
440
|
+
if (fallback.port) {
|
|
441
|
+
asString = `${asString}:${fallback.port}`;
|
|
442
|
+
}
|
|
443
|
+
errors.push(
|
|
444
|
+
`Application '${applicationId}' requires a string (not an object) for the 'development.fallback' field. Please set 'development.fallback' to '${asString}'.`
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
if (application.development?.local && typeof application.development.local !== "string" && typeof application.development.local !== "number") {
|
|
448
|
+
const local = application.development.local;
|
|
449
|
+
let asString;
|
|
450
|
+
if (local.port && !local.protocol && !local.host) {
|
|
451
|
+
asString = String(local.port);
|
|
452
|
+
} else {
|
|
453
|
+
asString = local.host ?? "localhost";
|
|
454
|
+
if (local.protocol) {
|
|
455
|
+
asString = `${local.protocol}://${asString}`;
|
|
456
|
+
}
|
|
457
|
+
if (local.port) {
|
|
458
|
+
asString = `${asString}:${local.port}`;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
427
461
|
errors.push(
|
|
428
|
-
`Application '${applicationId}'
|
|
462
|
+
`Application '${applicationId}' requires a string or number (not an object) for the 'development.local' field. Please set 'development.local' to '${asString}'.`
|
|
429
463
|
);
|
|
430
464
|
}
|
|
431
465
|
}
|
|
@@ -489,10 +523,10 @@ var Host = class {
|
|
|
489
523
|
}
|
|
490
524
|
this.local = options?.isLocal;
|
|
491
525
|
}
|
|
492
|
-
static parseUrl(url) {
|
|
526
|
+
static parseUrl(url, defaultProtocol = "https") {
|
|
493
527
|
let hostToParse = url;
|
|
494
528
|
if (!/^https?:\/\//.exec(hostToParse)) {
|
|
495
|
-
hostToParse =
|
|
529
|
+
hostToParse = `${defaultProtocol}://${hostToParse}`;
|
|
496
530
|
}
|
|
497
531
|
const parsed = new URL(hostToParse);
|
|
498
532
|
if (!parsed.hostname) {
|
|
@@ -545,12 +579,39 @@ var LocalHost = class extends Host {
|
|
|
545
579
|
constructor({
|
|
546
580
|
appName,
|
|
547
581
|
localPort,
|
|
548
|
-
|
|
582
|
+
local
|
|
549
583
|
}) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
584
|
+
if (localPort && local) {
|
|
585
|
+
throw new Error(
|
|
586
|
+
`Microfrontends configuration error: '${appName}' has both the 'development.local' and 'development.localPort' fields set. Please remove the 'development.localPort' field and ensure the 'development.local' field has the correct port.`
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
let protocol;
|
|
590
|
+
let host;
|
|
591
|
+
let port;
|
|
592
|
+
if (localPort) {
|
|
593
|
+
port = localPort;
|
|
594
|
+
} else if (typeof local === "number") {
|
|
595
|
+
port = local;
|
|
596
|
+
} else if (typeof local === "string") {
|
|
597
|
+
if (/^\d+$/.test(local)) {
|
|
598
|
+
port = Number.parseInt(local);
|
|
599
|
+
} else {
|
|
600
|
+
const parsed = Host.parseUrl(local, "http");
|
|
601
|
+
protocol = parsed.protocol;
|
|
602
|
+
host = parsed.host;
|
|
603
|
+
port = parsed.port;
|
|
604
|
+
}
|
|
605
|
+
} else if (local) {
|
|
606
|
+
protocol = local.protocol;
|
|
607
|
+
host = local.host;
|
|
608
|
+
port = local.port;
|
|
609
|
+
}
|
|
610
|
+
super({
|
|
611
|
+
protocol: protocol ?? "http",
|
|
612
|
+
host: host ?? "localhost",
|
|
613
|
+
port: port ?? generatePortFromName({ name: appName })
|
|
614
|
+
});
|
|
554
615
|
}
|
|
555
616
|
};
|
|
556
617
|
|
|
@@ -566,7 +627,7 @@ var Application = class {
|
|
|
566
627
|
local: new LocalHost({
|
|
567
628
|
appName: name,
|
|
568
629
|
localPort: app.development?.localPort,
|
|
569
|
-
|
|
630
|
+
local: app.development?.local
|
|
570
631
|
}),
|
|
571
632
|
fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
|
|
572
633
|
};
|
|
@@ -576,6 +637,7 @@ var Application = class {
|
|
|
576
637
|
this.fallback = new Host(app.production);
|
|
577
638
|
}
|
|
578
639
|
this.projectId = app.projectId ?? app.vercel?.projectId;
|
|
640
|
+
this.packageName = app.packageName;
|
|
579
641
|
this.overrides = overrides?.environment ? {
|
|
580
642
|
environment: new Host(overrides.environment)
|
|
581
643
|
} : void 0;
|
|
@@ -741,10 +803,12 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
741
803
|
].filter(Boolean);
|
|
742
804
|
}
|
|
743
805
|
getApplication(name) {
|
|
744
|
-
if (this.defaultApplication?.name === name) {
|
|
806
|
+
if (this.defaultApplication?.name === name || this.defaultApplication?.packageName === name) {
|
|
745
807
|
return this.defaultApplication;
|
|
746
808
|
}
|
|
747
|
-
const app = this.childApplications[name]
|
|
809
|
+
const app = this.childApplications[name] || Object.values(this.childApplications).find(
|
|
810
|
+
(child) => child.packageName === name
|
|
811
|
+
);
|
|
748
812
|
if (!app) {
|
|
749
813
|
throw new MicrofrontendError(
|
|
750
814
|
`Could not find microfrontends configuration for application "${name}"`,
|
|
@@ -933,10 +997,20 @@ function getFlagHandler({
|
|
|
933
997
|
}
|
|
934
998
|
};
|
|
935
999
|
if (routeToLocalProxy()) {
|
|
1000
|
+
if (process.env.MFE_DEBUG) {
|
|
1001
|
+
console.log(
|
|
1002
|
+
`Routing flagged path "${pathname}" to local proxy for application "${application.name}"`
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
936
1005
|
const url = req.nextUrl;
|
|
937
1006
|
url.host = `localhost:${localProxyPort}`;
|
|
938
1007
|
return import_server.NextResponse.rewrite(url, middlewareResponseInit);
|
|
939
1008
|
}
|
|
1009
|
+
if (process.env.MFE_DEBUG) {
|
|
1010
|
+
console.log(
|
|
1011
|
+
`Routing flagged path "${pathname}" to application "${application.name}"`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
940
1014
|
return import_server.NextResponse.next(middlewareResponseInit);
|
|
941
1015
|
}
|
|
942
1016
|
} catch (e) {
|