@vercel/microfrontends 0.18.0 → 0.19.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.
- package/dist/bin/cli.cjs +151 -71
- package/dist/config.cjs +102 -56
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.js +102 -56
- package/dist/config.js.map +1 -1
- package/dist/{index-24024799.d.ts → index-09b1ddf9.d.ts} +16 -19
- package/dist/{index-ef8657e6.d.ts → index-2f78c0ca.d.ts} +44 -7
- package/dist/microfrontends/server.cjs +147 -67
- package/dist/microfrontends/server.cjs.map +1 -1
- package/dist/microfrontends/server.d.ts +4 -4
- package/dist/microfrontends/server.js +147 -67
- package/dist/microfrontends/server.js.map +1 -1
- package/dist/microfrontends.cjs +103 -57
- package/dist/microfrontends.cjs.map +1 -1
- package/dist/microfrontends.d.ts +4 -4
- package/dist/microfrontends.js +103 -57
- package/dist/microfrontends.js.map +1 -1
- package/dist/next/config.cjs +166 -79
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +166 -79
- package/dist/next/config.js.map +1 -1
- package/dist/next/endpoints.d.ts +2 -2
- package/dist/next/middleware.cjs +120 -75
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.js +120 -75
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +109 -62
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.d.ts +4 -4
- package/dist/next/testing.js +109 -62
- 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-089498fd.d.ts → types-4ef2bddb.d.ts} +1 -1
- package/dist/{types-9f161cec.d.ts → types-b6d38aea.d.ts} +1 -1
- package/dist/utils/mfe-port.cjs +148 -68
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.js +148 -68
- package/dist/utils/mfe-port.js.map +1 -1
- package/dist/validation.cjs +43 -9
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +43 -9
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
- package/schema/schema.json +71 -40
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: "0.
|
|
32
|
+
version: "0.19.1",
|
|
33
33
|
private: false,
|
|
34
34
|
description: "Defines configuration and utilities for microfrontends development",
|
|
35
35
|
keywords: [
|
|
@@ -337,7 +337,8 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
337
337
|
if (isDefaultApp(app)) {
|
|
338
338
|
continue;
|
|
339
339
|
}
|
|
340
|
-
|
|
340
|
+
const childApp = app;
|
|
341
|
+
for (const pathMatch of childApp.routing) {
|
|
341
342
|
for (const path6 of pathMatch.paths) {
|
|
342
343
|
const maybeError = validatePathExpression(path6);
|
|
343
344
|
if (maybeError) {
|
|
@@ -357,33 +358,31 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
357
358
|
}
|
|
358
359
|
}
|
|
359
360
|
const entries = Array.from(pathsByApplicationId.entries());
|
|
360
|
-
|
|
361
|
+
for (const [path6, { applications: ids, matcher, applicationId }] of entries) {
|
|
361
362
|
if (ids.length > 1) {
|
|
362
363
|
errors.push(
|
|
363
364
|
`Duplicate path "${path6}" for applications "${ids.join(", ")}"`
|
|
364
365
|
);
|
|
365
366
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
if (applicationId === matchApplicationId) {
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
if (matcher.test(matchPath)) {
|
|
378
|
-
const source = `"${path6}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
379
|
-
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
380
|
-
errors.push(
|
|
381
|
-
`Overlapping path detected between ${source} and ${destination}`
|
|
382
|
-
);
|
|
383
|
-
}
|
|
367
|
+
for (const [
|
|
368
|
+
matchPath,
|
|
369
|
+
{ applications: matchIds, applicationId: matchApplicationId }
|
|
370
|
+
] of entries) {
|
|
371
|
+
if (path6 === matchPath) {
|
|
372
|
+
continue;
|
|
384
373
|
}
|
|
385
|
-
|
|
386
|
-
|
|
374
|
+
if (applicationId === matchApplicationId) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (matcher.test(matchPath)) {
|
|
378
|
+
const source = `"${path6}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
379
|
+
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
380
|
+
errors.push(
|
|
381
|
+
`Overlapping path detected between ${source} and ${destination}`
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
387
386
|
if (errors.length) {
|
|
388
387
|
throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
|
|
389
388
|
type: "config",
|
|
@@ -452,7 +451,7 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
452
451
|
const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
|
|
453
452
|
if (numApplicationsWithoutRouting === 0) {
|
|
454
453
|
throw new MicrofrontendError(
|
|
455
|
-
|
|
454
|
+
"No default application found. At least one application needs to be the default by omitting routing.",
|
|
456
455
|
{ type: "config", subtype: "no_default_application" }
|
|
457
456
|
);
|
|
458
457
|
}
|
|
@@ -498,47 +497,80 @@ function generatePortFromName({
|
|
|
498
497
|
// src/config/microfrontends-config/isomorphic/host.ts
|
|
499
498
|
var Host = class {
|
|
500
499
|
constructor(hostConfig, options) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
500
|
+
if (typeof hostConfig === "string") {
|
|
501
|
+
({
|
|
502
|
+
protocol: this.protocol,
|
|
503
|
+
host: this.host,
|
|
504
|
+
port: this.port
|
|
505
|
+
} = Host.parseUrl(hostConfig));
|
|
506
|
+
} else {
|
|
507
|
+
const { protocol = "https", host, port } = hostConfig;
|
|
508
|
+
this.protocol = protocol;
|
|
509
|
+
this.host = host;
|
|
510
|
+
this.port = port;
|
|
511
|
+
}
|
|
505
512
|
this.local = options?.isLocal;
|
|
506
513
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
514
|
+
static parseUrl(url) {
|
|
515
|
+
let hostToParse = url;
|
|
516
|
+
if (!/^https?:\/\//.exec(hostToParse)) {
|
|
517
|
+
hostToParse = `https://${hostToParse}`;
|
|
518
|
+
}
|
|
519
|
+
const parsed = new URL(hostToParse);
|
|
520
|
+
if (!parsed.hostname) {
|
|
521
|
+
throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
|
|
522
|
+
}
|
|
523
|
+
if (parsed.hash) {
|
|
524
|
+
throw new Error(
|
|
525
|
+
Host.getMicrofrontendsError(url, "cannot have a fragment")
|
|
526
|
+
);
|
|
519
527
|
}
|
|
520
|
-
|
|
528
|
+
if (parsed.username || parsed.password) {
|
|
529
|
+
throw new Error(
|
|
530
|
+
Host.getMicrofrontendsError(
|
|
531
|
+
url,
|
|
532
|
+
"cannot have authentication credentials (username and/or password)"
|
|
533
|
+
)
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
if (parsed.pathname !== "/") {
|
|
537
|
+
throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
|
|
538
|
+
}
|
|
539
|
+
if (parsed.search) {
|
|
540
|
+
throw new Error(
|
|
541
|
+
Host.getMicrofrontendsError(url, "cannot have query parameters")
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
const protocol = parsed.protocol.slice(0, -1);
|
|
545
|
+
return {
|
|
546
|
+
protocol,
|
|
547
|
+
host: parsed.hostname,
|
|
548
|
+
port: parsed.port ? Number.parseInt(parsed.port) : void 0
|
|
549
|
+
};
|
|
521
550
|
}
|
|
522
|
-
|
|
523
|
-
return
|
|
551
|
+
static getMicrofrontendsError(url, message) {
|
|
552
|
+
return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
|
|
553
|
+
}
|
|
554
|
+
isLocal() {
|
|
555
|
+
return this.local || this.host === "localhost" || this.host === "127.0.0.1";
|
|
524
556
|
}
|
|
525
|
-
toString(
|
|
526
|
-
const url = this.toUrl(
|
|
557
|
+
toString() {
|
|
558
|
+
const url = this.toUrl();
|
|
527
559
|
return url.toString().replace(/\/$/, "");
|
|
528
560
|
}
|
|
529
|
-
toUrl(
|
|
530
|
-
const {
|
|
531
|
-
const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
|
|
561
|
+
toUrl() {
|
|
562
|
+
const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
|
|
532
563
|
return new URL(url);
|
|
533
564
|
}
|
|
534
565
|
};
|
|
535
566
|
var LocalHost = class extends Host {
|
|
536
567
|
constructor({
|
|
537
568
|
appName,
|
|
569
|
+
localPort,
|
|
538
570
|
...hostConfig
|
|
539
571
|
}) {
|
|
540
572
|
const host = hostConfig.host ?? "localhost";
|
|
541
|
-
const port = hostConfig.port ?? generatePortFromName({ name: appName });
|
|
573
|
+
const port = localPort ?? hostConfig.port ?? generatePortFromName({ name: appName });
|
|
542
574
|
const protocol = hostConfig.protocol ?? "http";
|
|
543
575
|
super({ protocol, host, port });
|
|
544
576
|
}
|
|
@@ -555,12 +587,17 @@ var Application = class {
|
|
|
555
587
|
this.development = {
|
|
556
588
|
local: new LocalHost({
|
|
557
589
|
appName: name,
|
|
590
|
+
localPort: app.development?.localPort,
|
|
558
591
|
...app.development?.local
|
|
559
592
|
}),
|
|
560
593
|
fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
|
|
561
594
|
};
|
|
562
|
-
|
|
563
|
-
|
|
595
|
+
if (app.development?.fallback) {
|
|
596
|
+
this.fallback = new Host(app.development.fallback);
|
|
597
|
+
} else if (app.production) {
|
|
598
|
+
this.fallback = new Host(app.production);
|
|
599
|
+
}
|
|
600
|
+
this.projectId = app.projectId ?? app.vercel?.projectId;
|
|
564
601
|
this.overrides = overrides?.environment ? {
|
|
565
602
|
environment: new Host(overrides.environment)
|
|
566
603
|
} : void 0;
|
|
@@ -588,7 +625,16 @@ var DefaultApplication = class extends Application {
|
|
|
588
625
|
isDefault: true
|
|
589
626
|
});
|
|
590
627
|
this.default = true;
|
|
591
|
-
|
|
628
|
+
const fallbackHost = app.development?.fallback ?? app.production;
|
|
629
|
+
if (fallbackHost === void 0) {
|
|
630
|
+
throw new Error(
|
|
631
|
+
"`app.production` or `app.development.fallback` must be set in the default application in microfrontends.json."
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
this.fallback = new Host(fallbackHost);
|
|
635
|
+
if (app.production) {
|
|
636
|
+
this.production = new Host(app.production);
|
|
637
|
+
}
|
|
592
638
|
}
|
|
593
639
|
getAssetPrefix() {
|
|
594
640
|
return "";
|
|
@@ -777,7 +823,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
777
823
|
}
|
|
778
824
|
if (isMainConfig(config) && !this.defaultApplication) {
|
|
779
825
|
throw new MicrofrontendError(
|
|
780
|
-
|
|
826
|
+
"Could not find default application in microfrontends configuration",
|
|
781
827
|
{
|
|
782
828
|
type: "application",
|
|
783
829
|
subtype: "not_found"
|
|
@@ -853,11 +899,11 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
853
899
|
return app;
|
|
854
900
|
}
|
|
855
901
|
getApplicationByProjectId(projectId) {
|
|
856
|
-
if (this.defaultApplication?.
|
|
902
|
+
if (this.defaultApplication?.projectId === projectId) {
|
|
857
903
|
return this.defaultApplication;
|
|
858
904
|
}
|
|
859
905
|
return Object.values(this.childApplications).find(
|
|
860
|
-
(app) => app.
|
|
906
|
+
(app) => app.projectId === projectId
|
|
861
907
|
);
|
|
862
908
|
}
|
|
863
909
|
/**
|
|
@@ -867,7 +913,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
867
913
|
getDefaultApplication() {
|
|
868
914
|
if (!this.defaultApplication) {
|
|
869
915
|
throw new MicrofrontendError(
|
|
870
|
-
|
|
916
|
+
"Could not find default application in microfrontends configuration",
|
|
871
917
|
{
|
|
872
918
|
type: "application",
|
|
873
919
|
subtype: "not_found"
|
|
@@ -880,7 +926,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
880
926
|
* Returns the configured port for the local proxy
|
|
881
927
|
*/
|
|
882
928
|
getLocalProxyPort() {
|
|
883
|
-
return this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
929
|
+
return this.config.options?.localProxyPort ?? this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
884
930
|
}
|
|
885
931
|
/**
|
|
886
932
|
* Serializes the class back to the Schema type.
|
|
@@ -941,7 +987,7 @@ var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
|
|
|
941
987
|
}
|
|
942
988
|
if (!defaultApplication) {
|
|
943
989
|
throw new MicrofrontendError(
|
|
944
|
-
|
|
990
|
+
"Could not find default application in microfrontends configuration",
|
|
945
991
|
{
|
|
946
992
|
type: "application",
|
|
947
993
|
subtype: "not_found"
|
|
@@ -1263,11 +1309,21 @@ var schema_default = {
|
|
|
1263
1309
|
properties: {
|
|
1264
1310
|
vercel: {
|
|
1265
1311
|
$ref: "#/definitions/VercelOptions",
|
|
1266
|
-
description: "
|
|
1312
|
+
description: "Microfrontends wide options for Vercel.",
|
|
1313
|
+
deprecated: "This is being replaced by the `disableOverrides` field below."
|
|
1314
|
+
},
|
|
1315
|
+
disableOverrides: {
|
|
1316
|
+
type: "boolean",
|
|
1317
|
+
description: "If you want to disable the overrides for the site. For example, if you are managing rewrites between applications externally, you may wish to disable the overrides on the toolbar as they will have no effect."
|
|
1267
1318
|
},
|
|
1268
1319
|
localProxy: {
|
|
1269
1320
|
$ref: "#/definitions/LocalProxyOptions",
|
|
1270
|
-
description: "Options for local proxy."
|
|
1321
|
+
description: "Options for local proxy.",
|
|
1322
|
+
deprecated: "This is being replaced by the `localProxyPort` field below."
|
|
1323
|
+
},
|
|
1324
|
+
localProxyPort: {
|
|
1325
|
+
type: "number",
|
|
1326
|
+
description: "The port number used by the local proxy server.\n\nThe default is `3024`."
|
|
1271
1327
|
}
|
|
1272
1328
|
},
|
|
1273
1329
|
additionalProperties: false
|
|
@@ -1315,13 +1371,19 @@ var schema_default = {
|
|
|
1315
1371
|
type: "object",
|
|
1316
1372
|
properties: {
|
|
1317
1373
|
vercel: {
|
|
1318
|
-
$ref: "#/definitions/Vercel"
|
|
1374
|
+
$ref: "#/definitions/Vercel",
|
|
1375
|
+
deprecated: "This is being replaced by the `projectId` field below."
|
|
1376
|
+
},
|
|
1377
|
+
projectId: {
|
|
1378
|
+
type: "string",
|
|
1379
|
+
description: "Vercel project ID"
|
|
1319
1380
|
},
|
|
1320
1381
|
development: {
|
|
1321
1382
|
$ref: "#/definitions/Development"
|
|
1322
1383
|
},
|
|
1323
1384
|
production: {
|
|
1324
|
-
$ref: "#/definitions/HostConfig"
|
|
1385
|
+
$ref: "#/definitions/HostConfig",
|
|
1386
|
+
deprecated: "This is a duplicate of the `development.fallback` field and this will be removed soon."
|
|
1325
1387
|
}
|
|
1326
1388
|
},
|
|
1327
1389
|
required: ["production"],
|
|
@@ -1342,11 +1404,23 @@ var schema_default = {
|
|
|
1342
1404
|
type: "object",
|
|
1343
1405
|
properties: {
|
|
1344
1406
|
local: {
|
|
1345
|
-
$ref: "#/definitions/LocalHostConfig"
|
|
1407
|
+
$ref: "#/definitions/LocalHostConfig",
|
|
1408
|
+
deprecated: "This is being replaced by the `localPort` field below."
|
|
1409
|
+
},
|
|
1410
|
+
localPort: {
|
|
1411
|
+
type: "number",
|
|
1412
|
+
description: "The local port number that this application runs on when it is running locally. Common values include `80` for HTTP and `443` for HTTPS."
|
|
1346
1413
|
},
|
|
1347
1414
|
fallback: {
|
|
1348
|
-
|
|
1349
|
-
|
|
1415
|
+
anyOf: [
|
|
1416
|
+
{
|
|
1417
|
+
$ref: "#/definitions/HostConfig"
|
|
1418
|
+
},
|
|
1419
|
+
{
|
|
1420
|
+
type: "string"
|
|
1421
|
+
}
|
|
1422
|
+
],
|
|
1423
|
+
description: "Fallback for local development, could be a host config that points to any environment. If this is not provided, or the application is not running - requests to the application in local development will error.\n\nIf passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTPS. If omitted, the port defaults to `80` for HTTP and `443` for HTTPS."
|
|
1350
1424
|
},
|
|
1351
1425
|
task: {
|
|
1352
1426
|
type: "string",
|
|
@@ -1398,7 +1472,12 @@ var schema_default = {
|
|
|
1398
1472
|
type: "object",
|
|
1399
1473
|
properties: {
|
|
1400
1474
|
vercel: {
|
|
1401
|
-
$ref: "#/definitions/Vercel"
|
|
1475
|
+
$ref: "#/definitions/Vercel",
|
|
1476
|
+
deprecated: "This is being replaced by the `projectId` field below."
|
|
1477
|
+
},
|
|
1478
|
+
projectId: {
|
|
1479
|
+
type: "string",
|
|
1480
|
+
description: "Vercel project ID"
|
|
1402
1481
|
},
|
|
1403
1482
|
development: {
|
|
1404
1483
|
$ref: "#/definitions/Development"
|
|
@@ -1408,7 +1487,8 @@ var schema_default = {
|
|
|
1408
1487
|
description: "Groups of path expressions that are routed to this application."
|
|
1409
1488
|
},
|
|
1410
1489
|
production: {
|
|
1411
|
-
$ref: "#/definitions/HostConfig"
|
|
1490
|
+
$ref: "#/definitions/HostConfig",
|
|
1491
|
+
deprecated: "This is a duplicate of the `development.fallback` field and this will be removed soon."
|
|
1412
1492
|
}
|
|
1413
1493
|
},
|
|
1414
1494
|
required: ["routing"],
|
|
@@ -1704,7 +1784,7 @@ var MicrofrontendsServer = class extends Microfrontends {
|
|
|
1704
1784
|
const [defaultApplication] = Object.entries(validatedConfig.applications).filter(([, app]) => isDefaultApp(app)).map(([name]) => name);
|
|
1705
1785
|
if (!defaultApplication) {
|
|
1706
1786
|
throw new MicrofrontendError(
|
|
1707
|
-
|
|
1787
|
+
"No default application found. At least one application needs to be the default by omitting routing.",
|
|
1708
1788
|
{ type: "config", subtype: "no_default_application" }
|
|
1709
1789
|
);
|
|
1710
1790
|
}
|
|
@@ -1742,13 +1822,13 @@ var ProxyRequestRouter = class {
|
|
|
1742
1822
|
getApplicationTarget(application) {
|
|
1743
1823
|
const useDev = this.localApps.includes(application.name);
|
|
1744
1824
|
let applicationName = application.name;
|
|
1745
|
-
let host = useDev ? application.development.local : application.
|
|
1825
|
+
let host = useDev ? application.development.local : application.fallback;
|
|
1746
1826
|
if (application.overrides?.environment?.host) {
|
|
1747
1827
|
host = application.overrides.environment;
|
|
1748
1828
|
}
|
|
1749
1829
|
if (!host) {
|
|
1750
1830
|
const defaultApp = this.config.getDefaultApplication();
|
|
1751
|
-
host = defaultApp.
|
|
1831
|
+
host = defaultApp.fallback;
|
|
1752
1832
|
applicationName = defaultApp.name;
|
|
1753
1833
|
}
|
|
1754
1834
|
const protocol = host.protocol;
|
|
@@ -2089,7 +2169,7 @@ function loadConfig({
|
|
|
2089
2169
|
return void 0;
|
|
2090
2170
|
}
|
|
2091
2171
|
const app = config.config.getApplication(appName);
|
|
2092
|
-
const port = app.development.local.port;
|
|
2172
|
+
const port = app.development.local.port ?? (app.development.local.protocol === "https" ? 443 : 80);
|
|
2093
2173
|
return { port };
|
|
2094
2174
|
}
|
|
2095
2175
|
|
package/dist/config.cjs
CHANGED
|
@@ -250,7 +250,8 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
250
250
|
if (isDefaultApp(app)) {
|
|
251
251
|
continue;
|
|
252
252
|
}
|
|
253
|
-
|
|
253
|
+
const childApp = app;
|
|
254
|
+
for (const pathMatch of childApp.routing) {
|
|
254
255
|
for (const path of pathMatch.paths) {
|
|
255
256
|
const maybeError = validatePathExpression(path);
|
|
256
257
|
if (maybeError) {
|
|
@@ -270,33 +271,31 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
270
271
|
}
|
|
271
272
|
}
|
|
272
273
|
const entries = Array.from(pathsByApplicationId.entries());
|
|
273
|
-
|
|
274
|
+
for (const [path, { applications: ids, matcher, applicationId }] of entries) {
|
|
274
275
|
if (ids.length > 1) {
|
|
275
276
|
errors.push(
|
|
276
277
|
`Duplicate path "${path}" for applications "${ids.join(", ")}"`
|
|
277
278
|
);
|
|
278
279
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
if (applicationId === matchApplicationId) {
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
if (matcher.test(matchPath)) {
|
|
291
|
-
const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
292
|
-
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
293
|
-
errors.push(
|
|
294
|
-
`Overlapping path detected between ${source} and ${destination}`
|
|
295
|
-
);
|
|
296
|
-
}
|
|
280
|
+
for (const [
|
|
281
|
+
matchPath,
|
|
282
|
+
{ applications: matchIds, applicationId: matchApplicationId }
|
|
283
|
+
] of entries) {
|
|
284
|
+
if (path === matchPath) {
|
|
285
|
+
continue;
|
|
297
286
|
}
|
|
298
|
-
|
|
299
|
-
|
|
287
|
+
if (applicationId === matchApplicationId) {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (matcher.test(matchPath)) {
|
|
291
|
+
const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
292
|
+
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
293
|
+
errors.push(
|
|
294
|
+
`Overlapping path detected between ${source} and ${destination}`
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
300
299
|
if (errors.length) {
|
|
301
300
|
throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
|
|
302
301
|
type: "config",
|
|
@@ -365,7 +364,7 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
365
364
|
const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
|
|
366
365
|
if (numApplicationsWithoutRouting === 0) {
|
|
367
366
|
throw new MicrofrontendError(
|
|
368
|
-
|
|
367
|
+
"No default application found. At least one application needs to be the default by omitting routing.",
|
|
369
368
|
{ type: "config", subtype: "no_default_application" }
|
|
370
369
|
);
|
|
371
370
|
}
|
|
@@ -411,47 +410,80 @@ function generatePortFromName({
|
|
|
411
410
|
// src/config/microfrontends-config/isomorphic/host.ts
|
|
412
411
|
var Host = class {
|
|
413
412
|
constructor(hostConfig, options) {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
413
|
+
if (typeof hostConfig === "string") {
|
|
414
|
+
({
|
|
415
|
+
protocol: this.protocol,
|
|
416
|
+
host: this.host,
|
|
417
|
+
port: this.port
|
|
418
|
+
} = Host.parseUrl(hostConfig));
|
|
419
|
+
} else {
|
|
420
|
+
const { protocol = "https", host, port } = hostConfig;
|
|
421
|
+
this.protocol = protocol;
|
|
422
|
+
this.host = host;
|
|
423
|
+
this.port = port;
|
|
424
|
+
}
|
|
418
425
|
this.local = options?.isLocal;
|
|
419
426
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
427
|
+
static parseUrl(url) {
|
|
428
|
+
let hostToParse = url;
|
|
429
|
+
if (!/^https?:\/\//.exec(hostToParse)) {
|
|
430
|
+
hostToParse = `https://${hostToParse}`;
|
|
431
|
+
}
|
|
432
|
+
const parsed = new URL(hostToParse);
|
|
433
|
+
if (!parsed.hostname) {
|
|
434
|
+
throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
|
|
435
|
+
}
|
|
436
|
+
if (parsed.hash) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
Host.getMicrofrontendsError(url, "cannot have a fragment")
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
if (parsed.username || parsed.password) {
|
|
442
|
+
throw new Error(
|
|
443
|
+
Host.getMicrofrontendsError(
|
|
444
|
+
url,
|
|
445
|
+
"cannot have authentication credentials (username and/or password)"
|
|
446
|
+
)
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
if (parsed.pathname !== "/") {
|
|
450
|
+
throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
|
|
451
|
+
}
|
|
452
|
+
if (parsed.search) {
|
|
453
|
+
throw new Error(
|
|
454
|
+
Host.getMicrofrontendsError(url, "cannot have query parameters")
|
|
455
|
+
);
|
|
432
456
|
}
|
|
433
|
-
|
|
457
|
+
const protocol = parsed.protocol.slice(0, -1);
|
|
458
|
+
return {
|
|
459
|
+
protocol,
|
|
460
|
+
host: parsed.hostname,
|
|
461
|
+
port: parsed.port ? Number.parseInt(parsed.port) : void 0
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
static getMicrofrontendsError(url, message) {
|
|
465
|
+
return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
|
|
434
466
|
}
|
|
435
|
-
|
|
436
|
-
return this.
|
|
467
|
+
isLocal() {
|
|
468
|
+
return this.local || this.host === "localhost" || this.host === "127.0.0.1";
|
|
437
469
|
}
|
|
438
|
-
toString(
|
|
439
|
-
const url = this.toUrl(
|
|
470
|
+
toString() {
|
|
471
|
+
const url = this.toUrl();
|
|
440
472
|
return url.toString().replace(/\/$/, "");
|
|
441
473
|
}
|
|
442
|
-
toUrl(
|
|
443
|
-
const {
|
|
444
|
-
const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
|
|
474
|
+
toUrl() {
|
|
475
|
+
const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
|
|
445
476
|
return new URL(url);
|
|
446
477
|
}
|
|
447
478
|
};
|
|
448
479
|
var LocalHost = class extends Host {
|
|
449
480
|
constructor({
|
|
450
481
|
appName,
|
|
482
|
+
localPort,
|
|
451
483
|
...hostConfig
|
|
452
484
|
}) {
|
|
453
485
|
const host = hostConfig.host ?? "localhost";
|
|
454
|
-
const port = hostConfig.port ?? generatePortFromName({ name: appName });
|
|
486
|
+
const port = localPort ?? hostConfig.port ?? generatePortFromName({ name: appName });
|
|
455
487
|
const protocol = hostConfig.protocol ?? "http";
|
|
456
488
|
super({ protocol, host, port });
|
|
457
489
|
}
|
|
@@ -468,12 +500,17 @@ var Application = class {
|
|
|
468
500
|
this.development = {
|
|
469
501
|
local: new LocalHost({
|
|
470
502
|
appName: name,
|
|
503
|
+
localPort: app.development?.localPort,
|
|
471
504
|
...app.development?.local
|
|
472
505
|
}),
|
|
473
506
|
fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
|
|
474
507
|
};
|
|
475
|
-
|
|
476
|
-
|
|
508
|
+
if (app.development?.fallback) {
|
|
509
|
+
this.fallback = new Host(app.development.fallback);
|
|
510
|
+
} else if (app.production) {
|
|
511
|
+
this.fallback = new Host(app.production);
|
|
512
|
+
}
|
|
513
|
+
this.projectId = app.projectId ?? app.vercel?.projectId;
|
|
477
514
|
this.overrides = overrides?.environment ? {
|
|
478
515
|
environment: new Host(overrides.environment)
|
|
479
516
|
} : void 0;
|
|
@@ -501,7 +538,16 @@ var DefaultApplication = class extends Application {
|
|
|
501
538
|
isDefault: true
|
|
502
539
|
});
|
|
503
540
|
this.default = true;
|
|
504
|
-
|
|
541
|
+
const fallbackHost = app.development?.fallback ?? app.production;
|
|
542
|
+
if (fallbackHost === void 0) {
|
|
543
|
+
throw new Error(
|
|
544
|
+
"`app.production` or `app.development.fallback` must be set in the default application in microfrontends.json."
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
this.fallback = new Host(fallbackHost);
|
|
548
|
+
if (app.production) {
|
|
549
|
+
this.production = new Host(app.production);
|
|
550
|
+
}
|
|
505
551
|
}
|
|
506
552
|
getAssetPrefix() {
|
|
507
553
|
return "";
|
|
@@ -571,7 +617,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
571
617
|
}
|
|
572
618
|
if (isMainConfig(config) && !this.defaultApplication) {
|
|
573
619
|
throw new MicrofrontendError(
|
|
574
|
-
|
|
620
|
+
"Could not find default application in microfrontends configuration",
|
|
575
621
|
{
|
|
576
622
|
type: "application",
|
|
577
623
|
subtype: "not_found"
|
|
@@ -647,11 +693,11 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
647
693
|
return app;
|
|
648
694
|
}
|
|
649
695
|
getApplicationByProjectId(projectId) {
|
|
650
|
-
if (this.defaultApplication?.
|
|
696
|
+
if (this.defaultApplication?.projectId === projectId) {
|
|
651
697
|
return this.defaultApplication;
|
|
652
698
|
}
|
|
653
699
|
return Object.values(this.childApplications).find(
|
|
654
|
-
(app) => app.
|
|
700
|
+
(app) => app.projectId === projectId
|
|
655
701
|
);
|
|
656
702
|
}
|
|
657
703
|
/**
|
|
@@ -661,7 +707,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
661
707
|
getDefaultApplication() {
|
|
662
708
|
if (!this.defaultApplication) {
|
|
663
709
|
throw new MicrofrontendError(
|
|
664
|
-
|
|
710
|
+
"Could not find default application in microfrontends configuration",
|
|
665
711
|
{
|
|
666
712
|
type: "application",
|
|
667
713
|
subtype: "not_found"
|
|
@@ -674,7 +720,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
674
720
|
* Returns the configured port for the local proxy
|
|
675
721
|
*/
|
|
676
722
|
getLocalProxyPort() {
|
|
677
|
-
return this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
723
|
+
return this.config.options?.localProxyPort ?? this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
678
724
|
}
|
|
679
725
|
/**
|
|
680
726
|
* Serializes the class back to the Schema type.
|