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