@vercel/microfrontends 1.5.0-canary.2 → 2.0.0-canary.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 (59) hide show
  1. package/CHANGELOG.md +10 -18
  2. package/dist/bin/cli.cjs +103 -117
  3. package/dist/config.cjs +48 -101
  4. package/dist/config.cjs.map +1 -1
  5. package/dist/config.d.ts +2 -29
  6. package/dist/config.js +37 -100
  7. package/dist/config.js.map +1 -1
  8. package/dist/experimental/sveltekit.cjs +93 -109
  9. package/dist/experimental/sveltekit.cjs.map +1 -1
  10. package/dist/experimental/sveltekit.js +92 -108
  11. package/dist/experimental/sveltekit.js.map +1 -1
  12. package/dist/experimental/vite.cjs +93 -109
  13. package/dist/experimental/vite.cjs.map +1 -1
  14. package/dist/experimental/vite.js +92 -108
  15. package/dist/experimental/vite.js.map +1 -1
  16. package/dist/get-application-context-e8a5a0e2.d.ts +14 -0
  17. package/dist/microfrontends/server.cjs +93 -109
  18. package/dist/microfrontends/server.cjs.map +1 -1
  19. package/dist/microfrontends/server.d.ts +4 -13
  20. package/dist/microfrontends/server.js +92 -108
  21. package/dist/microfrontends/server.js.map +1 -1
  22. package/dist/microfrontends/utils.cjs +24 -4
  23. package/dist/microfrontends/utils.cjs.map +1 -1
  24. package/dist/microfrontends/utils.d.ts +3 -1
  25. package/dist/microfrontends/utils.js +24 -4
  26. package/dist/microfrontends/utils.js.map +1 -1
  27. package/dist/next/client.cjs +1 -1
  28. package/dist/next/client.cjs.map +1 -1
  29. package/dist/next/client.js +1 -1
  30. package/dist/next/client.js.map +1 -1
  31. package/dist/next/config.cjs +244 -117
  32. package/dist/next/config.cjs.map +1 -1
  33. package/dist/next/config.d.ts +1 -1
  34. package/dist/next/config.js +243 -116
  35. package/dist/next/config.js.map +1 -1
  36. package/dist/next/middleware.cjs +88 -44
  37. package/dist/next/middleware.cjs.map +1 -1
  38. package/dist/next/middleware.js +78 -44
  39. package/dist/next/middleware.js.map +1 -1
  40. package/dist/next/testing.cjs +51 -104
  41. package/dist/next/testing.cjs.map +1 -1
  42. package/dist/next/testing.d.ts +2 -2
  43. package/dist/next/testing.js +39 -102
  44. package/dist/next/testing.js.map +1 -1
  45. package/dist/overrides.d.ts +3 -3
  46. package/dist/schema.d.ts +2 -2
  47. package/dist/{types-1cec43e6.d.ts → types-0deb756b.d.ts} +16 -1
  48. package/dist/{types-1fb60496.d.ts → types-4299bff1.d.ts} +1 -1
  49. package/dist/utils/mfe-port.cjs +93 -109
  50. package/dist/utils/mfe-port.cjs.map +1 -1
  51. package/dist/utils/mfe-port.js +92 -108
  52. package/dist/utils/mfe-port.js.map +1 -1
  53. package/dist/validation.cjs +4 -0
  54. package/dist/validation.cjs.map +1 -1
  55. package/dist/validation.d.ts +1 -1
  56. package/dist/validation.js +4 -0
  57. package/dist/validation.js.map +1 -1
  58. package/package.json +3 -1
  59. package/schema/schema.json +4 -0
@@ -242,8 +242,9 @@ var CONFIGURATION_FILENAMES = [
242
242
  var configCache = {};
243
243
  function findPackageWithMicrofrontendsConfig({
244
244
  repositoryRoot,
245
- applicationName
245
+ applicationContext
246
246
  }) {
247
+ const applicationName = applicationContext.name;
247
248
  try {
248
249
  const microfrontendsJsonPaths = import_fast_glob.default.globSync(
249
250
  `**/{${CONFIGURATION_FILENAMES.join(",")}}`,
@@ -285,26 +286,45 @@ ${matchingPaths.join("\n \u2022 ")}`,
285
286
  );
286
287
  }
287
288
  if (matchingPaths.length === 0) {
289
+ let additionalErrorMessage = "";
290
+ if (microfrontendsJsonPaths.length > 0) {
291
+ if (!applicationContext.projectName) {
292
+ additionalErrorMessage = `
293
+
294
+ If the name in package.json (${applicationContext.packageJsonName}) differs from your Vercel Project name, set the \`packageName\` field for the application in \`microfrontends.json\` to ensure that the configuration can be found locally.`;
295
+ } else {
296
+ additionalErrorMessage = `
297
+
298
+ Names of applications in \`microfrontends.json\` must match the Vercel Project name (${applicationContext.projectName}).`;
299
+ }
300
+ }
288
301
  throw new MicrofrontendError(
289
- `Could not find a \`microfrontends.json\` file in the repository that contains "applications.${applicationName}". If your Vercel Microfrontends configuration is not in this repository, you can use the Vercel CLI to pull the Vercel Microfrontends configuration using the "vercel microfrontends pull" command, or you can specify the path manually using the VC_MICROFRONTENDS_CONFIG environment variable. If you suspect this is thrown in error, please reach out to the Vercel team.`,
302
+ `Could not find a \`microfrontends.json\` file in the repository that contains the "${applicationName}" application.${additionalErrorMessage}
303
+
304
+ If your Vercel Microfrontends configuration is not in this repository, you can use the Vercel CLI to pull the Vercel Microfrontends configuration using the "vercel microfrontends pull" command, or you can specify the path manually using the VC_MICROFRONTENDS_CONFIG environment variable.
305
+
306
+ If you suspect this is thrown in error, please reach out to the Vercel team.`,
290
307
  { type: "config", subtype: "inference_failed" }
291
308
  );
292
309
  }
293
310
  const [packageJsonPath] = matchingPaths;
294
311
  return (0, import_node_path2.dirname)(packageJsonPath);
295
312
  } catch (error) {
313
+ if (error instanceof MicrofrontendError) {
314
+ throw error;
315
+ }
296
316
  return null;
297
317
  }
298
318
  }
299
319
  function inferMicrofrontendsLocation(opts) {
300
- const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;
320
+ const cacheKey = `${opts.repositoryRoot}-${opts.applicationContext.name}`;
301
321
  if (configCache[cacheKey]) {
302
322
  return configCache[cacheKey];
303
323
  }
304
324
  const result = findPackageWithMicrofrontendsConfig(opts);
305
325
  if (!result) {
306
326
  throw new MicrofrontendError(
307
- `Could not infer the location of the \`microfrontends.json\` file for application "${opts.applicationName}" starting in directory "${opts.repositoryRoot}".`,
327
+ `Could not infer the location of the \`microfrontends.json\` file for application "${opts.applicationContext.name}" starting in directory "${opts.repositoryRoot}".`,
308
328
  { type: "config", subtype: "inference_failed" }
309
329
  );
310
330
  }
@@ -376,90 +396,13 @@ function findConfig({ dir }) {
376
396
  // src/config/microfrontends-config/isomorphic/index.ts
377
397
  var import_jsonc_parser2 = require("jsonc-parser");
378
398
 
379
- // src/config/microfrontends-config/client/index.ts
380
- var import_path_to_regexp = require("path-to-regexp");
381
- var regexpCache = /* @__PURE__ */ new Map();
382
- var getRegexp = (path6) => {
383
- const existing = regexpCache.get(path6);
384
- if (existing) {
385
- return existing;
386
- }
387
- const regexp = (0, import_path_to_regexp.pathToRegexp)(path6);
388
- regexpCache.set(path6, regexp);
389
- return regexp;
390
- };
391
- var MicrofrontendConfigClient = class {
392
- constructor(config, opts) {
393
- this.pathCache = {};
394
- this.serialized = config;
395
- if (opts?.removeFlaggedPaths) {
396
- for (const app of Object.values(config.applications)) {
397
- if (app.routing) {
398
- app.routing = app.routing.filter((match) => !match.flag);
399
- }
400
- }
401
- }
402
- this.applications = config.applications;
403
- }
404
- /**
405
- * Create a new `MicrofrontendConfigClient` from a JSON string.
406
- * Config must be passed in to remain framework agnostic
407
- */
408
- static fromEnv(config, opts) {
409
- if (!config) {
410
- throw new Error(
411
- "Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
412
- );
413
- }
414
- return new MicrofrontendConfigClient(
415
- JSON.parse(config),
416
- opts
417
- );
418
- }
419
- isEqual(other) {
420
- return this === other || JSON.stringify(this.applications) === JSON.stringify(other.applications);
421
- }
422
- getApplicationNameForPath(path6) {
423
- if (!path6.startsWith("/")) {
424
- throw new Error(`Path must start with a /`);
425
- }
426
- if (this.pathCache[path6]) {
427
- return this.pathCache[path6];
428
- }
429
- const pathname = new URL(path6, "https://example.com").pathname;
430
- for (const [name, application] of Object.entries(this.applications)) {
431
- if (application.routing) {
432
- for (const group of application.routing) {
433
- for (const childPath of group.paths) {
434
- const regexp = getRegexp(childPath);
435
- if (regexp.test(pathname)) {
436
- this.pathCache[path6] = name;
437
- return name;
438
- }
439
- }
440
- }
441
- }
442
- }
443
- const defaultApplication = Object.entries(this.applications).find(
444
- ([, application]) => application.default
445
- );
446
- if (!defaultApplication) {
447
- return null;
448
- }
449
- this.pathCache[path6] = defaultApplication[0];
450
- return defaultApplication[0];
451
- }
452
- serialize() {
453
- return this.serialized;
454
- }
455
- };
456
-
457
399
  // src/config/microfrontends-config/isomorphic/validation.ts
458
- var import_path_to_regexp2 = require("path-to-regexp");
400
+ var import_path_to_regexp = require("path-to-regexp");
459
401
  var LIST_FORMATTER = new Intl.ListFormat("en", {
460
402
  style: "long",
461
403
  type: "conjunction"
462
404
  });
405
+ var VALID_ASSET_PREFIX_REGEXP = /^[a-z](?:[a-z0-9-]*[a-z0-9])?$/;
463
406
  var validateConfigPaths = (applicationConfigsById) => {
464
407
  if (!applicationConfigsById) {
465
408
  return;
@@ -482,7 +425,7 @@ var validateConfigPaths = (applicationConfigsById) => {
482
425
  } else {
483
426
  pathsByApplicationId.set(path6, {
484
427
  applications: [id],
485
- matcher: (0, import_path_to_regexp2.pathToRegexp)(path6),
428
+ matcher: (0, import_path_to_regexp.pathToRegexp)(path6),
486
429
  applicationId: id
487
430
  });
488
431
  }
@@ -529,7 +472,7 @@ var validateConfigPaths = (applicationConfigsById) => {
529
472
  var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
530
473
  function validatePathExpression(path6) {
531
474
  try {
532
- const tokens = (0, import_path_to_regexp2.parse)(path6);
475
+ const tokens = (0, import_path_to_regexp.parse)(path6);
533
476
  if (/(?<!\\)\{/.test(path6)) {
534
477
  return `Optional paths are not supported: ${path6}`;
535
478
  }
@@ -586,6 +529,22 @@ var validateAppPaths = (name, app) => {
586
529
  }
587
530
  }
588
531
  }
532
+ if (app.assetPrefix) {
533
+ if (!VALID_ASSET_PREFIX_REGEXP.test(app.assetPrefix)) {
534
+ throw new MicrofrontendError(
535
+ `Invalid asset prefix for application "${name}". ${app.assetPrefix} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`,
536
+ { type: "application", subtype: "invalid_asset_prefix" }
537
+ );
538
+ }
539
+ if (app.assetPrefix !== `vc-ap-${name}` && !app.routing.some(
540
+ (group) => group.paths.includes(`/${app.assetPrefix}/:path*`) && !group.flag
541
+ )) {
542
+ throw new MicrofrontendError(
543
+ `When \`assetPrefix\` is specified, \`/${app.assetPrefix}/:path*\` must be added the routing paths for the application. Changing the asset prefix is not a forwards and backwards compatible change, and the custom asset prefix should be added to \`paths\` and deployed before setting the \`assetPrefix\` field.`,
544
+ { type: "application", subtype: "invalid_asset_prefix" }
545
+ );
546
+ }
547
+ }
589
548
  };
590
549
  var validateConfigDefaultApplication = (applicationConfigsById) => {
591
550
  if (!applicationConfigsById) {
@@ -617,6 +576,15 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
617
576
  }
618
577
  };
619
578
 
579
+ // src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
580
+ var import_md5 = __toESM(require("md5"), 1);
581
+ function hashApplicationName(name) {
582
+ if (!name) {
583
+ throw new Error("Application name is required to generate hash");
584
+ }
585
+ return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
586
+ }
587
+
620
588
  // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
621
589
  var PREFIX = "vc-ap";
622
590
  function generateAssetPrefixFromName({
@@ -625,7 +593,7 @@ function generateAssetPrefixFromName({
625
593
  if (!name) {
626
594
  throw new Error("Name is required to generate an asset prefix");
627
595
  }
628
- return `${PREFIX}-${name}`;
596
+ return `${PREFIX}-${hashApplicationName(name)}`;
629
597
  }
630
598
 
631
599
  // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
@@ -785,7 +753,13 @@ var Application = class {
785
753
  return this.default;
786
754
  }
787
755
  getAssetPrefix() {
788
- return generateAssetPrefixFromName({ name: this.name });
756
+ const generatedAssetPrefix = generateAssetPrefixFromName({
757
+ name: this.name
758
+ });
759
+ if ("assetPrefix" in this.serialized) {
760
+ return this.serialized.assetPrefix ?? generatedAssetPrefix;
761
+ }
762
+ return generatedAssetPrefix;
789
763
  }
790
764
  getAutomationBypassEnvVarName() {
791
765
  return generateAutomationBypassEnvVarName({ name: this.name });
@@ -919,7 +893,7 @@ var MicrofrontendConfigIsomorphic = class {
919
893
  );
920
894
  if (!app) {
921
895
  throw new MicrofrontendError(
922
- `Could not find microfrontends configuration for application "${name}"`,
896
+ `Could not find microfrontends configuration for application "${name}". If the name in package.json differs from your Vercel Project name, set the \`packageName\` field for the application in \`microfrontends.json\` to ensure that the configuration can be found locally.`,
923
897
  {
924
898
  type: "application",
925
899
  subtype: "not_found"
@@ -964,23 +938,6 @@ var MicrofrontendConfigIsomorphic = class {
964
938
  toSchemaJson() {
965
939
  return this.serialized.config;
966
940
  }
967
- toClientConfig() {
968
- const applications = Object.fromEntries(
969
- Object.entries(this.childApplications).map(([name, application]) => [
970
- name,
971
- {
972
- default: false,
973
- routing: application.routing
974
- }
975
- ])
976
- );
977
- applications[this.defaultApplication.name] = {
978
- default: true
979
- };
980
- return new MicrofrontendConfigClient({
981
- applications
982
- });
983
- }
984
941
  serialize() {
985
942
  return this.serialized;
986
943
  }
@@ -993,8 +950,31 @@ function getApplicationContext(opts) {
993
950
  if (opts?.appName) {
994
951
  return { name: opts.appName };
995
952
  }
953
+ if (process.env.VERCEL_PROJECT_NAME) {
954
+ return {
955
+ name: process.env.VERCEL_PROJECT_NAME,
956
+ projectName: process.env.VERCEL_PROJECT_NAME
957
+ };
958
+ }
996
959
  if (process.env.NX_TASK_TARGET_PROJECT) {
997
- return { name: process.env.NX_TASK_TARGET_PROJECT };
960
+ return {
961
+ name: process.env.NX_TASK_TARGET_PROJECT,
962
+ packageJsonName: process.env.NX_TASK_TARGET_PROJECT
963
+ };
964
+ }
965
+ try {
966
+ const vercelProjectJsonPath = import_node_fs6.default.readFileSync(
967
+ import_node_path6.default.join(opts?.packageRoot || ".", ".vercel", "project.json"),
968
+ "utf-8"
969
+ );
970
+ const projectJson = JSON.parse(vercelProjectJsonPath);
971
+ if (projectJson.projectName) {
972
+ return {
973
+ name: projectJson.projectName,
974
+ projectName: projectJson.projectName
975
+ };
976
+ }
977
+ } catch (_) {
998
978
  }
999
979
  try {
1000
980
  const packageJsonString = import_node_fs6.default.readFileSync(
@@ -1012,7 +992,7 @@ function getApplicationContext(opts) {
1012
992
  }
1013
993
  );
1014
994
  }
1015
- return { name: packageJson.name };
995
+ return { name: packageJson.name, packageJsonName: packageJson.name };
1016
996
  } catch (err) {
1017
997
  throw MicrofrontendError.handle(err, {
1018
998
  fileName: "package.json"
@@ -1152,6 +1132,10 @@ var schema_default = {
1152
1132
  routing: {
1153
1133
  $ref: "#/definitions/Routing",
1154
1134
  description: "Groups of path expressions that are routed to this application."
1135
+ },
1136
+ assetPrefix: {
1137
+ type: "string",
1138
+ 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."
1155
1139
  }
1156
1140
  },
1157
1141
  required: [
@@ -1377,7 +1361,7 @@ var MicrofrontendsServer = class {
1377
1361
  }
1378
1362
  try {
1379
1363
  const packageRoot = findPackageRoot(directory);
1380
- const { name: appName } = getApplicationContext({ packageRoot });
1364
+ const applicationContext = getApplicationContext({ packageRoot });
1381
1365
  const maybeConfig = findConfig({ dir: packageRoot });
1382
1366
  if (maybeConfig) {
1383
1367
  return MicrofrontendsServer.fromFile({
@@ -1411,7 +1395,7 @@ var MicrofrontendsServer = class {
1411
1395
  if (isMonorepo2) {
1412
1396
  const defaultPackage = inferMicrofrontendsLocation({
1413
1397
  repositoryRoot,
1414
- applicationName: appName
1398
+ applicationContext
1415
1399
  });
1416
1400
  const maybeConfigFromDefault = findConfig({ dir: defaultPackage });
1417
1401
  if (maybeConfigFromDefault) {
@@ -1591,6 +1575,20 @@ ${indent} - Automatically redirecting all requests to local microfrontends proxy
1591
1575
  return { next };
1592
1576
  }
1593
1577
 
1578
+ // src/next/config/transforms/transpile-packages.ts
1579
+ function transform5(args) {
1580
+ const { next } = args;
1581
+ if (next.transpilePackages === void 0 || !next.transpilePackages.includes("@vercel/microfrontends")) {
1582
+ next.transpilePackages = [
1583
+ ...next.transpilePackages || [],
1584
+ "@vercel/microfrontends"
1585
+ ];
1586
+ }
1587
+ return {
1588
+ next
1589
+ };
1590
+ }
1591
+
1594
1592
  // src/next/config/transforms/rewrites.ts
1595
1593
  function debugRewrites(rewrites) {
1596
1594
  if (process.env.MFE_DEBUG) {
@@ -1623,7 +1621,7 @@ function rewritesMapToArr(rewrites) {
1623
1621
  ];
1624
1622
  });
1625
1623
  }
1626
- function transform5(args) {
1624
+ function transform6(args) {
1627
1625
  const { app, next } = args;
1628
1626
  const buildBeforeFiles = () => {
1629
1627
  const rewrites = /* @__PURE__ */ new Map();
@@ -1708,7 +1706,7 @@ var SortChunksPlugin = class {
1708
1706
  // src/next/config/transforms/webpack.ts
1709
1707
  var import_meta = {};
1710
1708
  var nextVersion = getNextJsVersion();
1711
- function transform6(args) {
1709
+ function transform7(args) {
1712
1710
  const useDefineServer = args.opts?.preferWebpackEnvironmentPlugin ? false : semver.gte(nextVersion, "15.4.0-canary.41");
1713
1711
  const { next, microfrontend, opts } = args;
1714
1712
  const configWithWebpack = {
@@ -1792,10 +1790,133 @@ var transforms = {
1792
1790
  buildId: transform2,
1793
1791
  draftMode: transform3,
1794
1792
  redirects: transform4,
1795
- rewrites: transform5,
1796
- webpack: transform6
1793
+ rewrites: transform6,
1794
+ transpilePackages: transform5,
1795
+ webpack: transform7
1797
1796
  };
1798
1797
 
1798
+ // src/config/microfrontends-config/client/index.ts
1799
+ var import_path_to_regexp2 = require("path-to-regexp");
1800
+ var regexpCache = /* @__PURE__ */ new Map();
1801
+ var getRegexp = (path6) => {
1802
+ const existing = regexpCache.get(path6);
1803
+ if (existing) {
1804
+ return existing;
1805
+ }
1806
+ const regexp = (0, import_path_to_regexp2.pathToRegexp)(path6);
1807
+ regexpCache.set(path6, regexp);
1808
+ return regexp;
1809
+ };
1810
+ var MicrofrontendConfigClient = class {
1811
+ constructor(config, opts) {
1812
+ this.pathCache = {};
1813
+ this.hasFlaggedPaths = config.hasFlaggedPaths ?? false;
1814
+ for (const app of Object.values(config.applications)) {
1815
+ if (app.routing) {
1816
+ if (app.routing.some((match) => match.flag)) {
1817
+ this.hasFlaggedPaths = true;
1818
+ }
1819
+ const newRouting = [];
1820
+ const pathsWithoutFlags = [];
1821
+ for (const group of app.routing) {
1822
+ if (group.flag) {
1823
+ if (opts?.removeFlaggedPaths) {
1824
+ continue;
1825
+ }
1826
+ if (group.group) {
1827
+ delete group.group;
1828
+ }
1829
+ newRouting.push(group);
1830
+ } else {
1831
+ pathsWithoutFlags.push(...group.paths);
1832
+ }
1833
+ }
1834
+ if (pathsWithoutFlags.length > 0) {
1835
+ newRouting.push({ paths: pathsWithoutFlags });
1836
+ }
1837
+ app.routing = newRouting;
1838
+ }
1839
+ }
1840
+ this.serialized = config;
1841
+ if (this.hasFlaggedPaths) {
1842
+ this.serialized.hasFlaggedPaths = this.hasFlaggedPaths;
1843
+ }
1844
+ this.applications = config.applications;
1845
+ }
1846
+ /**
1847
+ * Create a new `MicrofrontendConfigClient` from a JSON string.
1848
+ * Config must be passed in to remain framework agnostic
1849
+ */
1850
+ static fromEnv(config) {
1851
+ if (!config) {
1852
+ throw new Error(
1853
+ "Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
1854
+ );
1855
+ }
1856
+ return new MicrofrontendConfigClient(JSON.parse(config));
1857
+ }
1858
+ isEqual(other) {
1859
+ return this === other || JSON.stringify(this.applications) === JSON.stringify(other.applications);
1860
+ }
1861
+ getApplicationNameForPath(path6) {
1862
+ if (!path6.startsWith("/")) {
1863
+ throw new Error(`Path must start with a /`);
1864
+ }
1865
+ if (this.pathCache[path6]) {
1866
+ return this.pathCache[path6];
1867
+ }
1868
+ const pathname = new URL(path6, "https://example.com").pathname;
1869
+ for (const [name, application] of Object.entries(this.applications)) {
1870
+ if (application.routing) {
1871
+ for (const group of application.routing) {
1872
+ for (const childPath of group.paths) {
1873
+ const regexp = getRegexp(childPath);
1874
+ if (regexp.test(pathname)) {
1875
+ this.pathCache[path6] = name;
1876
+ return name;
1877
+ }
1878
+ }
1879
+ }
1880
+ }
1881
+ }
1882
+ const defaultApplication = Object.entries(this.applications).find(
1883
+ ([, application]) => application.default
1884
+ );
1885
+ if (!defaultApplication) {
1886
+ return null;
1887
+ }
1888
+ this.pathCache[path6] = defaultApplication[0];
1889
+ return defaultApplication[0];
1890
+ }
1891
+ serialize() {
1892
+ return this.serialized;
1893
+ }
1894
+ };
1895
+
1896
+ // src/config/microfrontends-config/client/from-isomorphic-config.ts
1897
+ function fromIsomorphicConfig(config, options) {
1898
+ const applications = Object.fromEntries(
1899
+ Object.entries(config.childApplications).map(([name, application]) => [
1900
+ hashApplicationName(name),
1901
+ {
1902
+ default: false,
1903
+ routing: application.routing
1904
+ }
1905
+ ])
1906
+ );
1907
+ applications[hashApplicationName(config.defaultApplication.name)] = {
1908
+ default: true
1909
+ };
1910
+ return new MicrofrontendConfigClient(
1911
+ {
1912
+ applications
1913
+ },
1914
+ {
1915
+ removeFlaggedPaths: options?.removeFlaggedPaths
1916
+ }
1917
+ );
1918
+ }
1919
+
1799
1920
  // src/next/config/env.ts
1800
1921
  function debugEnv(env) {
1801
1922
  if (process.env.MFE_DEBUG) {
@@ -1819,8 +1940,11 @@ function setEnvironment({
1819
1940
  }) {
1820
1941
  const clientEnvs = {
1821
1942
  NEXT_PUBLIC_MFE_CURRENT_APPLICATION: app.name,
1943
+ NEXT_PUBLIC_MFE_CURRENT_APPLICATION_HASH: hashApplicationName(app.name),
1822
1944
  NEXT_PUBLIC_MFE_CLIENT_CONFIG: JSON.stringify(
1823
- microfrontends.config.toClientConfig().serialize()
1945
+ fromIsomorphicConfig(microfrontends.config, {
1946
+ removeFlaggedPaths: true
1947
+ }).serialize()
1824
1948
  ),
1825
1949
  ...process.env.ROUTE_OBSERVABILITY_TO_THIS_PROJECT && app.getAssetPrefix() ? {
1826
1950
  NEXT_PUBLIC_VERCEL_OBSERVABILITY_BASEPATH: `/${app.getAssetPrefix()}/_vercel`
@@ -1828,7 +1952,10 @@ function setEnvironment({
1828
1952
  };
1829
1953
  const serverEnvs = {
1830
1954
  MFE_CURRENT_APPLICATION: app.name,
1831
- MFE_CONFIG: JSON.stringify(microfrontends.config.getConfig())
1955
+ MFE_CONFIG: JSON.stringify(microfrontends.config.getConfig()),
1956
+ MFE_CLIENT_CONFIG_FULL: JSON.stringify(
1957
+ fromIsomorphicConfig(microfrontends.config).serialize()
1958
+ )
1832
1959
  };
1833
1960
  const allEnvs = { ...clientEnvs, ...serverEnvs };
1834
1961
  for (const [key, value] of Object.entries(allEnvs)) {
@@ -1858,13 +1985,13 @@ function withMicrofrontends(nextConfig, opts) {
1858
1985
  const app = microfrontends.config.getApplication(fromApp);
1859
1986
  setEnvironment({ app, microfrontends });
1860
1987
  let next = { ...nextConfig };
1861
- for (const [key, transform7] of typedEntries(transforms)) {
1988
+ for (const [key, transform8] of typedEntries(transforms)) {
1862
1989
  if (opts?.skipTransforms?.includes(key)) {
1863
1990
  console.log(`Skipping ${key} transform`);
1864
1991
  continue;
1865
1992
  }
1866
1993
  try {
1867
- const transformedConfig = transform7({
1994
+ const transformedConfig = transform8({
1868
1995
  app,
1869
1996
  next,
1870
1997
  microfrontend: microfrontends.config,