@vercel/microfrontends 1.5.0 → 2.0.0-canary.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/CHANGELOG.md +11 -0
- package/dist/bin/cli.cjs +103 -117
- package/dist/config.cjs +48 -101
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.ts +2 -29
- package/dist/config.js +37 -100
- package/dist/config.js.map +1 -1
- package/dist/experimental/sveltekit.cjs +93 -109
- package/dist/experimental/sveltekit.cjs.map +1 -1
- package/dist/experimental/sveltekit.js +92 -108
- package/dist/experimental/sveltekit.js.map +1 -1
- package/dist/experimental/vite.cjs +93 -109
- package/dist/experimental/vite.cjs.map +1 -1
- package/dist/experimental/vite.js +92 -108
- package/dist/experimental/vite.js.map +1 -1
- package/dist/get-application-context-e8a5a0e2.d.ts +14 -0
- package/dist/microfrontends/server.cjs +93 -109
- package/dist/microfrontends/server.cjs.map +1 -1
- package/dist/microfrontends/server.d.ts +4 -13
- package/dist/microfrontends/server.js +92 -108
- package/dist/microfrontends/server.js.map +1 -1
- package/dist/microfrontends/utils.cjs +24 -4
- package/dist/microfrontends/utils.cjs.map +1 -1
- package/dist/microfrontends/utils.d.ts +3 -1
- package/dist/microfrontends/utils.js +24 -4
- package/dist/microfrontends/utils.js.map +1 -1
- package/dist/next/client.cjs +1 -1
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.js +1 -1
- package/dist/next/client.js.map +1 -1
- package/dist/next/config.cjs +223 -111
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +222 -110
- package/dist/next/config.js.map +1 -1
- package/dist/next/middleware.cjs +88 -44
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.js +78 -44
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +51 -104
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.d.ts +2 -2
- package/dist/next/testing.js +39 -102
- package/dist/next/testing.js.map +1 -1
- package/dist/overrides.d.ts +3 -3
- package/dist/schema.d.ts +2 -2
- package/dist/{types-1cec43e6.d.ts → types-0deb756b.d.ts} +16 -1
- package/dist/{types-1fb60496.d.ts → types-4299bff1.d.ts} +1 -1
- package/dist/utils/mfe-port.cjs +93 -109
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.js +92 -108
- package/dist/utils/mfe-port.js.map +1 -1
- package/dist/validation.cjs +4 -0
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +4 -0
- package/dist/validation.js.map +1 -1
- package/package.json +3 -1
- package/schema/schema.json +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @vercel/microfrontends
|
|
2
2
|
|
|
3
|
+
## 2.0.0-canary.0
|
|
4
|
+
|
|
5
|
+
> **Check out our [Public Beta](https://vercel.com/changelog/microfrontends-are-now-in-public-beta) changelog to learn more about this release.**
|
|
6
|
+
|
|
7
|
+
### Major Changes
|
|
8
|
+
|
|
9
|
+
- This release removes the project name and flag names from being visible to client side code.
|
|
10
|
+
- Modify the auto-generated asset prefix to use a hash of the project name instead of the project name itself.
|
|
11
|
+
- Allow users to specify a custom asset prefix in the `microfrontends.json`
|
|
12
|
+
- Remove project names and flag names from the Microfrontends client configuration.
|
|
13
|
+
|
|
3
14
|
## 1.5.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/dist/bin/cli.cjs
CHANGED
|
@@ -30,7 +30,7 @@ var import_env = require("@next/env");
|
|
|
30
30
|
// package.json
|
|
31
31
|
var package_default = {
|
|
32
32
|
name: "@vercel/microfrontends",
|
|
33
|
-
version: "
|
|
33
|
+
version: "2.0.0-canary.0",
|
|
34
34
|
private: false,
|
|
35
35
|
description: "Defines configuration and utilities for microfrontends development",
|
|
36
36
|
keywords: [
|
|
@@ -165,12 +165,14 @@ var package_default = {
|
|
|
165
165
|
},
|
|
166
166
|
dependencies: {
|
|
167
167
|
"@next/env": "15.4.0-canary.41",
|
|
168
|
+
"@types/md5": "^2.3.5",
|
|
168
169
|
ajv: "^8.17.1",
|
|
169
170
|
commander: "^12.1.0",
|
|
170
171
|
cookie: "0.4.0",
|
|
171
172
|
"fast-glob": "^3.3.2",
|
|
172
173
|
"http-proxy": "^1.18.1",
|
|
173
174
|
"jsonc-parser": "^3.3.1",
|
|
175
|
+
md5: "^2.3.0",
|
|
174
176
|
nanoid: "^3.3.9",
|
|
175
177
|
"path-to-regexp": "6.2.1",
|
|
176
178
|
semver: "^7.7.2"
|
|
@@ -242,7 +244,7 @@ var http = __toESM(require("http"), 1);
|
|
|
242
244
|
var https = __toESM(require("https"), 1);
|
|
243
245
|
var import_node_url = require("url");
|
|
244
246
|
var import_cookie = require("cookie");
|
|
245
|
-
var
|
|
247
|
+
var import_path_to_regexp2 = require("path-to-regexp");
|
|
246
248
|
var import_http_proxy = __toESM(require("http-proxy"), 1);
|
|
247
249
|
|
|
248
250
|
// src/config/microfrontends-config/isomorphic/index.ts
|
|
@@ -357,84 +359,6 @@ function isDefaultApp(a) {
|
|
|
357
359
|
return !("routing" in a);
|
|
358
360
|
}
|
|
359
361
|
|
|
360
|
-
// src/config/microfrontends-config/client/index.ts
|
|
361
|
-
var import_path_to_regexp = require("path-to-regexp");
|
|
362
|
-
var regexpCache = /* @__PURE__ */ new Map();
|
|
363
|
-
var getRegexp = (path7) => {
|
|
364
|
-
const existing = regexpCache.get(path7);
|
|
365
|
-
if (existing) {
|
|
366
|
-
return existing;
|
|
367
|
-
}
|
|
368
|
-
const regexp = (0, import_path_to_regexp.pathToRegexp)(path7);
|
|
369
|
-
regexpCache.set(path7, regexp);
|
|
370
|
-
return regexp;
|
|
371
|
-
};
|
|
372
|
-
var MicrofrontendConfigClient = class {
|
|
373
|
-
constructor(config, opts) {
|
|
374
|
-
this.pathCache = {};
|
|
375
|
-
this.serialized = config;
|
|
376
|
-
if (opts?.removeFlaggedPaths) {
|
|
377
|
-
for (const app of Object.values(config.applications)) {
|
|
378
|
-
if (app.routing) {
|
|
379
|
-
app.routing = app.routing.filter((match) => !match.flag);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
this.applications = config.applications;
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Create a new `MicrofrontendConfigClient` from a JSON string.
|
|
387
|
-
* Config must be passed in to remain framework agnostic
|
|
388
|
-
*/
|
|
389
|
-
static fromEnv(config, opts) {
|
|
390
|
-
if (!config) {
|
|
391
|
-
throw new Error(
|
|
392
|
-
"Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
return new MicrofrontendConfigClient(
|
|
396
|
-
JSON.parse(config),
|
|
397
|
-
opts
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
isEqual(other) {
|
|
401
|
-
return this === other || JSON.stringify(this.applications) === JSON.stringify(other.applications);
|
|
402
|
-
}
|
|
403
|
-
getApplicationNameForPath(path7) {
|
|
404
|
-
if (!path7.startsWith("/")) {
|
|
405
|
-
throw new Error(`Path must start with a /`);
|
|
406
|
-
}
|
|
407
|
-
if (this.pathCache[path7]) {
|
|
408
|
-
return this.pathCache[path7];
|
|
409
|
-
}
|
|
410
|
-
const pathname = new URL(path7, "https://example.com").pathname;
|
|
411
|
-
for (const [name, application] of Object.entries(this.applications)) {
|
|
412
|
-
if (application.routing) {
|
|
413
|
-
for (const group of application.routing) {
|
|
414
|
-
for (const childPath of group.paths) {
|
|
415
|
-
const regexp = getRegexp(childPath);
|
|
416
|
-
if (regexp.test(pathname)) {
|
|
417
|
-
this.pathCache[path7] = name;
|
|
418
|
-
return name;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
const defaultApplication = Object.entries(this.applications).find(
|
|
425
|
-
([, application]) => application.default
|
|
426
|
-
);
|
|
427
|
-
if (!defaultApplication) {
|
|
428
|
-
return null;
|
|
429
|
-
}
|
|
430
|
-
this.pathCache[path7] = defaultApplication[0];
|
|
431
|
-
return defaultApplication[0];
|
|
432
|
-
}
|
|
433
|
-
serialize() {
|
|
434
|
-
return this.serialized;
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
|
|
438
362
|
// src/config/overrides/constants.ts
|
|
439
363
|
var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
|
|
440
364
|
var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
|
|
@@ -469,11 +393,12 @@ function parseOverrides(cookies) {
|
|
|
469
393
|
}
|
|
470
394
|
|
|
471
395
|
// src/config/microfrontends-config/isomorphic/validation.ts
|
|
472
|
-
var
|
|
396
|
+
var import_path_to_regexp = require("path-to-regexp");
|
|
473
397
|
var LIST_FORMATTER = new Intl.ListFormat("en", {
|
|
474
398
|
style: "long",
|
|
475
399
|
type: "conjunction"
|
|
476
400
|
});
|
|
401
|
+
var VALID_ASSET_PREFIX_REGEXP = /^[a-z](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
477
402
|
var validateConfigPaths = (applicationConfigsById) => {
|
|
478
403
|
if (!applicationConfigsById) {
|
|
479
404
|
return;
|
|
@@ -496,7 +421,7 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
496
421
|
} else {
|
|
497
422
|
pathsByApplicationId.set(path7, {
|
|
498
423
|
applications: [id],
|
|
499
|
-
matcher: (0,
|
|
424
|
+
matcher: (0, import_path_to_regexp.pathToRegexp)(path7),
|
|
500
425
|
applicationId: id
|
|
501
426
|
});
|
|
502
427
|
}
|
|
@@ -543,7 +468,7 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
543
468
|
var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
|
|
544
469
|
function validatePathExpression(path7) {
|
|
545
470
|
try {
|
|
546
|
-
const tokens = (0,
|
|
471
|
+
const tokens = (0, import_path_to_regexp.parse)(path7);
|
|
547
472
|
if (/(?<!\\)\{/.test(path7)) {
|
|
548
473
|
return `Optional paths are not supported: ${path7}`;
|
|
549
474
|
}
|
|
@@ -600,6 +525,22 @@ var validateAppPaths = (name, app) => {
|
|
|
600
525
|
}
|
|
601
526
|
}
|
|
602
527
|
}
|
|
528
|
+
if (app.assetPrefix) {
|
|
529
|
+
if (!VALID_ASSET_PREFIX_REGEXP.test(app.assetPrefix)) {
|
|
530
|
+
throw new MicrofrontendError(
|
|
531
|
+
`Invalid asset prefix for application "${name}". ${app.assetPrefix} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`,
|
|
532
|
+
{ type: "application", subtype: "invalid_asset_prefix" }
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
if (app.assetPrefix !== `vc-ap-${name}` && !app.routing.some(
|
|
536
|
+
(group) => group.paths.includes(`/${app.assetPrefix}/:path*`) && !group.flag
|
|
537
|
+
)) {
|
|
538
|
+
throw new MicrofrontendError(
|
|
539
|
+
`When \`assetPrefix\` is specified, \`/${app.assetPrefix}/:path*\` must be added the routing paths for the application. Changing the asset prefix is not a forwards and backwards compatible change, and the custom asset prefix should be added to \`paths\` and deployed before setting the \`assetPrefix\` field.`,
|
|
540
|
+
{ type: "application", subtype: "invalid_asset_prefix" }
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
603
544
|
};
|
|
604
545
|
var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
605
546
|
if (!applicationConfigsById) {
|
|
@@ -631,6 +572,15 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
631
572
|
}
|
|
632
573
|
};
|
|
633
574
|
|
|
575
|
+
// src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
|
|
576
|
+
var import_md5 = __toESM(require("md5"), 1);
|
|
577
|
+
function hashApplicationName(name) {
|
|
578
|
+
if (!name) {
|
|
579
|
+
throw new Error("Application name is required to generate hash");
|
|
580
|
+
}
|
|
581
|
+
return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
|
|
582
|
+
}
|
|
583
|
+
|
|
634
584
|
// src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
|
|
635
585
|
var PREFIX = "vc-ap";
|
|
636
586
|
function generateAssetPrefixFromName({
|
|
@@ -639,7 +589,7 @@ function generateAssetPrefixFromName({
|
|
|
639
589
|
if (!name) {
|
|
640
590
|
throw new Error("Name is required to generate an asset prefix");
|
|
641
591
|
}
|
|
642
|
-
return `${PREFIX}-${name}`;
|
|
592
|
+
return `${PREFIX}-${hashApplicationName(name)}`;
|
|
643
593
|
}
|
|
644
594
|
|
|
645
595
|
// src/config/microfrontends-config/isomorphic/utils/generate-port.ts
|
|
@@ -799,7 +749,13 @@ var Application = class {
|
|
|
799
749
|
return this.default;
|
|
800
750
|
}
|
|
801
751
|
getAssetPrefix() {
|
|
802
|
-
|
|
752
|
+
const generatedAssetPrefix = generateAssetPrefixFromName({
|
|
753
|
+
name: this.name
|
|
754
|
+
});
|
|
755
|
+
if ("assetPrefix" in this.serialized) {
|
|
756
|
+
return this.serialized.assetPrefix ?? generatedAssetPrefix;
|
|
757
|
+
}
|
|
758
|
+
return generatedAssetPrefix;
|
|
803
759
|
}
|
|
804
760
|
getAutomationBypassEnvVarName() {
|
|
805
761
|
return generateAutomationBypassEnvVarName({ name: this.name });
|
|
@@ -933,7 +889,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
933
889
|
);
|
|
934
890
|
if (!app) {
|
|
935
891
|
throw new MicrofrontendError(
|
|
936
|
-
`Could not find microfrontends configuration for application "${name}"
|
|
892
|
+
`Could not find microfrontends configuration for application "${name}". If the name in package.json differs from your Vercel Project name, set the \`packageName\` field for the application in \`microfrontends.json\` to ensure that the configuration can be found locally.`,
|
|
937
893
|
{
|
|
938
894
|
type: "application",
|
|
939
895
|
subtype: "not_found"
|
|
@@ -978,23 +934,6 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
978
934
|
toSchemaJson() {
|
|
979
935
|
return this.serialized.config;
|
|
980
936
|
}
|
|
981
|
-
toClientConfig() {
|
|
982
|
-
const applications = Object.fromEntries(
|
|
983
|
-
Object.entries(this.childApplications).map(([name, application]) => [
|
|
984
|
-
name,
|
|
985
|
-
{
|
|
986
|
-
default: false,
|
|
987
|
-
routing: application.routing
|
|
988
|
-
}
|
|
989
|
-
])
|
|
990
|
-
);
|
|
991
|
-
applications[this.defaultApplication.name] = {
|
|
992
|
-
default: true
|
|
993
|
-
};
|
|
994
|
-
return new MicrofrontendConfigClient({
|
|
995
|
-
applications
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
937
|
serialize() {
|
|
999
938
|
return this.serialized;
|
|
1000
939
|
}
|
|
@@ -1057,8 +996,9 @@ var CONFIGURATION_FILENAMES = [
|
|
|
1057
996
|
var configCache = {};
|
|
1058
997
|
function findPackageWithMicrofrontendsConfig({
|
|
1059
998
|
repositoryRoot,
|
|
1060
|
-
|
|
999
|
+
applicationContext
|
|
1061
1000
|
}) {
|
|
1001
|
+
const applicationName = applicationContext.name;
|
|
1062
1002
|
try {
|
|
1063
1003
|
const microfrontendsJsonPaths = import_fast_glob.default.globSync(
|
|
1064
1004
|
`**/{${CONFIGURATION_FILENAMES.join(",")}}`,
|
|
@@ -1100,26 +1040,45 @@ ${matchingPaths.join("\n \u2022 ")}`,
|
|
|
1100
1040
|
);
|
|
1101
1041
|
}
|
|
1102
1042
|
if (matchingPaths.length === 0) {
|
|
1043
|
+
let additionalErrorMessage = "";
|
|
1044
|
+
if (microfrontendsJsonPaths.length > 0) {
|
|
1045
|
+
if (!applicationContext.projectName) {
|
|
1046
|
+
additionalErrorMessage = `
|
|
1047
|
+
|
|
1048
|
+
If the name in package.json (${applicationContext.packageJsonName}) differs from your Vercel Project name, set the \`packageName\` field for the application in \`microfrontends.json\` to ensure that the configuration can be found locally.`;
|
|
1049
|
+
} else {
|
|
1050
|
+
additionalErrorMessage = `
|
|
1051
|
+
|
|
1052
|
+
Names of applications in \`microfrontends.json\` must match the Vercel Project name (${applicationContext.projectName}).`;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1103
1055
|
throw new MicrofrontendError(
|
|
1104
|
-
`Could not find a \`microfrontends.json\` file in the repository that contains "
|
|
1056
|
+
`Could not find a \`microfrontends.json\` file in the repository that contains the "${applicationName}" application.${additionalErrorMessage}
|
|
1057
|
+
|
|
1058
|
+
If your Vercel Microfrontends configuration is not in this repository, you can use the Vercel CLI to pull the Vercel Microfrontends configuration using the "vercel microfrontends pull" command, or you can specify the path manually using the VC_MICROFRONTENDS_CONFIG environment variable.
|
|
1059
|
+
|
|
1060
|
+
If you suspect this is thrown in error, please reach out to the Vercel team.`,
|
|
1105
1061
|
{ type: "config", subtype: "inference_failed" }
|
|
1106
1062
|
);
|
|
1107
1063
|
}
|
|
1108
1064
|
const [packageJsonPath] = matchingPaths;
|
|
1109
1065
|
return (0, import_node_path2.dirname)(packageJsonPath);
|
|
1110
1066
|
} catch (error) {
|
|
1067
|
+
if (error instanceof MicrofrontendError) {
|
|
1068
|
+
throw error;
|
|
1069
|
+
}
|
|
1111
1070
|
return null;
|
|
1112
1071
|
}
|
|
1113
1072
|
}
|
|
1114
1073
|
function inferMicrofrontendsLocation(opts) {
|
|
1115
|
-
const cacheKey = `${opts.repositoryRoot}-${opts.
|
|
1074
|
+
const cacheKey = `${opts.repositoryRoot}-${opts.applicationContext.name}`;
|
|
1116
1075
|
if (configCache[cacheKey]) {
|
|
1117
1076
|
return configCache[cacheKey];
|
|
1118
1077
|
}
|
|
1119
1078
|
const result = findPackageWithMicrofrontendsConfig(opts);
|
|
1120
1079
|
if (!result) {
|
|
1121
1080
|
throw new MicrofrontendError(
|
|
1122
|
-
`Could not infer the location of the \`microfrontends.json\` file for application "${opts.
|
|
1081
|
+
`Could not infer the location of the \`microfrontends.json\` file for application "${opts.applicationContext.name}" starting in directory "${opts.repositoryRoot}".`,
|
|
1123
1082
|
{ type: "config", subtype: "inference_failed" }
|
|
1124
1083
|
);
|
|
1125
1084
|
}
|
|
@@ -1195,8 +1154,31 @@ function getApplicationContext(opts) {
|
|
|
1195
1154
|
if (opts?.appName) {
|
|
1196
1155
|
return { name: opts.appName };
|
|
1197
1156
|
}
|
|
1157
|
+
if (process.env.VERCEL_PROJECT_NAME) {
|
|
1158
|
+
return {
|
|
1159
|
+
name: process.env.VERCEL_PROJECT_NAME,
|
|
1160
|
+
projectName: process.env.VERCEL_PROJECT_NAME
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1198
1163
|
if (process.env.NX_TASK_TARGET_PROJECT) {
|
|
1199
|
-
return {
|
|
1164
|
+
return {
|
|
1165
|
+
name: process.env.NX_TASK_TARGET_PROJECT,
|
|
1166
|
+
packageJsonName: process.env.NX_TASK_TARGET_PROJECT
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
try {
|
|
1170
|
+
const vercelProjectJsonPath = import_node_fs6.default.readFileSync(
|
|
1171
|
+
import_node_path6.default.join(opts?.packageRoot || ".", ".vercel", "project.json"),
|
|
1172
|
+
"utf-8"
|
|
1173
|
+
);
|
|
1174
|
+
const projectJson = JSON.parse(vercelProjectJsonPath);
|
|
1175
|
+
if (projectJson.projectName) {
|
|
1176
|
+
return {
|
|
1177
|
+
name: projectJson.projectName,
|
|
1178
|
+
projectName: projectJson.projectName
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
} catch (_) {
|
|
1200
1182
|
}
|
|
1201
1183
|
try {
|
|
1202
1184
|
const packageJsonString = import_node_fs6.default.readFileSync(
|
|
@@ -1214,7 +1196,7 @@ function getApplicationContext(opts) {
|
|
|
1214
1196
|
}
|
|
1215
1197
|
);
|
|
1216
1198
|
}
|
|
1217
|
-
return { name: packageJson.name };
|
|
1199
|
+
return { name: packageJson.name, packageJsonName: packageJson.name };
|
|
1218
1200
|
} catch (err) {
|
|
1219
1201
|
throw MicrofrontendError.handle(err, {
|
|
1220
1202
|
fileName: "package.json"
|
|
@@ -1354,6 +1336,10 @@ var schema_default = {
|
|
|
1354
1336
|
routing: {
|
|
1355
1337
|
$ref: "#/definitions/Routing",
|
|
1356
1338
|
description: "Groups of path expressions that are routed to this application."
|
|
1339
|
+
},
|
|
1340
|
+
assetPrefix: {
|
|
1341
|
+
type: "string",
|
|
1342
|
+
description: "The name of the asset prefix to use instead of the auto-generated name.\n\nThe asset prefix is used to prefix all paths to static assets, such as JS, CSS, or images that are served by a specific application. It is necessary to ensure there are no conflicts with other applications on the same domain.\n\nAn auto-generated asset prefix of the form `vc-ap-<hash>` is used when this field is not provided.\n\nWhen this field is provided, `/${assetPrefix}/:path*` must also be added to the list of paths in the `routing` field. Changing the asset prefix after a microfrontend application has already been deployed is not a forwards and backwards compatible change, and the asset prefix should be added to the `routing` field and deployed before setting the `assetPrefix` field."
|
|
1357
1343
|
}
|
|
1358
1344
|
},
|
|
1359
1345
|
required: [
|
|
@@ -1579,7 +1565,7 @@ var MicrofrontendsServer = class {
|
|
|
1579
1565
|
}
|
|
1580
1566
|
try {
|
|
1581
1567
|
const packageRoot = findPackageRoot(directory);
|
|
1582
|
-
const
|
|
1568
|
+
const applicationContext = getApplicationContext({ packageRoot });
|
|
1583
1569
|
const maybeConfig = findConfig({ dir: packageRoot });
|
|
1584
1570
|
if (maybeConfig) {
|
|
1585
1571
|
return MicrofrontendsServer.fromFile({
|
|
@@ -1613,7 +1599,7 @@ var MicrofrontendsServer = class {
|
|
|
1613
1599
|
if (isMonorepo2) {
|
|
1614
1600
|
const defaultPackage = inferMicrofrontendsLocation({
|
|
1615
1601
|
repositoryRoot,
|
|
1616
|
-
|
|
1602
|
+
applicationContext
|
|
1617
1603
|
});
|
|
1618
1604
|
const maybeConfigFromDefault = findConfig({ dir: defaultPackage });
|
|
1619
1605
|
if (maybeConfigFromDefault) {
|
|
@@ -2145,7 +2131,7 @@ var ProxyRequestRouter = class {
|
|
|
2145
2131
|
}
|
|
2146
2132
|
for (const group of application.routing) {
|
|
2147
2133
|
for (const childPath of group.paths) {
|
|
2148
|
-
const regexp = (0,
|
|
2134
|
+
const regexp = (0, import_path_to_regexp2.pathToRegexp)(childPath);
|
|
2149
2135
|
if (regexp.test(url.pathname)) {
|
|
2150
2136
|
mfeDebug(
|
|
2151
2137
|
`routing ${path7} to '${target.application}' at ${target.hostname}`
|
|
@@ -2188,7 +2174,7 @@ var ProxyRequestRouter = class {
|
|
|
2188
2174
|
const pathname = url.pathname;
|
|
2189
2175
|
const target = this.getApplicationTarget(app);
|
|
2190
2176
|
for (const rewrite of rewrites) {
|
|
2191
|
-
if ((0,
|
|
2177
|
+
if ((0, import_path_to_regexp2.pathToRegexp)(`/${app.getAssetPrefix()}${rewrite}`).test(pathname)) {
|
|
2192
2178
|
mfeDebug(
|
|
2193
2179
|
`routing ${pathname} to '${target.application}' at ${target.hostname}`
|
|
2194
2180
|
);
|
|
@@ -2205,8 +2191,8 @@ var ProxyRequestRouter = class {
|
|
|
2205
2191
|
referer = void 0,
|
|
2206
2192
|
applications
|
|
2207
2193
|
}) {
|
|
2208
|
-
const isStackFrame = (0,
|
|
2209
|
-
(0,
|
|
2194
|
+
const isStackFrame = (0, import_path_to_regexp2.pathToRegexp)("/__nextjs_original-stack-frame").test(url.pathname) || // Plural form was introduced in https://github.com/vercel/next.js/pull/75557
|
|
2195
|
+
(0, import_path_to_regexp2.pathToRegexp)("/__nextjs_original-stack-frames").test(url.pathname);
|
|
2210
2196
|
if (!referer || !isStackFrame) {
|
|
2211
2197
|
return null;
|
|
2212
2198
|
}
|
|
@@ -2226,7 +2212,7 @@ var ProxyRequestRouter = class {
|
|
|
2226
2212
|
} : null;
|
|
2227
2213
|
}
|
|
2228
2214
|
checkNextSourceMap({ url }) {
|
|
2229
|
-
const isSourceMap = (0,
|
|
2215
|
+
const isSourceMap = (0, import_path_to_regexp2.pathToRegexp)("/__nextjs_source-map").test(url.pathname);
|
|
2230
2216
|
if (!isSourceMap) {
|
|
2231
2217
|
return null;
|
|
2232
2218
|
}
|
|
@@ -2246,7 +2232,7 @@ var ProxyRequestRouter = class {
|
|
|
2246
2232
|
url,
|
|
2247
2233
|
applications
|
|
2248
2234
|
}) {
|
|
2249
|
-
const isNextImage = (0,
|
|
2235
|
+
const isNextImage = (0, import_path_to_regexp2.pathToRegexp)("/_next/image").test(url.pathname);
|
|
2250
2236
|
if (!isNextImage) {
|
|
2251
2237
|
return null;
|
|
2252
2238
|
}
|
package/dist/config.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/config/microfrontends-config/isomorphic/index.ts
|
|
@@ -134,84 +144,6 @@ function isDefaultApp(a) {
|
|
|
134
144
|
return !("routing" in a);
|
|
135
145
|
}
|
|
136
146
|
|
|
137
|
-
// src/config/microfrontends-config/client/index.ts
|
|
138
|
-
var import_path_to_regexp = require("path-to-regexp");
|
|
139
|
-
var regexpCache = /* @__PURE__ */ new Map();
|
|
140
|
-
var getRegexp = (path) => {
|
|
141
|
-
const existing = regexpCache.get(path);
|
|
142
|
-
if (existing) {
|
|
143
|
-
return existing;
|
|
144
|
-
}
|
|
145
|
-
const regexp = (0, import_path_to_regexp.pathToRegexp)(path);
|
|
146
|
-
regexpCache.set(path, regexp);
|
|
147
|
-
return regexp;
|
|
148
|
-
};
|
|
149
|
-
var MicrofrontendConfigClient = class {
|
|
150
|
-
constructor(config, opts) {
|
|
151
|
-
this.pathCache = {};
|
|
152
|
-
this.serialized = config;
|
|
153
|
-
if (opts?.removeFlaggedPaths) {
|
|
154
|
-
for (const app of Object.values(config.applications)) {
|
|
155
|
-
if (app.routing) {
|
|
156
|
-
app.routing = app.routing.filter((match) => !match.flag);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
this.applications = config.applications;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Create a new `MicrofrontendConfigClient` from a JSON string.
|
|
164
|
-
* Config must be passed in to remain framework agnostic
|
|
165
|
-
*/
|
|
166
|
-
static fromEnv(config, opts) {
|
|
167
|
-
if (!config) {
|
|
168
|
-
throw new Error(
|
|
169
|
-
"Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
return new MicrofrontendConfigClient(
|
|
173
|
-
JSON.parse(config),
|
|
174
|
-
opts
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
isEqual(other) {
|
|
178
|
-
return this === other || JSON.stringify(this.applications) === JSON.stringify(other.applications);
|
|
179
|
-
}
|
|
180
|
-
getApplicationNameForPath(path) {
|
|
181
|
-
if (!path.startsWith("/")) {
|
|
182
|
-
throw new Error(`Path must start with a /`);
|
|
183
|
-
}
|
|
184
|
-
if (this.pathCache[path]) {
|
|
185
|
-
return this.pathCache[path];
|
|
186
|
-
}
|
|
187
|
-
const pathname = new URL(path, "https://example.com").pathname;
|
|
188
|
-
for (const [name, application] of Object.entries(this.applications)) {
|
|
189
|
-
if (application.routing) {
|
|
190
|
-
for (const group of application.routing) {
|
|
191
|
-
for (const childPath of group.paths) {
|
|
192
|
-
const regexp = getRegexp(childPath);
|
|
193
|
-
if (regexp.test(pathname)) {
|
|
194
|
-
this.pathCache[path] = name;
|
|
195
|
-
return name;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const defaultApplication = Object.entries(this.applications).find(
|
|
202
|
-
([, application]) => application.default
|
|
203
|
-
);
|
|
204
|
-
if (!defaultApplication) {
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
207
|
-
this.pathCache[path] = defaultApplication[0];
|
|
208
|
-
return defaultApplication[0];
|
|
209
|
-
}
|
|
210
|
-
serialize() {
|
|
211
|
-
return this.serialized;
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
|
|
215
147
|
// src/config/overrides/constants.ts
|
|
216
148
|
var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
|
|
217
149
|
var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
|
|
@@ -246,11 +178,12 @@ function parseOverrides(cookies) {
|
|
|
246
178
|
}
|
|
247
179
|
|
|
248
180
|
// src/config/microfrontends-config/isomorphic/validation.ts
|
|
249
|
-
var
|
|
181
|
+
var import_path_to_regexp = require("path-to-regexp");
|
|
250
182
|
var LIST_FORMATTER = new Intl.ListFormat("en", {
|
|
251
183
|
style: "long",
|
|
252
184
|
type: "conjunction"
|
|
253
185
|
});
|
|
186
|
+
var VALID_ASSET_PREFIX_REGEXP = /^[a-z](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
254
187
|
var validateConfigPaths = (applicationConfigsById) => {
|
|
255
188
|
if (!applicationConfigsById) {
|
|
256
189
|
return;
|
|
@@ -273,7 +206,7 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
273
206
|
} else {
|
|
274
207
|
pathsByApplicationId.set(path, {
|
|
275
208
|
applications: [id],
|
|
276
|
-
matcher: (0,
|
|
209
|
+
matcher: (0, import_path_to_regexp.pathToRegexp)(path),
|
|
277
210
|
applicationId: id
|
|
278
211
|
});
|
|
279
212
|
}
|
|
@@ -320,7 +253,7 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
320
253
|
var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
|
|
321
254
|
function validatePathExpression(path) {
|
|
322
255
|
try {
|
|
323
|
-
const tokens = (0,
|
|
256
|
+
const tokens = (0, import_path_to_regexp.parse)(path);
|
|
324
257
|
if (/(?<!\\)\{/.test(path)) {
|
|
325
258
|
return `Optional paths are not supported: ${path}`;
|
|
326
259
|
}
|
|
@@ -377,6 +310,22 @@ var validateAppPaths = (name, app) => {
|
|
|
377
310
|
}
|
|
378
311
|
}
|
|
379
312
|
}
|
|
313
|
+
if (app.assetPrefix) {
|
|
314
|
+
if (!VALID_ASSET_PREFIX_REGEXP.test(app.assetPrefix)) {
|
|
315
|
+
throw new MicrofrontendError(
|
|
316
|
+
`Invalid asset prefix for application "${name}". ${app.assetPrefix} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`,
|
|
317
|
+
{ type: "application", subtype: "invalid_asset_prefix" }
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
if (app.assetPrefix !== `vc-ap-${name}` && !app.routing.some(
|
|
321
|
+
(group) => group.paths.includes(`/${app.assetPrefix}/:path*`) && !group.flag
|
|
322
|
+
)) {
|
|
323
|
+
throw new MicrofrontendError(
|
|
324
|
+
`When \`assetPrefix\` is specified, \`/${app.assetPrefix}/:path*\` must be added the routing paths for the application. Changing the asset prefix is not a forwards and backwards compatible change, and the custom asset prefix should be added to \`paths\` and deployed before setting the \`assetPrefix\` field.`,
|
|
325
|
+
{ type: "application", subtype: "invalid_asset_prefix" }
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
380
329
|
};
|
|
381
330
|
var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
382
331
|
if (!applicationConfigsById) {
|
|
@@ -408,6 +357,15 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
408
357
|
}
|
|
409
358
|
};
|
|
410
359
|
|
|
360
|
+
// src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
|
|
361
|
+
var import_md5 = __toESM(require("md5"), 1);
|
|
362
|
+
function hashApplicationName(name) {
|
|
363
|
+
if (!name) {
|
|
364
|
+
throw new Error("Application name is required to generate hash");
|
|
365
|
+
}
|
|
366
|
+
return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
|
|
367
|
+
}
|
|
368
|
+
|
|
411
369
|
// src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
|
|
412
370
|
var PREFIX = "vc-ap";
|
|
413
371
|
function generateAssetPrefixFromName({
|
|
@@ -416,7 +374,7 @@ function generateAssetPrefixFromName({
|
|
|
416
374
|
if (!name) {
|
|
417
375
|
throw new Error("Name is required to generate an asset prefix");
|
|
418
376
|
}
|
|
419
|
-
return `${PREFIX}-${name}`;
|
|
377
|
+
return `${PREFIX}-${hashApplicationName(name)}`;
|
|
420
378
|
}
|
|
421
379
|
|
|
422
380
|
// src/config/microfrontends-config/isomorphic/utils/generate-port.ts
|
|
@@ -576,7 +534,13 @@ var Application = class {
|
|
|
576
534
|
return this.default;
|
|
577
535
|
}
|
|
578
536
|
getAssetPrefix() {
|
|
579
|
-
|
|
537
|
+
const generatedAssetPrefix = generateAssetPrefixFromName({
|
|
538
|
+
name: this.name
|
|
539
|
+
});
|
|
540
|
+
if ("assetPrefix" in this.serialized) {
|
|
541
|
+
return this.serialized.assetPrefix ?? generatedAssetPrefix;
|
|
542
|
+
}
|
|
543
|
+
return generatedAssetPrefix;
|
|
580
544
|
}
|
|
581
545
|
getAutomationBypassEnvVarName() {
|
|
582
546
|
return generateAutomationBypassEnvVarName({ name: this.name });
|
|
@@ -710,7 +674,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
710
674
|
);
|
|
711
675
|
if (!app) {
|
|
712
676
|
throw new MicrofrontendError(
|
|
713
|
-
`Could not find microfrontends configuration for application "${name}"
|
|
677
|
+
`Could not find microfrontends configuration for application "${name}". If the name in package.json differs from your Vercel Project name, set the \`packageName\` field for the application in \`microfrontends.json\` to ensure that the configuration can be found locally.`,
|
|
714
678
|
{
|
|
715
679
|
type: "application",
|
|
716
680
|
subtype: "not_found"
|
|
@@ -755,23 +719,6 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
755
719
|
toSchemaJson() {
|
|
756
720
|
return this.serialized.config;
|
|
757
721
|
}
|
|
758
|
-
toClientConfig() {
|
|
759
|
-
const applications = Object.fromEntries(
|
|
760
|
-
Object.entries(this.childApplications).map(([name, application]) => [
|
|
761
|
-
name,
|
|
762
|
-
{
|
|
763
|
-
default: false,
|
|
764
|
-
routing: application.routing
|
|
765
|
-
}
|
|
766
|
-
])
|
|
767
|
-
);
|
|
768
|
-
applications[this.defaultApplication.name] = {
|
|
769
|
-
default: true
|
|
770
|
-
};
|
|
771
|
-
return new MicrofrontendConfigClient({
|
|
772
|
-
applications
|
|
773
|
-
});
|
|
774
|
-
}
|
|
775
722
|
serialize() {
|
|
776
723
|
return this.serialized;
|
|
777
724
|
}
|