@vercel/microfrontends 2.2.1 → 2.3.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 +25 -0
  2. package/cli/index.cjs +0 -1
  3. package/dist/bin/cli.cjs +486 -397
  4. package/dist/config.cjs +193 -171
  5. package/dist/config.cjs.map +1 -1
  6. package/dist/config.d.ts +3 -2
  7. package/dist/config.js +194 -172
  8. package/dist/config.js.map +1 -1
  9. package/dist/experimental/sveltekit.cjs +585 -513
  10. package/dist/experimental/sveltekit.cjs.map +1 -1
  11. package/dist/experimental/sveltekit.js +591 -519
  12. package/dist/experimental/sveltekit.js.map +1 -1
  13. package/dist/experimental/vite.cjs +607 -535
  14. package/dist/experimental/vite.cjs.map +1 -1
  15. package/dist/experimental/vite.js +616 -544
  16. package/dist/experimental/vite.js.map +1 -1
  17. package/dist/microfrontends/server.cjs +603 -531
  18. package/dist/microfrontends/server.cjs.map +1 -1
  19. package/dist/microfrontends/server.d.ts +2 -2
  20. package/dist/microfrontends/server.js +609 -537
  21. package/dist/microfrontends/server.js.map +1 -1
  22. package/dist/microfrontends/utils.cjs +101 -50
  23. package/dist/microfrontends/utils.cjs.map +1 -1
  24. package/dist/microfrontends/utils.d.ts +4 -4
  25. package/dist/microfrontends/utils.js +102 -51
  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.d.ts +8 -8
  30. package/dist/next/client.js +1 -1
  31. package/dist/next/client.js.map +1 -1
  32. package/dist/next/config.cjs +725 -649
  33. package/dist/next/config.cjs.map +1 -1
  34. package/dist/next/config.js +722 -646
  35. package/dist/next/config.js.map +1 -1
  36. package/dist/next/middleware.cjs +246 -224
  37. package/dist/next/middleware.cjs.map +1 -1
  38. package/dist/next/middleware.js +247 -225
  39. package/dist/next/middleware.js.map +1 -1
  40. package/dist/next/testing.cjs +194 -172
  41. package/dist/next/testing.cjs.map +1 -1
  42. package/dist/next/testing.d.ts +1 -1
  43. package/dist/next/testing.js +195 -173
  44. package/dist/next/testing.js.map +1 -1
  45. package/dist/overrides.cjs +5 -5
  46. package/dist/overrides.cjs.map +1 -1
  47. package/dist/overrides.d.ts +9 -9
  48. package/dist/overrides.js +5 -5
  49. package/dist/overrides.js.map +1 -1
  50. package/dist/utils/mfe-port.cjs +622 -535
  51. package/dist/utils/mfe-port.cjs.map +1 -1
  52. package/dist/utils/mfe-port.d.ts +9 -1
  53. package/dist/utils/mfe-port.js +634 -548
  54. package/dist/utils/mfe-port.js.map +1 -1
  55. package/dist/validation.cjs +8 -24
  56. package/dist/validation.cjs.map +1 -1
  57. package/dist/validation.js +8 -24
  58. package/dist/validation.js.map +1 -1
  59. package/package.json +5 -7
package/dist/config.cjs CHANGED
@@ -127,23 +127,6 @@ var MicrofrontendError = class extends Error {
127
127
  }
128
128
  };
129
129
 
130
- // src/config/microfrontends-config/utils/get-config-from-env.ts
131
- function getConfigStringFromEnv() {
132
- const config = process.env.MFE_CONFIG;
133
- if (!config) {
134
- throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
135
- type: "config",
136
- subtype: "not_found_in_env"
137
- });
138
- }
139
- return config;
140
- }
141
-
142
- // src/config/schema/utils/is-default-app.ts
143
- function isDefaultApp(a) {
144
- return !("routing" in a);
145
- }
146
-
147
130
  // src/config/overrides/constants.ts
148
131
  var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
149
132
  var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
@@ -177,6 +160,11 @@ function parseOverrides(cookies) {
177
160
  return overridesConfig;
178
161
  }
179
162
 
163
+ // src/config/schema/utils/is-default-app.ts
164
+ function isDefaultApp(a) {
165
+ return !("routing" in a);
166
+ }
167
+
180
168
  // src/config/microfrontends-config/client/index.ts
181
169
  var import_path_to_regexp = require("path-to-regexp");
182
170
  var regexpCache = /* @__PURE__ */ new Map();
@@ -275,6 +263,183 @@ var MicrofrontendConfigClient = class {
275
263
  }
276
264
  };
277
265
 
266
+ // src/config/microfrontends-config/utils/get-config-from-env.ts
267
+ function getConfigStringFromEnv() {
268
+ const config = process.env.MFE_CONFIG;
269
+ if (!config) {
270
+ throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
271
+ type: "config",
272
+ subtype: "not_found_in_env"
273
+ });
274
+ }
275
+ return config;
276
+ }
277
+
278
+ // src/config/microfrontends-config/isomorphic/constants.ts
279
+ var DEFAULT_LOCAL_PROXY_PORT = 3024;
280
+ var MFE_APP_PORT_ENV = "MFE_APP_PORT";
281
+ var MFE_LOCAL_PROXY_PORT_ENV = "MFE_LOCAL_PROXY_PORT";
282
+
283
+ // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
284
+ function generatePortFromName({
285
+ name,
286
+ minPort = 3e3,
287
+ maxPort = 8e3
288
+ }) {
289
+ if (!name) {
290
+ throw new Error("Name is required to generate a port");
291
+ }
292
+ let hash = 0;
293
+ for (let i = 0; i < name.length; i++) {
294
+ hash = (hash << 5) - hash + name.charCodeAt(i);
295
+ hash |= 0;
296
+ }
297
+ hash = Math.abs(hash);
298
+ const range = maxPort - minPort;
299
+ const port = minPort + hash % range;
300
+ return port;
301
+ }
302
+
303
+ // src/config/microfrontends-config/isomorphic/host.ts
304
+ var Host = class {
305
+ constructor(hostConfig, options) {
306
+ if (typeof hostConfig === "string") {
307
+ ({
308
+ protocol: this.protocol,
309
+ host: this.host,
310
+ port: this.port
311
+ } = Host.parseUrl(hostConfig));
312
+ } else {
313
+ const { protocol = "https", host, port } = hostConfig;
314
+ this.protocol = protocol;
315
+ this.host = host;
316
+ this.port = port;
317
+ }
318
+ this.local = options?.isLocal;
319
+ }
320
+ static parseUrl(url, defaultProtocol = "https") {
321
+ let hostToParse = url;
322
+ if (!/^https?:\/\//.exec(hostToParse)) {
323
+ hostToParse = `${defaultProtocol}://${hostToParse}`;
324
+ }
325
+ const parsed = new URL(hostToParse);
326
+ if (!parsed.hostname) {
327
+ throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
328
+ }
329
+ if (parsed.hash) {
330
+ throw new Error(
331
+ Host.getMicrofrontendsError(url, "cannot have a fragment")
332
+ );
333
+ }
334
+ if (parsed.username || parsed.password) {
335
+ throw new Error(
336
+ Host.getMicrofrontendsError(
337
+ url,
338
+ "cannot have authentication credentials (username and/or password)"
339
+ )
340
+ );
341
+ }
342
+ if (parsed.pathname !== "/") {
343
+ throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
344
+ }
345
+ if (parsed.search) {
346
+ throw new Error(
347
+ Host.getMicrofrontendsError(url, "cannot have query parameters")
348
+ );
349
+ }
350
+ const protocol = parsed.protocol.slice(0, -1);
351
+ return {
352
+ protocol,
353
+ host: parsed.hostname,
354
+ port: parsed.port ? Number.parseInt(parsed.port, 10) : void 0
355
+ };
356
+ }
357
+ static getMicrofrontendsError(url, message) {
358
+ return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
359
+ }
360
+ isLocal() {
361
+ return this.local || this.host === "localhost" || this.host === "127.0.0.1";
362
+ }
363
+ toString() {
364
+ const url = this.toUrl();
365
+ return url.toString().replace(/\/$/, "");
366
+ }
367
+ toUrl() {
368
+ const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
369
+ return new URL(url);
370
+ }
371
+ };
372
+ var LocalHost = class extends Host {
373
+ constructor({
374
+ appName,
375
+ local
376
+ }) {
377
+ const portOverride = process.env[MFE_APP_PORT_ENV];
378
+ if (portOverride) {
379
+ const overridePort = Number.parseInt(portOverride, 10);
380
+ if (!Number.isNaN(overridePort) && overridePort > 0 && overridePort < 65536) {
381
+ super({
382
+ protocol: "http",
383
+ host: "localhost",
384
+ port: overridePort
385
+ });
386
+ return;
387
+ }
388
+ }
389
+ let protocol;
390
+ let host;
391
+ let port;
392
+ if (typeof local === "number") {
393
+ port = local;
394
+ } else if (typeof local === "string") {
395
+ if (/^\d+$/.test(local)) {
396
+ port = Number.parseInt(local, 10);
397
+ } else {
398
+ const parsed = Host.parseUrl(local, "http");
399
+ protocol = parsed.protocol;
400
+ host = parsed.host;
401
+ port = parsed.port;
402
+ }
403
+ } else if (local) {
404
+ protocol = local.protocol;
405
+ host = local.host;
406
+ port = local.port;
407
+ }
408
+ super({
409
+ protocol: protocol ?? "http",
410
+ host: host ?? "localhost",
411
+ port: port ?? generatePortFromName({ name: appName })
412
+ });
413
+ }
414
+ };
415
+
416
+ // src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
417
+ var import_md5 = __toESM(require("md5"), 1);
418
+ function hashApplicationName(name) {
419
+ if (!name) {
420
+ throw new Error("Application name is required to generate hash");
421
+ }
422
+ return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
423
+ }
424
+
425
+ // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
426
+ var PREFIX = "vc-ap";
427
+ function generateAssetPrefixFromName({
428
+ name
429
+ }) {
430
+ if (!name) {
431
+ throw new Error("Name is required to generate an asset prefix");
432
+ }
433
+ return `${PREFIX}-${hashApplicationName(name)}`;
434
+ }
435
+
436
+ // src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
437
+ function generateAutomationBypassEnvVarName({
438
+ name
439
+ }) {
440
+ return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
441
+ }
442
+
278
443
  // src/config/microfrontends-config/isomorphic/validation.ts
279
444
  var import_path_to_regexp2 = require("path-to-regexp");
280
445
  var LIST_FORMATTER = new Intl.ListFormat("en", {
@@ -348,7 +513,7 @@ var validateConfigPaths = (applicationConfigsById) => {
348
513
  );
349
514
  }
350
515
  };
351
- var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
516
+ var PATH_DEFAULT_PATTERNS = ["[^\\/#\\?]+?", "(?:(?!\\.)[^\\/#\\?])+?"];
352
517
  function validatePathExpression(path) {
353
518
  try {
354
519
  const tokens = (0, import_path_to_regexp2.parse)(path);
@@ -370,7 +535,7 @@ function validatePathExpression(path) {
370
535
  if (!token.name) {
371
536
  return `Only named wildcards are allowed: ${path} (hint: add ":path" to the wildcard)`;
372
537
  }
373
- if (token.pattern !== PATH_DEFAULT_PATTERN && // Allows (a|b|c) and ((?!a|b|c).*) regex
538
+ if (!PATH_DEFAULT_PATTERNS.includes(token.pattern) && // Allows (a|b|c) and ((?!a|b|c).*) regex
374
539
  // Only limited regex is supported for now, due to performance considerations
375
540
  // Allows all letters, numbers, and hyphens. Other characters must be escaped.
376
541
  !/^(?<allowed>[\w-~]+(?:\|[^:|()]+)+)$|^\(\?!(?<disallowed>[\w-~]+(?:\|[^:|()]+)*)\)\.\*$/.test(
@@ -456,154 +621,6 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
456
621
  }
457
622
  };
458
623
 
459
- // src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
460
- var import_md5 = __toESM(require("md5"), 1);
461
- function hashApplicationName(name) {
462
- if (!name) {
463
- throw new Error("Application name is required to generate hash");
464
- }
465
- return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
466
- }
467
-
468
- // src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
469
- var PREFIX = "vc-ap";
470
- function generateAssetPrefixFromName({
471
- name
472
- }) {
473
- if (!name) {
474
- throw new Error("Name is required to generate an asset prefix");
475
- }
476
- return `${PREFIX}-${hashApplicationName(name)}`;
477
- }
478
-
479
- // src/config/microfrontends-config/isomorphic/utils/generate-port.ts
480
- function generatePortFromName({
481
- name,
482
- minPort = 3e3,
483
- maxPort = 8e3
484
- }) {
485
- if (!name) {
486
- throw new Error("Name is required to generate a port");
487
- }
488
- let hash = 0;
489
- for (let i = 0; i < name.length; i++) {
490
- hash = (hash << 5) - hash + name.charCodeAt(i);
491
- hash |= 0;
492
- }
493
- hash = Math.abs(hash);
494
- const range = maxPort - minPort;
495
- const port = minPort + hash % range;
496
- return port;
497
- }
498
-
499
- // src/config/microfrontends-config/isomorphic/host.ts
500
- var Host = class {
501
- constructor(hostConfig, options) {
502
- if (typeof hostConfig === "string") {
503
- ({
504
- protocol: this.protocol,
505
- host: this.host,
506
- port: this.port
507
- } = Host.parseUrl(hostConfig));
508
- } else {
509
- const { protocol = "https", host, port } = hostConfig;
510
- this.protocol = protocol;
511
- this.host = host;
512
- this.port = port;
513
- }
514
- this.local = options?.isLocal;
515
- }
516
- static parseUrl(url, defaultProtocol = "https") {
517
- let hostToParse = url;
518
- if (!/^https?:\/\//.exec(hostToParse)) {
519
- hostToParse = `${defaultProtocol}://${hostToParse}`;
520
- }
521
- const parsed = new URL(hostToParse);
522
- if (!parsed.hostname) {
523
- throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
524
- }
525
- if (parsed.hash) {
526
- throw new Error(
527
- Host.getMicrofrontendsError(url, "cannot have a fragment")
528
- );
529
- }
530
- if (parsed.username || parsed.password) {
531
- throw new Error(
532
- Host.getMicrofrontendsError(
533
- url,
534
- "cannot have authentication credentials (username and/or password)"
535
- )
536
- );
537
- }
538
- if (parsed.pathname !== "/") {
539
- throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
540
- }
541
- if (parsed.search) {
542
- throw new Error(
543
- Host.getMicrofrontendsError(url, "cannot have query parameters")
544
- );
545
- }
546
- const protocol = parsed.protocol.slice(0, -1);
547
- return {
548
- protocol,
549
- host: parsed.hostname,
550
- port: parsed.port ? Number.parseInt(parsed.port) : void 0
551
- };
552
- }
553
- static getMicrofrontendsError(url, message) {
554
- return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
555
- }
556
- isLocal() {
557
- return this.local || this.host === "localhost" || this.host === "127.0.0.1";
558
- }
559
- toString() {
560
- const url = this.toUrl();
561
- return url.toString().replace(/\/$/, "");
562
- }
563
- toUrl() {
564
- const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
565
- return new URL(url);
566
- }
567
- };
568
- var LocalHost = class extends Host {
569
- constructor({
570
- appName,
571
- local
572
- }) {
573
- let protocol;
574
- let host;
575
- let port;
576
- if (typeof local === "number") {
577
- port = local;
578
- } else if (typeof local === "string") {
579
- if (/^\d+$/.test(local)) {
580
- port = Number.parseInt(local);
581
- } else {
582
- const parsed = Host.parseUrl(local, "http");
583
- protocol = parsed.protocol;
584
- host = parsed.host;
585
- port = parsed.port;
586
- }
587
- } else if (local) {
588
- protocol = local.protocol;
589
- host = local.host;
590
- port = local.port;
591
- }
592
- super({
593
- protocol: protocol ?? "http",
594
- host: host ?? "localhost",
595
- port: port ?? generatePortFromName({ name: appName })
596
- });
597
- }
598
- };
599
-
600
- // src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
601
- function generateAutomationBypassEnvVarName({
602
- name
603
- }) {
604
- return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
605
- }
606
-
607
624
  // src/config/microfrontends-config/isomorphic/application.ts
608
625
  var Application = class {
609
626
  constructor(name, {
@@ -684,9 +701,6 @@ var ChildApplication = class extends Application {
684
701
  }
685
702
  };
686
703
 
687
- // src/config/microfrontends-config/isomorphic/constants.ts
688
- var DEFAULT_LOCAL_PROXY_PORT = 3024;
689
-
690
704
  // src/config/microfrontends-config/isomorphic/index.ts
691
705
  var MicrofrontendConfigIsomorphic = class {
692
706
  constructor({
@@ -805,9 +819,17 @@ var MicrofrontendConfigIsomorphic = class {
805
819
  return this.defaultApplication;
806
820
  }
807
821
  /**
808
- * Returns the configured port for the local proxy
822
+ * Returns the configured port for the local proxy.
823
+ * Can be overridden via MFE_LOCAL_PROXY_PORT environment variable.
809
824
  */
810
825
  getLocalProxyPort() {
826
+ const portOverride = process.env[MFE_LOCAL_PROXY_PORT_ENV];
827
+ if (portOverride) {
828
+ const port = Number.parseInt(portOverride, 10);
829
+ if (!Number.isNaN(port) && port > 0 && port < 65536) {
830
+ return port;
831
+ }
832
+ }
811
833
  return this.config.options?.localProxyPort ?? DEFAULT_LOCAL_PROXY_PORT;
812
834
  }
813
835
  toClientConfig(options) {