@vercel/microfrontends 1.0.1-canary.1 → 1.0.1-canary.2

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 (40) hide show
  1. package/dist/bin/cli.cjs +41 -27
  2. package/dist/config.cjs +39 -26
  3. package/dist/config.cjs.map +1 -1
  4. package/dist/config.js +39 -26
  5. package/dist/config.js.map +1 -1
  6. package/dist/experimental/sveltekit.cjs +39 -26
  7. package/dist/experimental/sveltekit.cjs.map +1 -1
  8. package/dist/experimental/sveltekit.js +39 -26
  9. package/dist/experimental/sveltekit.js.map +1 -1
  10. package/dist/experimental/vite.cjs +39 -26
  11. package/dist/experimental/vite.cjs.map +1 -1
  12. package/dist/experimental/vite.js +39 -26
  13. package/dist/experimental/vite.js.map +1 -1
  14. package/dist/microfrontends/server.cjs +39 -26
  15. package/dist/microfrontends/server.cjs.map +1 -1
  16. package/dist/microfrontends/server.js +39 -26
  17. package/dist/microfrontends/server.js.map +1 -1
  18. package/dist/microfrontends.cjs +39 -26
  19. package/dist/microfrontends.cjs.map +1 -1
  20. package/dist/microfrontends.js +39 -26
  21. package/dist/microfrontends.js.map +1 -1
  22. package/dist/next/config.cjs +203 -125
  23. package/dist/next/config.cjs.map +1 -1
  24. package/dist/next/config.d.ts +7 -1
  25. package/dist/next/config.js +203 -125
  26. package/dist/next/config.js.map +1 -1
  27. package/dist/next/middleware.cjs +39 -26
  28. package/dist/next/middleware.cjs.map +1 -1
  29. package/dist/next/middleware.js +39 -26
  30. package/dist/next/middleware.js.map +1 -1
  31. package/dist/next/testing.cjs +39 -26
  32. package/dist/next/testing.cjs.map +1 -1
  33. package/dist/next/testing.d.ts +1 -1
  34. package/dist/next/testing.js +40 -27
  35. package/dist/next/testing.js.map +1 -1
  36. package/dist/utils/mfe-port.cjs +39 -26
  37. package/dist/utils/mfe-port.cjs.map +1 -1
  38. package/dist/utils/mfe-port.js +39 -26
  39. package/dist/utils/mfe-port.js.map +1 -1
  40. package/package.json +2 -1
@@ -281,16 +281,17 @@ var validateConfigPaths = (applicationConfigsById) => {
281
281
  const maybeError = validatePathExpression(path5);
282
282
  if (maybeError) {
283
283
  errors.push(maybeError);
284
- }
285
- const existing = pathsByApplicationId.get(path5);
286
- if (existing) {
287
- existing.applications.push(id);
288
284
  } else {
289
- pathsByApplicationId.set(path5, {
290
- applications: [id],
291
- matcher: (0, import_path_to_regexp2.pathToRegexp)(path5),
292
- applicationId: id
293
- });
285
+ const existing = pathsByApplicationId.get(path5);
286
+ if (existing) {
287
+ existing.applications.push(id);
288
+ } else {
289
+ pathsByApplicationId.set(path5, {
290
+ applications: [id],
291
+ matcher: (0, import_path_to_regexp2.pathToRegexp)(path5),
292
+ applicationId: id
293
+ });
294
+ }
294
295
  }
295
296
  }
296
297
  }
@@ -330,26 +331,38 @@ var validateConfigPaths = (applicationConfigsById) => {
330
331
  };
331
332
  var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
332
333
  function validatePathExpression(path5) {
333
- const tokens = (0, import_path_to_regexp2.parse)(path5);
334
- for (let i = 0; i < tokens.length; i++) {
335
- const token = tokens[i];
336
- if (token === void 0) {
337
- return `token ${i} in ${path5} is undefined, this shouldn't happen`;
338
- }
339
- if (typeof token !== "string") {
340
- if (token.pattern !== PATH_DEFAULT_PATTERN) {
341
- return `Path ${path5} cannot use a regular expression wildcard`;
342
- }
343
- if (token.prefix !== "/") {
344
- return `Wildcard :${token.name} must be immediately after a / in ${path5}`;
345
- }
346
- if (token.suffix) {
347
- return `Wildcard suffix on :${token.name} is not allowed. Suffixes are not supported`;
334
+ try {
335
+ const tokens = (0, import_path_to_regexp2.parse)(path5);
336
+ if (/(?<!\\)\{/.test(path5)) {
337
+ return `Optional paths are not supported: ${path5}`;
338
+ }
339
+ if (/(?<!\\|\()\?/.test(path5)) {
340
+ return `Optional paths are not supported: ${path5}`;
341
+ }
342
+ if (/\/[^/]*(?<!\\):[^/]*(?<!\\):[^/]*/.test(path5)) {
343
+ return `Only one wildcard is allowed per path segment: ${path5}`;
344
+ }
345
+ for (let i = 0; i < tokens.length; i++) {
346
+ const token = tokens[i];
347
+ if (token === void 0) {
348
+ return `token ${i} in ${path5} is undefined, this shouldn't happen`;
348
349
  }
349
- if (token.modifier && i !== tokens.length - 1) {
350
- return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path5}. Modifiers are only allowed in the last path component`;
350
+ if (typeof token !== "string") {
351
+ if (token.pattern !== PATH_DEFAULT_PATTERN && // Allows (a|b|c) and ((?!a|b|c).*) regex
352
+ // Only limited regex is supported for now, due to performance considerations
353
+ !/^(?<allowed>[\w]+(?:\|[^|()]+)+)$|^\(\?!(?<disallowed>[\w]+(?:\|[^|()]+)+)\)\.\*$/.test(
354
+ token.pattern
355
+ )) {
356
+ return `Path ${path5} cannot use unsupported regular expression wildcard`;
357
+ }
358
+ if (token.modifier && i !== tokens.length - 1) {
359
+ return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path5}. Modifiers are only allowed in the last path component`;
360
+ }
351
361
  }
352
362
  }
363
+ } catch (e) {
364
+ const message = e instanceof Error ? e.message : String(e);
365
+ return `Path ${path5} could not be parsed into regexp: ${message}`;
353
366
  }
354
367
  return void 0;
355
368
  }
@@ -1723,8 +1736,30 @@ function transform(args) {
1723
1736
  };
1724
1737
  }
1725
1738
 
1726
- // src/next/config/transforms/draft-mode.ts
1739
+ // src/next/config/transforms/build-id.ts
1740
+ var import_nanoid = require("nanoid");
1727
1741
  function transform2(args) {
1742
+ const { app, next, opts } = args;
1743
+ if (!opts?.supportPagesRouter) {
1744
+ return { next };
1745
+ }
1746
+ if (next.generateBuildId !== void 0) {
1747
+ throw new Error(
1748
+ '"generateBuildId" must not already be set in next.config.js when using microfrontends with "supportPagesRouter"'
1749
+ );
1750
+ }
1751
+ if (!app.isDefault()) {
1752
+ next.generateBuildId = () => {
1753
+ return `${app.getAssetPrefix()}-${(0, import_nanoid.nanoid)()}`;
1754
+ };
1755
+ }
1756
+ return {
1757
+ next
1758
+ };
1759
+ }
1760
+
1761
+ // src/next/config/transforms/draft-mode.ts
1762
+ function transform3(args) {
1728
1763
  const { next } = args;
1729
1764
  if (next.experimental?.multiZoneDraftMode !== void 0) {
1730
1765
  return {
@@ -1745,7 +1780,7 @@ function routeToLocalProxy() {
1745
1780
  }
1746
1781
 
1747
1782
  // src/next/config/transforms/redirects.ts
1748
- function transform3(args) {
1783
+ function transform4(args) {
1749
1784
  const { next, microfrontend, opts } = args;
1750
1785
  const isProduction2 = opts?.isProduction ?? false;
1751
1786
  const requireLocalProxyHeader = routeToLocalProxy() && !isProduction2 && !process.env.MFE_DISABLE_LOCAL_PROXY_REWRITE;
@@ -1771,9 +1806,92 @@ function transform3(args) {
1771
1806
  return { next };
1772
1807
  }
1773
1808
 
1809
+ // src/routing/get-domain-from-environment.ts
1810
+ function getDomainFromEnvironment({
1811
+ app,
1812
+ target
1813
+ }) {
1814
+ const mfeProjects = JSON.parse(
1815
+ process.env.VERCEL_MICROFRONTENDS_PROJECTS ?? "[]"
1816
+ );
1817
+ if (mfeProjects.length === 0) {
1818
+ throw new Error("Missing related microfrontends project information");
1819
+ }
1820
+ if (!app.projectId) {
1821
+ throw new Error(`Missing applications[${app.name}].vercel.projectId`);
1822
+ }
1823
+ const vercelProject = mfeProjects.find((p) => p.project.id === app.projectId);
1824
+ if (!vercelProject) {
1825
+ throw new Error(
1826
+ `Missing related microfrontends project information for application "${app.name}"`
1827
+ );
1828
+ }
1829
+ const domain = target === "preview" && vercelProject.preview.branch ? vercelProject.preview.branch : vercelProject.production.alias ?? vercelProject.production.url;
1830
+ if (!domain) {
1831
+ throw new Error(
1832
+ `Missing domain for target "${target}" in application "${app.name}"`
1833
+ );
1834
+ }
1835
+ return domain.startsWith("https://") ? domain : `https://${domain}`;
1836
+ }
1837
+
1838
+ // src/routing/get-domain-for-current-environment.ts
1839
+ function debugDomains(zone, env, domain) {
1840
+ if (process.env.MFE_DEBUG === "true") {
1841
+ const indent = " ".repeat(4);
1842
+ const header = "domains (zone (env) -> domain)";
1843
+ const separator = "\u23AF".repeat(header.length);
1844
+ const line = `${indent} 1. ${zone} (${env}) -> ${domain}`;
1845
+ console.log(`${indent}${header}
1846
+ ${indent}${separator}
1847
+ ${line}
1848
+ `);
1849
+ }
1850
+ }
1851
+ function getCurrentEnvironment() {
1852
+ const isDevelopment = !process.env.VERCEL_ENV || process.env.VERCEL_ENV === "development";
1853
+ const isPreview = process.env.VERCEL_ENV === "preview";
1854
+ const isProduction2 = process.env.VERCEL_ENV === "production";
1855
+ if (isDevelopment) {
1856
+ return { group: "development" };
1857
+ }
1858
+ if (isProduction2) {
1859
+ return { group: "production" };
1860
+ }
1861
+ if (isPreview) {
1862
+ return { group: "preview" };
1863
+ }
1864
+ return { group: "custom", name: process.env.VERCEL_ENV };
1865
+ }
1866
+ function getDomainForCurrentEnvironment(config, appName, opts = {}) {
1867
+ const app = config.getApplication(appName);
1868
+ if (!opts.ignoreOverride && app.overrides?.environment) {
1869
+ return app.overrides.environment.toString();
1870
+ }
1871
+ const { group } = getCurrentEnvironment();
1872
+ const fallbackHost = config.getDefaultApplication().fallback.toString();
1873
+ switch (group) {
1874
+ case "development": {
1875
+ const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : fallbackHost;
1876
+ debugDomains(appName, "development", domain);
1877
+ return domain;
1878
+ }
1879
+ case "preview": {
1880
+ return getDomainFromEnvironment({ app, target: "preview" });
1881
+ }
1882
+ case "production": {
1883
+ return getDomainFromEnvironment({ app, target: "production" });
1884
+ }
1885
+ case "custom":
1886
+ throw new Error(
1887
+ "Custom environments are not supported in getDomainForCurrentEnvironment"
1888
+ );
1889
+ }
1890
+ }
1891
+
1774
1892
  // src/next/config/transforms/rewrites.ts
1775
1893
  function debugRewrites(rewrites) {
1776
- if (process.env.MFE_DEBUG === "true") {
1894
+ if (process.env.MFE_DEBUG === "true" || process.env.MFE_DEBUG === "1") {
1777
1895
  const indent = " ".repeat(4);
1778
1896
  const header = "rewrites (source \u2192 destination)";
1779
1897
  const separator = "\u23AF".repeat(header.length);
@@ -1803,8 +1921,8 @@ function rewritesMapToArr(rewrites) {
1803
1921
  ];
1804
1922
  });
1805
1923
  }
1806
- function transform4(args) {
1807
- const { next, app } = args;
1924
+ function transform5(args) {
1925
+ const { app, microfrontend, next, opts } = args;
1808
1926
  const buildBeforeFiles = () => {
1809
1927
  const rewrites = /* @__PURE__ */ new Map();
1810
1928
  if (!app.isDefault()) {
@@ -1823,6 +1941,15 @@ function transform4(args) {
1823
1941
  pathname: "/_vercel/:path*"
1824
1942
  }
1825
1943
  });
1944
+ } else if (opts?.supportPagesRouter && !(microfrontend instanceof MicrofrontendChildConfig)) {
1945
+ for (const child of microfrontend.getChildApplications()) {
1946
+ rewrites.set(`/_next/data/${child.getAssetPrefix()}-:buildId/:path*`, {
1947
+ destination: {
1948
+ domain: getDomainForCurrentEnvironment(microfrontend, child.name),
1949
+ pathname: `/_next/data/${child.getAssetPrefix()}-:buildId/:path*`
1950
+ }
1951
+ });
1952
+ }
1826
1953
  }
1827
1954
  return rewritesMapToArr(rewrites);
1828
1955
  };
@@ -1858,89 +1985,6 @@ function transform4(args) {
1858
1985
  };
1859
1986
  }
1860
1987
 
1861
- // src/routing/get-domain-from-environment.ts
1862
- function getDomainFromEnvironment({
1863
- app,
1864
- target
1865
- }) {
1866
- const mfeProjects = JSON.parse(
1867
- process.env.VERCEL_MICROFRONTENDS_PROJECTS ?? "[]"
1868
- );
1869
- if (mfeProjects.length === 0) {
1870
- throw new Error("Missing related microfrontends project information");
1871
- }
1872
- if (!app.projectId) {
1873
- throw new Error(`Missing applications[${app.name}].vercel.projectId`);
1874
- }
1875
- const vercelProject = mfeProjects.find((p) => p.project.id === app.projectId);
1876
- if (!vercelProject) {
1877
- throw new Error(
1878
- `Missing related microfrontends project information for application "${app.name}"`
1879
- );
1880
- }
1881
- const domain = target === "preview" && vercelProject.preview.branch ? vercelProject.preview.branch : vercelProject.production.alias ?? vercelProject.production.url;
1882
- if (!domain) {
1883
- throw new Error(
1884
- `Missing domain for target "${target}" in application "${app.name}"`
1885
- );
1886
- }
1887
- return domain.startsWith("https://") ? domain : `https://${domain}`;
1888
- }
1889
-
1890
- // src/routing/get-domain-for-current-environment.ts
1891
- function debugDomains(zone, env, domain) {
1892
- if (process.env.MFE_DEBUG === "true") {
1893
- const indent = " ".repeat(4);
1894
- const header = "domains (zone (env) -> domain)";
1895
- const separator = "\u23AF".repeat(header.length);
1896
- const line = `${indent} 1. ${zone} (${env}) -> ${domain}`;
1897
- console.log(`${indent}${header}
1898
- ${indent}${separator}
1899
- ${line}
1900
- `);
1901
- }
1902
- }
1903
- function getCurrentEnvironment() {
1904
- const isDevelopment = !process.env.VERCEL_ENV || process.env.VERCEL_ENV === "development";
1905
- const isPreview = process.env.VERCEL_ENV === "preview";
1906
- const isProduction2 = process.env.VERCEL_ENV === "production";
1907
- if (isDevelopment) {
1908
- return { group: "development" };
1909
- }
1910
- if (isProduction2) {
1911
- return { group: "production" };
1912
- }
1913
- if (isPreview) {
1914
- return { group: "preview" };
1915
- }
1916
- return { group: "custom", name: process.env.VERCEL_ENV };
1917
- }
1918
- function getDomainForCurrentEnvironment(config, appName, opts = {}) {
1919
- const app = config.getApplication(appName);
1920
- if (!opts.ignoreOverride && app.overrides?.environment) {
1921
- return app.overrides.environment.toString();
1922
- }
1923
- const { group } = getCurrentEnvironment();
1924
- const fallbackHost = config.getDefaultApplication().fallback.toString();
1925
- switch (group) {
1926
- case "development": {
1927
- const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : fallbackHost;
1928
- debugDomains(appName, "development", domain);
1929
- return domain;
1930
- }
1931
- case "preview": {
1932
- return getDomainFromEnvironment({ app, target: "preview" });
1933
- }
1934
- case "production": {
1935
- return getDomainFromEnvironment({ app, target: "production" });
1936
- }
1937
- case "custom":
1938
- throw new Error(
1939
- "Custom environments are not supported in getDomainForCurrentEnvironment"
1940
- );
1941
- }
1942
- }
1943
-
1944
1988
  // src/next/config/transforms/server-actions.ts
1945
1989
  function debugRewrites2(allowedOrigins) {
1946
1990
  if (process.env.MFE_DEBUG === "true" && allowedOrigins) {
@@ -1961,7 +2005,7 @@ ${table}
1961
2005
  }
1962
2006
  }
1963
2007
  var formatDomainForServerAction = (domain) => domain.replace(/https?:\/\//, "");
1964
- function transform5(args) {
2008
+ function transform6(args) {
1965
2009
  const { next, app, microfrontend } = args;
1966
2010
  if (microfrontend instanceof MicrofrontendChildConfig) {
1967
2011
  console.warn(
@@ -2018,8 +2062,8 @@ function transform5(args) {
2018
2062
  }
2019
2063
 
2020
2064
  // src/next/config/transforms/webpack.ts
2021
- function transform6(args) {
2022
- const { next, microfrontend } = args;
2065
+ function transform7(args) {
2066
+ const { next, microfrontend, opts } = args;
2023
2067
  const configWithWebpack = {
2024
2068
  ...next,
2025
2069
  webpack(cfg, context) {
@@ -2050,6 +2094,38 @@ function transform6(args) {
2050
2094
  ...config.resolve.fallback
2051
2095
  };
2052
2096
  }
2097
+ if (opts?.supportPagesRouter) {
2098
+ config.optimization.moduleIds = "deterministic";
2099
+ config.optimization.chunkIds = "deterministic";
2100
+ config.plugins.push({
2101
+ apply: (compiler) => {
2102
+ compiler.hooks.compilation.tap(
2103
+ "SortChunksPlugin",
2104
+ (compilation) => {
2105
+ compilation.hooks.optimizeChunks.tap(
2106
+ "SortChunksPlugin",
2107
+ (chunks) => {
2108
+ const sortedChunks = Array.from(chunks).sort((a, b) => {
2109
+ if (a.name && b.name) {
2110
+ return a.name.localeCompare(b.name);
2111
+ }
2112
+ return (String(a.id) || "").localeCompare(
2113
+ String(b.id) || ""
2114
+ );
2115
+ });
2116
+ Array.from(chunks).forEach((chunk) => {
2117
+ compilation.chunks.delete(chunk);
2118
+ });
2119
+ sortedChunks.forEach((chunk) => {
2120
+ compilation.chunks.add(chunk);
2121
+ });
2122
+ }
2123
+ );
2124
+ }
2125
+ );
2126
+ }
2127
+ });
2128
+ }
2053
2129
  return config;
2054
2130
  }
2055
2131
  };
@@ -2061,11 +2137,12 @@ function transform6(args) {
2061
2137
  // src/next/config/transforms/index.ts
2062
2138
  var transforms = {
2063
2139
  assetPrefix: transform,
2064
- draftMode: transform2,
2065
- redirects: transform3,
2066
- rewrites: transform4,
2067
- serverActions: transform5,
2068
- webpack: transform6
2140
+ buildId: transform2,
2141
+ draftMode: transform3,
2142
+ redirects: transform4,
2143
+ rewrites: transform5,
2144
+ serverActions: transform6,
2145
+ webpack: transform7
2069
2146
  };
2070
2147
 
2071
2148
  // src/next/config/env.ts
@@ -2133,18 +2210,19 @@ function withMicrofrontends(nextConfig, opts) {
2133
2210
  const app = microfrontends.config.getApplication(fromApp);
2134
2211
  setEnvironment({ app, microfrontends });
2135
2212
  let next = { ...nextConfig };
2136
- for (const [key, transform7] of typedEntries(transforms)) {
2213
+ for (const [key, transform8] of typedEntries(transforms)) {
2137
2214
  if (opts?.skipTransforms?.includes(key)) {
2138
2215
  console.log(`Skipping ${key} transform`);
2139
2216
  continue;
2140
2217
  }
2141
2218
  try {
2142
- const transformedConfig = transform7({
2219
+ const transformedConfig = transform8({
2143
2220
  app,
2144
2221
  next,
2145
2222
  microfrontend: microfrontends.config,
2146
2223
  opts: {
2147
- isProduction: isProduction(opts)
2224
+ isProduction: isProduction(opts),
2225
+ supportPagesRouter: opts?.supportPagesRouter
2148
2226
  }
2149
2227
  });
2150
2228
  next = transformedConfig.next;