@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/testing.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MiddlewareConfig, NextRequest, NextFetchEvent } from 'next/server';
|
|
2
|
-
import { M as MicrofrontendConfigIsomorphic } from '../index-
|
|
3
|
-
import '../index-
|
|
4
|
-
import '../types-
|
|
5
|
-
import '../types-
|
|
2
|
+
import { M as MicrofrontendConfigIsomorphic } from '../index-09b1ddf9.js';
|
|
3
|
+
import '../index-2f78c0ca.js';
|
|
4
|
+
import '../types-4ef2bddb.js';
|
|
5
|
+
import '../types-b6d38aea.js';
|
|
6
6
|
|
|
7
7
|
/** Replaces path wildcards (if they exist) with synthesized paths. */
|
|
8
8
|
declare function expandWildcards(path: string): string[];
|
package/dist/next/testing.js
CHANGED
|
@@ -15,7 +15,7 @@ import { parse } from "jsonc-parser";
|
|
|
15
15
|
// src/config/errors.ts
|
|
16
16
|
var MicrofrontendError = class extends Error {
|
|
17
17
|
constructor(message, opts) {
|
|
18
|
-
super(message);
|
|
18
|
+
super(message, { cause: opts?.cause });
|
|
19
19
|
this.name = "MicrofrontendsError";
|
|
20
20
|
this.source = opts?.source ?? "@vercel/microfrontends";
|
|
21
21
|
this.type = opts?.type ?? "unknown";
|
|
@@ -237,7 +237,8 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
237
237
|
if (isDefaultApp(app)) {
|
|
238
238
|
continue;
|
|
239
239
|
}
|
|
240
|
-
|
|
240
|
+
const childApp = app;
|
|
241
|
+
for (const pathMatch of childApp.routing) {
|
|
241
242
|
for (const path of pathMatch.paths) {
|
|
242
243
|
const maybeError = validatePathExpression(path);
|
|
243
244
|
if (maybeError) {
|
|
@@ -257,33 +258,31 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
260
|
const entries = Array.from(pathsByApplicationId.entries());
|
|
260
|
-
|
|
261
|
+
for (const [path, { applications: ids, matcher, applicationId }] of entries) {
|
|
261
262
|
if (ids.length > 1) {
|
|
262
263
|
errors.push(
|
|
263
264
|
`Duplicate path "${path}" for applications "${ids.join(", ")}"`
|
|
264
265
|
);
|
|
265
266
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
if (applicationId === matchApplicationId) {
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
if (matcher.test(matchPath)) {
|
|
278
|
-
const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
279
|
-
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
280
|
-
errors.push(
|
|
281
|
-
`Overlapping path detected between ${source} and ${destination}`
|
|
282
|
-
);
|
|
283
|
-
}
|
|
267
|
+
for (const [
|
|
268
|
+
matchPath,
|
|
269
|
+
{ applications: matchIds, applicationId: matchApplicationId }
|
|
270
|
+
] of entries) {
|
|
271
|
+
if (path === matchPath) {
|
|
272
|
+
continue;
|
|
284
273
|
}
|
|
285
|
-
|
|
286
|
-
|
|
274
|
+
if (applicationId === matchApplicationId) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (matcher.test(matchPath)) {
|
|
278
|
+
const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
279
|
+
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
280
|
+
errors.push(
|
|
281
|
+
`Overlapping path detected between ${source} and ${destination}`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
287
286
|
if (errors.length) {
|
|
288
287
|
throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
|
|
289
288
|
type: "config",
|
|
@@ -352,7 +351,7 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
352
351
|
const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
|
|
353
352
|
if (numApplicationsWithoutRouting === 0) {
|
|
354
353
|
throw new MicrofrontendError(
|
|
355
|
-
|
|
354
|
+
"No default application found. At least one application needs to be the default by omitting routing.",
|
|
356
355
|
{ type: "config", subtype: "no_default_application" }
|
|
357
356
|
);
|
|
358
357
|
}
|
|
@@ -398,47 +397,80 @@ function generatePortFromName({
|
|
|
398
397
|
// src/config/microfrontends-config/isomorphic/host.ts
|
|
399
398
|
var Host = class {
|
|
400
399
|
constructor(hostConfig, options) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
400
|
+
if (typeof hostConfig === "string") {
|
|
401
|
+
({
|
|
402
|
+
protocol: this.protocol,
|
|
403
|
+
host: this.host,
|
|
404
|
+
port: this.port
|
|
405
|
+
} = Host.parseUrl(hostConfig));
|
|
406
|
+
} else {
|
|
407
|
+
const { protocol = "https", host, port } = hostConfig;
|
|
408
|
+
this.protocol = protocol;
|
|
409
|
+
this.host = host;
|
|
410
|
+
this.port = port;
|
|
411
|
+
}
|
|
405
412
|
this.local = options?.isLocal;
|
|
406
413
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
protocol,
|
|
412
|
-
port
|
|
413
|
-
}) {
|
|
414
|
-
if (!port) {
|
|
415
|
-
if (protocol === "http") {
|
|
416
|
-
return 80;
|
|
417
|
-
}
|
|
418
|
-
return 443;
|
|
414
|
+
static parseUrl(url) {
|
|
415
|
+
let hostToParse = url;
|
|
416
|
+
if (!/^https?:\/\//.exec(hostToParse)) {
|
|
417
|
+
hostToParse = `https://${hostToParse}`;
|
|
419
418
|
}
|
|
420
|
-
|
|
419
|
+
const parsed = new URL(hostToParse);
|
|
420
|
+
if (!parsed.hostname) {
|
|
421
|
+
throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
|
|
422
|
+
}
|
|
423
|
+
if (parsed.hash) {
|
|
424
|
+
throw new Error(
|
|
425
|
+
Host.getMicrofrontendsError(url, "cannot have a fragment")
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
if (parsed.username || parsed.password) {
|
|
429
|
+
throw new Error(
|
|
430
|
+
Host.getMicrofrontendsError(
|
|
431
|
+
url,
|
|
432
|
+
"cannot have authentication credentials (username and/or password)"
|
|
433
|
+
)
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
if (parsed.pathname !== "/") {
|
|
437
|
+
throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
|
|
438
|
+
}
|
|
439
|
+
if (parsed.search) {
|
|
440
|
+
throw new Error(
|
|
441
|
+
Host.getMicrofrontendsError(url, "cannot have query parameters")
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
const protocol = parsed.protocol.slice(0, -1);
|
|
445
|
+
return {
|
|
446
|
+
protocol,
|
|
447
|
+
host: parsed.hostname,
|
|
448
|
+
port: parsed.port ? Number.parseInt(parsed.port) : void 0
|
|
449
|
+
};
|
|
421
450
|
}
|
|
422
|
-
|
|
423
|
-
return
|
|
451
|
+
static getMicrofrontendsError(url, message) {
|
|
452
|
+
return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
|
|
424
453
|
}
|
|
425
|
-
|
|
426
|
-
|
|
454
|
+
isLocal() {
|
|
455
|
+
return this.local || this.host === "localhost" || this.host === "127.0.0.1";
|
|
456
|
+
}
|
|
457
|
+
toString() {
|
|
458
|
+
const url = this.toUrl();
|
|
427
459
|
return url.toString().replace(/\/$/, "");
|
|
428
460
|
}
|
|
429
|
-
toUrl(
|
|
430
|
-
const {
|
|
431
|
-
const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
|
|
461
|
+
toUrl() {
|
|
462
|
+
const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
|
|
432
463
|
return new URL(url);
|
|
433
464
|
}
|
|
434
465
|
};
|
|
435
466
|
var LocalHost = class extends Host {
|
|
436
467
|
constructor({
|
|
437
468
|
appName,
|
|
469
|
+
localPort,
|
|
438
470
|
...hostConfig
|
|
439
471
|
}) {
|
|
440
472
|
const host = hostConfig.host ?? "localhost";
|
|
441
|
-
const port = hostConfig.port ?? generatePortFromName({ name: appName });
|
|
473
|
+
const port = localPort ?? hostConfig.port ?? generatePortFromName({ name: appName });
|
|
442
474
|
const protocol = hostConfig.protocol ?? "http";
|
|
443
475
|
super({ protocol, host, port });
|
|
444
476
|
}
|
|
@@ -455,12 +487,17 @@ var Application = class {
|
|
|
455
487
|
this.development = {
|
|
456
488
|
local: new LocalHost({
|
|
457
489
|
appName: name,
|
|
490
|
+
localPort: app.development?.localPort,
|
|
458
491
|
...app.development?.local
|
|
459
492
|
}),
|
|
460
493
|
fallback: app.development?.fallback ? new Host(app.development.fallback) : void 0
|
|
461
494
|
};
|
|
462
|
-
|
|
463
|
-
|
|
495
|
+
if (app.development?.fallback) {
|
|
496
|
+
this.fallback = new Host(app.development.fallback);
|
|
497
|
+
} else if (app.production) {
|
|
498
|
+
this.fallback = new Host(app.production);
|
|
499
|
+
}
|
|
500
|
+
this.projectId = app.projectId ?? app.vercel?.projectId;
|
|
464
501
|
this.overrides = overrides?.environment ? {
|
|
465
502
|
environment: new Host(overrides.environment)
|
|
466
503
|
} : void 0;
|
|
@@ -488,7 +525,16 @@ var DefaultApplication = class extends Application {
|
|
|
488
525
|
isDefault: true
|
|
489
526
|
});
|
|
490
527
|
this.default = true;
|
|
491
|
-
|
|
528
|
+
const fallbackHost = app.development?.fallback ?? app.production;
|
|
529
|
+
if (fallbackHost === void 0) {
|
|
530
|
+
throw new Error(
|
|
531
|
+
"`app.production` or `app.development.fallback` must be set in the default application in microfrontends.json."
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
this.fallback = new Host(fallbackHost);
|
|
535
|
+
if (app.production) {
|
|
536
|
+
this.production = new Host(app.production);
|
|
537
|
+
}
|
|
492
538
|
}
|
|
493
539
|
getAssetPrefix() {
|
|
494
540
|
return "";
|
|
@@ -558,7 +604,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
558
604
|
}
|
|
559
605
|
if (isMainConfig(config) && !this.defaultApplication) {
|
|
560
606
|
throw new MicrofrontendError(
|
|
561
|
-
|
|
607
|
+
"Could not find default application in microfrontends configuration",
|
|
562
608
|
{
|
|
563
609
|
type: "application",
|
|
564
610
|
subtype: "not_found"
|
|
@@ -634,11 +680,11 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
634
680
|
return app;
|
|
635
681
|
}
|
|
636
682
|
getApplicationByProjectId(projectId) {
|
|
637
|
-
if (this.defaultApplication?.
|
|
683
|
+
if (this.defaultApplication?.projectId === projectId) {
|
|
638
684
|
return this.defaultApplication;
|
|
639
685
|
}
|
|
640
686
|
return Object.values(this.childApplications).find(
|
|
641
|
-
(app) => app.
|
|
687
|
+
(app) => app.projectId === projectId
|
|
642
688
|
);
|
|
643
689
|
}
|
|
644
690
|
/**
|
|
@@ -648,7 +694,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
648
694
|
getDefaultApplication() {
|
|
649
695
|
if (!this.defaultApplication) {
|
|
650
696
|
throw new MicrofrontendError(
|
|
651
|
-
|
|
697
|
+
"Could not find default application in microfrontends configuration",
|
|
652
698
|
{
|
|
653
699
|
type: "application",
|
|
654
700
|
subtype: "not_found"
|
|
@@ -661,7 +707,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
661
707
|
* Returns the configured port for the local proxy
|
|
662
708
|
*/
|
|
663
709
|
getLocalProxyPort() {
|
|
664
|
-
return this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
710
|
+
return this.config.options?.localProxyPort ?? this.config.options?.localProxy?.port ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
665
711
|
}
|
|
666
712
|
/**
|
|
667
713
|
* Serializes the class back to the Schema type.
|
|
@@ -706,12 +752,10 @@ function getDomainFromEnvironment({
|
|
|
706
752
|
if (mfeProjects.length === 0) {
|
|
707
753
|
throw new Error("Missing related microfrontends project information");
|
|
708
754
|
}
|
|
709
|
-
if (!app.
|
|
755
|
+
if (!app.projectId) {
|
|
710
756
|
throw new Error(`Missing applications[${app.name}].vercel.projectId`);
|
|
711
757
|
}
|
|
712
|
-
const vercelProject = mfeProjects.find(
|
|
713
|
-
(p) => p.project.id === app.vercel?.projectId
|
|
714
|
-
);
|
|
758
|
+
const vercelProject = mfeProjects.find((p) => p.project.id === app.projectId);
|
|
715
759
|
if (!vercelProject) {
|
|
716
760
|
throw new Error(
|
|
717
761
|
`Missing related microfrontends project information for application "${app.name}"`
|
|
@@ -783,7 +827,7 @@ function getExpectedDomainForApp(mfConfig, appName, env) {
|
|
|
783
827
|
const target = env;
|
|
784
828
|
return getDomainFromEnvironment({ app, target });
|
|
785
829
|
}
|
|
786
|
-
return defaultApp.
|
|
830
|
+
return defaultApp.fallback.toString();
|
|
787
831
|
}
|
|
788
832
|
function getAllMultiZonesPaths(mfConfig) {
|
|
789
833
|
return mfConfig.getChildApplications().flatMap((app) => {
|
|
@@ -830,8 +874,11 @@ function validateMiddlewareConfig(middlewareConfig, microfrontendConfigOrPath, e
|
|
|
830
874
|
for (const path of aMatch.paths) {
|
|
831
875
|
const pathsToTest = expandWildcards(path);
|
|
832
876
|
for (const testPath of pathsToTest) {
|
|
833
|
-
const productionHost = microfrontendConfig.getDefaultApplication().production
|
|
877
|
+
const productionHost = microfrontendConfig.getDefaultApplication().production?.host;
|
|
834
878
|
const pathForDisplay = `${testPath}${path === testPath ? "" : ` (synthesized from ${path})`}`;
|
|
879
|
+
if (!productionHost) {
|
|
880
|
+
continue;
|
|
881
|
+
}
|
|
835
882
|
if (!urlMatches(middlewareConfig, testPath, "test.nonproduction.host")) {
|
|
836
883
|
errors.push(
|
|
837
884
|
`Matcher misconfigured for ${pathForDisplay}. This path should have matched the middleware config on a non-production host, but did not. Microfrontends require a middleware config matcher that matches on this host everywhere but in production. That can be configured with a configuration like this:
|