@vercel/microfrontends 1.0.0 → 1.0.1-canary.1

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 (49) hide show
  1. package/dist/bin/cli.cjs +183 -27
  2. package/dist/config.cjs +46 -1
  3. package/dist/config.cjs.map +1 -1
  4. package/dist/config.d.ts +1 -1
  5. package/dist/config.js +46 -1
  6. package/dist/config.js.map +1 -1
  7. package/dist/experimental/sveltekit.cjs +1735 -0
  8. package/dist/experimental/sveltekit.cjs.map +1 -0
  9. package/dist/experimental/sveltekit.d.ts +12 -0
  10. package/dist/experimental/sveltekit.js +1698 -0
  11. package/dist/experimental/sveltekit.js.map +1 -0
  12. package/dist/experimental/vite.cjs +1745 -0
  13. package/dist/experimental/vite.cjs.map +1 -0
  14. package/dist/experimental/vite.d.ts +29 -0
  15. package/dist/experimental/vite.js +1710 -0
  16. package/dist/experimental/vite.js.map +1 -0
  17. package/dist/{index-09b1ddf9.d.ts → index-d5994ac5.d.ts} +1 -1
  18. package/dist/microfrontends/server.cjs +73 -10
  19. package/dist/microfrontends/server.cjs.map +1 -1
  20. package/dist/microfrontends/server.d.ts +1 -1
  21. package/dist/microfrontends/server.js +73 -10
  22. package/dist/microfrontends/server.js.map +1 -1
  23. package/dist/microfrontends.cjs +47 -2
  24. package/dist/microfrontends.cjs.map +1 -1
  25. package/dist/microfrontends.d.ts +1 -1
  26. package/dist/microfrontends.js +47 -2
  27. package/dist/microfrontends.js.map +1 -1
  28. package/dist/next/config.cjs +123 -51
  29. package/dist/next/config.cjs.map +1 -1
  30. package/dist/next/config.js +122 -52
  31. package/dist/next/config.js.map +1 -1
  32. package/dist/next/middleware.cjs +77 -7
  33. package/dist/next/middleware.cjs.map +1 -1
  34. package/dist/next/middleware.js +77 -7
  35. package/dist/next/middleware.js.map +1 -1
  36. package/dist/next/testing.cjs +46 -5
  37. package/dist/next/testing.cjs.map +1 -1
  38. package/dist/next/testing.d.ts +1 -1
  39. package/dist/next/testing.js +46 -5
  40. package/dist/next/testing.js.map +1 -1
  41. package/dist/utils/mfe-port.cjs +73 -10
  42. package/dist/utils/mfe-port.cjs.map +1 -1
  43. package/dist/utils/mfe-port.js +73 -10
  44. package/dist/utils/mfe-port.js.map +1 -1
  45. package/dist/validation.cjs +26 -8
  46. package/dist/validation.cjs.map +1 -1
  47. package/dist/validation.js +26 -8
  48. package/dist/validation.js.map +1 -1
  49. package/package.json +26 -2
package/dist/bin/cli.cjs CHANGED
@@ -29,7 +29,7 @@ var import_commander = require("commander");
29
29
  // package.json
30
30
  var package_default = {
31
31
  name: "@vercel/microfrontends",
32
- version: "1.0.0",
32
+ version: "1.0.1-canary.1",
33
33
  private: false,
34
34
  description: "Defines configuration and utilities for microfrontends development",
35
35
  keywords: [
@@ -54,6 +54,14 @@ var package_default = {
54
54
  import: "./dist/config.js",
55
55
  require: "./dist/config.cjs"
56
56
  },
57
+ "./experimental/sveltekit": {
58
+ import: "./dist/experimental/sveltekit.js",
59
+ require: "./dist/experimental/sveltekit.cjs"
60
+ },
61
+ "./experimental/vite": {
62
+ import: "./dist/experimental/vite.js",
63
+ require: "./dist/experimental/vite.cjs"
64
+ },
57
65
  "./microfrontends": {
58
66
  import: "./dist/microfrontends.js",
59
67
  require: "./dist/microfrontends.cjs"
@@ -111,6 +119,12 @@ var package_default = {
111
119
  config: [
112
120
  "./dist/config.d.ts"
113
121
  ],
122
+ "experimental/sveltekit": [
123
+ "./dist/experimental/sveltekit.d.ts"
124
+ ],
125
+ "experimental/vite": [
126
+ "./dist/experimental/vite.d.ts"
127
+ ],
114
128
  microfrontends: [
115
129
  "./dist/microfrontends.d.ts"
116
130
  ],
@@ -180,6 +194,7 @@ var package_default = {
180
194
  devDependencies: {
181
195
  "@edge-runtime/jest-environment": "^4.0.0",
182
196
  "@edge-runtime/types": "^3.0.2",
197
+ "@sveltejs/kit": "2.17.2",
183
198
  "@testing-library/react": "^15.0.7",
184
199
  "@types/cookie": "0.5.1",
185
200
  "@types/http-proxy": "^1.17.15",
@@ -200,16 +215,22 @@ var package_default = {
200
215
  tsup: "^6.6.2",
201
216
  tsx: "^4.6.2",
202
217
  typescript: "5.7.3",
218
+ vite: "^5.1.6",
203
219
  webpack: "5"
204
220
  },
205
221
  peerDependencies: {
222
+ "@sveltejs/kit": ">=1",
206
223
  "@vercel/analytics": ">=1.5.0",
207
224
  "@vercel/speed-insights": ">=1.2.0",
208
225
  next: ">=13",
209
226
  react: ">=17.0.0",
210
- "react-dom": ">=17.0.0"
227
+ "react-dom": ">=17.0.0",
228
+ vite: ">=5"
211
229
  },
212
230
  peerDependenciesMeta: {
231
+ "@sveltejs/kit": {
232
+ optional: true
233
+ },
213
234
  "@vercel/analytics": {
214
235
  optional: true
215
236
  },
@@ -224,6 +245,9 @@ var package_default = {
224
245
  },
225
246
  "react-dom": {
226
247
  optional: true
248
+ },
249
+ vite: {
250
+ optional: true
227
251
  }
228
252
  }
229
253
  };
@@ -470,6 +494,48 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
470
494
  );
471
495
  }
472
496
  };
497
+ var validateDeprecatedFields = (config) => {
498
+ const errors = [];
499
+ if (config.options?.vercel) {
500
+ errors.push(
501
+ `Configuration cannot contain deprecated field 'options.vercel'. Use 'options.disableOverrides' instead.`
502
+ );
503
+ }
504
+ if (config.options?.localProxy) {
505
+ errors.push(
506
+ `Configuration cannot contain deprecated field 'options.localProxy'. Use 'options.localProxyPort' instead.`
507
+ );
508
+ }
509
+ for (const [applicationId, application] of Object.entries(
510
+ config.applications
511
+ )) {
512
+ if (application.vercel) {
513
+ errors.push(
514
+ `Application '${applicationId}' cannot contain deprecated field 'vercel'. Use 'projectId' instead.`
515
+ );
516
+ }
517
+ if (application.production) {
518
+ errors.push(
519
+ `Application '${applicationId}' cannot contain deprecated field 'production'. Use 'development.fallback' instead.`
520
+ );
521
+ }
522
+ if (application.development?.local) {
523
+ errors.push(
524
+ `Application '${applicationId}' cannot contain deprecated field 'development.local'. Use 'developement.localPort' instead.`
525
+ );
526
+ }
527
+ }
528
+ if (errors.length) {
529
+ throw new MicrofrontendError(
530
+ `Microfrontends configuration file errors:
531
+ - ${errors.join("\n- ")}`,
532
+ {
533
+ type: "config",
534
+ subtype: "depcrecated_field"
535
+ }
536
+ );
537
+ }
538
+ };
473
539
 
474
540
  // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
475
541
  var PREFIX = "vc-ap";
@@ -799,7 +865,7 @@ var MicrofrontendConfigIsomorphic = class {
799
865
  }) {
800
866
  this.childApplications = {};
801
867
  MicrofrontendConfigIsomorphic.validate(config, opts);
802
- const disableOverrides = config.options?.vercel?.disableOverrides ?? false;
868
+ const disableOverrides = config.options?.disableOverrides ?? config.options?.vercel?.disableOverrides ?? false;
803
869
  this.overrides = overrides && !disableOverrides ? overrides : void 0;
804
870
  this.isMainConfig = isMainConfig(config);
805
871
  if (isMainConfig(config)) {
@@ -856,6 +922,9 @@ var MicrofrontendConfigIsomorphic = class {
856
922
  if (!skipValidation.includes("defaultApplication")) {
857
923
  validateConfigDefaultApplication(c.applications);
858
924
  }
925
+ if (!skipValidation.includes("deprecatedFields")) {
926
+ validateDeprecatedFields(c);
927
+ }
859
928
  }
860
929
  return c;
861
930
  }
@@ -977,7 +1046,7 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
977
1046
  }) {
978
1047
  super({ config, overrides, meta });
979
1048
  this.isMainConfig = true;
980
- const disableOverrides = config.options?.vercel?.disableOverrides ?? false;
1049
+ const disableOverrides = config.options?.disableOverrides ?? config.options?.vercel?.disableOverrides ?? false;
981
1050
  let defaultApplication;
982
1051
  for (const [appId, appConfig] of Object.entries(config.applications)) {
983
1052
  const appOverrides = !disableOverrides ? this.overrides?.applications[appId] : void 0;
@@ -1312,7 +1381,9 @@ var schema_default = {
1312
1381
  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"
1313
1382
  }
1314
1383
  },
1315
- required: ["applications"],
1384
+ required: [
1385
+ "applications"
1386
+ ],
1316
1387
  additionalProperties: false
1317
1388
  },
1318
1389
  Options: {
@@ -1407,7 +1478,9 @@ var schema_default = {
1407
1478
  description: "Vercel project ID"
1408
1479
  }
1409
1480
  },
1410
- required: ["projectId"],
1481
+ required: [
1482
+ "projectId"
1483
+ ],
1411
1484
  additionalProperties: false
1412
1485
  },
1413
1486
  HostConfig: {
@@ -1415,7 +1488,10 @@ var schema_default = {
1415
1488
  properties: {
1416
1489
  protocol: {
1417
1490
  type: "string",
1418
- enum: ["http", "https"],
1491
+ enum: [
1492
+ "http",
1493
+ "https"
1494
+ ],
1419
1495
  description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1420
1496
  },
1421
1497
  host: {
@@ -1427,7 +1503,9 @@ var schema_default = {
1427
1503
  description: "The port number to be used for the connection. Common values include `80` for HTTP and `443` for HTTPS."
1428
1504
  }
1429
1505
  },
1430
- required: ["host"],
1506
+ required: [
1507
+ "host"
1508
+ ],
1431
1509
  additionalProperties: false
1432
1510
  },
1433
1511
  Development: {
@@ -1469,7 +1547,10 @@ var schema_default = {
1469
1547
  },
1470
1548
  protocol: {
1471
1549
  type: "string",
1472
- enum: ["http", "https"],
1550
+ enum: [
1551
+ "http",
1552
+ "https"
1553
+ ],
1473
1554
  description: "The protocol to be used for the connection.\n- `http`: Hypertext Transfer Protocol (HTTP).\n- `https`: Secure Hypertext Transfer Protocol (HTTPS).\n\n*"
1474
1555
  },
1475
1556
  port: {
@@ -1501,7 +1582,9 @@ var schema_default = {
1501
1582
  description: "Groups of path expressions that are routed to this application."
1502
1583
  }
1503
1584
  },
1504
- required: ["routing"],
1585
+ required: [
1586
+ "routing"
1587
+ ],
1505
1588
  additionalProperties: false
1506
1589
  },
1507
1590
  Routing: {
@@ -1528,7 +1611,9 @@ var schema_default = {
1528
1611
  }
1529
1612
  }
1530
1613
  },
1531
- required: ["paths"],
1614
+ required: [
1615
+ "paths"
1616
+ ],
1532
1617
  additionalProperties: false
1533
1618
  },
1534
1619
  ChildConfig: {
@@ -1549,7 +1634,9 @@ var schema_default = {
1549
1634
  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."
1550
1635
  }
1551
1636
  },
1552
- required: ["partOf"],
1637
+ required: [
1638
+ "partOf"
1639
+ ],
1553
1640
  additionalProperties: false
1554
1641
  }
1555
1642
  }
@@ -1813,6 +1900,8 @@ var MicrofrontendsServer = class extends Microfrontends {
1813
1900
 
1814
1901
  // src/bin/local-proxy.ts
1815
1902
  var MFE_LOCAL_PROXY_HEADER = "x-vercel-mfe-local-proxy-origin";
1903
+ var MFE_FLAG_VALUE = "vercel-mfe-flag-value";
1904
+ var MFE_FLAG_VALUE_HEADER = `x-${MFE_FLAG_VALUE}`;
1816
1905
  var MFE_DEBUG = process.env.MFE_DEBUG;
1817
1906
  var mfeDebug = (message) => {
1818
1907
  if (MFE_DEBUG === "true" || MFE_DEBUG === "1") {
@@ -1904,10 +1993,10 @@ var ProxyRequestRouter = class {
1904
1993
  getTarget(request2) {
1905
1994
  const cookies = (0, import_cookie.parse)(request2.headers.cookie || "");
1906
1995
  const config = this.getConfigWithOverrides(cookies);
1907
- const path6 = request2.url;
1908
- if (!path6) {
1996
+ if (!request2.url) {
1909
1997
  return this.getDefaultHost(config);
1910
1998
  }
1999
+ const { path: path6, mfeFlagValue } = extractMfeFlagValue(request2.url);
1911
2000
  const authTarget = this.getAuthTarget(request2, config);
1912
2001
  if (authTarget) {
1913
2002
  return authTarget;
@@ -1917,7 +2006,14 @@ var ProxyRequestRouter = class {
1917
2006
  path: path6,
1918
2007
  url,
1919
2008
  applications: config.getChildApplications(),
1920
- referer: request2.headers.referer
2009
+ referer: request2.headers.referer,
2010
+ // If a request already has the local proxy header, then the request has
2011
+ // already gone through the local proxy.
2012
+ // This should only happen if middleware indicates that a flagged route
2013
+ // is enabled, so we treat this as enabling all flagged routes for this request.
2014
+ middlewareMfeZone: request2.headers["x-vercel-mfe-zone"],
2015
+ // Value to use when encountering any flagged paths instead of checking middleware
2016
+ mfeFlagValue
1921
2017
  });
1922
2018
  if (target)
1923
2019
  return target;
@@ -1931,14 +2027,23 @@ var ProxyRequestRouter = class {
1931
2027
  path: path6,
1932
2028
  url,
1933
2029
  applications,
1934
- referer = void 0
2030
+ referer = void 0,
2031
+ middlewareMfeZone = void 0,
2032
+ mfeFlagValue = void 0
1935
2033
  }) {
1936
2034
  for (const application of Object.values(applications)) {
1937
2035
  const target = this.getApplicationTarget(application);
2036
+ if (middlewareMfeZone) {
2037
+ if (middlewareMfeZone === application.name) {
2038
+ mfeDebug(
2039
+ `routing ${path6} to '${target.application}' at ${target.hostname} according to 'x-vercel-mfe-zone' header`
2040
+ );
2041
+ return { path: path6, ...target };
2042
+ }
2043
+ continue;
2044
+ }
1938
2045
  const builtInRewrite = this.checkBuiltinAssetPrefix({
1939
- rewrites: [
1940
- "/:path*"
1941
- ],
2046
+ rewrites: ["/:path*"],
1942
2047
  path: path6,
1943
2048
  url,
1944
2049
  app: application
@@ -1953,11 +2058,33 @@ var ProxyRequestRouter = class {
1953
2058
  mfeDebug(
1954
2059
  `routing ${path6} to '${target.application}' at ${target.hostname}`
1955
2060
  );
2061
+ if (group.flag) {
2062
+ if (mfeFlagValue === true) {
2063
+ } else if (mfeFlagValue === false) {
2064
+ continue;
2065
+ } else {
2066
+ mfeDebug(
2067
+ "Routing group is behind flag. Routing to default app to check flag via middleware."
2068
+ );
2069
+ if (!this.isDefaultAppLocal()) {
2070
+ const defaultApp = this.getDefaultHost(this.config);
2071
+ console.error(
2072
+ `'${path6}' is a flagged path, but the default application is not running locally. Using '${defaultApp.hostname}' to handle this request.`
2073
+ );
2074
+ }
2075
+ return null;
2076
+ }
2077
+ }
1956
2078
  return { path: path6, ...target };
1957
2079
  }
1958
2080
  }
1959
2081
  }
1960
2082
  }
2083
+ if (middlewareMfeZone) {
2084
+ console.error(
2085
+ `A request contained 'x-vercel-mfe-zone: ${middlewareMfeZone}', but no application was found with that name.`
2086
+ );
2087
+ }
1961
2088
  return null;
1962
2089
  }
1963
2090
  checkBuiltinAssetPrefix({
@@ -1968,15 +2095,13 @@ var ProxyRequestRouter = class {
1968
2095
  }) {
1969
2096
  const pathname = url.pathname;
1970
2097
  const target = this.getApplicationTarget(app);
1971
- const isTargetDefault = target.application === this.config.getDefaultApplication().name;
1972
2098
  for (const rewrite of rewrites) {
1973
2099
  if ((0, import_path_to_regexp3.pathToRegexp)(`/${app.getAssetPrefix()}${rewrite}`).test(pathname)) {
1974
2100
  mfeDebug(
1975
2101
  `routing ${pathname} to '${target.application}' at ${target.hostname}`
1976
2102
  );
1977
- const processedPath = isTargetDefault ? path6 : path6.replace(`/${app.getAssetPrefix()}`, "");
1978
2103
  return {
1979
- path: processedPath,
2104
+ path: path6,
1980
2105
  ...target
1981
2106
  };
1982
2107
  }
@@ -2008,6 +2133,9 @@ var ProxyRequestRouter = class {
2008
2133
  path: `${url.pathname}${url.search}`
2009
2134
  } : null;
2010
2135
  }
2136
+ isDefaultAppLocal() {
2137
+ return this.localApps.includes(this.config.getDefaultApplication().name);
2138
+ }
2011
2139
  };
2012
2140
  var LocalProxy = class {
2013
2141
  constructor(config, {
@@ -2070,16 +2198,14 @@ var LocalProxy = class {
2070
2198
  return;
2071
2199
  }
2072
2200
  const target = this.router.getTarget(req);
2201
+ const { req: strippedReq, mfeFlagValue } = removeMfeFlagQuery(req);
2073
2202
  if (target.protocol === "https") {
2074
2203
  const { hostname, port, path: path6 } = target;
2075
2204
  const requestOptions = {
2076
2205
  hostname,
2077
2206
  path: path6,
2078
2207
  method: req.method,
2079
- headers: {
2080
- ...req.headers,
2081
- host: hostname
2082
- },
2208
+ headers: { ...req.headers, host: hostname },
2083
2209
  port
2084
2210
  };
2085
2211
  const localhost = `http://localhost:${this.proxyPort}`;
@@ -2108,7 +2234,10 @@ var LocalProxy = class {
2108
2234
  } else {
2109
2235
  const headers = {};
2110
2236
  headers[MFE_LOCAL_PROXY_HEADER] = "1";
2111
- this.proxy.web(req, res, {
2237
+ if (mfeFlagValue !== void 0) {
2238
+ headers[MFE_FLAG_VALUE_HEADER] = mfeFlagValue.toString();
2239
+ }
2240
+ this.proxy.web(strippedReq, res, {
2112
2241
  target: target.url,
2113
2242
  headers
2114
2243
  });
@@ -2143,6 +2272,33 @@ var LocalProxy = class {
2143
2272
  return false;
2144
2273
  }
2145
2274
  };
2275
+ function extractMfeFlagValue(path6) {
2276
+ const host = "http://example.com";
2277
+ const url = new import_node_url.URL(`${host}${path6}`);
2278
+ const mfeFlagValue = stringAsBoolean(url.searchParams.get(MFE_FLAG_VALUE));
2279
+ url.searchParams.delete(MFE_FLAG_VALUE);
2280
+ const pathWithoutMfe = mfeFlagValue === void 0 ? path6 : url.toString().substring(host.length);
2281
+ return { path: pathWithoutMfe, mfeFlagValue };
2282
+ }
2283
+ function stringAsBoolean(value) {
2284
+ if (value === "true") {
2285
+ return true;
2286
+ } else if (value === "false") {
2287
+ return false;
2288
+ }
2289
+ return void 0;
2290
+ }
2291
+ function removeMfeFlagQuery(req) {
2292
+ if (!req.url) {
2293
+ return { req };
2294
+ }
2295
+ const { path: path6, mfeFlagValue } = extractMfeFlagValue(req.url);
2296
+ if (mfeFlagValue === void 0) {
2297
+ return { req };
2298
+ }
2299
+ req.url = path6;
2300
+ return { req, mfeFlagValue };
2301
+ }
2146
2302
 
2147
2303
  // src/bin/port.ts
2148
2304
  var import_node_process = require("process");
package/dist/config.cjs CHANGED
@@ -375,6 +375,48 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
375
375
  );
376
376
  }
377
377
  };
378
+ var validateDeprecatedFields = (config) => {
379
+ const errors = [];
380
+ if (config.options?.vercel) {
381
+ errors.push(
382
+ `Configuration cannot contain deprecated field 'options.vercel'. Use 'options.disableOverrides' instead.`
383
+ );
384
+ }
385
+ if (config.options?.localProxy) {
386
+ errors.push(
387
+ `Configuration cannot contain deprecated field 'options.localProxy'. Use 'options.localProxyPort' instead.`
388
+ );
389
+ }
390
+ for (const [applicationId, application] of Object.entries(
391
+ config.applications
392
+ )) {
393
+ if (application.vercel) {
394
+ errors.push(
395
+ `Application '${applicationId}' cannot contain deprecated field 'vercel'. Use 'projectId' instead.`
396
+ );
397
+ }
398
+ if (application.production) {
399
+ errors.push(
400
+ `Application '${applicationId}' cannot contain deprecated field 'production'. Use 'development.fallback' instead.`
401
+ );
402
+ }
403
+ if (application.development?.local) {
404
+ errors.push(
405
+ `Application '${applicationId}' cannot contain deprecated field 'development.local'. Use 'developement.localPort' instead.`
406
+ );
407
+ }
408
+ }
409
+ if (errors.length) {
410
+ throw new MicrofrontendError(
411
+ `Microfrontends configuration file errors:
412
+ - ${errors.join("\n- ")}`,
413
+ {
414
+ type: "config",
415
+ subtype: "depcrecated_field"
416
+ }
417
+ );
418
+ }
419
+ };
378
420
 
379
421
  // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
380
422
  var PREFIX = "vc-ap";
@@ -585,7 +627,7 @@ var MicrofrontendConfigIsomorphic = class {
585
627
  }) {
586
628
  this.childApplications = {};
587
629
  MicrofrontendConfigIsomorphic.validate(config, opts);
588
- const disableOverrides = config.options?.vercel?.disableOverrides ?? false;
630
+ const disableOverrides = config.options?.disableOverrides ?? config.options?.vercel?.disableOverrides ?? false;
589
631
  this.overrides = overrides && !disableOverrides ? overrides : void 0;
590
632
  this.isMainConfig = isMainConfig(config);
591
633
  if (isMainConfig(config)) {
@@ -642,6 +684,9 @@ var MicrofrontendConfigIsomorphic = class {
642
684
  if (!skipValidation.includes("defaultApplication")) {
643
685
  validateConfigDefaultApplication(c.applications);
644
686
  }
687
+ if (!skipValidation.includes("deprecatedFields")) {
688
+ validateDeprecatedFields(c);
689
+ }
645
690
  }
646
691
  return c;
647
692
  }