@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/dist/utils/mfe-port.cjs
CHANGED
|
@@ -235,8 +235,9 @@ var CONFIGURATION_FILENAMES = [
|
|
|
235
235
|
var configCache = {};
|
|
236
236
|
function findPackageWithMicrofrontendsConfig({
|
|
237
237
|
repositoryRoot,
|
|
238
|
-
|
|
238
|
+
applicationContext
|
|
239
239
|
}) {
|
|
240
|
+
const applicationName = applicationContext.name;
|
|
240
241
|
try {
|
|
241
242
|
const microfrontendsJsonPaths = import_fast_glob.default.globSync(
|
|
242
243
|
`**/{${CONFIGURATION_FILENAMES.join(",")}}`,
|
|
@@ -278,26 +279,45 @@ ${matchingPaths.join("\n \u2022 ")}`,
|
|
|
278
279
|
);
|
|
279
280
|
}
|
|
280
281
|
if (matchingPaths.length === 0) {
|
|
282
|
+
let additionalErrorMessage = "";
|
|
283
|
+
if (microfrontendsJsonPaths.length > 0) {
|
|
284
|
+
if (!applicationContext.projectName) {
|
|
285
|
+
additionalErrorMessage = `
|
|
286
|
+
|
|
287
|
+
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.`;
|
|
288
|
+
} else {
|
|
289
|
+
additionalErrorMessage = `
|
|
290
|
+
|
|
291
|
+
Names of applications in \`microfrontends.json\` must match the Vercel Project name (${applicationContext.projectName}).`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
281
294
|
throw new MicrofrontendError(
|
|
282
|
-
`Could not find a \`microfrontends.json\` file in the repository that contains "
|
|
295
|
+
`Could not find a \`microfrontends.json\` file in the repository that contains the "${applicationName}" application.${additionalErrorMessage}
|
|
296
|
+
|
|
297
|
+
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.
|
|
298
|
+
|
|
299
|
+
If you suspect this is thrown in error, please reach out to the Vercel team.`,
|
|
283
300
|
{ type: "config", subtype: "inference_failed" }
|
|
284
301
|
);
|
|
285
302
|
}
|
|
286
303
|
const [packageJsonPath] = matchingPaths;
|
|
287
304
|
return (0, import_node_path2.dirname)(packageJsonPath);
|
|
288
305
|
} catch (error) {
|
|
306
|
+
if (error instanceof MicrofrontendError) {
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
289
309
|
return null;
|
|
290
310
|
}
|
|
291
311
|
}
|
|
292
312
|
function inferMicrofrontendsLocation(opts) {
|
|
293
|
-
const cacheKey = `${opts.repositoryRoot}-${opts.
|
|
313
|
+
const cacheKey = `${opts.repositoryRoot}-${opts.applicationContext.name}`;
|
|
294
314
|
if (configCache[cacheKey]) {
|
|
295
315
|
return configCache[cacheKey];
|
|
296
316
|
}
|
|
297
317
|
const result = findPackageWithMicrofrontendsConfig(opts);
|
|
298
318
|
if (!result) {
|
|
299
319
|
throw new MicrofrontendError(
|
|
300
|
-
`Could not infer the location of the \`microfrontends.json\` file for application "${opts.
|
|
320
|
+
`Could not infer the location of the \`microfrontends.json\` file for application "${opts.applicationContext.name}" starting in directory "${opts.repositoryRoot}".`,
|
|
301
321
|
{ type: "config", subtype: "inference_failed" }
|
|
302
322
|
);
|
|
303
323
|
}
|
|
@@ -369,90 +389,13 @@ function findConfig({ dir }) {
|
|
|
369
389
|
// src/config/microfrontends-config/isomorphic/index.ts
|
|
370
390
|
var import_jsonc_parser2 = require("jsonc-parser");
|
|
371
391
|
|
|
372
|
-
// src/config/microfrontends-config/client/index.ts
|
|
373
|
-
var import_path_to_regexp = require("path-to-regexp");
|
|
374
|
-
var regexpCache = /* @__PURE__ */ new Map();
|
|
375
|
-
var getRegexp = (path7) => {
|
|
376
|
-
const existing = regexpCache.get(path7);
|
|
377
|
-
if (existing) {
|
|
378
|
-
return existing;
|
|
379
|
-
}
|
|
380
|
-
const regexp = (0, import_path_to_regexp.pathToRegexp)(path7);
|
|
381
|
-
regexpCache.set(path7, regexp);
|
|
382
|
-
return regexp;
|
|
383
|
-
};
|
|
384
|
-
var MicrofrontendConfigClient = class {
|
|
385
|
-
constructor(config, opts) {
|
|
386
|
-
this.pathCache = {};
|
|
387
|
-
this.serialized = config;
|
|
388
|
-
if (opts?.removeFlaggedPaths) {
|
|
389
|
-
for (const app of Object.values(config.applications)) {
|
|
390
|
-
if (app.routing) {
|
|
391
|
-
app.routing = app.routing.filter((match) => !match.flag);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
this.applications = config.applications;
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Create a new `MicrofrontendConfigClient` from a JSON string.
|
|
399
|
-
* Config must be passed in to remain framework agnostic
|
|
400
|
-
*/
|
|
401
|
-
static fromEnv(config, opts) {
|
|
402
|
-
if (!config) {
|
|
403
|
-
throw new Error(
|
|
404
|
-
"Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
return new MicrofrontendConfigClient(
|
|
408
|
-
JSON.parse(config),
|
|
409
|
-
opts
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
isEqual(other) {
|
|
413
|
-
return this === other || JSON.stringify(this.applications) === JSON.stringify(other.applications);
|
|
414
|
-
}
|
|
415
|
-
getApplicationNameForPath(path7) {
|
|
416
|
-
if (!path7.startsWith("/")) {
|
|
417
|
-
throw new Error(`Path must start with a /`);
|
|
418
|
-
}
|
|
419
|
-
if (this.pathCache[path7]) {
|
|
420
|
-
return this.pathCache[path7];
|
|
421
|
-
}
|
|
422
|
-
const pathname = new URL(path7, "https://example.com").pathname;
|
|
423
|
-
for (const [name, application] of Object.entries(this.applications)) {
|
|
424
|
-
if (application.routing) {
|
|
425
|
-
for (const group of application.routing) {
|
|
426
|
-
for (const childPath of group.paths) {
|
|
427
|
-
const regexp = getRegexp(childPath);
|
|
428
|
-
if (regexp.test(pathname)) {
|
|
429
|
-
this.pathCache[path7] = name;
|
|
430
|
-
return name;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
const defaultApplication = Object.entries(this.applications).find(
|
|
437
|
-
([, application]) => application.default
|
|
438
|
-
);
|
|
439
|
-
if (!defaultApplication) {
|
|
440
|
-
return null;
|
|
441
|
-
}
|
|
442
|
-
this.pathCache[path7] = defaultApplication[0];
|
|
443
|
-
return defaultApplication[0];
|
|
444
|
-
}
|
|
445
|
-
serialize() {
|
|
446
|
-
return this.serialized;
|
|
447
|
-
}
|
|
448
|
-
};
|
|
449
|
-
|
|
450
392
|
// src/config/microfrontends-config/isomorphic/validation.ts
|
|
451
|
-
var
|
|
393
|
+
var import_path_to_regexp = require("path-to-regexp");
|
|
452
394
|
var LIST_FORMATTER = new Intl.ListFormat("en", {
|
|
453
395
|
style: "long",
|
|
454
396
|
type: "conjunction"
|
|
455
397
|
});
|
|
398
|
+
var VALID_ASSET_PREFIX_REGEXP = /^[a-z](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
456
399
|
var validateConfigPaths = (applicationConfigsById) => {
|
|
457
400
|
if (!applicationConfigsById) {
|
|
458
401
|
return;
|
|
@@ -475,7 +418,7 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
475
418
|
} else {
|
|
476
419
|
pathsByApplicationId.set(path7, {
|
|
477
420
|
applications: [id],
|
|
478
|
-
matcher: (0,
|
|
421
|
+
matcher: (0, import_path_to_regexp.pathToRegexp)(path7),
|
|
479
422
|
applicationId: id
|
|
480
423
|
});
|
|
481
424
|
}
|
|
@@ -522,7 +465,7 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
522
465
|
var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
|
|
523
466
|
function validatePathExpression(path7) {
|
|
524
467
|
try {
|
|
525
|
-
const tokens = (0,
|
|
468
|
+
const tokens = (0, import_path_to_regexp.parse)(path7);
|
|
526
469
|
if (/(?<!\\)\{/.test(path7)) {
|
|
527
470
|
return `Optional paths are not supported: ${path7}`;
|
|
528
471
|
}
|
|
@@ -579,6 +522,22 @@ var validateAppPaths = (name, app) => {
|
|
|
579
522
|
}
|
|
580
523
|
}
|
|
581
524
|
}
|
|
525
|
+
if (app.assetPrefix) {
|
|
526
|
+
if (!VALID_ASSET_PREFIX_REGEXP.test(app.assetPrefix)) {
|
|
527
|
+
throw new MicrofrontendError(
|
|
528
|
+
`Invalid asset prefix for application "${name}". ${app.assetPrefix} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.`,
|
|
529
|
+
{ type: "application", subtype: "invalid_asset_prefix" }
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
if (app.assetPrefix !== `vc-ap-${name}` && !app.routing.some(
|
|
533
|
+
(group) => group.paths.includes(`/${app.assetPrefix}/:path*`) && !group.flag
|
|
534
|
+
)) {
|
|
535
|
+
throw new MicrofrontendError(
|
|
536
|
+
`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.`,
|
|
537
|
+
{ type: "application", subtype: "invalid_asset_prefix" }
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
582
541
|
};
|
|
583
542
|
var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
584
543
|
if (!applicationConfigsById) {
|
|
@@ -610,6 +569,15 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
610
569
|
}
|
|
611
570
|
};
|
|
612
571
|
|
|
572
|
+
// src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
|
|
573
|
+
var import_md5 = __toESM(require("md5"), 1);
|
|
574
|
+
function hashApplicationName(name) {
|
|
575
|
+
if (!name) {
|
|
576
|
+
throw new Error("Application name is required to generate hash");
|
|
577
|
+
}
|
|
578
|
+
return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
|
|
579
|
+
}
|
|
580
|
+
|
|
613
581
|
// src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
|
|
614
582
|
var PREFIX = "vc-ap";
|
|
615
583
|
function generateAssetPrefixFromName({
|
|
@@ -618,7 +586,7 @@ function generateAssetPrefixFromName({
|
|
|
618
586
|
if (!name) {
|
|
619
587
|
throw new Error("Name is required to generate an asset prefix");
|
|
620
588
|
}
|
|
621
|
-
return `${PREFIX}-${name}`;
|
|
589
|
+
return `${PREFIX}-${hashApplicationName(name)}`;
|
|
622
590
|
}
|
|
623
591
|
|
|
624
592
|
// src/config/microfrontends-config/isomorphic/utils/generate-port.ts
|
|
@@ -778,7 +746,13 @@ var Application = class {
|
|
|
778
746
|
return this.default;
|
|
779
747
|
}
|
|
780
748
|
getAssetPrefix() {
|
|
781
|
-
|
|
749
|
+
const generatedAssetPrefix = generateAssetPrefixFromName({
|
|
750
|
+
name: this.name
|
|
751
|
+
});
|
|
752
|
+
if ("assetPrefix" in this.serialized) {
|
|
753
|
+
return this.serialized.assetPrefix ?? generatedAssetPrefix;
|
|
754
|
+
}
|
|
755
|
+
return generatedAssetPrefix;
|
|
782
756
|
}
|
|
783
757
|
getAutomationBypassEnvVarName() {
|
|
784
758
|
return generateAutomationBypassEnvVarName({ name: this.name });
|
|
@@ -912,7 +886,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
912
886
|
);
|
|
913
887
|
if (!app) {
|
|
914
888
|
throw new MicrofrontendError(
|
|
915
|
-
`Could not find microfrontends configuration for application "${name}"
|
|
889
|
+
`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.`,
|
|
916
890
|
{
|
|
917
891
|
type: "application",
|
|
918
892
|
subtype: "not_found"
|
|
@@ -957,23 +931,6 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
957
931
|
toSchemaJson() {
|
|
958
932
|
return this.serialized.config;
|
|
959
933
|
}
|
|
960
|
-
toClientConfig() {
|
|
961
|
-
const applications = Object.fromEntries(
|
|
962
|
-
Object.entries(this.childApplications).map(([name, application]) => [
|
|
963
|
-
name,
|
|
964
|
-
{
|
|
965
|
-
default: false,
|
|
966
|
-
routing: application.routing
|
|
967
|
-
}
|
|
968
|
-
])
|
|
969
|
-
);
|
|
970
|
-
applications[this.defaultApplication.name] = {
|
|
971
|
-
default: true
|
|
972
|
-
};
|
|
973
|
-
return new MicrofrontendConfigClient({
|
|
974
|
-
applications
|
|
975
|
-
});
|
|
976
|
-
}
|
|
977
934
|
serialize() {
|
|
978
935
|
return this.serialized;
|
|
979
936
|
}
|
|
@@ -986,8 +943,31 @@ function getApplicationContext(opts) {
|
|
|
986
943
|
if (opts?.appName) {
|
|
987
944
|
return { name: opts.appName };
|
|
988
945
|
}
|
|
946
|
+
if (process.env.VERCEL_PROJECT_NAME) {
|
|
947
|
+
return {
|
|
948
|
+
name: process.env.VERCEL_PROJECT_NAME,
|
|
949
|
+
projectName: process.env.VERCEL_PROJECT_NAME
|
|
950
|
+
};
|
|
951
|
+
}
|
|
989
952
|
if (process.env.NX_TASK_TARGET_PROJECT) {
|
|
990
|
-
return {
|
|
953
|
+
return {
|
|
954
|
+
name: process.env.NX_TASK_TARGET_PROJECT,
|
|
955
|
+
packageJsonName: process.env.NX_TASK_TARGET_PROJECT
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
try {
|
|
959
|
+
const vercelProjectJsonPath = import_node_fs6.default.readFileSync(
|
|
960
|
+
import_node_path6.default.join(opts?.packageRoot || ".", ".vercel", "project.json"),
|
|
961
|
+
"utf-8"
|
|
962
|
+
);
|
|
963
|
+
const projectJson = JSON.parse(vercelProjectJsonPath);
|
|
964
|
+
if (projectJson.projectName) {
|
|
965
|
+
return {
|
|
966
|
+
name: projectJson.projectName,
|
|
967
|
+
projectName: projectJson.projectName
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
} catch (_) {
|
|
991
971
|
}
|
|
992
972
|
try {
|
|
993
973
|
const packageJsonString = import_node_fs6.default.readFileSync(
|
|
@@ -1005,7 +985,7 @@ function getApplicationContext(opts) {
|
|
|
1005
985
|
}
|
|
1006
986
|
);
|
|
1007
987
|
}
|
|
1008
|
-
return { name: packageJson.name };
|
|
988
|
+
return { name: packageJson.name, packageJsonName: packageJson.name };
|
|
1009
989
|
} catch (err) {
|
|
1010
990
|
throw MicrofrontendError.handle(err, {
|
|
1011
991
|
fileName: "package.json"
|
|
@@ -1145,6 +1125,10 @@ var schema_default = {
|
|
|
1145
1125
|
routing: {
|
|
1146
1126
|
$ref: "#/definitions/Routing",
|
|
1147
1127
|
description: "Groups of path expressions that are routed to this application."
|
|
1128
|
+
},
|
|
1129
|
+
assetPrefix: {
|
|
1130
|
+
type: "string",
|
|
1131
|
+
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."
|
|
1148
1132
|
}
|
|
1149
1133
|
},
|
|
1150
1134
|
required: [
|
|
@@ -1370,7 +1354,7 @@ var MicrofrontendsServer = class {
|
|
|
1370
1354
|
}
|
|
1371
1355
|
try {
|
|
1372
1356
|
const packageRoot = findPackageRoot(directory);
|
|
1373
|
-
const
|
|
1357
|
+
const applicationContext = getApplicationContext({ packageRoot });
|
|
1374
1358
|
const maybeConfig = findConfig({ dir: packageRoot });
|
|
1375
1359
|
if (maybeConfig) {
|
|
1376
1360
|
return MicrofrontendsServer.fromFile({
|
|
@@ -1404,7 +1388,7 @@ var MicrofrontendsServer = class {
|
|
|
1404
1388
|
if (isMonorepo2) {
|
|
1405
1389
|
const defaultPackage = inferMicrofrontendsLocation({
|
|
1406
1390
|
repositoryRoot,
|
|
1407
|
-
|
|
1391
|
+
applicationContext
|
|
1408
1392
|
});
|
|
1409
1393
|
const maybeConfigFromDefault = findConfig({ dir: defaultPackage });
|
|
1410
1394
|
if (maybeConfigFromDefault) {
|