@vercel/microfrontends 2.1.3 → 2.2.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/CHANGELOG.md +20 -0
- package/README.md +4 -0
- package/dist/bin/cli.cjs +207 -90
- package/dist/config.d.ts +2 -2
- package/dist/experimental/sveltekit.cjs +180 -63
- package/dist/experimental/sveltekit.cjs.map +1 -1
- package/dist/experimental/sveltekit.d.ts +6 -0
- package/dist/experimental/sveltekit.js +180 -63
- package/dist/experimental/sveltekit.js.map +1 -1
- package/dist/experimental/vite.cjs +177 -66
- package/dist/experimental/vite.cjs.map +1 -1
- package/dist/experimental/vite.js +177 -66
- package/dist/experimental/vite.js.map +1 -1
- package/dist/microfrontends/server.cjs +173 -60
- package/dist/microfrontends/server.cjs.map +1 -1
- package/dist/microfrontends/server.d.ts +2 -2
- package/dist/microfrontends/server.js +173 -60
- package/dist/microfrontends/server.js.map +1 -1
- package/dist/microfrontends/utils.cjs +50 -7
- package/dist/microfrontends/utils.cjs.map +1 -1
- package/dist/microfrontends/utils.d.ts +1 -1
- package/dist/microfrontends/utils.js +50 -7
- package/dist/microfrontends/utils.js.map +1 -1
- package/dist/next/config.cjs +208 -113
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.d.ts +11 -1
- package/dist/next/config.js +208 -113
- package/dist/next/config.js.map +1 -1
- package/dist/next/middleware.cjs +35 -17
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.js +35 -17
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.d.ts +2 -2
- package/dist/overrides.d.ts +3 -3
- package/dist/schema.d.ts +2 -2
- package/dist/{types-88602303.d.ts → types-b9ea41b2.d.ts} +1 -1
- package/dist/{types-e7523e61.d.ts → types-dcd8b17a.d.ts} +71 -24
- package/dist/utils/mfe-port.cjs +173 -60
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.js +173 -60
- package/dist/utils/mfe-port.js.map +1 -1
- package/dist/validation.cjs +47 -38
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +47 -38
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
- package/schema/schema.json +47 -38
package/dist/next/config.js
CHANGED
|
@@ -6,12 +6,38 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
throw new Error('Dynamic require of "' + x + '" is not supported');
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
+
// src/bin/local-proxy-is-running.ts
|
|
10
|
+
function localProxyIsRunning() {
|
|
11
|
+
return process.env.TURBO_TASK_HAS_MFE_PROXY === "true";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/bin/logger.ts
|
|
15
|
+
function debug(...args) {
|
|
16
|
+
if (process.env.MFE_DEBUG) {
|
|
17
|
+
console.log(...args);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function info(...args) {
|
|
21
|
+
console.log(...args);
|
|
22
|
+
}
|
|
23
|
+
function warn(...args) {
|
|
24
|
+
console.warn(...args);
|
|
25
|
+
}
|
|
26
|
+
function error(...args) {
|
|
27
|
+
console.error(...args);
|
|
28
|
+
}
|
|
29
|
+
var logger = {
|
|
30
|
+
debug,
|
|
31
|
+
info,
|
|
32
|
+
warn,
|
|
33
|
+
error
|
|
34
|
+
};
|
|
35
|
+
|
|
9
36
|
// src/bin/check-proxy.ts
|
|
10
37
|
function displayLocalProxyInfo(port) {
|
|
11
|
-
|
|
12
|
-
if (TURBO_TASK_HAS_MFE_PROXY === "true" && MFE_PROXY_MESSAGE_PRINTED !== "true") {
|
|
38
|
+
if (localProxyIsRunning() && process.env.MFE_PROXY_MESSAGE_PRINTED !== "true") {
|
|
13
39
|
process.env.MFE_PROXY_MESSAGE_PRINTED = "true";
|
|
14
|
-
|
|
40
|
+
logger.info(`Microfrontends Proxy running on http://localhost:${port}`);
|
|
15
41
|
}
|
|
16
42
|
}
|
|
17
43
|
|
|
@@ -206,8 +232,8 @@ import fg from "fast-glob";
|
|
|
206
232
|
|
|
207
233
|
// src/config/microfrontends/utils/get-config-file-name.ts
|
|
208
234
|
var DEFAULT_CONFIGURATION_FILENAMES = [
|
|
209
|
-
"microfrontends.
|
|
210
|
-
"microfrontends.
|
|
235
|
+
"microfrontends.json",
|
|
236
|
+
"microfrontends.jsonc"
|
|
211
237
|
];
|
|
212
238
|
function getPossibleConfigurationFilenames({
|
|
213
239
|
customConfigFilename
|
|
@@ -215,7 +241,7 @@ function getPossibleConfigurationFilenames({
|
|
|
215
241
|
if (customConfigFilename) {
|
|
216
242
|
if (!customConfigFilename.endsWith(".json") && !customConfigFilename.endsWith(".jsonc")) {
|
|
217
243
|
throw new Error(
|
|
218
|
-
`
|
|
244
|
+
`Found VC_MICROFRONTENDS_CONFIG_FILE_NAME but the name is invalid. Received: ${customConfigFilename}. The file name must end with '.json' or '.jsonc'. It's also possible for the env var to include the path, eg microfrontends-dev.json or /path/to/microfrontends-dev.json.`
|
|
219
245
|
);
|
|
220
246
|
}
|
|
221
247
|
return Array.from(
|
|
@@ -233,6 +259,10 @@ function findPackageWithMicrofrontendsConfig({
|
|
|
233
259
|
customConfigFilename
|
|
234
260
|
}) {
|
|
235
261
|
const applicationName = applicationContext.name;
|
|
262
|
+
logger.debug(
|
|
263
|
+
"[MFE Config] Searching repository for configs containing application:",
|
|
264
|
+
applicationName
|
|
265
|
+
);
|
|
236
266
|
try {
|
|
237
267
|
const microfrontendsJsonPaths = fg.globSync(
|
|
238
268
|
`**/{${getPossibleConfigurationFilenames({ customConfigFilename }).join(",")}}`,
|
|
@@ -244,6 +274,11 @@ function findPackageWithMicrofrontendsConfig({
|
|
|
244
274
|
ignore: ["**/node_modules/**", "**/.git/**"]
|
|
245
275
|
}
|
|
246
276
|
);
|
|
277
|
+
logger.debug(
|
|
278
|
+
"[MFE Config] Found",
|
|
279
|
+
microfrontendsJsonPaths.length,
|
|
280
|
+
"config file(s) in repository"
|
|
281
|
+
);
|
|
247
282
|
const matchingPaths = [];
|
|
248
283
|
for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
|
|
249
284
|
try {
|
|
@@ -253,19 +288,31 @@ function findPackageWithMicrofrontendsConfig({
|
|
|
253
288
|
);
|
|
254
289
|
const microfrontendsJson = parse(microfrontendsJsonContent);
|
|
255
290
|
if (microfrontendsJson.applications[applicationName]) {
|
|
291
|
+
logger.debug(
|
|
292
|
+
"[MFE Config] Found application in config:",
|
|
293
|
+
microfrontendsJsonPath
|
|
294
|
+
);
|
|
256
295
|
matchingPaths.push(microfrontendsJsonPath);
|
|
257
296
|
} else {
|
|
258
297
|
for (const [_, app] of Object.entries(
|
|
259
298
|
microfrontendsJson.applications
|
|
260
299
|
)) {
|
|
261
300
|
if (app.packageName === applicationName) {
|
|
301
|
+
logger.debug(
|
|
302
|
+
"[MFE Config] Found application via packageName in config:",
|
|
303
|
+
microfrontendsJsonPath
|
|
304
|
+
);
|
|
262
305
|
matchingPaths.push(microfrontendsJsonPath);
|
|
263
306
|
}
|
|
264
307
|
}
|
|
265
308
|
}
|
|
266
|
-
} catch (
|
|
309
|
+
} catch (error2) {
|
|
267
310
|
}
|
|
268
311
|
}
|
|
312
|
+
logger.debug(
|
|
313
|
+
"[MFE Config] Total matching config files:",
|
|
314
|
+
matchingPaths.length
|
|
315
|
+
);
|
|
269
316
|
if (matchingPaths.length > 1) {
|
|
270
317
|
throw new MicrofrontendError(
|
|
271
318
|
`Found multiple \`microfrontends.json\` files in the repository referencing the application "${applicationName}", but only one is allowed.
|
|
@@ -299,9 +346,9 @@ If you suspect this is thrown in error, please reach out to the Vercel team.`,
|
|
|
299
346
|
}
|
|
300
347
|
const [packageJsonPath] = matchingPaths;
|
|
301
348
|
return dirname(packageJsonPath);
|
|
302
|
-
} catch (
|
|
303
|
-
if (
|
|
304
|
-
throw
|
|
349
|
+
} catch (error2) {
|
|
350
|
+
if (error2 instanceof MicrofrontendError) {
|
|
351
|
+
throw error2;
|
|
305
352
|
}
|
|
306
353
|
return null;
|
|
307
354
|
}
|
|
@@ -346,8 +393,8 @@ function isMonorepo({
|
|
|
346
393
|
fs2.readFileSync(packageJsonPath, "utf-8")
|
|
347
394
|
);
|
|
348
395
|
return packageJson.workspaces !== void 0;
|
|
349
|
-
} catch (
|
|
350
|
-
|
|
396
|
+
} catch (error2) {
|
|
397
|
+
logger.error("Error determining if repository is a monorepo", error2);
|
|
351
398
|
return false;
|
|
352
399
|
}
|
|
353
400
|
}
|
|
@@ -1064,15 +1111,18 @@ import fs5 from "node:fs";
|
|
|
1064
1111
|
import path4 from "node:path";
|
|
1065
1112
|
function getApplicationContext(opts) {
|
|
1066
1113
|
if (opts?.appName) {
|
|
1114
|
+
logger.debug("[MFE Config] Application name from appName parameter:", opts.appName);
|
|
1067
1115
|
return { name: opts.appName };
|
|
1068
1116
|
}
|
|
1069
1117
|
if (process.env.VERCEL_PROJECT_NAME) {
|
|
1118
|
+
logger.debug("[MFE Config] Application name from VERCEL_PROJECT_NAME:", process.env.VERCEL_PROJECT_NAME);
|
|
1070
1119
|
return {
|
|
1071
1120
|
name: process.env.VERCEL_PROJECT_NAME,
|
|
1072
1121
|
projectName: process.env.VERCEL_PROJECT_NAME
|
|
1073
1122
|
};
|
|
1074
1123
|
}
|
|
1075
1124
|
if (process.env.NX_TASK_TARGET_PROJECT) {
|
|
1125
|
+
logger.debug("[MFE Config] Application name from NX_TASK_TARGET_PROJECT:", process.env.NX_TASK_TARGET_PROJECT);
|
|
1076
1126
|
return {
|
|
1077
1127
|
name: process.env.NX_TASK_TARGET_PROJECT,
|
|
1078
1128
|
packageJsonName: process.env.NX_TASK_TARGET_PROJECT
|
|
@@ -1085,6 +1135,7 @@ function getApplicationContext(opts) {
|
|
|
1085
1135
|
);
|
|
1086
1136
|
const projectJson = JSON.parse(vercelProjectJsonPath);
|
|
1087
1137
|
if (projectJson.projectName) {
|
|
1138
|
+
logger.debug("[MFE Config] Application name from .vercel/project.json:", projectJson.projectName);
|
|
1088
1139
|
return {
|
|
1089
1140
|
name: projectJson.projectName,
|
|
1090
1141
|
projectName: projectJson.projectName
|
|
@@ -1108,6 +1159,7 @@ function getApplicationContext(opts) {
|
|
|
1108
1159
|
}
|
|
1109
1160
|
);
|
|
1110
1161
|
}
|
|
1162
|
+
logger.debug("[MFE Config] Application name from package.json:", packageJson.name);
|
|
1111
1163
|
return { name: packageJson.name, packageJsonName: packageJson.name };
|
|
1112
1164
|
} catch (err) {
|
|
1113
1165
|
throw MicrofrontendError.handle(err, {
|
|
@@ -1141,38 +1193,28 @@ var schema_default = {
|
|
|
1141
1193
|
type: "object",
|
|
1142
1194
|
properties: {
|
|
1143
1195
|
$schema: {
|
|
1144
|
-
type: "string"
|
|
1196
|
+
type: "string",
|
|
1197
|
+
description: "See https://openapi.vercel.sh/microfrontends.json."
|
|
1145
1198
|
},
|
|
1146
1199
|
version: {
|
|
1147
1200
|
type: "string",
|
|
1148
|
-
const: "1"
|
|
1149
|
-
|
|
1150
|
-
options: {
|
|
1151
|
-
$ref: "#/definitions/Options"
|
|
1201
|
+
const: "1",
|
|
1202
|
+
description: "The version of the microfrontends config schema."
|
|
1152
1203
|
},
|
|
1153
1204
|
applications: {
|
|
1154
1205
|
$ref: "#/definitions/ApplicationRouting",
|
|
1155
|
-
description: "Mapping of
|
|
1206
|
+
description: "Mapping of Vercel project names to their microfrontend configurations."
|
|
1207
|
+
},
|
|
1208
|
+
options: {
|
|
1209
|
+
$ref: "#/definitions/Options",
|
|
1210
|
+
description: "Optional configuration options for the microfrontend."
|
|
1156
1211
|
}
|
|
1157
1212
|
},
|
|
1158
1213
|
required: [
|
|
1159
1214
|
"applications"
|
|
1160
1215
|
],
|
|
1161
|
-
additionalProperties: false
|
|
1162
|
-
|
|
1163
|
-
Options: {
|
|
1164
|
-
type: "object",
|
|
1165
|
-
properties: {
|
|
1166
|
-
disableOverrides: {
|
|
1167
|
-
type: "boolean",
|
|
1168
|
-
description: "If you want to disable the overrides for the site. For example, if you are managing rewrites between applications externally, you may wish to disable the overrides on the toolbar as they will have no effect."
|
|
1169
|
-
},
|
|
1170
|
-
localProxyPort: {
|
|
1171
|
-
type: "number",
|
|
1172
|
-
description: "The port number used by the local proxy server.\n\nThe default is `3024`."
|
|
1173
|
-
}
|
|
1174
|
-
},
|
|
1175
|
-
additionalProperties: false
|
|
1216
|
+
additionalProperties: false,
|
|
1217
|
+
description: "The microfrontends configuration schema. See https://vercel.com/docs/microfrontends/configuration."
|
|
1176
1218
|
},
|
|
1177
1219
|
ApplicationRouting: {
|
|
1178
1220
|
type: "object",
|
|
@@ -1180,8 +1222,9 @@ var schema_default = {
|
|
|
1180
1222
|
$ref: "#/definitions/Application"
|
|
1181
1223
|
},
|
|
1182
1224
|
propertyNames: {
|
|
1183
|
-
description: "The
|
|
1184
|
-
}
|
|
1225
|
+
description: "The Vercel project name of the microfrontend application.\n\nNote: If this name does not also match the name `name` from the `package.json`, set `packageName` with the name used in `package.json`.\n\nSee https://vercel.com/docs/microfrontends/configuration#application-naming."
|
|
1226
|
+
},
|
|
1227
|
+
description: "Mapping of Vercel project names to their microfrontend configurations."
|
|
1185
1228
|
},
|
|
1186
1229
|
Application: {
|
|
1187
1230
|
anyOf: [
|
|
@@ -1191,14 +1234,15 @@ var schema_default = {
|
|
|
1191
1234
|
{
|
|
1192
1235
|
$ref: "#/definitions/ChildApplication"
|
|
1193
1236
|
}
|
|
1194
|
-
]
|
|
1237
|
+
],
|
|
1238
|
+
description: "The configuration for a microfrontend application. There must always be one default application."
|
|
1195
1239
|
},
|
|
1196
1240
|
DefaultApplication: {
|
|
1197
1241
|
type: "object",
|
|
1198
1242
|
properties: {
|
|
1199
1243
|
packageName: {
|
|
1200
1244
|
type: "string",
|
|
1201
|
-
description: "The name used to run the application, e.g. the `name` field in the `package.json`.\n\nThis is used by the local proxy to map the application config to the locally running app.\n\nThis is only necessary when the application name does not match the `name` used in `package.json
|
|
1245
|
+
description: "The name used to run the application, e.g. the `name` field in the `package.json`.\n\nThis is used by the local proxy to map the application config to the locally running app.\n\nThis is only necessary when the application name does not match the `name` used in `package.json`.\n\nSee https://vercel.com/docs/microfrontends/configuration#application-naming."
|
|
1202
1246
|
},
|
|
1203
1247
|
development: {
|
|
1204
1248
|
$ref: "#/definitions/DefaultDevelopment",
|
|
@@ -1218,15 +1262,15 @@ var schema_default = {
|
|
|
1218
1262
|
"number",
|
|
1219
1263
|
"string"
|
|
1220
1264
|
],
|
|
1221
|
-
description: "A local port number or host
|
|
1265
|
+
description: "A local port number or host that this application runs on when it is running locally. If passing a string, include the protocol (optional), host (required) and port (optional).\n\nExamples of valid values: 8080, my.localhost.me, my.localhost.me:8080, https://my.localhost.me, https://my.localhost.me:8080.\n\nThe default value is http://localhost:<port> where port is a stable, unique port number (based on the application name).\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1222
1266
|
},
|
|
1223
1267
|
task: {
|
|
1224
1268
|
type: "string",
|
|
1225
|
-
description:
|
|
1269
|
+
description: 'The task to run when starting the development server. Should reference a script in the package.json of the application.\n\nThe default value is "dev".\n\nSee https://vercel.com/docs/microfrontends/local-development.'
|
|
1226
1270
|
},
|
|
1227
1271
|
fallback: {
|
|
1228
1272
|
type: "string",
|
|
1229
|
-
description: "Fallback for local development, could point to any environment. This is required for the default app. This value is used as the fallback for child apps as well if they do not have a fallback.\n\nIf passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTPS. If omitted, the port defaults to `80` for HTTP and `443` for HTTPS."
|
|
1273
|
+
description: "Fallback for local development, could point to any environment. This is required for the default app. This value is used as the fallback for child apps as well if they do not have a fallback.\n\nIf passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTPS. If omitted, the port defaults to `80` for HTTP and `443` for HTTPS.\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1230
1274
|
}
|
|
1231
1275
|
},
|
|
1232
1276
|
required: [
|
|
@@ -1239,7 +1283,7 @@ var schema_default = {
|
|
|
1239
1283
|
properties: {
|
|
1240
1284
|
packageName: {
|
|
1241
1285
|
type: "string",
|
|
1242
|
-
description: "The name used to run the application, e.g. the `name` field in the `package.json`.\n\nThis is used by the local proxy to map the application config to the locally running app.\n\nThis is only necessary when the application name does not match the `name` used in `package.json
|
|
1286
|
+
description: "The name used to run the application, e.g. the `name` field in the `package.json`.\n\nThis is used by the local proxy to map the application config to the locally running app.\n\nThis is only necessary when the application name does not match the `name` used in `package.json`.\n\nSee https://vercel.com/docs/microfrontends/configuration#application-naming."
|
|
1243
1287
|
},
|
|
1244
1288
|
development: {
|
|
1245
1289
|
$ref: "#/definitions/ChildDevelopment",
|
|
@@ -1247,11 +1291,11 @@ var schema_default = {
|
|
|
1247
1291
|
},
|
|
1248
1292
|
routing: {
|
|
1249
1293
|
$ref: "#/definitions/Routing",
|
|
1250
|
-
description: "Groups of path expressions that are routed to this application."
|
|
1294
|
+
description: "Groups of path expressions that are routed to this application.\n\nSee https://vercel.com/docs/microfrontends/path-routing."
|
|
1251
1295
|
},
|
|
1252
1296
|
assetPrefix: {
|
|
1253
1297
|
type: "string",
|
|
1254
|
-
description: "The name of the asset prefix to use instead of the auto-generated name.\n\nThe asset prefix is used to prefix all paths to static assets, such as JS, CSS, or images that are served by a specific application. It is necessary to ensure there are no conflicts with other applications on the same domain.\n\nAn auto-generated asset prefix of the form `vc-ap-<hash>` is used when this field is not provided.\n\nWhen this field is provided, `/${assetPrefix}/:path*` must also be added to the list of paths in the `routing` field. Changing the asset prefix after a microfrontend application has already been deployed is not a forwards and backwards compatible change, and the asset prefix should be added to the `routing` field and deployed before setting the `assetPrefix` field."
|
|
1298
|
+
description: "The name of the asset prefix to use instead of the auto-generated name.\n\nThe asset prefix is used to prefix all paths to static assets, such as JS, CSS, or images that are served by a specific application. It is necessary to ensure there are no conflicts with other applications on the same domain.\n\nAn auto-generated asset prefix of the form `vc-ap-<hash>` is used when this field is not provided.\n\nWhen this field is provided, `/${assetPrefix}/:path*` must also be added to the list of paths in the `routing` field. Changing the asset prefix after a microfrontend application has already been deployed is not a forwards and backwards compatible change, and the asset prefix should be added to the `routing` field and deployed before setting the `assetPrefix` field.\n\nThe default value is the auto-generated asset prefix of the form `vc-ap-<hash>`.\n\nSee https://vercel.com/docs/microfrontends/path-routing#asset-prefix."
|
|
1255
1299
|
}
|
|
1256
1300
|
},
|
|
1257
1301
|
required: [
|
|
@@ -1267,15 +1311,15 @@ var schema_default = {
|
|
|
1267
1311
|
"number",
|
|
1268
1312
|
"string"
|
|
1269
1313
|
],
|
|
1270
|
-
description: "A local port number or host
|
|
1314
|
+
description: "A local port number or host that this application runs on when it is running locally. If passing a string, include the protocol (optional), host (required) and port (optional).\n\nExamples of valid values: 8080, my.localhost.me, my.localhost.me:8080, https://my.localhost.me, https://my.localhost.me:8080.\n\nThe default value is http://localhost:<port> where port is a stable, unique port number (based on the application name).\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1271
1315
|
},
|
|
1272
1316
|
task: {
|
|
1273
1317
|
type: "string",
|
|
1274
|
-
description:
|
|
1318
|
+
description: 'The task to run when starting the development server. Should reference a script in the package.json of the application.\n\nThe default value is "dev".\n\nSee https://vercel.com/docs/microfrontends/local-development.'
|
|
1275
1319
|
},
|
|
1276
1320
|
fallback: {
|
|
1277
1321
|
type: "string",
|
|
1278
|
-
description: "Fallback for local development, could point to any environment.
|
|
1322
|
+
description: "Fallback for local development, could point to any environment. If not provided for child apps, the fallback of the default app will be used.\n\nIf passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTPS. If omitted, the port defaults to `80` for HTTP and `443` for HTTPS.\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1279
1323
|
}
|
|
1280
1324
|
},
|
|
1281
1325
|
additionalProperties: false
|
|
@@ -1284,29 +1328,46 @@ var schema_default = {
|
|
|
1284
1328
|
type: "array",
|
|
1285
1329
|
items: {
|
|
1286
1330
|
$ref: "#/definitions/PathGroup"
|
|
1287
|
-
}
|
|
1331
|
+
},
|
|
1332
|
+
description: "A list of path groups that are routed to this application."
|
|
1288
1333
|
},
|
|
1289
1334
|
PathGroup: {
|
|
1290
1335
|
type: "object",
|
|
1291
1336
|
properties: {
|
|
1292
1337
|
group: {
|
|
1293
1338
|
type: "string",
|
|
1294
|
-
description: "
|
|
1339
|
+
description: "Group name for the paths."
|
|
1295
1340
|
},
|
|
1296
1341
|
flag: {
|
|
1297
1342
|
type: "string",
|
|
1298
|
-
description: "
|
|
1343
|
+
description: "The name of the feature flag that controls routing for this group of paths. See https://vercel.com/docs/microfrontends/path-routing#routing-changes-safely-with-flags."
|
|
1299
1344
|
},
|
|
1300
1345
|
paths: {
|
|
1301
1346
|
type: "array",
|
|
1302
1347
|
items: {
|
|
1303
1348
|
type: "string"
|
|
1304
|
-
}
|
|
1349
|
+
},
|
|
1350
|
+
description: "A list of path expressions that are routed to this application. See https://vercel.com/docs/microfrontends/path-routing#supported-path-expressions."
|
|
1305
1351
|
}
|
|
1306
1352
|
},
|
|
1307
1353
|
required: [
|
|
1308
1354
|
"paths"
|
|
1309
1355
|
],
|
|
1356
|
+
additionalProperties: false,
|
|
1357
|
+
description: "A group of paths that is routed to this application."
|
|
1358
|
+
},
|
|
1359
|
+
Options: {
|
|
1360
|
+
type: "object",
|
|
1361
|
+
properties: {
|
|
1362
|
+
disableOverrides: {
|
|
1363
|
+
type: "boolean",
|
|
1364
|
+
description: "If you want to disable the overrides for the site. For example, if you are managing rewrites between applications externally, you may wish to disable the overrides on the toolbar as they will have no effect.\n\nSee https://vercel.com/docs/microfrontends/managing-microfrontends/vercel-toolbar#routing-overrides."
|
|
1365
|
+
},
|
|
1366
|
+
localProxyPort: {
|
|
1367
|
+
type: "number",
|
|
1368
|
+
description: "The port number used by the local proxy server.\n\nThe default value is 3024.\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1369
|
+
}
|
|
1370
|
+
},
|
|
1310
1371
|
additionalProperties: false
|
|
1311
1372
|
}
|
|
1312
1373
|
}
|
|
@@ -1325,19 +1386,19 @@ function formatAjvErrors(errors) {
|
|
|
1325
1386
|
return [];
|
|
1326
1387
|
}
|
|
1327
1388
|
const errorMessages = [];
|
|
1328
|
-
for (const
|
|
1329
|
-
if (
|
|
1389
|
+
for (const error2 of errors) {
|
|
1390
|
+
if (error2.instancePath === "" && (error2.keyword === "anyOf" || error2.keyword === "required" && error2.params.missingProperty === "partOf")) {
|
|
1330
1391
|
continue;
|
|
1331
1392
|
}
|
|
1332
|
-
const instancePath =
|
|
1393
|
+
const instancePath = error2.instancePath.slice(1);
|
|
1333
1394
|
const formattedInstancePath = instancePath === "" ? "at the root" : `in field ${instancePath}`;
|
|
1334
|
-
if (
|
|
1395
|
+
if (error2.keyword === "required" && error2.params.missingProperty === "routing" && instancePath.split("/").length === 2) {
|
|
1335
1396
|
errorMessages.push(
|
|
1336
1397
|
`Unable to infer if ${instancePath} is the default app or a child app. This usually means that there is another error in the configuration.`
|
|
1337
1398
|
);
|
|
1338
|
-
} else if (
|
|
1399
|
+
} else if (error2.keyword === "anyOf" && instancePath.split("/").length > 2) {
|
|
1339
1400
|
const anyOfErrors = errors.filter(
|
|
1340
|
-
(e) => e.instancePath ===
|
|
1401
|
+
(e) => e.instancePath === error2.instancePath && e.keyword !== "anyOf"
|
|
1341
1402
|
);
|
|
1342
1403
|
if (anyOfErrors.every((e) => e.keyword === "type")) {
|
|
1343
1404
|
const allowedTypes = LIST_FORMATTER2.format(
|
|
@@ -1353,13 +1414,13 @@ function formatAjvErrors(errors) {
|
|
|
1353
1414
|
`Invalid field for ${instancePath}. Possible error messages are ${LIST_FORMATTER2.format(anyOfErrors.map((e) => e.message ?? ""))}`
|
|
1354
1415
|
);
|
|
1355
1416
|
}
|
|
1356
|
-
} else if (
|
|
1417
|
+
} else if (error2.keyword === "additionalProperties" && !(error2.params.additionalProperty === "routing" && instancePath.split("/").length === 2)) {
|
|
1357
1418
|
errorMessages.push(
|
|
1358
|
-
`Property '${
|
|
1419
|
+
`Property '${error2.params.additionalProperty}' is not allowed ${formattedInstancePath}`
|
|
1359
1420
|
);
|
|
1360
|
-
} else if (
|
|
1421
|
+
} else if (error2.keyword === "required") {
|
|
1361
1422
|
errorMessages.push(
|
|
1362
|
-
`Property '${
|
|
1423
|
+
`Property '${error2.params.missingProperty}' is required ${formattedInstancePath}`
|
|
1363
1424
|
);
|
|
1364
1425
|
}
|
|
1365
1426
|
}
|
|
@@ -1372,8 +1433,8 @@ function validateSchema(configString) {
|
|
|
1372
1433
|
const isValid = validate(parsedConfig);
|
|
1373
1434
|
if (!isValid) {
|
|
1374
1435
|
throw new MicrofrontendError(
|
|
1375
|
-
`Invalid microfrontends config:${formatAjvErrors(validate.errors).map((
|
|
1376
|
-
- ${
|
|
1436
|
+
`Invalid microfrontends config:${formatAjvErrors(validate.errors).map((error2) => `
|
|
1437
|
+
- ${error2}`).join(
|
|
1377
1438
|
""
|
|
1378
1439
|
)}
|
|
1379
1440
|
|
|
@@ -1470,7 +1531,13 @@ var MicrofrontendsServer = class {
|
|
|
1470
1531
|
filePath,
|
|
1471
1532
|
cookies
|
|
1472
1533
|
} = {}) {
|
|
1534
|
+
logger.debug("[MFE Config] Starting config inference", {
|
|
1535
|
+
appName,
|
|
1536
|
+
directory: directory || process.cwd(),
|
|
1537
|
+
filePath
|
|
1538
|
+
});
|
|
1473
1539
|
if (filePath) {
|
|
1540
|
+
logger.debug("[MFE Config] Using explicit filePath:", filePath);
|
|
1474
1541
|
return MicrofrontendsServer.fromFile({
|
|
1475
1542
|
filePath,
|
|
1476
1543
|
cookies
|
|
@@ -1478,16 +1545,25 @@ var MicrofrontendsServer = class {
|
|
|
1478
1545
|
}
|
|
1479
1546
|
try {
|
|
1480
1547
|
const packageRoot = findPackageRoot(directory);
|
|
1548
|
+
logger.debug("[MFE Config] Package root:", packageRoot);
|
|
1481
1549
|
const applicationContext = getApplicationContext({
|
|
1482
1550
|
appName,
|
|
1483
1551
|
packageRoot
|
|
1484
1552
|
});
|
|
1553
|
+
logger.debug("[MFE Config] Application context:", applicationContext);
|
|
1485
1554
|
const customConfigFilename = process.env.VC_MICROFRONTENDS_CONFIG_FILE_NAME;
|
|
1555
|
+
if (customConfigFilename) {
|
|
1556
|
+
logger.debug(
|
|
1557
|
+
"[MFE Config] Custom config filename from VC_MICROFRONTENDS_CONFIG_FILE_NAME:",
|
|
1558
|
+
customConfigFilename
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1486
1561
|
const maybeConfig = findConfig({
|
|
1487
1562
|
dir: packageRoot,
|
|
1488
1563
|
customConfigFilename
|
|
1489
1564
|
});
|
|
1490
1565
|
if (maybeConfig) {
|
|
1566
|
+
logger.debug("[MFE Config] Config found at package root:", maybeConfig);
|
|
1491
1567
|
return MicrofrontendsServer.fromFile({
|
|
1492
1568
|
filePath: maybeConfig,
|
|
1493
1569
|
cookies
|
|
@@ -1495,42 +1571,78 @@ var MicrofrontendsServer = class {
|
|
|
1495
1571
|
}
|
|
1496
1572
|
const repositoryRoot = findRepositoryRoot();
|
|
1497
1573
|
const isMonorepo2 = isMonorepo({ repositoryRoot });
|
|
1574
|
+
logger.debug(
|
|
1575
|
+
"[MFE Config] Repository root:",
|
|
1576
|
+
repositoryRoot,
|
|
1577
|
+
"Is monorepo:",
|
|
1578
|
+
isMonorepo2
|
|
1579
|
+
);
|
|
1498
1580
|
const configFromEnv = process.env.VC_MICROFRONTENDS_CONFIG;
|
|
1499
1581
|
if (typeof configFromEnv === "string") {
|
|
1582
|
+
logger.debug(
|
|
1583
|
+
"[MFE Config] Checking VC_MICROFRONTENDS_CONFIG:",
|
|
1584
|
+
configFromEnv
|
|
1585
|
+
);
|
|
1500
1586
|
const maybeConfigFromEnv = resolve(packageRoot, configFromEnv);
|
|
1501
1587
|
if (maybeConfigFromEnv) {
|
|
1588
|
+
logger.debug(
|
|
1589
|
+
"[MFE Config] Config loaded from VC_MICROFRONTENDS_CONFIG:",
|
|
1590
|
+
maybeConfigFromEnv
|
|
1591
|
+
);
|
|
1502
1592
|
return MicrofrontendsServer.fromFile({
|
|
1503
1593
|
filePath: maybeConfigFromEnv,
|
|
1504
1594
|
cookies
|
|
1505
1595
|
});
|
|
1506
1596
|
}
|
|
1507
1597
|
} else {
|
|
1598
|
+
const vercelDir = join2(packageRoot, ".vercel");
|
|
1599
|
+
logger.debug(
|
|
1600
|
+
"[MFE Config] Searching for config in .vercel directory:",
|
|
1601
|
+
vercelDir
|
|
1602
|
+
);
|
|
1508
1603
|
const maybeConfigFromVercel = findConfig({
|
|
1509
|
-
dir:
|
|
1604
|
+
dir: vercelDir,
|
|
1510
1605
|
customConfigFilename
|
|
1511
1606
|
});
|
|
1512
1607
|
if (maybeConfigFromVercel) {
|
|
1608
|
+
logger.debug(
|
|
1609
|
+
"[MFE Config] Config found in .vercel directory:",
|
|
1610
|
+
maybeConfigFromVercel
|
|
1611
|
+
);
|
|
1513
1612
|
return MicrofrontendsServer.fromFile({
|
|
1514
1613
|
filePath: maybeConfigFromVercel,
|
|
1515
1614
|
cookies
|
|
1516
1615
|
});
|
|
1517
1616
|
}
|
|
1518
1617
|
if (isMonorepo2) {
|
|
1618
|
+
logger.debug(
|
|
1619
|
+
"[MFE Config] Inferring microfrontends location in monorepo for application:",
|
|
1620
|
+
applicationContext.name
|
|
1621
|
+
);
|
|
1519
1622
|
const defaultPackage = inferMicrofrontendsLocation({
|
|
1520
1623
|
repositoryRoot,
|
|
1521
1624
|
applicationContext,
|
|
1522
1625
|
customConfigFilename
|
|
1523
1626
|
});
|
|
1627
|
+
logger.debug(
|
|
1628
|
+
"[MFE Config] Inferred package location:",
|
|
1629
|
+
defaultPackage
|
|
1630
|
+
);
|
|
1524
1631
|
const maybeConfigFromDefault = findConfig({
|
|
1525
1632
|
dir: defaultPackage,
|
|
1526
1633
|
customConfigFilename
|
|
1527
1634
|
});
|
|
1528
1635
|
if (maybeConfigFromDefault) {
|
|
1636
|
+
logger.debug(
|
|
1637
|
+
"[MFE Config] Config found in inferred package:",
|
|
1638
|
+
maybeConfigFromDefault
|
|
1639
|
+
);
|
|
1529
1640
|
return MicrofrontendsServer.fromFile({
|
|
1530
1641
|
filePath: maybeConfigFromDefault,
|
|
1531
1642
|
cookies
|
|
1532
1643
|
});
|
|
1533
1644
|
}
|
|
1645
|
+
logger.debug("[MFE Config] No config found in inferred package");
|
|
1534
1646
|
}
|
|
1535
1647
|
}
|
|
1536
1648
|
throw new MicrofrontendError(
|
|
@@ -1556,8 +1668,13 @@ var MicrofrontendsServer = class {
|
|
|
1556
1668
|
cookies
|
|
1557
1669
|
}) {
|
|
1558
1670
|
try {
|
|
1671
|
+
logger.debug("[MFE Config] Reading config from file:", filePath);
|
|
1559
1672
|
const configJson = fs6.readFileSync(filePath, "utf-8");
|
|
1560
1673
|
const config = MicrofrontendsServer.validate(configJson);
|
|
1674
|
+
logger.debug(
|
|
1675
|
+
"[MFE Config] Config loaded with applications:",
|
|
1676
|
+
Object.keys(config.applications)
|
|
1677
|
+
);
|
|
1561
1678
|
return new MicrofrontendsServer({
|
|
1562
1679
|
config,
|
|
1563
1680
|
overrides: cookies ? parseOverrides(cookies) : void 0
|
|
@@ -1658,17 +1775,10 @@ function transform3(args) {
|
|
|
1658
1775
|
};
|
|
1659
1776
|
}
|
|
1660
1777
|
|
|
1661
|
-
// src/next/utils/route-to-local-proxy.ts
|
|
1662
|
-
function routeToLocalProxy() {
|
|
1663
|
-
const isDevEnv = (process.env.VERCEL_ENV ?? "development") === "development";
|
|
1664
|
-
return isDevEnv && Boolean(process.env.TURBO_TASK_HAS_MFE_PROXY);
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
1778
|
// src/next/config/transforms/redirects.ts
|
|
1668
1779
|
function transform4(args) {
|
|
1669
|
-
const { next, microfrontend
|
|
1670
|
-
const
|
|
1671
|
-
const requireLocalProxyHeader = routeToLocalProxy() && !isProduction2 && !process.env.MFE_DISABLE_LOCAL_PROXY_REWRITE;
|
|
1780
|
+
const { next, microfrontend } = args;
|
|
1781
|
+
const requireLocalProxyHeader = localProxyIsRunning() && !process.env.MFE_DISABLE_LOCAL_PROXY_REWRITE;
|
|
1672
1782
|
if (requireLocalProxyHeader) {
|
|
1673
1783
|
const proxyRedirects = [
|
|
1674
1784
|
{
|
|
@@ -1695,17 +1805,15 @@ function transform4(args) {
|
|
|
1695
1805
|
} else {
|
|
1696
1806
|
next.redirects = async () => proxyRedirects;
|
|
1697
1807
|
}
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
`${indent}${header}
|
|
1808
|
+
const indent = " ".repeat(4);
|
|
1809
|
+
const header = "redirects";
|
|
1810
|
+
const separator = "\u23AF".repeat(header.length);
|
|
1811
|
+
logger.debug(
|
|
1812
|
+
`${indent}${header}
|
|
1704
1813
|
${indent}${separator}
|
|
1705
1814
|
${indent} - Automatically redirecting all requests to local microfrontends proxy
|
|
1706
1815
|
`
|
|
1707
|
-
|
|
1708
|
-
}
|
|
1816
|
+
);
|
|
1709
1817
|
}
|
|
1710
1818
|
return { next };
|
|
1711
1819
|
}
|
|
@@ -1726,22 +1834,18 @@ function transform5(args) {
|
|
|
1726
1834
|
|
|
1727
1835
|
// src/next/config/transforms/rewrites.ts
|
|
1728
1836
|
function debugRewrites(rewrites) {
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
return `${indent} ${idx + 1}. ${paddedSource} \u2192 ${route.destination}`;
|
|
1739
|
-
}).join("\n");
|
|
1740
|
-
console.log(`${indent}${header}
|
|
1837
|
+
const indent = " ".repeat(4);
|
|
1838
|
+
const header = "rewrites (source \u2192 destination)";
|
|
1839
|
+
const separator = "\u23AF".repeat(header.length);
|
|
1840
|
+
const maxSourceLength = Math.max(...rewrites.map((key) => key.source.length));
|
|
1841
|
+
const table = rewrites.map((route, idx) => {
|
|
1842
|
+
const paddedSource = route.source.padEnd(maxSourceLength);
|
|
1843
|
+
return `${indent} ${idx + 1}. ${paddedSource} \u2192 ${route.destination}`;
|
|
1844
|
+
}).join("\n");
|
|
1845
|
+
logger.debug(`${indent}${header}
|
|
1741
1846
|
${indent}${separator}
|
|
1742
1847
|
${table}
|
|
1743
1848
|
`);
|
|
1744
|
-
}
|
|
1745
1849
|
}
|
|
1746
1850
|
function rewritesMapToArr(rewrites) {
|
|
1747
1851
|
return Array.from(rewrites.entries()).flatMap(([source, rewrite]) => {
|
|
@@ -1939,20 +2043,18 @@ var transforms = {
|
|
|
1939
2043
|
|
|
1940
2044
|
// src/next/config/env.ts
|
|
1941
2045
|
function debugEnv(env) {
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
const
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
console.log(`${indent}${header}
|
|
2046
|
+
const indent = " ".repeat(4);
|
|
2047
|
+
const header = "env (key \u2192 val)";
|
|
2048
|
+
const separator = "\u23AF".repeat(header.length);
|
|
2049
|
+
const maxKeyLength = Math.max(...Object.keys(env).map((key) => key.length));
|
|
2050
|
+
const table = Object.keys(env).map((key, idx) => {
|
|
2051
|
+
const paddedKey = key.padEnd(maxKeyLength);
|
|
2052
|
+
return `${indent} ${idx + 1}. ${paddedKey} = ${env[key]}`;
|
|
2053
|
+
}).join("\n");
|
|
2054
|
+
logger.debug(`${indent}${header}
|
|
1952
2055
|
${indent}${separator}
|
|
1953
2056
|
${table}
|
|
1954
2057
|
`);
|
|
1955
|
-
}
|
|
1956
2058
|
}
|
|
1957
2059
|
function setEnvironment({
|
|
1958
2060
|
app,
|
|
@@ -1988,12 +2090,6 @@ function setEnvironment({
|
|
|
1988
2090
|
function typedEntries(obj) {
|
|
1989
2091
|
return Object.entries(obj);
|
|
1990
2092
|
}
|
|
1991
|
-
function isProduction(opts) {
|
|
1992
|
-
if (opts?.isProduction) {
|
|
1993
|
-
return opts.isProduction();
|
|
1994
|
-
}
|
|
1995
|
-
return process.env.VERCEL_ENV === "production";
|
|
1996
|
-
}
|
|
1997
2093
|
function withMicrofrontends(nextConfig, opts) {
|
|
1998
2094
|
if (opts?.debug) {
|
|
1999
2095
|
process.env.MFE_DEBUG = "true";
|
|
@@ -2008,7 +2104,7 @@ function withMicrofrontends(nextConfig, opts) {
|
|
|
2008
2104
|
let next = { ...nextConfig };
|
|
2009
2105
|
for (const [key, transform8] of typedEntries(transforms)) {
|
|
2010
2106
|
if (opts?.skipTransforms?.includes(key)) {
|
|
2011
|
-
|
|
2107
|
+
logger.info(`Skipping ${key} transform`);
|
|
2012
2108
|
continue;
|
|
2013
2109
|
}
|
|
2014
2110
|
try {
|
|
@@ -2017,13 +2113,12 @@ function withMicrofrontends(nextConfig, opts) {
|
|
|
2017
2113
|
next,
|
|
2018
2114
|
microfrontend: microfrontends.config,
|
|
2019
2115
|
opts: {
|
|
2020
|
-
isProduction: isProduction(opts),
|
|
2021
2116
|
supportPagesRouter: opts?.supportPagesRouter
|
|
2022
2117
|
}
|
|
2023
2118
|
});
|
|
2024
2119
|
next = transformedConfig.next;
|
|
2025
2120
|
} catch (e) {
|
|
2026
|
-
|
|
2121
|
+
logger.error("Error transforming next config", e);
|
|
2027
2122
|
throw e;
|
|
2028
2123
|
}
|
|
2029
2124
|
}
|