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