@vercel/microfrontends 0.17.4 → 0.19.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.
- package/README.md +7 -159
- package/dist/bin/cli.cjs +202 -139
- package/dist/config.cjs +103 -57
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.js +103 -57
- package/dist/config.js.map +1 -1
- package/dist/{index-f094deb1.d.ts → index-09b1ddf9.d.ts} +16 -19
- package/dist/{index-5fcf0863.d.ts → index-2f78c0ca.d.ts} +44 -17
- package/dist/microfrontends/server.cjs +180 -133
- package/dist/microfrontends/server.cjs.map +1 -1
- package/dist/microfrontends/server.d.ts +4 -4
- package/dist/microfrontends/server.js +180 -133
- package/dist/microfrontends/server.js.map +1 -1
- package/dist/microfrontends.cjs +104 -58
- package/dist/microfrontends.cjs.map +1 -1
- package/dist/microfrontends.d.ts +4 -4
- package/dist/microfrontends.js +104 -58
- package/dist/microfrontends.js.map +1 -1
- package/dist/next/client.cjs +1 -1
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.d.ts +1 -1
- package/dist/next/client.js +1 -1
- package/dist/next/client.js.map +1 -1
- package/dist/next/config.cjs +197 -145
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +197 -145
- package/dist/next/config.js.map +1 -1
- package/dist/next/endpoints.d.ts +2 -2
- package/dist/next/middleware.cjs +121 -80
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.js +121 -80
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +110 -63
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.d.ts +4 -4
- package/dist/next/testing.js +110 -63
- package/dist/next/testing.js.map +1 -1
- package/dist/overrides.d.ts +3 -3
- package/dist/schema.d.ts +1 -1
- package/dist/{types-5900be7c.d.ts → types-4ef2bddb.d.ts} +1 -1
- package/dist/{types-ecd7b91b.d.ts → types-b6d38aea.d.ts} +1 -1
- package/dist/utils/mfe-port.cjs +181 -134
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.js +181 -134
- package/dist/utils/mfe-port.js.map +1 -1
- package/dist/validation.cjs +74 -73
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +74 -73
- package/dist/validation.js.map +1 -1
- package/package.json +19 -3
- package/schema/schema.json +80 -73
package/dist/next/middleware.js
CHANGED
|
@@ -8,7 +8,7 @@ import { parse } from "jsonc-parser";
|
|
|
8
8
|
// src/config/errors.ts
|
|
9
9
|
var MicrofrontendError = class extends Error {
|
|
10
10
|
constructor(message, opts) {
|
|
11
|
-
super(message);
|
|
11
|
+
super(message, { cause: opts?.cause });
|
|
12
12
|
this.name = "MicrofrontendsError";
|
|
13
13
|
this.source = opts?.source ?? "@vercel/microfrontends";
|
|
14
14
|
this.type = opts?.type ?? "unknown";
|
|
@@ -230,7 +230,8 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
230
230
|
if (isDefaultApp(app)) {
|
|
231
231
|
continue;
|
|
232
232
|
}
|
|
233
|
-
|
|
233
|
+
const childApp = app;
|
|
234
|
+
for (const pathMatch of childApp.routing) {
|
|
234
235
|
for (const path of pathMatch.paths) {
|
|
235
236
|
const maybeError = validatePathExpression(path);
|
|
236
237
|
if (maybeError) {
|
|
@@ -250,33 +251,31 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
250
251
|
}
|
|
251
252
|
}
|
|
252
253
|
const entries = Array.from(pathsByApplicationId.entries());
|
|
253
|
-
|
|
254
|
+
for (const [path, { applications: ids, matcher, applicationId }] of entries) {
|
|
254
255
|
if (ids.length > 1) {
|
|
255
256
|
errors.push(
|
|
256
257
|
`Duplicate path "${path}" for applications "${ids.join(", ")}"`
|
|
257
258
|
);
|
|
258
259
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
if (applicationId === matchApplicationId) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (matcher.test(matchPath)) {
|
|
271
|
-
const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
272
|
-
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
273
|
-
errors.push(
|
|
274
|
-
`Overlapping path detected between ${source} and ${destination}`
|
|
275
|
-
);
|
|
276
|
-
}
|
|
260
|
+
for (const [
|
|
261
|
+
matchPath,
|
|
262
|
+
{ applications: matchIds, applicationId: matchApplicationId }
|
|
263
|
+
] of entries) {
|
|
264
|
+
if (path === matchPath) {
|
|
265
|
+
continue;
|
|
277
266
|
}
|
|
278
|
-
|
|
279
|
-
|
|
267
|
+
if (applicationId === matchApplicationId) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (matcher.test(matchPath)) {
|
|
271
|
+
const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
272
|
+
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
273
|
+
errors.push(
|
|
274
|
+
`Overlapping path detected between ${source} and ${destination}`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
280
279
|
if (errors.length) {
|
|
281
280
|
throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
|
|
282
281
|
type: "config",
|
|
@@ -345,7 +344,7 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
345
344
|
const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
|
|
346
345
|
if (numApplicationsWithoutRouting === 0) {
|
|
347
346
|
throw new MicrofrontendError(
|
|
348
|
-
|
|
347
|
+
"No default application found. At least one application needs to be the default by omitting routing.",
|
|
349
348
|
{ type: "config", subtype: "no_default_application" }
|
|
350
349
|
);
|
|
351
350
|
}
|
|
@@ -391,47 +390,80 @@ function generatePortFromName({
|
|
|
391
390
|
// src/config/microfrontends-config/isomorphic/host.ts
|
|
392
391
|
var Host = class {
|
|
393
392
|
constructor(hostConfig, options) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
393
|
+
if (typeof hostConfig === "string") {
|
|
394
|
+
({
|
|
395
|
+
protocol: this.protocol,
|
|
396
|
+
host: this.host,
|
|
397
|
+
port: this.port
|
|
398
|
+
} = Host.parseUrl(hostConfig));
|
|
399
|
+
} else {
|
|
400
|
+
const { protocol = "https", host, port } = hostConfig;
|
|
401
|
+
this.protocol = protocol;
|
|
402
|
+
this.host = host;
|
|
403
|
+
this.port = port;
|
|
404
|
+
}
|
|
398
405
|
this.local = options?.isLocal;
|
|
399
406
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
protocol,
|
|
405
|
-
port
|
|
406
|
-
}) {
|
|
407
|
-
if (!port) {
|
|
408
|
-
if (protocol === "http") {
|
|
409
|
-
return 80;
|
|
410
|
-
}
|
|
411
|
-
return 443;
|
|
407
|
+
static parseUrl(url) {
|
|
408
|
+
let hostToParse = url;
|
|
409
|
+
if (!/^https?:\/\//.exec(hostToParse)) {
|
|
410
|
+
hostToParse = `https://${hostToParse}`;
|
|
412
411
|
}
|
|
413
|
-
|
|
412
|
+
const parsed = new URL(hostToParse);
|
|
413
|
+
if (!parsed.hostname) {
|
|
414
|
+
throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
|
|
415
|
+
}
|
|
416
|
+
if (parsed.hash) {
|
|
417
|
+
throw new Error(
|
|
418
|
+
Host.getMicrofrontendsError(url, "cannot have a fragment")
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
if (parsed.username || parsed.password) {
|
|
422
|
+
throw new Error(
|
|
423
|
+
Host.getMicrofrontendsError(
|
|
424
|
+
url,
|
|
425
|
+
"cannot have authentication credentials (username and/or password)"
|
|
426
|
+
)
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
if (parsed.pathname !== "/") {
|
|
430
|
+
throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
|
|
431
|
+
}
|
|
432
|
+
if (parsed.search) {
|
|
433
|
+
throw new Error(
|
|
434
|
+
Host.getMicrofrontendsError(url, "cannot have query parameters")
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
const protocol = parsed.protocol.slice(0, -1);
|
|
438
|
+
return {
|
|
439
|
+
protocol,
|
|
440
|
+
host: parsed.hostname,
|
|
441
|
+
port: parsed.port ? Number.parseInt(parsed.port) : void 0
|
|
442
|
+
};
|
|
414
443
|
}
|
|
415
|
-
|
|
416
|
-
return
|
|
444
|
+
static getMicrofrontendsError(url, message) {
|
|
445
|
+
return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
|
|
417
446
|
}
|
|
418
|
-
|
|
419
|
-
|
|
447
|
+
isLocal() {
|
|
448
|
+
return this.local || this.host === "localhost" || this.host === "127.0.0.1";
|
|
449
|
+
}
|
|
450
|
+
toString() {
|
|
451
|
+
const url = this.toUrl();
|
|
420
452
|
return url.toString().replace(/\/$/, "");
|
|
421
453
|
}
|
|
422
|
-
toUrl(
|
|
423
|
-
const {
|
|
424
|
-
const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
|
|
454
|
+
toUrl() {
|
|
455
|
+
const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
|
|
425
456
|
return new URL(url);
|
|
426
457
|
}
|
|
427
458
|
};
|
|
428
459
|
var LocalHost = class extends Host {
|
|
429
460
|
constructor({
|
|
430
461
|
appName,
|
|
462
|
+
localPort,
|
|
431
463
|
...hostConfig
|
|
432
464
|
}) {
|
|
433
465
|
const host = hostConfig.host ?? "localhost";
|
|
434
|
-
const port = hostConfig.port ?? generatePortFromName({ name: appName });
|
|
466
|
+
const port = localPort ?? hostConfig.port ?? generatePortFromName({ name: appName });
|
|
435
467
|
const protocol = hostConfig.protocol ?? "http";
|
|
436
468
|
super({ protocol, host, port });
|
|
437
469
|
}
|
|
@@ -448,12 +480,17 @@ var Application = class {
|
|
|
448
480
|
this.development = {
|
|
449
481
|
local: new LocalHost({
|
|
450
482
|
appName: name,
|
|
483
|
+
localPort: app.development?.localPort,
|
|
451
484
|
...app.development?.local
|
|
452
485
|
}),
|
|
453
486
|
fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
|
|
454
487
|
};
|
|
455
|
-
|
|
456
|
-
|
|
488
|
+
if (app.development?.fallback) {
|
|
489
|
+
this.fallback = new Host(app.development.fallback);
|
|
490
|
+
} else if (app.production) {
|
|
491
|
+
this.fallback = new Host(app.production);
|
|
492
|
+
}
|
|
493
|
+
this.projectId = app.projectId ?? app.vercel?.projectId;
|
|
457
494
|
this.overrides = overrides?.environment ? {
|
|
458
495
|
environment: new Host(overrides.environment)
|
|
459
496
|
} : void 0;
|
|
@@ -481,7 +518,16 @@ var DefaultApplication = class extends Application {
|
|
|
481
518
|
isDefault: true
|
|
482
519
|
});
|
|
483
520
|
this.default = true;
|
|
484
|
-
|
|
521
|
+
const fallbackHost = app.development?.fallback ?? app.production;
|
|
522
|
+
if (fallbackHost === void 0) {
|
|
523
|
+
throw new Error(
|
|
524
|
+
"`app.production` or `app.development.fallback` must be set in the default application in microfrontends.json."
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
this.fallback = new Host(fallbackHost);
|
|
528
|
+
if (app.production) {
|
|
529
|
+
this.production = new Host(app.production);
|
|
530
|
+
}
|
|
485
531
|
}
|
|
486
532
|
getAssetPrefix() {
|
|
487
533
|
return "";
|
|
@@ -551,7 +597,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
551
597
|
}
|
|
552
598
|
if (isMainConfig(config) && !this.defaultApplication) {
|
|
553
599
|
throw new MicrofrontendError(
|
|
554
|
-
|
|
600
|
+
"Could not find default application in microfrontends configuration",
|
|
555
601
|
{
|
|
556
602
|
type: "application",
|
|
557
603
|
subtype: "not_found"
|
|
@@ -627,11 +673,11 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
627
673
|
return app;
|
|
628
674
|
}
|
|
629
675
|
getApplicationByProjectId(projectId) {
|
|
630
|
-
if (this.defaultApplication?.
|
|
676
|
+
if (this.defaultApplication?.projectId === projectId) {
|
|
631
677
|
return this.defaultApplication;
|
|
632
678
|
}
|
|
633
679
|
return Object.values(this.childApplications).find(
|
|
634
|
-
(app) => app.
|
|
680
|
+
(app) => app.projectId === projectId
|
|
635
681
|
);
|
|
636
682
|
}
|
|
637
683
|
/**
|
|
@@ -641,7 +687,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
641
687
|
getDefaultApplication() {
|
|
642
688
|
if (!this.defaultApplication) {
|
|
643
689
|
throw new MicrofrontendError(
|
|
644
|
-
|
|
690
|
+
"Could not find default application in microfrontends configuration",
|
|
645
691
|
{
|
|
646
692
|
type: "application",
|
|
647
693
|
subtype: "not_found"
|
|
@@ -654,7 +700,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
654
700
|
* Returns the configured port for the local proxy
|
|
655
701
|
*/
|
|
656
702
|
getLocalProxyPort() {
|
|
657
|
-
return this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
703
|
+
return this.config.options?.localProxyPort ?? this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
658
704
|
}
|
|
659
705
|
/**
|
|
660
706
|
* Serializes the class back to the Schema type.
|
|
@@ -728,7 +774,7 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
|
|
|
728
774
|
}
|
|
729
775
|
if (!defaultApplication) {
|
|
730
776
|
throw new MicrofrontendError(
|
|
731
|
-
|
|
777
|
+
"Could not find default application in microfrontends configuration",
|
|
732
778
|
{
|
|
733
779
|
type: "application",
|
|
734
780
|
subtype: "not_found"
|
|
@@ -778,12 +824,10 @@ function getDomainFromEnvironment({
|
|
|
778
824
|
if (mfeProjects.length === 0) {
|
|
779
825
|
throw new Error("Missing related microfrontends project information");
|
|
780
826
|
}
|
|
781
|
-
if (!app.
|
|
827
|
+
if (!app.projectId) {
|
|
782
828
|
throw new Error(`Missing applications[${app.name}].vercel.projectId`);
|
|
783
829
|
}
|
|
784
|
-
const vercelProject = mfeProjects.find(
|
|
785
|
-
(p) => p.project.id === app.vercel?.projectId
|
|
786
|
-
);
|
|
830
|
+
const vercelProject = mfeProjects.find((p) => p.project.id === app.projectId);
|
|
787
831
|
if (!vercelProject) {
|
|
788
832
|
throw new Error(
|
|
789
833
|
`Missing related microfrontends project information for application "${app.name}"`
|
|
@@ -817,9 +861,11 @@ function getCurrentEnvironment() {
|
|
|
817
861
|
const isProduction = process.env.VERCEL_ENV === "production";
|
|
818
862
|
if (isDevelopment) {
|
|
819
863
|
return { group: "development" };
|
|
820
|
-
}
|
|
864
|
+
}
|
|
865
|
+
if (isProduction) {
|
|
821
866
|
return { group: "production" };
|
|
822
|
-
}
|
|
867
|
+
}
|
|
868
|
+
if (isPreview) {
|
|
823
869
|
return { group: "preview" };
|
|
824
870
|
}
|
|
825
871
|
return { group: "custom", name: process.env.VERCEL_ENV };
|
|
@@ -830,10 +876,10 @@ function getDomainForCurrentEnvironment(config, appName, opts = {}) {
|
|
|
830
876
|
return app.overrides.environment.toString();
|
|
831
877
|
}
|
|
832
878
|
const { group } = getCurrentEnvironment();
|
|
833
|
-
const
|
|
879
|
+
const fallbackHost = config.getDefaultApplication().fallback.toString();
|
|
834
880
|
switch (group) {
|
|
835
881
|
case "development": {
|
|
836
|
-
const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() :
|
|
882
|
+
const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : fallbackHost;
|
|
837
883
|
debugDomains(appName, "development", domain);
|
|
838
884
|
return domain;
|
|
839
885
|
}
|
|
@@ -844,10 +890,9 @@ function getDomainForCurrentEnvironment(config, appName, opts = {}) {
|
|
|
844
890
|
return getDomainFromEnvironment({ app, target: "production" });
|
|
845
891
|
}
|
|
846
892
|
case "custom":
|
|
847
|
-
|
|
848
|
-
|
|
893
|
+
throw new Error(
|
|
894
|
+
"Custom environments are not supported in getDomainForCurrentEnvironment"
|
|
849
895
|
);
|
|
850
|
-
return productionHost;
|
|
851
896
|
}
|
|
852
897
|
}
|
|
853
898
|
|
|
@@ -875,7 +920,7 @@ function getHandler({
|
|
|
875
920
|
application,
|
|
876
921
|
flagFn,
|
|
877
922
|
pattern,
|
|
878
|
-
|
|
923
|
+
fallback
|
|
879
924
|
}) {
|
|
880
925
|
return async (req) => {
|
|
881
926
|
try {
|
|
@@ -895,7 +940,7 @@ function getHandler({
|
|
|
895
940
|
const zoneFallbackCookieName = `__zone_${application.name}_production_fallback`;
|
|
896
941
|
const assetPrefix = application.getAssetPrefix();
|
|
897
942
|
if (assetPrefix && pathname.startsWith(`/${assetPrefix}`) && req.cookies.get(zoneFallbackCookieName)?.value === "1") {
|
|
898
|
-
rewriteDomain =
|
|
943
|
+
rewriteDomain = fallback.toString();
|
|
899
944
|
} else {
|
|
900
945
|
try {
|
|
901
946
|
let deploymentFound;
|
|
@@ -905,7 +950,7 @@ function getHandler({
|
|
|
905
950
|
deploymentFound = await verifyPreviewDomain(req, rewriteDomain);
|
|
906
951
|
}
|
|
907
952
|
if (!deploymentFound) {
|
|
908
|
-
rewriteDomain =
|
|
953
|
+
rewriteDomain = fallback.toString();
|
|
909
954
|
responseCallbacks.push((response) => {
|
|
910
955
|
response.cookies.set(zoneFallbackCookieName, "1", {
|
|
911
956
|
httpOnly: true,
|
|
@@ -920,7 +965,7 @@ function getHandler({
|
|
|
920
965
|
if (!existingCookie?.includes("__vercel_toolbar")) {
|
|
921
966
|
patchedHeaders.set(
|
|
922
967
|
"cookie",
|
|
923
|
-
[
|
|
968
|
+
["__vercel_toolbar=1", existingCookie].join("; ")
|
|
924
969
|
);
|
|
925
970
|
responseCallbacks.push((response) => {
|
|
926
971
|
response.cookies.set("__vercel_toolbar", "1", {
|
|
@@ -956,10 +1001,6 @@ function getHandler({
|
|
|
956
1001
|
NextResponse.next({
|
|
957
1002
|
request: {
|
|
958
1003
|
headers
|
|
959
|
-
},
|
|
960
|
-
headers: {
|
|
961
|
-
// temporary, can delete when proxyRouting flag is removed
|
|
962
|
-
"x-vercel-mfe-middleware-sent-proxy": application.name
|
|
963
1004
|
}
|
|
964
1005
|
})
|
|
965
1006
|
);
|
|
@@ -994,7 +1035,7 @@ function getMicrofrontendsMiddleware({
|
|
|
994
1035
|
return middlewares;
|
|
995
1036
|
}
|
|
996
1037
|
const config = microfrontends.config;
|
|
997
|
-
const
|
|
1038
|
+
const fallback = config.defaultApplication.fallback;
|
|
998
1039
|
for (const application of config.getChildApplications()) {
|
|
999
1040
|
if (application.name === process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION) {
|
|
1000
1041
|
continue;
|
|
@@ -1007,7 +1048,7 @@ function getMicrofrontendsMiddleware({
|
|
|
1007
1048
|
config,
|
|
1008
1049
|
application,
|
|
1009
1050
|
pattern,
|
|
1010
|
-
|
|
1051
|
+
fallback
|
|
1011
1052
|
})
|
|
1012
1053
|
});
|
|
1013
1054
|
}
|
|
@@ -1032,7 +1073,7 @@ function getMicrofrontendsMiddleware({
|
|
|
1032
1073
|
application,
|
|
1033
1074
|
flagFn,
|
|
1034
1075
|
pattern,
|
|
1035
|
-
|
|
1076
|
+
fallback
|
|
1036
1077
|
})
|
|
1037
1078
|
});
|
|
1038
1079
|
}
|