@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.
Files changed (48) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +4 -0
  3. package/dist/bin/cli.cjs +207 -90
  4. package/dist/config.d.ts +2 -2
  5. package/dist/experimental/sveltekit.cjs +180 -63
  6. package/dist/experimental/sveltekit.cjs.map +1 -1
  7. package/dist/experimental/sveltekit.d.ts +6 -0
  8. package/dist/experimental/sveltekit.js +180 -63
  9. package/dist/experimental/sveltekit.js.map +1 -1
  10. package/dist/experimental/vite.cjs +177 -66
  11. package/dist/experimental/vite.cjs.map +1 -1
  12. package/dist/experimental/vite.js +177 -66
  13. package/dist/experimental/vite.js.map +1 -1
  14. package/dist/microfrontends/server.cjs +173 -60
  15. package/dist/microfrontends/server.cjs.map +1 -1
  16. package/dist/microfrontends/server.d.ts +2 -2
  17. package/dist/microfrontends/server.js +173 -60
  18. package/dist/microfrontends/server.js.map +1 -1
  19. package/dist/microfrontends/utils.cjs +50 -7
  20. package/dist/microfrontends/utils.cjs.map +1 -1
  21. package/dist/microfrontends/utils.d.ts +1 -1
  22. package/dist/microfrontends/utils.js +50 -7
  23. package/dist/microfrontends/utils.js.map +1 -1
  24. package/dist/next/config.cjs +208 -113
  25. package/dist/next/config.cjs.map +1 -1
  26. package/dist/next/config.d.ts +11 -1
  27. package/dist/next/config.js +208 -113
  28. package/dist/next/config.js.map +1 -1
  29. package/dist/next/middleware.cjs +35 -17
  30. package/dist/next/middleware.cjs.map +1 -1
  31. package/dist/next/middleware.js +35 -17
  32. package/dist/next/middleware.js.map +1 -1
  33. package/dist/next/testing.d.ts +2 -2
  34. package/dist/overrides.d.ts +3 -3
  35. package/dist/schema.d.ts +2 -2
  36. package/dist/{types-88602303.d.ts → types-b9ea41b2.d.ts} +1 -1
  37. package/dist/{types-e7523e61.d.ts → types-dcd8b17a.d.ts} +71 -24
  38. package/dist/utils/mfe-port.cjs +173 -60
  39. package/dist/utils/mfe-port.cjs.map +1 -1
  40. package/dist/utils/mfe-port.js +173 -60
  41. package/dist/utils/mfe-port.js.map +1 -1
  42. package/dist/validation.cjs +47 -38
  43. package/dist/validation.cjs.map +1 -1
  44. package/dist/validation.d.ts +1 -1
  45. package/dist/validation.js +47 -38
  46. package/dist/validation.js.map +1 -1
  47. package/package.json +1 -1
  48. package/schema/schema.json +47 -38
package/dist/bin/cli.cjs CHANGED
@@ -30,7 +30,7 @@ var import_env = require("@next/env");
30
30
  // package.json
31
31
  var package_default = {
32
32
  name: "@vercel/microfrontends",
33
- version: "2.1.3",
33
+ version: "2.2.1",
34
34
  private: false,
35
35
  description: "Defines configuration and utilities for microfrontends development",
36
36
  keywords: [
@@ -1117,10 +1117,32 @@ var import_node_fs2 = require("fs");
1117
1117
  var import_jsonc_parser2 = require("jsonc-parser");
1118
1118
  var import_fast_glob = __toESM(require("fast-glob"), 1);
1119
1119
 
1120
+ // src/bin/logger.ts
1121
+ function debug(...args) {
1122
+ if (process.env.MFE_DEBUG) {
1123
+ console.log(...args);
1124
+ }
1125
+ }
1126
+ function info(...args) {
1127
+ console.log(...args);
1128
+ }
1129
+ function warn(...args) {
1130
+ console.warn(...args);
1131
+ }
1132
+ function error(...args) {
1133
+ console.error(...args);
1134
+ }
1135
+ var logger = {
1136
+ debug,
1137
+ info,
1138
+ warn,
1139
+ error
1140
+ };
1141
+
1120
1142
  // src/config/microfrontends/utils/get-config-file-name.ts
1121
1143
  var DEFAULT_CONFIGURATION_FILENAMES = [
1122
- "microfrontends.jsonc",
1123
- "microfrontends.json"
1144
+ "microfrontends.json",
1145
+ "microfrontends.jsonc"
1124
1146
  ];
1125
1147
  function getPossibleConfigurationFilenames({
1126
1148
  customConfigFilename
@@ -1128,7 +1150,7 @@ function getPossibleConfigurationFilenames({
1128
1150
  if (customConfigFilename) {
1129
1151
  if (!customConfigFilename.endsWith(".json") && !customConfigFilename.endsWith(".jsonc")) {
1130
1152
  throw new Error(
1131
- `The VC_MICROFRONTENDS_CONFIG_FILE_NAME environment variable must end with '.json' or '.jsonc'. Received: ${customConfigFilename}`
1153
+ `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.`
1132
1154
  );
1133
1155
  }
1134
1156
  return Array.from(
@@ -1146,6 +1168,10 @@ function findPackageWithMicrofrontendsConfig({
1146
1168
  customConfigFilename
1147
1169
  }) {
1148
1170
  const applicationName = applicationContext.name;
1171
+ logger.debug(
1172
+ "[MFE Config] Searching repository for configs containing application:",
1173
+ applicationName
1174
+ );
1149
1175
  try {
1150
1176
  const microfrontendsJsonPaths = import_fast_glob.default.globSync(
1151
1177
  `**/{${getPossibleConfigurationFilenames({ customConfigFilename }).join(",")}}`,
@@ -1157,6 +1183,11 @@ function findPackageWithMicrofrontendsConfig({
1157
1183
  ignore: ["**/node_modules/**", "**/.git/**"]
1158
1184
  }
1159
1185
  );
1186
+ logger.debug(
1187
+ "[MFE Config] Found",
1188
+ microfrontendsJsonPaths.length,
1189
+ "config file(s) in repository"
1190
+ );
1160
1191
  const matchingPaths = [];
1161
1192
  for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
1162
1193
  try {
@@ -1166,19 +1197,31 @@ function findPackageWithMicrofrontendsConfig({
1166
1197
  );
1167
1198
  const microfrontendsJson = (0, import_jsonc_parser2.parse)(microfrontendsJsonContent);
1168
1199
  if (microfrontendsJson.applications[applicationName]) {
1200
+ logger.debug(
1201
+ "[MFE Config] Found application in config:",
1202
+ microfrontendsJsonPath
1203
+ );
1169
1204
  matchingPaths.push(microfrontendsJsonPath);
1170
1205
  } else {
1171
1206
  for (const [_, app] of Object.entries(
1172
1207
  microfrontendsJson.applications
1173
1208
  )) {
1174
1209
  if (app.packageName === applicationName) {
1210
+ logger.debug(
1211
+ "[MFE Config] Found application via packageName in config:",
1212
+ microfrontendsJsonPath
1213
+ );
1175
1214
  matchingPaths.push(microfrontendsJsonPath);
1176
1215
  }
1177
1216
  }
1178
1217
  }
1179
- } catch (error) {
1218
+ } catch (error2) {
1180
1219
  }
1181
1220
  }
1221
+ logger.debug(
1222
+ "[MFE Config] Total matching config files:",
1223
+ matchingPaths.length
1224
+ );
1182
1225
  if (matchingPaths.length > 1) {
1183
1226
  throw new MicrofrontendError(
1184
1227
  `Found multiple \`microfrontends.json\` files in the repository referencing the application "${applicationName}", but only one is allowed.
@@ -1212,9 +1255,9 @@ If you suspect this is thrown in error, please reach out to the Vercel team.`,
1212
1255
  }
1213
1256
  const [packageJsonPath] = matchingPaths;
1214
1257
  return (0, import_node_path2.dirname)(packageJsonPath);
1215
- } catch (error) {
1216
- if (error instanceof MicrofrontendError) {
1217
- throw error;
1258
+ } catch (error2) {
1259
+ if (error2 instanceof MicrofrontendError) {
1260
+ throw error2;
1218
1261
  }
1219
1262
  return null;
1220
1263
  }
@@ -1259,8 +1302,8 @@ function isMonorepo({
1259
1302
  import_node_fs3.default.readFileSync(packageJsonPath, "utf-8")
1260
1303
  );
1261
1304
  return packageJson.workspaces !== void 0;
1262
- } catch (error) {
1263
- console.error("Error determining if repository is a monorepo", error);
1305
+ } catch (error2) {
1306
+ logger.error("Error determining if repository is a monorepo", error2);
1264
1307
  return false;
1265
1308
  }
1266
1309
  }
@@ -1306,15 +1349,18 @@ var import_node_fs6 = __toESM(require("fs"), 1);
1306
1349
  var import_node_path6 = __toESM(require("path"), 1);
1307
1350
  function getApplicationContext(opts) {
1308
1351
  if (opts?.appName) {
1352
+ logger.debug("[MFE Config] Application name from appName parameter:", opts.appName);
1309
1353
  return { name: opts.appName };
1310
1354
  }
1311
1355
  if (process.env.VERCEL_PROJECT_NAME) {
1356
+ logger.debug("[MFE Config] Application name from VERCEL_PROJECT_NAME:", process.env.VERCEL_PROJECT_NAME);
1312
1357
  return {
1313
1358
  name: process.env.VERCEL_PROJECT_NAME,
1314
1359
  projectName: process.env.VERCEL_PROJECT_NAME
1315
1360
  };
1316
1361
  }
1317
1362
  if (process.env.NX_TASK_TARGET_PROJECT) {
1363
+ logger.debug("[MFE Config] Application name from NX_TASK_TARGET_PROJECT:", process.env.NX_TASK_TARGET_PROJECT);
1318
1364
  return {
1319
1365
  name: process.env.NX_TASK_TARGET_PROJECT,
1320
1366
  packageJsonName: process.env.NX_TASK_TARGET_PROJECT
@@ -1327,6 +1373,7 @@ function getApplicationContext(opts) {
1327
1373
  );
1328
1374
  const projectJson = JSON.parse(vercelProjectJsonPath);
1329
1375
  if (projectJson.projectName) {
1376
+ logger.debug("[MFE Config] Application name from .vercel/project.json:", projectJson.projectName);
1330
1377
  return {
1331
1378
  name: projectJson.projectName,
1332
1379
  projectName: projectJson.projectName
@@ -1350,6 +1397,7 @@ function getApplicationContext(opts) {
1350
1397
  }
1351
1398
  );
1352
1399
  }
1400
+ logger.debug("[MFE Config] Application name from package.json:", packageJson.name);
1353
1401
  return { name: packageJson.name, packageJsonName: packageJson.name };
1354
1402
  } catch (err) {
1355
1403
  throw MicrofrontendError.handle(err, {
@@ -1383,38 +1431,28 @@ var schema_default = {
1383
1431
  type: "object",
1384
1432
  properties: {
1385
1433
  $schema: {
1386
- type: "string"
1434
+ type: "string",
1435
+ description: "See https://openapi.vercel.sh/microfrontends.json."
1387
1436
  },
1388
1437
  version: {
1389
1438
  type: "string",
1390
- const: "1"
1391
- },
1392
- options: {
1393
- $ref: "#/definitions/Options"
1439
+ const: "1",
1440
+ description: "The version of the microfrontends config schema."
1394
1441
  },
1395
1442
  applications: {
1396
1443
  $ref: "#/definitions/ApplicationRouting",
1397
- description: "Mapping of application names to the routes that they host. Only needs to be defined in the application that owns the primary microfrontend domain"
1444
+ description: "Mapping of Vercel project names to their microfrontend configurations."
1445
+ },
1446
+ options: {
1447
+ $ref: "#/definitions/Options",
1448
+ description: "Optional configuration options for the microfrontend."
1398
1449
  }
1399
1450
  },
1400
1451
  required: [
1401
1452
  "applications"
1402
1453
  ],
1403
- additionalProperties: false
1404
- },
1405
- Options: {
1406
- type: "object",
1407
- properties: {
1408
- disableOverrides: {
1409
- type: "boolean",
1410
- 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."
1411
- },
1412
- localProxyPort: {
1413
- type: "number",
1414
- description: "The port number used by the local proxy server.\n\nThe default is `3024`."
1415
- }
1416
- },
1417
- additionalProperties: false
1454
+ additionalProperties: false,
1455
+ description: "The microfrontends configuration schema. See https://vercel.com/docs/microfrontends/configuration."
1418
1456
  },
1419
1457
  ApplicationRouting: {
1420
1458
  type: "object",
@@ -1422,8 +1460,9 @@ var schema_default = {
1422
1460
  $ref: "#/definitions/Application"
1423
1461
  },
1424
1462
  propertyNames: {
1425
- description: "The unique identifier for a Microfrontend Application.\n\nMust match the Vercel project name.\n\nNote: If this name does not also match the name used to run the application, (e.g. the `name` from the `package.json`), then the `packageName` field should be set."
1426
- }
1463
+ 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."
1464
+ },
1465
+ description: "Mapping of Vercel project names to their microfrontend configurations."
1427
1466
  },
1428
1467
  Application: {
1429
1468
  anyOf: [
@@ -1433,14 +1472,15 @@ var schema_default = {
1433
1472
  {
1434
1473
  $ref: "#/definitions/ChildApplication"
1435
1474
  }
1436
- ]
1475
+ ],
1476
+ description: "The configuration for a microfrontend application. There must always be one default application."
1437
1477
  },
1438
1478
  DefaultApplication: {
1439
1479
  type: "object",
1440
1480
  properties: {
1441
1481
  packageName: {
1442
1482
  type: "string",
1443
- 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`."
1483
+ 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."
1444
1484
  },
1445
1485
  development: {
1446
1486
  $ref: "#/definitions/DefaultDevelopment",
@@ -1460,15 +1500,15 @@ var schema_default = {
1460
1500
  "number",
1461
1501
  "string"
1462
1502
  ],
1463
- description: "A local port number or host string that this application runs on when it is running locally. If passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTP. If omitted, the port defaults to a unique, but stable (based on the application name) number.\n\nExamples of valid values:\n- 8080\n- my.localhost.me\n- my.localhost.me:8080\n- https://my.localhost.me\n- https://my.localhost.me:8080"
1503
+ 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."
1464
1504
  },
1465
1505
  task: {
1466
1506
  type: "string",
1467
- description: "Optional task to run when starting the development server. Should reference a script in the package.json of the application."
1507
+ 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.'
1468
1508
  },
1469
1509
  fallback: {
1470
1510
  type: "string",
1471
- 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."
1511
+ 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."
1472
1512
  }
1473
1513
  },
1474
1514
  required: [
@@ -1481,7 +1521,7 @@ var schema_default = {
1481
1521
  properties: {
1482
1522
  packageName: {
1483
1523
  type: "string",
1484
- 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`."
1524
+ 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."
1485
1525
  },
1486
1526
  development: {
1487
1527
  $ref: "#/definitions/ChildDevelopment",
@@ -1489,11 +1529,11 @@ var schema_default = {
1489
1529
  },
1490
1530
  routing: {
1491
1531
  $ref: "#/definitions/Routing",
1492
- description: "Groups of path expressions that are routed to this application."
1532
+ description: "Groups of path expressions that are routed to this application.\n\nSee https://vercel.com/docs/microfrontends/path-routing."
1493
1533
  },
1494
1534
  assetPrefix: {
1495
1535
  type: "string",
1496
- 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."
1536
+ 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."
1497
1537
  }
1498
1538
  },
1499
1539
  required: [
@@ -1509,15 +1549,15 @@ var schema_default = {
1509
1549
  "number",
1510
1550
  "string"
1511
1551
  ],
1512
- description: "A local port number or host string that this application runs on when it is running locally. If passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTP. If omitted, the port defaults to a unique, but stable (based on the application name) number.\n\nExamples of valid values:\n- 8080\n- my.localhost.me\n- my.localhost.me:8080\n- https://my.localhost.me\n- https://my.localhost.me:8080"
1552
+ 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."
1513
1553
  },
1514
1554
  task: {
1515
1555
  type: "string",
1516
- description: "Optional task to run when starting the development server. Should reference a script in the package.json of the application."
1556
+ 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.'
1517
1557
  },
1518
1558
  fallback: {
1519
1559
  type: "string",
1520
- description: "Fallback for local development, could point to any environment. This is optional for child apps. If not provided, 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."
1560
+ 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."
1521
1561
  }
1522
1562
  },
1523
1563
  additionalProperties: false
@@ -1526,29 +1566,46 @@ var schema_default = {
1526
1566
  type: "array",
1527
1567
  items: {
1528
1568
  $ref: "#/definitions/PathGroup"
1529
- }
1569
+ },
1570
+ description: "A list of path groups that are routed to this application."
1530
1571
  },
1531
1572
  PathGroup: {
1532
1573
  type: "object",
1533
1574
  properties: {
1534
1575
  group: {
1535
1576
  type: "string",
1536
- description: "Optional group name for the paths"
1577
+ description: "Group name for the paths."
1537
1578
  },
1538
1579
  flag: {
1539
1580
  type: "string",
1540
- description: "flag name that can be used to enable/disable all paths in the group"
1581
+ 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."
1541
1582
  },
1542
1583
  paths: {
1543
1584
  type: "array",
1544
1585
  items: {
1545
1586
  type: "string"
1546
- }
1587
+ },
1588
+ description: "A list of path expressions that are routed to this application. See https://vercel.com/docs/microfrontends/path-routing#supported-path-expressions."
1547
1589
  }
1548
1590
  },
1549
1591
  required: [
1550
1592
  "paths"
1551
1593
  ],
1594
+ additionalProperties: false,
1595
+ description: "A group of paths that is routed to this application."
1596
+ },
1597
+ Options: {
1598
+ type: "object",
1599
+ properties: {
1600
+ disableOverrides: {
1601
+ type: "boolean",
1602
+ 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."
1603
+ },
1604
+ localProxyPort: {
1605
+ type: "number",
1606
+ 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."
1607
+ }
1608
+ },
1552
1609
  additionalProperties: false
1553
1610
  }
1554
1611
  }
@@ -1567,19 +1624,19 @@ function formatAjvErrors(errors) {
1567
1624
  return [];
1568
1625
  }
1569
1626
  const errorMessages = [];
1570
- for (const error of errors) {
1571
- if (error.instancePath === "" && (error.keyword === "anyOf" || error.keyword === "required" && error.params.missingProperty === "partOf")) {
1627
+ for (const error2 of errors) {
1628
+ if (error2.instancePath === "" && (error2.keyword === "anyOf" || error2.keyword === "required" && error2.params.missingProperty === "partOf")) {
1572
1629
  continue;
1573
1630
  }
1574
- const instancePath = error.instancePath.slice(1);
1631
+ const instancePath = error2.instancePath.slice(1);
1575
1632
  const formattedInstancePath = instancePath === "" ? "at the root" : `in field ${instancePath}`;
1576
- if (error.keyword === "required" && error.params.missingProperty === "routing" && instancePath.split("/").length === 2) {
1633
+ if (error2.keyword === "required" && error2.params.missingProperty === "routing" && instancePath.split("/").length === 2) {
1577
1634
  errorMessages.push(
1578
1635
  `Unable to infer if ${instancePath} is the default app or a child app. This usually means that there is another error in the configuration.`
1579
1636
  );
1580
- } else if (error.keyword === "anyOf" && instancePath.split("/").length > 2) {
1637
+ } else if (error2.keyword === "anyOf" && instancePath.split("/").length > 2) {
1581
1638
  const anyOfErrors = errors.filter(
1582
- (e) => e.instancePath === error.instancePath && e.keyword !== "anyOf"
1639
+ (e) => e.instancePath === error2.instancePath && e.keyword !== "anyOf"
1583
1640
  );
1584
1641
  if (anyOfErrors.every((e) => e.keyword === "type")) {
1585
1642
  const allowedTypes = LIST_FORMATTER2.format(
@@ -1595,13 +1652,13 @@ function formatAjvErrors(errors) {
1595
1652
  `Invalid field for ${instancePath}. Possible error messages are ${LIST_FORMATTER2.format(anyOfErrors.map((e) => e.message ?? ""))}`
1596
1653
  );
1597
1654
  }
1598
- } else if (error.keyword === "additionalProperties" && !(error.params.additionalProperty === "routing" && instancePath.split("/").length === 2)) {
1655
+ } else if (error2.keyword === "additionalProperties" && !(error2.params.additionalProperty === "routing" && instancePath.split("/").length === 2)) {
1599
1656
  errorMessages.push(
1600
- `Property '${error.params.additionalProperty}' is not allowed ${formattedInstancePath}`
1657
+ `Property '${error2.params.additionalProperty}' is not allowed ${formattedInstancePath}`
1601
1658
  );
1602
- } else if (error.keyword === "required") {
1659
+ } else if (error2.keyword === "required") {
1603
1660
  errorMessages.push(
1604
- `Property '${error.params.missingProperty}' is required ${formattedInstancePath}`
1661
+ `Property '${error2.params.missingProperty}' is required ${formattedInstancePath}`
1605
1662
  );
1606
1663
  }
1607
1664
  }
@@ -1614,8 +1671,8 @@ function validateSchema(configString) {
1614
1671
  const isValid = validate(parsedConfig);
1615
1672
  if (!isValid) {
1616
1673
  throw new MicrofrontendError(
1617
- `Invalid microfrontends config:${formatAjvErrors(validate.errors).map((error) => `
1618
- - ${error}`).join(
1674
+ `Invalid microfrontends config:${formatAjvErrors(validate.errors).map((error2) => `
1675
+ - ${error2}`).join(
1619
1676
  ""
1620
1677
  )}
1621
1678
 
@@ -1712,7 +1769,13 @@ var MicrofrontendsServer = class {
1712
1769
  filePath,
1713
1770
  cookies
1714
1771
  } = {}) {
1772
+ logger.debug("[MFE Config] Starting config inference", {
1773
+ appName,
1774
+ directory: directory || process.cwd(),
1775
+ filePath
1776
+ });
1715
1777
  if (filePath) {
1778
+ logger.debug("[MFE Config] Using explicit filePath:", filePath);
1716
1779
  return MicrofrontendsServer.fromFile({
1717
1780
  filePath,
1718
1781
  cookies
@@ -1720,16 +1783,25 @@ var MicrofrontendsServer = class {
1720
1783
  }
1721
1784
  try {
1722
1785
  const packageRoot = findPackageRoot(directory);
1786
+ logger.debug("[MFE Config] Package root:", packageRoot);
1723
1787
  const applicationContext = getApplicationContext({
1724
1788
  appName,
1725
1789
  packageRoot
1726
1790
  });
1791
+ logger.debug("[MFE Config] Application context:", applicationContext);
1727
1792
  const customConfigFilename = process.env.VC_MICROFRONTENDS_CONFIG_FILE_NAME;
1793
+ if (customConfigFilename) {
1794
+ logger.debug(
1795
+ "[MFE Config] Custom config filename from VC_MICROFRONTENDS_CONFIG_FILE_NAME:",
1796
+ customConfigFilename
1797
+ );
1798
+ }
1728
1799
  const maybeConfig = findConfig({
1729
1800
  dir: packageRoot,
1730
1801
  customConfigFilename
1731
1802
  });
1732
1803
  if (maybeConfig) {
1804
+ logger.debug("[MFE Config] Config found at package root:", maybeConfig);
1733
1805
  return MicrofrontendsServer.fromFile({
1734
1806
  filePath: maybeConfig,
1735
1807
  cookies
@@ -1737,42 +1809,78 @@ var MicrofrontendsServer = class {
1737
1809
  }
1738
1810
  const repositoryRoot = findRepositoryRoot();
1739
1811
  const isMonorepo2 = isMonorepo({ repositoryRoot });
1812
+ logger.debug(
1813
+ "[MFE Config] Repository root:",
1814
+ repositoryRoot,
1815
+ "Is monorepo:",
1816
+ isMonorepo2
1817
+ );
1740
1818
  const configFromEnv = process.env.VC_MICROFRONTENDS_CONFIG;
1741
1819
  if (typeof configFromEnv === "string") {
1820
+ logger.debug(
1821
+ "[MFE Config] Checking VC_MICROFRONTENDS_CONFIG:",
1822
+ configFromEnv
1823
+ );
1742
1824
  const maybeConfigFromEnv = (0, import_node_path8.resolve)(packageRoot, configFromEnv);
1743
1825
  if (maybeConfigFromEnv) {
1826
+ logger.debug(
1827
+ "[MFE Config] Config loaded from VC_MICROFRONTENDS_CONFIG:",
1828
+ maybeConfigFromEnv
1829
+ );
1744
1830
  return MicrofrontendsServer.fromFile({
1745
1831
  filePath: maybeConfigFromEnv,
1746
1832
  cookies
1747
1833
  });
1748
1834
  }
1749
1835
  } else {
1836
+ const vercelDir = (0, import_node_path8.join)(packageRoot, ".vercel");
1837
+ logger.debug(
1838
+ "[MFE Config] Searching for config in .vercel directory:",
1839
+ vercelDir
1840
+ );
1750
1841
  const maybeConfigFromVercel = findConfig({
1751
- dir: (0, import_node_path8.join)(packageRoot, ".vercel"),
1842
+ dir: vercelDir,
1752
1843
  customConfigFilename
1753
1844
  });
1754
1845
  if (maybeConfigFromVercel) {
1846
+ logger.debug(
1847
+ "[MFE Config] Config found in .vercel directory:",
1848
+ maybeConfigFromVercel
1849
+ );
1755
1850
  return MicrofrontendsServer.fromFile({
1756
1851
  filePath: maybeConfigFromVercel,
1757
1852
  cookies
1758
1853
  });
1759
1854
  }
1760
1855
  if (isMonorepo2) {
1856
+ logger.debug(
1857
+ "[MFE Config] Inferring microfrontends location in monorepo for application:",
1858
+ applicationContext.name
1859
+ );
1761
1860
  const defaultPackage = inferMicrofrontendsLocation({
1762
1861
  repositoryRoot,
1763
1862
  applicationContext,
1764
1863
  customConfigFilename
1765
1864
  });
1865
+ logger.debug(
1866
+ "[MFE Config] Inferred package location:",
1867
+ defaultPackage
1868
+ );
1766
1869
  const maybeConfigFromDefault = findConfig({
1767
1870
  dir: defaultPackage,
1768
1871
  customConfigFilename
1769
1872
  });
1770
1873
  if (maybeConfigFromDefault) {
1874
+ logger.debug(
1875
+ "[MFE Config] Config found in inferred package:",
1876
+ maybeConfigFromDefault
1877
+ );
1771
1878
  return MicrofrontendsServer.fromFile({
1772
1879
  filePath: maybeConfigFromDefault,
1773
1880
  cookies
1774
1881
  });
1775
1882
  }
1883
+ logger.debug("[MFE Config] No config found in inferred package");
1776
1884
  }
1777
1885
  }
1778
1886
  throw new MicrofrontendError(
@@ -1798,8 +1906,13 @@ var MicrofrontendsServer = class {
1798
1906
  cookies
1799
1907
  }) {
1800
1908
  try {
1909
+ logger.debug("[MFE Config] Reading config from file:", filePath);
1801
1910
  const configJson = import_node_fs7.default.readFileSync(filePath, "utf-8");
1802
1911
  const config = MicrofrontendsServer.validate(configJson);
1912
+ logger.debug(
1913
+ "[MFE Config] Config loaded with applications:",
1914
+ Object.keys(config.applications)
1915
+ );
1803
1916
  return new MicrofrontendsServer({
1804
1917
  config,
1805
1918
  overrides: cookies ? parseOverrides(cookies) : void 0
@@ -2293,7 +2406,7 @@ var ProxyRequestRouter = class {
2293
2406
  if (target)
2294
2407
  return target;
2295
2408
  const defaultHost = this.getDefaultHost(config);
2296
- console.log(
2409
+ logger.debug(
2297
2410
  ` ${path7} - Did not match any routes. Routing to default app: ${formatProxyTarget(defaultHost)}`
2298
2411
  );
2299
2412
  return { path: path7, ...defaultHost };
@@ -2310,7 +2423,7 @@ var ProxyRequestRouter = class {
2310
2423
  const target = this.getApplicationTarget(application);
2311
2424
  if (middlewareMfeZone) {
2312
2425
  if (middlewareMfeZone === application.name) {
2313
- console.log(
2426
+ logger.debug(
2314
2427
  ` ${path7} - Routing to ${formatProxyTarget(target)} according to 'x-vercel-mfe-zone' header`
2315
2428
  );
2316
2429
  return { path: path7, ...target };
@@ -2335,19 +2448,19 @@ var ProxyRequestRouter = class {
2335
2448
  } else if (mfeFlagValue === false) {
2336
2449
  continue;
2337
2450
  } else {
2338
- console.log(
2451
+ logger.debug(
2339
2452
  "Routing group is behind flag. Routing to default app to check flag via middleware."
2340
2453
  );
2341
2454
  if (!this.isDefaultAppLocal()) {
2342
2455
  const defaultApp = this.getDefaultHost(this.config);
2343
- console.error(
2456
+ logger.error(
2344
2457
  `'${path7}' is a flagged path, but the default application is not running locally. Using '${defaultApp.hostname}' to handle this request.`
2345
2458
  );
2346
2459
  }
2347
2460
  return null;
2348
2461
  }
2349
2462
  }
2350
- console.log(
2463
+ logger.debug(
2351
2464
  ` ${path7} - Matched ${childPath}. Routing to ${formatProxyTarget(target)}`
2352
2465
  );
2353
2466
  return { path: path7, ...target };
@@ -2356,7 +2469,7 @@ var ProxyRequestRouter = class {
2356
2469
  }
2357
2470
  }
2358
2471
  if (middlewareMfeZone) {
2359
- console.error(
2472
+ logger.error(
2360
2473
  `A request contained 'x-vercel-mfe-zone: ${middlewareMfeZone}', but no application was found with that name.`
2361
2474
  );
2362
2475
  }
@@ -2378,7 +2491,7 @@ var ProxyRequestRouter = class {
2378
2491
  for (const rewrite of rewrites) {
2379
2492
  for (const assetPrefix of assetPrefixes) {
2380
2493
  if ((0, import_path_to_regexp3.pathToRegexp)(`/${assetPrefix}${rewrite}`).test(pathname)) {
2381
- console.log(
2494
+ logger.debug(
2382
2495
  ` ${pathname} - Matched asset prefix. Routing to ${formatProxyTarget(target)}`
2383
2496
  );
2384
2497
  return {
@@ -2410,7 +2523,7 @@ var ProxyRequestRouter = class {
2410
2523
  if (!refererApp) {
2411
2524
  return null;
2412
2525
  }
2413
- console.log(
2526
+ logger.debug(
2414
2527
  ` ${refererURL.pathname} - Routing nextjs stack frame request to ${formatProxyTarget(refererApp)}`
2415
2528
  );
2416
2529
  return {
@@ -2425,13 +2538,13 @@ var ProxyRequestRouter = class {
2425
2538
  }
2426
2539
  const localApp = this.getArbitraryLocalApp();
2427
2540
  if (!localApp) {
2428
- console.error(
2541
+ logger.error(
2429
2542
  ` ${url.pathname} - No locally running application to route request to`
2430
2543
  );
2431
2544
  return null;
2432
2545
  }
2433
2546
  const target = this.getApplicationTarget(localApp);
2434
- console.log(
2547
+ logger.debug(
2435
2548
  ` ${url.pathname} - Routing nextjs source map request to randomly selected local application: ${formatProxyTarget(target)}`
2436
2549
  );
2437
2550
  return {
@@ -2449,7 +2562,7 @@ var ProxyRequestRouter = class {
2449
2562
  }
2450
2563
  const imageUrl = url.searchParams.get("url");
2451
2564
  if (!imageUrl) {
2452
- console.error(
2565
+ logger.error(
2453
2566
  ` ${url.pathname}?${url.search} - No url parameter found in _next/image request`
2454
2567
  );
2455
2568
  return null;
@@ -2464,7 +2577,7 @@ var ProxyRequestRouter = class {
2464
2577
  if (!imageApp) {
2465
2578
  return null;
2466
2579
  }
2467
- console.log(
2580
+ logger.debug(
2468
2581
  ` ${url.pathname}?${url.search} - Routing nextjs image request to ${formatProxyTarget(imageApp)}`
2469
2582
  );
2470
2583
  return {
@@ -2509,7 +2622,7 @@ var LocalProxy = class {
2509
2622
  res.end(
2510
2623
  `Error proxying request to ${formatProxyTarget(target)}. Is the server running locally on port ${target.port}?`
2511
2624
  );
2512
- console.error(
2625
+ logger.error(
2513
2626
  `Error proxying request for ${formatProxyTarget(target)}: `,
2514
2627
  err
2515
2628
  );
@@ -2565,7 +2678,7 @@ var LocalProxy = class {
2565
2678
  headers
2566
2679
  });
2567
2680
  } catch (err) {
2568
- console.error("Error proxying ws: ", err);
2681
+ logger.error("Error proxying ws: ", err);
2569
2682
  }
2570
2683
  });
2571
2684
  httpServer.listen(this.proxyPort, () => {
@@ -2662,7 +2775,7 @@ var LocalProxy = class {
2662
2775
  });
2663
2776
  req.pipe(proxyReq);
2664
2777
  proxyReq.on("error", (err) => {
2665
- console.error("Proxy request error: ", err);
2778
+ logger.error("Proxy request error: ", err);
2666
2779
  res.writeHead(500, { "Content-Type": "text/plain" });
2667
2780
  res.end(
2668
2781
  `Error proxying request for ${target.application} to ${hostname}:${port}${path7}`
@@ -2735,49 +2848,52 @@ var LocalProxy = class {
2735
2848
  });
2736
2849
  }
2737
2850
  }
2738
- console.log(`
2851
+ logger.info(`
2739
2852
  \u25B2 Microfrontends Proxy (${package_default.version}) Started`);
2740
- console.log(` - Proxy URL: http://localhost:${this.proxyPort}`);
2853
+ logger.info(` - Proxy URL: http://localhost:${this.proxyPort}`);
2741
2854
  if (this.configFilePath) {
2742
- console.log(` - Config: ${this.configFilePath}`);
2855
+ logger.info(` - Config: ${this.configFilePath}`);
2743
2856
  }
2744
2857
  if (localApps.length > 0) {
2745
- console.log(" - Local Applications:");
2858
+ logger.info(" - Local Applications:");
2746
2859
  const displayLocalApps = localApps.length > 5 ? [
2747
2860
  ...localApps.slice(0, 5),
2748
2861
  { name: `... and ${localApps.length - 5} more`, port: void 0 }
2749
2862
  ] : localApps;
2750
2863
  for (const app of displayLocalApps) {
2751
2864
  if (app.port !== void 0) {
2752
- console.log(` \u2022 ${app.name} (port ${app.port})`);
2865
+ logger.info(` \u2022 ${app.name} (port ${app.port})`);
2753
2866
  } else {
2754
- console.log(` \u2022 ${app.name}`);
2867
+ logger.info(` \u2022 ${app.name}`);
2755
2868
  }
2756
2869
  }
2757
2870
  }
2758
2871
  if (fallbackApps.length > 0) {
2759
- console.log(" - Fallback Applications:");
2872
+ logger.info(" - Fallback Applications:");
2760
2873
  const displayFallbackApps = fallbackApps.length > 5 ? [
2761
2874
  ...fallbackApps.slice(0, 5),
2762
2875
  { name: `... and ${fallbackApps.length - 5} more`, fallback: "" }
2763
2876
  ] : fallbackApps;
2764
2877
  for (const app of displayFallbackApps) {
2765
2878
  if (app.fallback) {
2766
- console.log(` \u2022 ${app.name} \u2192 ${app.fallback}`);
2879
+ logger.info(` \u2022 ${app.name} \u2192 ${app.fallback}`);
2767
2880
  } else {
2768
- console.log(` \u2022 ${app.name}`);
2881
+ logger.info(` \u2022 ${app.name}`);
2769
2882
  }
2770
2883
  }
2771
2884
  }
2772
2885
  if (localApps.length === 0 && fallbackApps.length === 0) {
2773
- console.log(" - No applications configured\n");
2886
+ logger.info(" - No applications configured\n");
2774
2887
  }
2775
2888
  if (localApps.length > 0) {
2776
- console.log(
2889
+ logger.info(
2777
2890
  "\nRequests directly to the ports of these applications may be automatically\nredirected to this proxy. Set the MFE_DISABLE_LOCAL_PROXY_REWRITE=1\nenvironment variable to disable this behavior."
2778
2891
  );
2779
2892
  }
2780
- console.log(`
2893
+ logger.info(
2894
+ "\nTo debug routing, set an environment variable MFE_DEBUG=1,\nor enable the debug option when calling withMicrofrontends.\nThis will print out all routing information to the console.\n"
2895
+ );
2896
+ logger.info(`
2781
2897
  ${"\u2500".repeat(50)}
2782
2898
  `);
2783
2899
  }
@@ -2854,12 +2970,13 @@ function loadConfig({
2854
2970
 
2855
2971
  // src/bin/port.ts
2856
2972
  function displayPort() {
2973
+ delete process.env.MFE_DEBUG;
2857
2974
  const portInfo = mfePort((0, import_node_process.cwd)());
2858
2975
  header(portInfo);
2859
- console.log(portInfo.port);
2976
+ logger.info(portInfo.port);
2860
2977
  }
2861
2978
  function header({ name, version, port }) {
2862
- console.error(`
2979
+ logger.error(`
2863
2980
  \u25B2 ${name}@${version}
2864
2981
  \xB7 setting port to ${port}
2865
2982
  `);