@vercel/microfrontends 1.0.1-canary.0 → 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 (44) hide show
  1. package/dist/bin/cli.cjs +143 -44
  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/{sveltekit.cjs → experimental/sveltekit.cjs} +39 -26
  7. package/dist/experimental/sveltekit.cjs.map +1 -0
  8. package/dist/{sveltekit.js → experimental/sveltekit.js} +39 -26
  9. package/dist/experimental/sveltekit.js.map +1 -0
  10. package/dist/experimental/vite.cjs +1758 -0
  11. package/dist/experimental/vite.cjs.map +1 -0
  12. package/dist/experimental/vite.d.ts +29 -0
  13. package/dist/experimental/vite.js +1723 -0
  14. package/dist/experimental/vite.js.map +1 -0
  15. package/dist/microfrontends/server.cjs +39 -26
  16. package/dist/microfrontends/server.cjs.map +1 -1
  17. package/dist/microfrontends/server.js +39 -26
  18. package/dist/microfrontends/server.js.map +1 -1
  19. package/dist/microfrontends.cjs +39 -26
  20. package/dist/microfrontends.cjs.map +1 -1
  21. package/dist/microfrontends.js +39 -26
  22. package/dist/microfrontends.js.map +1 -1
  23. package/dist/next/config.cjs +220 -135
  24. package/dist/next/config.cjs.map +1 -1
  25. package/dist/next/config.d.ts +7 -1
  26. package/dist/next/config.js +220 -135
  27. package/dist/next/config.js.map +1 -1
  28. package/dist/next/middleware.cjs +69 -31
  29. package/dist/next/middleware.cjs.map +1 -1
  30. package/dist/next/middleware.js +69 -31
  31. package/dist/next/middleware.js.map +1 -1
  32. package/dist/next/testing.cjs +39 -26
  33. package/dist/next/testing.cjs.map +1 -1
  34. package/dist/next/testing.d.ts +1 -1
  35. package/dist/next/testing.js +40 -27
  36. package/dist/next/testing.js.map +1 -1
  37. package/dist/utils/mfe-port.cjs +39 -26
  38. package/dist/utils/mfe-port.cjs.map +1 -1
  39. package/dist/utils/mfe-port.js +39 -26
  40. package/dist/utils/mfe-port.js.map +1 -1
  41. package/package.json +22 -9
  42. package/dist/sveltekit.cjs.map +0 -1
  43. package/dist/sveltekit.js.map +0 -1
  44. /package/dist/{sveltekit.d.ts → experimental/sveltekit.d.ts} +0 -0
@@ -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 {
@@ -1738,35 +1773,125 @@ function transform2(args) {
1738
1773
  };
1739
1774
  }
1740
1775
 
1776
+ // src/next/utils/route-to-local-proxy.ts
1777
+ function routeToLocalProxy() {
1778
+ const isDevEnv = (process.env.VERCEL_ENV ?? "development") === "development";
1779
+ return isDevEnv && Boolean(process.env.TURBO_TASK_HAS_MFE_PROXY);
1780
+ }
1781
+
1741
1782
  // src/next/config/transforms/redirects.ts
1742
- function transform3(args) {
1783
+ function transform4(args) {
1743
1784
  const { next, microfrontend, opts } = args;
1744
1785
  const isProduction2 = opts?.isProduction ?? false;
1745
- const isDevEnv = (process.env.VERCEL_ENV ?? "development") === "development";
1746
- const requireLocalProxyHeader = !isProduction2 && isDevEnv && Boolean(process.env.TURBO_TASK_HAS_MFE_PROXY) && !process.env.MFE_DISABLE_LOCAL_PROXY_REWRITE;
1786
+ const requireLocalProxyHeader = routeToLocalProxy() && !isProduction2 && !process.env.MFE_DISABLE_LOCAL_PROXY_REWRITE;
1747
1787
  if (requireLocalProxyHeader) {
1748
- const proxyRedirect = {
1749
- source: "/:path*",
1750
- destination: `http://localhost:${microfrontend.getLocalProxyPort()}/:path*`,
1751
- permanent: false,
1752
- missing: [{ type: "header", key: "x-vercel-mfe-local-proxy-origin" }]
1753
- };
1788
+ const proxyRedirects = [
1789
+ {
1790
+ source: "/:path*",
1791
+ destination: `http://localhost:${microfrontend.getLocalProxyPort()}/:path*`,
1792
+ permanent: false,
1793
+ missing: [{ type: "header", key: "x-vercel-mfe-local-proxy-origin" }]
1794
+ }
1795
+ ];
1754
1796
  if (next.redirects && typeof next.redirects === "function") {
1755
1797
  const originalRedirectsFn = next.redirects;
1756
1798
  next.redirects = async () => {
1757
1799
  const originalRedirects = await originalRedirectsFn();
1758
- return [proxyRedirect, ...originalRedirects];
1800
+ return [...proxyRedirects, ...originalRedirects];
1759
1801
  };
1760
1802
  } else {
1761
- next.redirects = async () => [proxyRedirect];
1803
+ next.redirects = async () => proxyRedirects;
1762
1804
  }
1763
1805
  }
1764
1806
  return { next };
1765
1807
  }
1766
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
+
1767
1892
  // src/next/config/transforms/rewrites.ts
1768
1893
  function debugRewrites(rewrites) {
1769
- if (process.env.MFE_DEBUG === "true") {
1894
+ if (process.env.MFE_DEBUG === "true" || process.env.MFE_DEBUG === "1") {
1770
1895
  const indent = " ".repeat(4);
1771
1896
  const header = "rewrites (source \u2192 destination)";
1772
1897
  const separator = "\u23AF".repeat(header.length);
@@ -1796,8 +1921,8 @@ function rewritesMapToArr(rewrites) {
1796
1921
  ];
1797
1922
  });
1798
1923
  }
1799
- function transform4(args) {
1800
- const { next, app } = args;
1924
+ function transform5(args) {
1925
+ const { app, microfrontend, next, opts } = args;
1801
1926
  const buildBeforeFiles = () => {
1802
1927
  const rewrites = /* @__PURE__ */ new Map();
1803
1928
  if (!app.isDefault()) {
@@ -1816,6 +1941,15 @@ function transform4(args) {
1816
1941
  pathname: "/_vercel/:path*"
1817
1942
  }
1818
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
+ }
1819
1953
  }
1820
1954
  return rewritesMapToArr(rewrites);
1821
1955
  };
@@ -1851,89 +1985,6 @@ function transform4(args) {
1851
1985
  };
1852
1986
  }
1853
1987
 
1854
- // src/routing/get-domain-from-environment.ts
1855
- function getDomainFromEnvironment({
1856
- app,
1857
- target
1858
- }) {
1859
- const mfeProjects = JSON.parse(
1860
- process.env.VERCEL_MICROFRONTENDS_PROJECTS ?? "[]"
1861
- );
1862
- if (mfeProjects.length === 0) {
1863
- throw new Error("Missing related microfrontends project information");
1864
- }
1865
- if (!app.projectId) {
1866
- throw new Error(`Missing applications[${app.name}].vercel.projectId`);
1867
- }
1868
- const vercelProject = mfeProjects.find((p) => p.project.id === app.projectId);
1869
- if (!vercelProject) {
1870
- throw new Error(
1871
- `Missing related microfrontends project information for application "${app.name}"`
1872
- );
1873
- }
1874
- const domain = target === "preview" && vercelProject.preview.branch ? vercelProject.preview.branch : vercelProject.production.alias ?? vercelProject.production.url;
1875
- if (!domain) {
1876
- throw new Error(
1877
- `Missing domain for target "${target}" in application "${app.name}"`
1878
- );
1879
- }
1880
- return domain.startsWith("https://") ? domain : `https://${domain}`;
1881
- }
1882
-
1883
- // src/routing/get-domain-for-current-environment.ts
1884
- function debugDomains(zone, env, domain) {
1885
- if (process.env.MFE_DEBUG === "true") {
1886
- const indent = " ".repeat(4);
1887
- const header = "domains (zone (env) -> domain)";
1888
- const separator = "\u23AF".repeat(header.length);
1889
- const line = `${indent} 1. ${zone} (${env}) -> ${domain}`;
1890
- console.log(`${indent}${header}
1891
- ${indent}${separator}
1892
- ${line}
1893
- `);
1894
- }
1895
- }
1896
- function getCurrentEnvironment() {
1897
- const isDevelopment = !process.env.VERCEL_ENV || process.env.VERCEL_ENV === "development";
1898
- const isPreview = process.env.VERCEL_ENV === "preview";
1899
- const isProduction2 = process.env.VERCEL_ENV === "production";
1900
- if (isDevelopment) {
1901
- return { group: "development" };
1902
- }
1903
- if (isProduction2) {
1904
- return { group: "production" };
1905
- }
1906
- if (isPreview) {
1907
- return { group: "preview" };
1908
- }
1909
- return { group: "custom", name: process.env.VERCEL_ENV };
1910
- }
1911
- function getDomainForCurrentEnvironment(config, appName, opts = {}) {
1912
- const app = config.getApplication(appName);
1913
- if (!opts.ignoreOverride && app.overrides?.environment) {
1914
- return app.overrides.environment.toString();
1915
- }
1916
- const { group } = getCurrentEnvironment();
1917
- const fallbackHost = config.getDefaultApplication().fallback.toString();
1918
- switch (group) {
1919
- case "development": {
1920
- const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : fallbackHost;
1921
- debugDomains(appName, "development", domain);
1922
- return domain;
1923
- }
1924
- case "preview": {
1925
- return getDomainFromEnvironment({ app, target: "preview" });
1926
- }
1927
- case "production": {
1928
- return getDomainFromEnvironment({ app, target: "production" });
1929
- }
1930
- case "custom":
1931
- throw new Error(
1932
- "Custom environments are not supported in getDomainForCurrentEnvironment"
1933
- );
1934
- }
1935
- }
1936
-
1937
1988
  // src/next/config/transforms/server-actions.ts
1938
1989
  function debugRewrites2(allowedOrigins) {
1939
1990
  if (process.env.MFE_DEBUG === "true" && allowedOrigins) {
@@ -1954,7 +2005,7 @@ ${table}
1954
2005
  }
1955
2006
  }
1956
2007
  var formatDomainForServerAction = (domain) => domain.replace(/https?:\/\//, "");
1957
- function transform5(args) {
2008
+ function transform6(args) {
1958
2009
  const { next, app, microfrontend } = args;
1959
2010
  if (microfrontend instanceof MicrofrontendChildConfig) {
1960
2011
  console.warn(
@@ -2011,8 +2062,8 @@ function transform5(args) {
2011
2062
  }
2012
2063
 
2013
2064
  // src/next/config/transforms/webpack.ts
2014
- function transform6(args) {
2015
- const { next, microfrontend } = args;
2065
+ function transform7(args) {
2066
+ const { next, microfrontend, opts } = args;
2016
2067
  const configWithWebpack = {
2017
2068
  ...next,
2018
2069
  webpack(cfg, context) {
@@ -2043,6 +2094,38 @@ function transform6(args) {
2043
2094
  ...config.resolve.fallback
2044
2095
  };
2045
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
+ }
2046
2129
  return config;
2047
2130
  }
2048
2131
  };
@@ -2054,11 +2137,12 @@ function transform6(args) {
2054
2137
  // src/next/config/transforms/index.ts
2055
2138
  var transforms = {
2056
2139
  assetPrefix: transform,
2057
- draftMode: transform2,
2058
- redirects: transform3,
2059
- rewrites: transform4,
2060
- serverActions: transform5,
2061
- webpack: transform6
2140
+ buildId: transform2,
2141
+ draftMode: transform3,
2142
+ redirects: transform4,
2143
+ rewrites: transform5,
2144
+ serverActions: transform6,
2145
+ webpack: transform7
2062
2146
  };
2063
2147
 
2064
2148
  // src/next/config/env.ts
@@ -2126,18 +2210,19 @@ function withMicrofrontends(nextConfig, opts) {
2126
2210
  const app = microfrontends.config.getApplication(fromApp);
2127
2211
  setEnvironment({ app, microfrontends });
2128
2212
  let next = { ...nextConfig };
2129
- for (const [key, transform7] of typedEntries(transforms)) {
2213
+ for (const [key, transform8] of typedEntries(transforms)) {
2130
2214
  if (opts?.skipTransforms?.includes(key)) {
2131
2215
  console.log(`Skipping ${key} transform`);
2132
2216
  continue;
2133
2217
  }
2134
2218
  try {
2135
- const transformedConfig = transform7({
2219
+ const transformedConfig = transform8({
2136
2220
  app,
2137
2221
  next,
2138
2222
  microfrontend: microfrontends.config,
2139
2223
  opts: {
2140
- isProduction: isProduction(opts)
2224
+ isProduction: isProduction(opts),
2225
+ supportPagesRouter: opts?.supportPagesRouter
2141
2226
  }
2142
2227
  });
2143
2228
  next = transformedConfig.next;