@vercel/microfrontends 2.0.0-canary.1 → 2.0.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 (45) hide show
  1. package/CHANGELOG.md +11 -9
  2. package/README.md +21 -4
  3. package/dist/bin/cli.cjs +142 -13
  4. package/dist/config.cjs +123 -3
  5. package/dist/config.cjs.map +1 -1
  6. package/dist/config.d.ts +33 -2
  7. package/dist/config.js +122 -2
  8. package/dist/config.js.map +1 -1
  9. package/dist/experimental/sveltekit.cjs +128 -4
  10. package/dist/experimental/sveltekit.cjs.map +1 -1
  11. package/dist/experimental/sveltekit.js +127 -3
  12. package/dist/experimental/sveltekit.js.map +1 -1
  13. package/dist/experimental/vite.cjs +128 -4
  14. package/dist/experimental/vite.cjs.map +1 -1
  15. package/dist/experimental/vite.js +127 -3
  16. package/dist/experimental/vite.js.map +1 -1
  17. package/dist/microfrontends/server.cjs +128 -4
  18. package/dist/microfrontends/server.cjs.map +1 -1
  19. package/dist/microfrontends/server.d.ts +4 -3
  20. package/dist/microfrontends/server.js +127 -3
  21. package/dist/microfrontends/server.js.map +1 -1
  22. package/dist/next/config.cjs +131 -131
  23. package/dist/next/config.cjs.map +1 -1
  24. package/dist/next/config.d.ts +5 -0
  25. package/dist/next/config.js +130 -130
  26. package/dist/next/config.js.map +1 -1
  27. package/dist/next/middleware.cjs +125 -105
  28. package/dist/next/middleware.cjs.map +1 -1
  29. package/dist/next/middleware.js +125 -105
  30. package/dist/next/middleware.js.map +1 -1
  31. package/dist/next/testing.cjs +126 -6
  32. package/dist/next/testing.cjs.map +1 -1
  33. package/dist/next/testing.d.ts +2 -2
  34. package/dist/next/testing.js +124 -4
  35. package/dist/next/testing.js.map +1 -1
  36. package/dist/overrides.d.ts +3 -3
  37. package/dist/schema.d.ts +2 -2
  38. package/dist/{types-4299bff1.d.ts → types-88602303.d.ts} +1 -1
  39. package/dist/{types-0deb756b.d.ts → types-e7523e61.d.ts} +1 -1
  40. package/dist/utils/mfe-port.cjs +128 -4
  41. package/dist/utils/mfe-port.cjs.map +1 -1
  42. package/dist/utils/mfe-port.js +127 -3
  43. package/dist/utils/mfe-port.js.map +1 -1
  44. package/dist/validation.d.ts +1 -1
  45. package/package.json +7 -2
@@ -396,8 +396,106 @@ function findConfig({ dir }) {
396
396
  // src/config/microfrontends-config/isomorphic/index.ts
397
397
  var import_jsonc_parser2 = require("jsonc-parser");
398
398
 
399
- // src/config/microfrontends-config/isomorphic/validation.ts
399
+ // src/config/microfrontends-config/client/index.ts
400
400
  var import_path_to_regexp = require("path-to-regexp");
401
+ var regexpCache = /* @__PURE__ */ new Map();
402
+ var getRegexp = (path6) => {
403
+ const existing = regexpCache.get(path6);
404
+ if (existing) {
405
+ return existing;
406
+ }
407
+ const regexp = (0, import_path_to_regexp.pathToRegexp)(path6);
408
+ regexpCache.set(path6, regexp);
409
+ return regexp;
410
+ };
411
+ var MicrofrontendConfigClient = class {
412
+ constructor(config, opts) {
413
+ this.pathCache = {};
414
+ this.hasFlaggedPaths = config.hasFlaggedPaths ?? false;
415
+ for (const app of Object.values(config.applications)) {
416
+ if (app.routing) {
417
+ if (app.routing.some((match) => match.flag)) {
418
+ this.hasFlaggedPaths = true;
419
+ }
420
+ const newRouting = [];
421
+ const pathsWithoutFlags = [];
422
+ for (const group of app.routing) {
423
+ if (group.flag) {
424
+ if (opts?.removeFlaggedPaths) {
425
+ continue;
426
+ }
427
+ if (group.group) {
428
+ delete group.group;
429
+ }
430
+ newRouting.push(group);
431
+ } else {
432
+ pathsWithoutFlags.push(...group.paths);
433
+ }
434
+ }
435
+ if (pathsWithoutFlags.length > 0) {
436
+ newRouting.push({ paths: pathsWithoutFlags });
437
+ }
438
+ app.routing = newRouting;
439
+ }
440
+ }
441
+ this.serialized = config;
442
+ if (this.hasFlaggedPaths) {
443
+ this.serialized.hasFlaggedPaths = this.hasFlaggedPaths;
444
+ }
445
+ this.applications = config.applications;
446
+ }
447
+ /**
448
+ * Create a new `MicrofrontendConfigClient` from a JSON string.
449
+ * Config must be passed in to remain framework agnostic
450
+ */
451
+ static fromEnv(config) {
452
+ if (!config) {
453
+ throw new Error(
454
+ "Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
455
+ );
456
+ }
457
+ return new MicrofrontendConfigClient(JSON.parse(config));
458
+ }
459
+ isEqual(other) {
460
+ return this === other || JSON.stringify(this.applications) === JSON.stringify(other.applications);
461
+ }
462
+ getApplicationNameForPath(path6) {
463
+ if (!path6.startsWith("/")) {
464
+ throw new Error(`Path must start with a /`);
465
+ }
466
+ if (this.pathCache[path6]) {
467
+ return this.pathCache[path6];
468
+ }
469
+ const pathname = new URL(path6, "https://example.com").pathname;
470
+ for (const [name, application] of Object.entries(this.applications)) {
471
+ if (application.routing) {
472
+ for (const group of application.routing) {
473
+ for (const childPath of group.paths) {
474
+ const regexp = getRegexp(childPath);
475
+ if (regexp.test(pathname)) {
476
+ this.pathCache[path6] = name;
477
+ return name;
478
+ }
479
+ }
480
+ }
481
+ }
482
+ }
483
+ const defaultApplication = Object.entries(this.applications).find(
484
+ ([, application]) => application.default
485
+ );
486
+ if (!defaultApplication) {
487
+ return null;
488
+ }
489
+ this.pathCache[path6] = defaultApplication[0];
490
+ return defaultApplication[0];
491
+ }
492
+ serialize() {
493
+ return this.serialized;
494
+ }
495
+ };
496
+
497
+ // src/config/microfrontends-config/isomorphic/validation.ts
498
+ var import_path_to_regexp2 = require("path-to-regexp");
401
499
  var LIST_FORMATTER = new Intl.ListFormat("en", {
402
500
  style: "long",
403
501
  type: "conjunction"
@@ -425,7 +523,7 @@ var validateConfigPaths = (applicationConfigsById) => {
425
523
  } else {
426
524
  pathsByApplicationId.set(path6, {
427
525
  applications: [id],
428
- matcher: (0, import_path_to_regexp.pathToRegexp)(path6),
526
+ matcher: (0, import_path_to_regexp2.pathToRegexp)(path6),
429
527
  applicationId: id
430
528
  });
431
529
  }
@@ -472,7 +570,7 @@ var validateConfigPaths = (applicationConfigsById) => {
472
570
  var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
473
571
  function validatePathExpression(path6) {
474
572
  try {
475
- const tokens = (0, import_path_to_regexp.parse)(path6);
573
+ const tokens = (0, import_path_to_regexp2.parse)(path6);
476
574
  if (/(?<!\\)\{/.test(path6)) {
477
575
  return `Optional paths are not supported: ${path6}`;
478
576
  }
@@ -930,6 +1028,28 @@ var MicrofrontendConfigIsomorphic = class {
930
1028
  getLocalProxyPort() {
931
1029
  return this.config.options?.localProxyPort ?? DEFAULT_LOCAL_PROXY_PORT;
932
1030
  }
1031
+ toClientConfig(options) {
1032
+ const applications = Object.fromEntries(
1033
+ Object.entries(this.childApplications).map(([name, application]) => [
1034
+ hashApplicationName(name),
1035
+ {
1036
+ default: false,
1037
+ routing: application.routing
1038
+ }
1039
+ ])
1040
+ );
1041
+ applications[hashApplicationName(this.defaultApplication.name)] = {
1042
+ default: true
1043
+ };
1044
+ return new MicrofrontendConfigClient(
1045
+ {
1046
+ applications
1047
+ },
1048
+ {
1049
+ removeFlaggedPaths: options?.removeFlaggedPaths
1050
+ }
1051
+ );
1052
+ }
933
1053
  /**
934
1054
  * Serializes the class back to the Schema type.
935
1055
  *
@@ -1349,6 +1469,7 @@ var MicrofrontendsServer = class {
1349
1469
  * This can return either a Child or Main configuration.
1350
1470
  */
1351
1471
  static infer({
1472
+ appName,
1352
1473
  directory,
1353
1474
  filePath,
1354
1475
  cookies
@@ -1361,7 +1482,10 @@ var MicrofrontendsServer = class {
1361
1482
  }
1362
1483
  try {
1363
1484
  const packageRoot = findPackageRoot(directory);
1364
- const applicationContext = getApplicationContext({ packageRoot });
1485
+ const applicationContext = getApplicationContext({
1486
+ appName,
1487
+ packageRoot
1488
+ });
1365
1489
  const maybeConfig = findConfig({ dir: packageRoot });
1366
1490
  if (maybeConfig) {
1367
1491
  return MicrofrontendsServer.fromFile({
@@ -1795,128 +1919,6 @@ var transforms = {
1795
1919
  webpack: transform7
1796
1920
  };
1797
1921
 
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
-
1920
1922
  // src/next/config/env.ts
1921
1923
  function debugEnv(env) {
1922
1924
  if (process.env.MFE_DEBUG) {
@@ -1942,7 +1944,7 @@ function setEnvironment({
1942
1944
  NEXT_PUBLIC_MFE_CURRENT_APPLICATION: app.name,
1943
1945
  NEXT_PUBLIC_MFE_CURRENT_APPLICATION_HASH: hashApplicationName(app.name),
1944
1946
  NEXT_PUBLIC_MFE_CLIENT_CONFIG: JSON.stringify(
1945
- fromIsomorphicConfig(microfrontends.config, {
1947
+ microfrontends.config.toClientConfig({
1946
1948
  removeFlaggedPaths: true
1947
1949
  }).serialize()
1948
1950
  ),
@@ -1952,10 +1954,7 @@ function setEnvironment({
1952
1954
  };
1953
1955
  const serverEnvs = {
1954
1956
  MFE_CURRENT_APPLICATION: app.name,
1955
- MFE_CONFIG: JSON.stringify(microfrontends.config.getConfig()),
1956
- MFE_CLIENT_CONFIG_FULL: JSON.stringify(
1957
- fromIsomorphicConfig(microfrontends.config).serialize()
1958
- )
1957
+ MFE_CONFIG: JSON.stringify(microfrontends.config.getConfig())
1959
1958
  };
1960
1959
  const allEnvs = { ...clientEnvs, ...serverEnvs };
1961
1960
  for (const [key, value] of Object.entries(allEnvs)) {
@@ -1980,6 +1979,7 @@ function withMicrofrontends(nextConfig, opts) {
1980
1979
  }
1981
1980
  const { name: fromApp } = getApplicationContext(opts);
1982
1981
  const microfrontends = MicrofrontendsServer.infer({
1982
+ appName: fromApp,
1983
1983
  filePath: opts?.configPath
1984
1984
  });
1985
1985
  const app = microfrontends.config.getApplication(fromApp);