@vercel/microfrontends 0.10.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/bin/cli.cjs +263 -102
  2. package/dist/config.cjs +0 -2
  3. package/dist/config.cjs.map +1 -1
  4. package/dist/config.js +0 -2
  5. package/dist/config.js.map +1 -1
  6. package/dist/{index-acb44057.d.ts → index-35038aec.d.ts} +2 -2
  7. package/dist/next/config.cjs +10 -3
  8. package/dist/next/config.cjs.map +1 -1
  9. package/dist/next/config.js +10 -3
  10. package/dist/next/config.js.map +1 -1
  11. package/dist/next/middleware.cjs +17 -1
  12. package/dist/next/middleware.cjs.map +1 -1
  13. package/dist/next/middleware.js +17 -1
  14. package/dist/next/middleware.js.map +1 -1
  15. package/dist/next/testing.cjs +0 -2
  16. package/dist/next/testing.cjs.map +1 -1
  17. package/dist/next/testing.js +0 -2
  18. package/dist/next/testing.js.map +1 -1
  19. package/dist/{types-c3d15d04.d.ts → types-15b7f215.d.ts} +1 -1
  20. package/dist/{types-7b1cd9f7.d.ts → types-a995174e.d.ts} +1 -4
  21. package/dist/v2/config.cjs +1 -1
  22. package/dist/v2/config.cjs.map +1 -1
  23. package/dist/v2/config.d.ts +3 -3
  24. package/dist/v2/config.js +1 -1
  25. package/dist/v2/config.js.map +1 -1
  26. package/dist/v2/microfrontends/server.cjs +215 -53
  27. package/dist/v2/microfrontends/server.cjs.map +1 -1
  28. package/dist/v2/microfrontends/server.d.ts +22 -3
  29. package/dist/v2/microfrontends/server.js +215 -53
  30. package/dist/v2/microfrontends/server.js.map +1 -1
  31. package/dist/v2/microfrontends.cjs +1 -2
  32. package/dist/v2/microfrontends.cjs.map +1 -1
  33. package/dist/v2/microfrontends.d.ts +3 -4
  34. package/dist/v2/microfrontends.js +1 -2
  35. package/dist/v2/microfrontends.js.map +1 -1
  36. package/dist/v2/next/config.cjs +249 -82
  37. package/dist/v2/next/config.cjs.map +1 -1
  38. package/dist/v2/next/config.js +249 -82
  39. package/dist/v2/next/config.js.map +1 -1
  40. package/dist/v2/next/endpoints.cjs +5 -2
  41. package/dist/v2/next/endpoints.cjs.map +1 -1
  42. package/dist/v2/next/endpoints.d.ts +1 -1
  43. package/dist/v2/next/endpoints.js +5 -2
  44. package/dist/v2/next/endpoints.js.map +1 -1
  45. package/dist/v2/next/middleware.cjs +107 -88
  46. package/dist/v2/next/middleware.cjs.map +1 -1
  47. package/dist/v2/next/middleware.js +107 -88
  48. package/dist/v2/next/middleware.js.map +1 -1
  49. package/dist/v2/overrides.cjs +1 -1
  50. package/dist/v2/overrides.cjs.map +1 -1
  51. package/dist/v2/overrides.d.ts +3 -3
  52. package/dist/v2/overrides.js +1 -1
  53. package/dist/v2/overrides.js.map +1 -1
  54. package/dist/v2/schema.d.ts +1 -1
  55. package/dist/validation.cjs +1 -11
  56. package/dist/validation.cjs.map +1 -1
  57. package/dist/validation.d.ts +0 -3
  58. package/dist/validation.js +1 -11
  59. package/dist/validation.js.map +1 -1
  60. package/package.json +8 -7
  61. package/schema/schema-v2.json +0 -14
@@ -1,9 +1,9 @@
1
1
  // src/config-v2/microfrontends/server/index.ts
2
- import fs2 from "node:fs";
3
- import { dirname as dirname2, join } from "node:path";
2
+ import fs4 from "node:fs";
3
+ import { dirname as dirname3, join } from "node:path";
4
4
 
5
5
  // src/config-v2/overrides/constants.ts
6
- var OVERRIDES_COOKIE_PREFIX = "vercel-microfrontends-override";
6
+ var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
7
7
  var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
8
8
 
9
9
  // src/config-v2/overrides/is-override-cookie.ts
@@ -184,21 +184,21 @@ var MicrofrontendConfigClient = class {
184
184
  isEqual(other) {
185
185
  return JSON.stringify(this.applications) === JSON.stringify(other.applications);
186
186
  }
187
- getApplicationNameForPath(path3) {
188
- if (!path3.startsWith("/")) {
187
+ getApplicationNameForPath(path5) {
188
+ if (!path5.startsWith("/")) {
189
189
  throw new Error(`Path must start with a /`);
190
190
  }
191
- if (this.pathCache[path3]) {
192
- return this.pathCache[path3];
191
+ if (this.pathCache[path5]) {
192
+ return this.pathCache[path5];
193
193
  }
194
- const pathname = new URL(path3, "https://example.com").pathname;
194
+ const pathname = new URL(path5, "https://example.com").pathname;
195
195
  for (const [name, application] of Object.entries(this.applications)) {
196
196
  if (application.routing) {
197
197
  for (const group of application.routing) {
198
198
  for (const childPath of group.paths) {
199
199
  const regexp = pathToRegexp(childPath);
200
200
  if (regexp.test(pathname)) {
201
- this.pathCache[path3] = name;
201
+ this.pathCache[path5] = name;
202
202
  return name;
203
203
  }
204
204
  }
@@ -211,7 +211,7 @@ var MicrofrontendConfigClient = class {
211
211
  if (!defaultApplication) {
212
212
  return null;
213
213
  }
214
- this.pathCache[path3] = defaultApplication[0];
214
+ this.pathCache[path5] = defaultApplication[0];
215
215
  return defaultApplication[0];
216
216
  }
217
217
  serialize() {
@@ -243,22 +243,22 @@ var validateConfigPaths = (applicationConfigsById) => {
243
243
  continue;
244
244
  }
245
245
  for (const pathMatch of app.routing) {
246
- for (const path3 of pathMatch.paths) {
247
- const tokens = parsePathRegexp(path3);
246
+ for (const path5 of pathMatch.paths) {
247
+ const tokens = parsePathRegexp(path5);
248
248
  for (const token of tokens.slice(0, -1)) {
249
249
  if (typeof token !== "string") {
250
250
  errors.push(
251
- `Path ${path3} may only have a :wildcard in the last path component`
251
+ `Path ${path5} may only have a :wildcard in the last path component`
252
252
  );
253
253
  }
254
254
  }
255
- const existing = pathsByApplicationId.get(path3);
255
+ const existing = pathsByApplicationId.get(path5);
256
256
  if (existing) {
257
257
  existing.applications.push(id);
258
258
  } else {
259
- pathsByApplicationId.set(path3, {
259
+ pathsByApplicationId.set(path5, {
260
260
  applications: [id],
261
- matcher: pathToRegexp2(path3),
261
+ matcher: pathToRegexp2(path5),
262
262
  applicationId: id
263
263
  });
264
264
  }
@@ -266,10 +266,10 @@ var validateConfigPaths = (applicationConfigsById) => {
266
266
  }
267
267
  }
268
268
  const entries = Array.from(pathsByApplicationId.entries());
269
- entries.forEach(([path3, { applications: ids, matcher, applicationId }]) => {
269
+ entries.forEach(([path5, { applications: ids, matcher, applicationId }]) => {
270
270
  if (ids.length > 1) {
271
271
  errors.push(
272
- `Duplicate path "${path3}" for applications "${ids.join(", ")}"`
272
+ `Duplicate path "${path5}" for applications "${ids.join(", ")}"`
273
273
  );
274
274
  }
275
275
  entries.forEach(
@@ -277,14 +277,14 @@ var validateConfigPaths = (applicationConfigsById) => {
277
277
  matchPath,
278
278
  { applications: matchIds, applicationId: matchApplicationId }
279
279
  ]) => {
280
- if (path3 === matchPath) {
280
+ if (path5 === matchPath) {
281
281
  return;
282
282
  }
283
283
  if (applicationId === matchApplicationId) {
284
284
  return;
285
285
  }
286
286
  if (matcher.test(matchPath)) {
287
- const source = `"${path3}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
287
+ const source = `"${path5}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
288
288
  const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
289
289
  errors.push(
290
290
  `Overlapping path detected between ${source} and ${destination}`
@@ -717,7 +717,6 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
717
717
  var _a, _b, _c;
718
718
  super({ config, overrides, meta });
719
719
  this.isMainConfig = true;
720
- this.provider = config.provider;
721
720
  const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
722
721
  let defaultApplication;
723
722
  for (const [appId, appConfig] of Object.entries(config.applications)) {
@@ -849,8 +848,115 @@ function findPackagePath(opts) {
849
848
  return result;
850
849
  }
851
850
 
852
- // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
851
+ // src/config-v2/microfrontends/utils/find-default-package.ts
852
+ import { dirname as dirname2 } from "node:path";
853
+ import { readFileSync as readFileSync2 } from "node:fs";
854
+ import fg2 from "fast-glob";
855
+ var configCache2 = {};
856
+ function findDefaultMicrofrontendsPackages({
857
+ repositoryRoot,
858
+ applicationName
859
+ }) {
860
+ try {
861
+ const microfrontendsJsonPaths = fg2.globSync("**/microfrontends.json", {
862
+ cwd: repositoryRoot,
863
+ absolute: true,
864
+ onlyFiles: true,
865
+ followSymbolicLinks: false,
866
+ ignore: ["**/node_modules/**", "**/.git/**"]
867
+ });
868
+ const matchingPaths = [];
869
+ for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
870
+ const microfrontendsJsonContent = readFileSync2(
871
+ microfrontendsJsonPath,
872
+ "utf-8"
873
+ );
874
+ const microfrontendsJson = JSON.parse(
875
+ microfrontendsJsonContent
876
+ );
877
+ if (isMainConfig(microfrontendsJson) && microfrontendsJson.applications[applicationName]) {
878
+ matchingPaths.push(microfrontendsJsonPath);
879
+ }
880
+ }
881
+ if (matchingPaths.length > 1) {
882
+ throw new Error(
883
+ `Found multiple default applications referencing "${applicationName}" in the repository, this is not yet supported.
884
+ ${matchingPaths.join("\n \u2022 ")}`
885
+ );
886
+ }
887
+ if (matchingPaths.length === 0) {
888
+ throw new Error(
889
+ `Could not find default application with "applications.${applicationName}"`
890
+ );
891
+ }
892
+ const [packageJsonPath] = matchingPaths;
893
+ return dirname2(packageJsonPath);
894
+ } catch (error) {
895
+ return null;
896
+ }
897
+ }
898
+ function findDefaultMicrofrontendsPackage(opts) {
899
+ const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;
900
+ if (configCache2[cacheKey]) {
901
+ return configCache2[cacheKey];
902
+ }
903
+ const result = findDefaultMicrofrontendsPackages(opts);
904
+ if (!result) {
905
+ throw new Error(
906
+ `Error trying to resolve the main microfrontends.json configuration`
907
+ );
908
+ }
909
+ configCache2[cacheKey] = result;
910
+ return result;
911
+ }
912
+
913
+ // src/config-v2/microfrontends/utils/is-monorepo.ts
914
+ import fs2 from "node:fs";
853
915
  import path2 from "node:path";
916
+ function isMonorepo({
917
+ repositoryRoot
918
+ }) {
919
+ try {
920
+ if (fs2.existsSync(path2.join(repositoryRoot, "pnpm-workspace.yaml"))) {
921
+ return true;
922
+ }
923
+ if (fs2.existsSync(path2.join(repositoryRoot, "vlt-workspaces.json"))) {
924
+ return true;
925
+ }
926
+ const packageJsonPath = path2.join(repositoryRoot, "package.json");
927
+ if (!fs2.existsSync(packageJsonPath)) {
928
+ return false;
929
+ }
930
+ const packageJson = JSON.parse(
931
+ fs2.readFileSync(packageJsonPath, "utf-8")
932
+ );
933
+ return packageJson.workspaces !== void 0;
934
+ } catch (error) {
935
+ console.error("Error determining if repository is a monorepo", error);
936
+ return false;
937
+ }
938
+ }
939
+
940
+ // src/config-v2/microfrontends/utils/find-package-root.ts
941
+ import fs3 from "node:fs";
942
+ import path3 from "node:path";
943
+ var PACKAGE_JSON = "package.json";
944
+ function findPackageRoot(startDir) {
945
+ let currentDir = startDir || process.cwd();
946
+ while (currentDir !== path3.parse(currentDir).root) {
947
+ const pkgJsonPath = path3.join(currentDir, PACKAGE_JSON);
948
+ if (fs3.existsSync(pkgJsonPath)) {
949
+ return currentDir;
950
+ }
951
+ currentDir = path3.dirname(currentDir);
952
+ }
953
+ throw new Error(
954
+ "Package root not found. Specify the root of the package with the `package.root` option."
955
+ );
956
+ }
957
+
958
+ // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
959
+ import path4 from "node:path";
854
960
 
855
961
  // src/config-v2/microfrontends/server/constants.ts
856
962
  var MFE_CONFIG_DEFAULT_FILE_PATH = "microfrontends";
@@ -864,13 +970,13 @@ function isVercel() {
864
970
  // src/config-v2/microfrontends/server/utils/get-output-file-path.ts
865
971
  function getOutputFilePath() {
866
972
  if (isVercel()) {
867
- return path2.join(
973
+ return path4.join(
868
974
  ".vercel",
869
975
  MFE_CONFIG_DEFAULT_FILE_PATH,
870
976
  MFE_CONFIG_DEFAULT_FILE_NAME
871
977
  );
872
978
  }
873
- return path2.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
979
+ return path4.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
874
980
  }
875
981
 
876
982
  // src/config-v2/microfrontends/server/validation.ts
@@ -1004,15 +1110,12 @@ var schema_v2_default = {
1004
1110
  },
1005
1111
  description: "Applications that only serve a subset of the microfrontend routes only need to reference the name of the primary application that owns the full microfrontends configuration."
1006
1112
  },
1007
- provider: {
1008
- $ref: "#/definitions/Provider"
1009
- },
1010
1113
  applications: {
1011
1114
  $ref: "#/definitions/ApplicationRouting",
1012
1115
  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"
1013
1116
  }
1014
1117
  },
1015
- required: ["applications", "provider", "version"]
1118
+ required: ["applications", "version"]
1016
1119
  },
1017
1120
  Options: {
1018
1121
  type: "object",
@@ -1084,9 +1187,6 @@ var schema_v2_default = {
1084
1187
  projectId: {
1085
1188
  type: "string",
1086
1189
  description: "Vercel project ID"
1087
- },
1088
- routeSpeedInsightsToDefaultZone: {
1089
- type: "boolean"
1090
1190
  }
1091
1191
  },
1092
1192
  required: ["projectId"]
@@ -1189,10 +1289,6 @@ var schema_v2_default = {
1189
1289
  },
1190
1290
  required: ["paths"]
1191
1291
  },
1192
- Provider: {
1193
- type: "string",
1194
- enum: ["vercel", "other"]
1195
- },
1196
1292
  ApplicationRouting: {
1197
1293
  type: "object",
1198
1294
  additionalProperties: {
@@ -1256,8 +1352,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1256
1352
  pretty: true
1257
1353
  }) {
1258
1354
  const outputPath = getOutputFilePath();
1259
- fs2.mkdirSync(dirname2(outputPath), { recursive: true });
1260
- fs2.writeFileSync(
1355
+ fs4.mkdirSync(dirname3(outputPath), { recursive: true });
1356
+ fs4.writeFileSync(
1261
1357
  outputPath,
1262
1358
  JSON.stringify(
1263
1359
  this.config.toSchemaJson(),
@@ -1319,6 +1415,69 @@ var MicrofrontendsServer = class extends Microfrontends {
1319
1415
  }
1320
1416
  return config;
1321
1417
  }
1418
+ /**
1419
+ * Looks up the configuration by inferring the package root and looking for a microfrontends.json file. If a file is not found,
1420
+ * it will look for a package in the repository with a microfrontends.json file that contains the current application
1421
+ * and use that configuration.
1422
+ *
1423
+ * This can return either a Child or Main configuration.
1424
+ */
1425
+ static infer({
1426
+ directory,
1427
+ filePath,
1428
+ meta,
1429
+ cookies,
1430
+ options
1431
+ } = {}) {
1432
+ if (filePath && meta) {
1433
+ return MicrofrontendsServer.fromFile({
1434
+ filePath,
1435
+ cookies,
1436
+ meta,
1437
+ options
1438
+ });
1439
+ }
1440
+ try {
1441
+ const packageRoot = findPackageRoot(directory);
1442
+ const packageJsonPath = join(packageRoot, "package.json");
1443
+ const packageJson = JSON.parse(
1444
+ fs4.readFileSync(packageJsonPath, "utf-8")
1445
+ );
1446
+ if (!packageJson.name) {
1447
+ throw new Error(`No name found in package.json at ${packageJsonPath}`);
1448
+ }
1449
+ const configMeta = meta ?? { fromApp: packageJson.name };
1450
+ const maybeConfig = join(packageRoot, "microfrontends.json");
1451
+ if (fs4.existsSync(maybeConfig)) {
1452
+ return MicrofrontendsServer.fromFile({
1453
+ filePath: maybeConfig,
1454
+ cookies,
1455
+ meta: configMeta,
1456
+ options
1457
+ });
1458
+ }
1459
+ const repositoryRoot = findRepositoryRoot();
1460
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1461
+ if (isMonorepo2) {
1462
+ const defaultPackage = findDefaultMicrofrontendsPackage({
1463
+ repositoryRoot,
1464
+ applicationName: packageJson.name
1465
+ });
1466
+ return MicrofrontendsServer.fromFile({
1467
+ filePath: join(defaultPackage, "microfrontends.json"),
1468
+ cookies,
1469
+ meta: configMeta,
1470
+ options
1471
+ });
1472
+ }
1473
+ throw new Error("Unable to infer");
1474
+ } catch (e) {
1475
+ throw new MicrofrontendError(
1476
+ "Unable to infer microfrontends configuration",
1477
+ { type: "config", subtype: "inference_failed" }
1478
+ );
1479
+ }
1480
+ }
1322
1481
  /*
1323
1482
  * Generates a MicrofrontendsServer instance from a file.
1324
1483
  */
@@ -1329,25 +1488,28 @@ var MicrofrontendsServer = class extends Microfrontends {
1329
1488
  options
1330
1489
  }) {
1331
1490
  try {
1332
- const configJson = fs2.readFileSync(filePath, "utf-8");
1491
+ const configJson = fs4.readFileSync(filePath, "utf-8");
1333
1492
  const config = MicrofrontendsServer.validate(configJson);
1334
1493
  if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
1335
1494
  const repositoryRoot = findRepositoryRoot();
1336
- const packagePath = findPackagePath({
1337
- repositoryRoot,
1338
- name: config.partOf
1339
- });
1340
- if (!packagePath) {
1341
- throw new MicrofrontendError(
1342
- `Could not find default application "${config.partOf}" in the repository`,
1343
- { type: "config", subtype: "not_found" }
1344
- );
1495
+ const isMonorepo2 = isMonorepo({ repositoryRoot });
1496
+ if (isMonorepo2) {
1497
+ const packagePath = findPackagePath({
1498
+ repositoryRoot,
1499
+ name: config.partOf
1500
+ });
1501
+ if (!packagePath) {
1502
+ throw new MicrofrontendError(
1503
+ `Could not find default application "${config.partOf}" in the repository`,
1504
+ { type: "config", subtype: "not_found" }
1505
+ );
1506
+ }
1507
+ const mainConfigPath = join(packagePath, "microfrontends.json");
1508
+ return MicrofrontendsServer.fromMainConfigFile({
1509
+ filePath: mainConfigPath,
1510
+ overrides: cookies ? parseOverrides(cookies) : void 0
1511
+ });
1345
1512
  }
1346
- const mainConfigPath = join(packagePath, "microfrontends.json");
1347
- return MicrofrontendsServer.fromMainConfigFile({
1348
- filePath: mainConfigPath,
1349
- overrides: cookies ? parseOverrides(cookies) : void 0
1350
- });
1351
1513
  }
1352
1514
  return new MicrofrontendsServer({
1353
1515
  config,
@@ -1368,7 +1530,7 @@ var MicrofrontendsServer = class extends Microfrontends {
1368
1530
  overrides
1369
1531
  }) {
1370
1532
  try {
1371
- const config = fs2.readFileSync(filePath, "utf-8");
1533
+ const config = fs4.readFileSync(filePath, "utf-8");
1372
1534
  const validatedConfig = MicrofrontendsServer.validate(config);
1373
1535
  if (!isMainConfig(validatedConfig)) {
1374
1536
  throw new MicrofrontendError(