@vercel/microfrontends 0.9.0 → 0.10.1
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 -7
- package/dist/bin/cli.cjs +1604 -221
- package/dist/config/client.d.ts +1 -1
- package/dist/config/edge.cjs +47 -47
- package/dist/config/edge.cjs.map +1 -1
- package/dist/config/edge.d.ts +6 -6
- package/dist/config/edge.js +46 -46
- package/dist/config/edge.js.map +1 -1
- package/dist/config.cjs +67 -66
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.js +66 -65
- package/dist/config.js.map +1 -1
- package/dist/{index-eff254d8.d.ts → index-acb44057.d.ts} +12 -23
- package/dist/{micro-frontend-config-42886104.d.ts → microfrontend-config-983a5139.d.ts} +13 -13
- 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 +86 -87
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.d.ts +3 -3
- package/dist/next/config.js +85 -86
- package/dist/next/config.js.map +1 -1
- package/dist/next/middleware.cjs +60 -62
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.d.ts +11 -11
- package/dist/next/middleware.js +58 -60
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +80 -79
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.d.ts +10 -10
- package/dist/next/testing.js +80 -79
- package/dist/next/testing.js.map +1 -1
- package/dist/overrides.cjs +9 -9
- package/dist/overrides.cjs.map +1 -1
- package/dist/overrides.d.ts +2 -2
- package/dist/overrides.js +9 -9
- package/dist/overrides.js.map +1 -1
- package/dist/{schema-83a75e61.d.ts → schema-2922d49e.d.ts} +1 -7
- package/dist/{types-4fd1c7c6.d.ts → types-7b1cd9f7.d.ts} +1 -7
- package/dist/types-c3d15d04.d.ts +15 -0
- package/dist/v2/config.cjs +39 -39
- package/dist/v2/config.cjs.map +1 -1
- package/dist/v2/config.d.ts +3 -2
- package/dist/v2/config.js +38 -38
- package/dist/v2/config.js.map +1 -1
- package/dist/v2/microfrontends/server.cjs +223 -96
- package/dist/v2/microfrontends/server.cjs.map +1 -1
- package/dist/v2/microfrontends/server.d.ts +11 -3
- package/dist/v2/microfrontends/server.js +223 -96
- package/dist/v2/microfrontends/server.js.map +1 -1
- package/dist/v2/microfrontends.cjs +44 -44
- package/dist/v2/microfrontends.cjs.map +1 -1
- package/dist/v2/microfrontends.d.ts +6 -5
- package/dist/v2/microfrontends.js +44 -44
- package/dist/v2/microfrontends.js.map +1 -1
- package/dist/v2/next/client.cjs +1 -1
- package/dist/v2/next/client.cjs.map +1 -1
- package/dist/v2/next/client.js +1 -1
- package/dist/v2/next/client.js.map +1 -1
- package/dist/v2/next/config.cjs +247 -122
- package/dist/v2/next/config.cjs.map +1 -1
- package/dist/v2/next/config.d.ts +4 -4
- package/dist/v2/next/config.js +246 -121
- package/dist/v2/next/config.js.map +1 -1
- package/dist/v2/next/endpoints.cjs +5 -5
- package/dist/v2/next/endpoints.cjs.map +1 -1
- package/dist/v2/next/endpoints.js +5 -5
- package/dist/v2/next/endpoints.js.map +1 -1
- package/dist/v2/next/middleware.cjs +55 -55
- package/dist/v2/next/middleware.cjs.map +1 -1
- package/dist/v2/next/middleware.d.ts +8 -8
- package/dist/v2/next/middleware.js +53 -53
- package/dist/v2/next/middleware.js.map +1 -1
- package/dist/v2/overrides.cjs +75 -0
- package/dist/v2/overrides.cjs.map +1 -0
- package/dist/v2/overrides.d.ts +24 -0
- package/dist/v2/overrides.js +45 -0
- package/dist/v2/overrides.js.map +1 -0
- package/dist/v2/schema.cjs.map +1 -1
- package/dist/v2/schema.d.ts +1 -1
- package/dist/validation.cjs +20 -28
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.ts +2 -8
- package/dist/validation.js +20 -28
- package/dist/validation.js.map +1 -1
- package/package.json +15 -7
- package/schema/schema-v2.json +0 -4
- package/schema/schema.json +0 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/config-v2/microfrontends/server/index.ts
|
|
2
|
-
import
|
|
3
|
-
import { dirname } from "node:path";
|
|
2
|
+
import fs2 from "node:fs";
|
|
3
|
+
import { dirname as dirname2, join } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/config-v2/overrides/constants.ts
|
|
6
6
|
var OVERRIDES_COOKIE_PREFIX = "vercel-microfrontends-override";
|
|
@@ -37,14 +37,14 @@ function parseOverrides(cookies) {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// src/config-v2/errors.ts
|
|
40
|
-
var
|
|
40
|
+
var MicrofrontendError = class extends Error {
|
|
41
41
|
constructor(message, opts) {
|
|
42
42
|
super(message);
|
|
43
|
-
this.name = "
|
|
44
|
-
this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/
|
|
43
|
+
this.name = "MicrofrontendsError";
|
|
44
|
+
this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/microfrontends";
|
|
45
45
|
this.type = (opts == null ? void 0 : opts.type) ?? "unknown";
|
|
46
46
|
this.subtype = opts == null ? void 0 : opts.subtype;
|
|
47
|
-
Error.captureStackTrace(this,
|
|
47
|
+
Error.captureStackTrace(this, MicrofrontendError);
|
|
48
48
|
}
|
|
49
49
|
isKnown() {
|
|
50
50
|
return this.type !== "unknown";
|
|
@@ -53,13 +53,13 @@ var MicroFrontendError = class extends Error {
|
|
|
53
53
|
return !this.isKnown();
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Converts an error to a
|
|
56
|
+
* Converts an error to a MicrofrontendsError.
|
|
57
57
|
* @param original - The original error to convert.
|
|
58
|
-
* @returns The converted
|
|
58
|
+
* @returns The converted MicrofrontendsError.
|
|
59
59
|
*/
|
|
60
60
|
static convert(original, opts) {
|
|
61
61
|
if (opts == null ? void 0 : opts.fileName) {
|
|
62
|
-
const err =
|
|
62
|
+
const err = MicrofrontendError.convertFSError(original, opts.fileName);
|
|
63
63
|
if (err) {
|
|
64
64
|
return err;
|
|
65
65
|
}
|
|
@@ -67,25 +67,25 @@ var MicroFrontendError = class extends Error {
|
|
|
67
67
|
if (original.message.includes(
|
|
68
68
|
"Code generation from strings disallowed for this context"
|
|
69
69
|
)) {
|
|
70
|
-
return new
|
|
70
|
+
return new MicrofrontendError(original.message, {
|
|
71
71
|
type: "config",
|
|
72
72
|
subtype: "unsupported_validation_env",
|
|
73
73
|
source: "ajv"
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
|
-
return new
|
|
76
|
+
return new MicrofrontendError(original.message);
|
|
77
77
|
}
|
|
78
78
|
static convertFSError(original, fileName) {
|
|
79
79
|
if (original instanceof Error && "code" in original) {
|
|
80
80
|
if (original.code === "ENOENT") {
|
|
81
|
-
return new
|
|
81
|
+
return new MicrofrontendError(`Could not find "${fileName}"`, {
|
|
82
82
|
type: "config",
|
|
83
83
|
subtype: "unable_to_read_file",
|
|
84
84
|
source: "fs"
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
if (original.code === "EACCES") {
|
|
88
|
-
return new
|
|
88
|
+
return new MicrofrontendError(
|
|
89
89
|
`Permission denied while accessing "${fileName}"`,
|
|
90
90
|
{
|
|
91
91
|
type: "config",
|
|
@@ -96,7 +96,7 @@ var MicroFrontendError = class extends Error {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
if (original instanceof SyntaxError) {
|
|
99
|
-
return new
|
|
99
|
+
return new MicrofrontendError(
|
|
100
100
|
`Failed to parse "${fileName}": Invalid JSON format.`,
|
|
101
101
|
{
|
|
102
102
|
type: "config",
|
|
@@ -108,23 +108,23 @@ var MicroFrontendError = class extends Error {
|
|
|
108
108
|
return null;
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
|
-
* Handles an unknown error and returns a
|
|
111
|
+
* Handles an unknown error and returns a MicrofrontendsError instance.
|
|
112
112
|
* @param err - The error to handle.
|
|
113
|
-
* @returns A
|
|
113
|
+
* @returns A MicrofrontendsError instance.
|
|
114
114
|
*/
|
|
115
115
|
static handle(err, opts) {
|
|
116
|
-
if (err instanceof
|
|
116
|
+
if (err instanceof MicrofrontendError) {
|
|
117
117
|
return err;
|
|
118
118
|
}
|
|
119
119
|
if (err instanceof Error) {
|
|
120
|
-
return
|
|
120
|
+
return MicrofrontendError.convert(err, opts);
|
|
121
121
|
}
|
|
122
122
|
if (typeof err === "object" && err !== null) {
|
|
123
123
|
if ("message" in err && typeof err.message === "string") {
|
|
124
|
-
return
|
|
124
|
+
return MicrofrontendError.convert(new Error(err.message), opts);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
-
return new
|
|
127
|
+
return new MicrofrontendError("An unknown error occurred");
|
|
128
128
|
}
|
|
129
129
|
};
|
|
130
130
|
|
|
@@ -132,7 +132,7 @@ var MicroFrontendError = class extends Error {
|
|
|
132
132
|
function getConfigStringFromEnv() {
|
|
133
133
|
const config = process.env.MFE_CONFIG;
|
|
134
134
|
if (!config) {
|
|
135
|
-
throw new
|
|
135
|
+
throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
|
|
136
136
|
type: "config",
|
|
137
137
|
subtype: "not_found_in_env"
|
|
138
138
|
});
|
|
@@ -155,7 +155,7 @@ function isDefaultApp(a) {
|
|
|
155
155
|
|
|
156
156
|
// src/config-v2/microfrontends-config/client/index.ts
|
|
157
157
|
import { pathToRegexp } from "path-to-regexp";
|
|
158
|
-
var
|
|
158
|
+
var MicrofrontendConfigClient = class {
|
|
159
159
|
constructor(config, opts) {
|
|
160
160
|
this.pathCache = {};
|
|
161
161
|
this.serialized = config;
|
|
@@ -169,14 +169,14 @@ var MicroFrontendConfigClient = class {
|
|
|
169
169
|
this.applications = config.applications;
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
|
-
* Create a new `
|
|
172
|
+
* Create a new `MicrofrontendConfigClient` from a JSON string.
|
|
173
173
|
* Config must be passed in to remain framework agnostic
|
|
174
174
|
*/
|
|
175
175
|
static fromEnv(config, opts) {
|
|
176
176
|
if (!config) {
|
|
177
|
-
throw new Error("No
|
|
177
|
+
throw new Error("No microfrontends configuration found");
|
|
178
178
|
}
|
|
179
|
-
return new
|
|
179
|
+
return new MicrofrontendConfigClient(
|
|
180
180
|
JSON.parse(config),
|
|
181
181
|
opts
|
|
182
182
|
);
|
|
@@ -184,21 +184,21 @@ var MicroFrontendConfigClient = class {
|
|
|
184
184
|
isEqual(other) {
|
|
185
185
|
return JSON.stringify(this.applications) === JSON.stringify(other.applications);
|
|
186
186
|
}
|
|
187
|
-
getApplicationNameForPath(
|
|
188
|
-
if (!
|
|
187
|
+
getApplicationNameForPath(path3) {
|
|
188
|
+
if (!path3.startsWith("/")) {
|
|
189
189
|
throw new Error(`Path must start with a /`);
|
|
190
190
|
}
|
|
191
|
-
if (this.pathCache[
|
|
192
|
-
return this.pathCache[
|
|
191
|
+
if (this.pathCache[path3]) {
|
|
192
|
+
return this.pathCache[path3];
|
|
193
193
|
}
|
|
194
|
-
const pathname = new URL(
|
|
194
|
+
const pathname = new URL(path3, "https://example.com").pathname;
|
|
195
195
|
for (const [name, application] of Object.entries(this.applications)) {
|
|
196
196
|
if (application.routing) {
|
|
197
197
|
for (const group of application.routing) {
|
|
198
198
|
for (const childPath of group.paths) {
|
|
199
199
|
const regexp = pathToRegexp(childPath);
|
|
200
200
|
if (regexp.test(pathname)) {
|
|
201
|
-
this.pathCache[
|
|
201
|
+
this.pathCache[path3] = name;
|
|
202
202
|
return name;
|
|
203
203
|
}
|
|
204
204
|
}
|
|
@@ -211,7 +211,7 @@ var MicroFrontendConfigClient = class {
|
|
|
211
211
|
if (!defaultApplication) {
|
|
212
212
|
return null;
|
|
213
213
|
}
|
|
214
|
-
this.pathCache[
|
|
214
|
+
this.pathCache[path3] = defaultApplication[0];
|
|
215
215
|
return defaultApplication[0];
|
|
216
216
|
}
|
|
217
217
|
serialize() {
|
|
@@ -224,7 +224,7 @@ import { pathToRegexp as pathToRegexp2, parse as parsePathRegexp } from "path-to
|
|
|
224
224
|
var SUPPORTED_VERSIONS = ["2"];
|
|
225
225
|
var validateConfigVersion = (version) => {
|
|
226
226
|
if (!SUPPORTED_VERSIONS.includes(version)) {
|
|
227
|
-
throw new
|
|
227
|
+
throw new MicrofrontendError(
|
|
228
228
|
`Unsupported version: ${version}. Supported versions are: ${SUPPORTED_VERSIONS.join(
|
|
229
229
|
", "
|
|
230
230
|
)}`,
|
|
@@ -243,22 +243,22 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
243
243
|
continue;
|
|
244
244
|
}
|
|
245
245
|
for (const pathMatch of app.routing) {
|
|
246
|
-
for (const
|
|
247
|
-
const tokens = parsePathRegexp(
|
|
246
|
+
for (const path3 of pathMatch.paths) {
|
|
247
|
+
const tokens = parsePathRegexp(path3);
|
|
248
248
|
for (const token of tokens.slice(0, -1)) {
|
|
249
249
|
if (typeof token !== "string") {
|
|
250
250
|
errors.push(
|
|
251
|
-
`Path ${
|
|
251
|
+
`Path ${path3} may only have a :wildcard in the last path component`
|
|
252
252
|
);
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
|
-
const existing = pathsByApplicationId.get(
|
|
255
|
+
const existing = pathsByApplicationId.get(path3);
|
|
256
256
|
if (existing) {
|
|
257
257
|
existing.applications.push(id);
|
|
258
258
|
} else {
|
|
259
|
-
pathsByApplicationId.set(
|
|
259
|
+
pathsByApplicationId.set(path3, {
|
|
260
260
|
applications: [id],
|
|
261
|
-
matcher: pathToRegexp2(
|
|
261
|
+
matcher: pathToRegexp2(path3),
|
|
262
262
|
applicationId: id
|
|
263
263
|
});
|
|
264
264
|
}
|
|
@@ -266,10 +266,10 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
const entries = Array.from(pathsByApplicationId.entries());
|
|
269
|
-
entries.forEach(([
|
|
269
|
+
entries.forEach(([path3, { applications: ids, matcher, applicationId }]) => {
|
|
270
270
|
if (ids.length > 1) {
|
|
271
271
|
errors.push(
|
|
272
|
-
`Duplicate path "${
|
|
272
|
+
`Duplicate path "${path3}" for applications "${ids.join(", ")}"`
|
|
273
273
|
);
|
|
274
274
|
}
|
|
275
275
|
entries.forEach(
|
|
@@ -277,14 +277,14 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
277
277
|
matchPath,
|
|
278
278
|
{ applications: matchIds, applicationId: matchApplicationId }
|
|
279
279
|
]) => {
|
|
280
|
-
if (
|
|
280
|
+
if (path3 === matchPath) {
|
|
281
281
|
return;
|
|
282
282
|
}
|
|
283
283
|
if (applicationId === matchApplicationId) {
|
|
284
284
|
return;
|
|
285
285
|
}
|
|
286
286
|
if (matcher.test(matchPath)) {
|
|
287
|
-
const source = `"${
|
|
287
|
+
const source = `"${path3}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
288
288
|
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
289
289
|
errors.push(
|
|
290
290
|
`Overlapping path detected between ${source} and ${destination}`
|
|
@@ -294,7 +294,7 @@ var validateConfigPaths = (applicationConfigsById) => {
|
|
|
294
294
|
);
|
|
295
295
|
});
|
|
296
296
|
if (errors.length) {
|
|
297
|
-
throw new
|
|
297
|
+
throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
|
|
298
298
|
type: "config",
|
|
299
299
|
subtype: "conflicting_paths"
|
|
300
300
|
});
|
|
@@ -307,13 +307,13 @@ var validateAppPaths = (name, app) => {
|
|
|
307
307
|
continue;
|
|
308
308
|
}
|
|
309
309
|
if (p.endsWith("/")) {
|
|
310
|
-
throw new
|
|
310
|
+
throw new MicrofrontendError(
|
|
311
311
|
`Invalid path for application "${name}". ${p} must not end with a slash.`,
|
|
312
312
|
{ type: "application", subtype: "invalid_path" }
|
|
313
313
|
);
|
|
314
314
|
}
|
|
315
315
|
if (!p.startsWith("/")) {
|
|
316
|
-
throw new
|
|
316
|
+
throw new MicrofrontendError(
|
|
317
317
|
`Invalid path for application "${name}". ${p} must start with a slash.`,
|
|
318
318
|
{ type: "application", subtype: "invalid_path" }
|
|
319
319
|
);
|
|
@@ -335,13 +335,13 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
335
335
|
const numApplicationsWithRouting = applicationsWithRoutingNames.length;
|
|
336
336
|
const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
|
|
337
337
|
if (numApplicationsWithoutRouting === 0) {
|
|
338
|
-
throw new
|
|
338
|
+
throw new MicrofrontendError(
|
|
339
339
|
`No default application found. At least one application needs to be the default by omitting routing.`,
|
|
340
340
|
{ type: "config", subtype: "no_default_application" }
|
|
341
341
|
);
|
|
342
342
|
}
|
|
343
343
|
if (numApplicationsWithoutRouting > 1) {
|
|
344
|
-
throw new
|
|
344
|
+
throw new MicrofrontendError(
|
|
345
345
|
`Only one application can omit "routing". Found ${applicationsWithRoutingNames.length - Object.keys(applicationConfigsById).length > 1}.`,
|
|
346
346
|
{ type: "config", subtype: "multiple_default_applications" }
|
|
347
347
|
);
|
|
@@ -353,7 +353,7 @@ var validateConfigOptions = (options) => {
|
|
|
353
353
|
if (!/^[a-zA-Z]{2,}\.[a-zA-Z]{2,}$/.test(
|
|
354
354
|
options.vercel.previewDeploymentSuffix
|
|
355
355
|
)) {
|
|
356
|
-
throw new
|
|
356
|
+
throw new MicrofrontendError(
|
|
357
357
|
`Invalid preview deployment suffix: ${options.vercel.previewDeploymentSuffix}. Should have be formatted like "vercel.app".`,
|
|
358
358
|
{ type: "config", subtype: "invalid_preview_deployment_suffix" }
|
|
359
359
|
);
|
|
@@ -512,7 +512,7 @@ var ChildApplication = class extends Application {
|
|
|
512
512
|
var DEFAULT_LOCAL_PROXY_PORT = 3024;
|
|
513
513
|
|
|
514
514
|
// src/config-v2/microfrontends-config/isomorphic/index.ts
|
|
515
|
-
var
|
|
515
|
+
var MicrofrontendConfigIsomorphic = class {
|
|
516
516
|
constructor({
|
|
517
517
|
config,
|
|
518
518
|
overrides,
|
|
@@ -520,7 +520,7 @@ var MicroFrontendConfigIsomorphic = class {
|
|
|
520
520
|
}) {
|
|
521
521
|
this.childApplications = {};
|
|
522
522
|
var _a, _b, _c, _d;
|
|
523
|
-
|
|
523
|
+
MicrofrontendConfigIsomorphic.validate(config);
|
|
524
524
|
const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
|
|
525
525
|
this.overrides = overrides && !disableOverrides ? overrides : void 0;
|
|
526
526
|
this.isMainConfig = isMainConfig(config);
|
|
@@ -552,7 +552,7 @@ var MicroFrontendConfigIsomorphic = class {
|
|
|
552
552
|
);
|
|
553
553
|
}
|
|
554
554
|
if (isMainConfig(config) && !this.defaultApplication) {
|
|
555
|
-
throw new
|
|
555
|
+
throw new MicrofrontendError(
|
|
556
556
|
`Could not find default application in microfrontends configuration`,
|
|
557
557
|
{
|
|
558
558
|
type: "application",
|
|
@@ -582,7 +582,7 @@ var MicroFrontendConfigIsomorphic = class {
|
|
|
582
582
|
meta,
|
|
583
583
|
cookies
|
|
584
584
|
}) {
|
|
585
|
-
return new
|
|
585
|
+
return new MicrofrontendConfigIsomorphic({
|
|
586
586
|
config: parse(getConfigStringFromEnv()),
|
|
587
587
|
overrides: parseOverrides(cookies ?? []),
|
|
588
588
|
meta
|
|
@@ -617,7 +617,7 @@ var MicroFrontendConfigIsomorphic = class {
|
|
|
617
617
|
}
|
|
618
618
|
const app = this.childApplications[name];
|
|
619
619
|
if (!app) {
|
|
620
|
-
throw new
|
|
620
|
+
throw new MicrofrontendError(
|
|
621
621
|
`Could not find microfrontends configuration for application "${name}"`,
|
|
622
622
|
{
|
|
623
623
|
type: "application",
|
|
@@ -645,7 +645,7 @@ var MicroFrontendConfigIsomorphic = class {
|
|
|
645
645
|
*/
|
|
646
646
|
getDefaultApplication() {
|
|
647
647
|
if (!this.defaultApplication) {
|
|
648
|
-
throw new
|
|
648
|
+
throw new MicrofrontendError(
|
|
649
649
|
`Could not find default application in microfrontends configuration`,
|
|
650
650
|
{
|
|
651
651
|
type: "application",
|
|
@@ -685,7 +685,7 @@ var MicroFrontendConfigIsomorphic = class {
|
|
|
685
685
|
default: true
|
|
686
686
|
};
|
|
687
687
|
}
|
|
688
|
-
return new
|
|
688
|
+
return new MicrofrontendConfigClient({
|
|
689
689
|
applications
|
|
690
690
|
});
|
|
691
691
|
}
|
|
@@ -695,7 +695,7 @@ var MicroFrontendConfigIsomorphic = class {
|
|
|
695
695
|
};
|
|
696
696
|
|
|
697
697
|
// src/config-v2/microfrontends-config/isomorphic/child.ts
|
|
698
|
-
var
|
|
698
|
+
var MicrofrontendChildConfig = class extends MicrofrontendConfigIsomorphic {
|
|
699
699
|
constructor({
|
|
700
700
|
config,
|
|
701
701
|
overrides,
|
|
@@ -708,7 +708,7 @@ var MicroFrontendChildConfig = class extends MicroFrontendConfigIsomorphic {
|
|
|
708
708
|
};
|
|
709
709
|
|
|
710
710
|
// src/config-v2/microfrontends-config/isomorphic/main.ts
|
|
711
|
-
var
|
|
711
|
+
var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
|
|
712
712
|
constructor({
|
|
713
713
|
config,
|
|
714
714
|
overrides,
|
|
@@ -735,7 +735,7 @@ var MicroFrontendMainConfig = class extends MicroFrontendConfigIsomorphic {
|
|
|
735
735
|
}
|
|
736
736
|
}
|
|
737
737
|
if (!defaultApplication) {
|
|
738
|
-
throw new
|
|
738
|
+
throw new MicrofrontendError(
|
|
739
739
|
`Could not find default application in microfrontends configuration`,
|
|
740
740
|
{
|
|
741
741
|
type: "application",
|
|
@@ -755,19 +755,19 @@ var Microfrontends = class {
|
|
|
755
755
|
meta
|
|
756
756
|
}) {
|
|
757
757
|
if (isMainConfig(config)) {
|
|
758
|
-
this.config = new
|
|
758
|
+
this.config = new MicrofrontendMainConfig({ config, overrides, meta });
|
|
759
759
|
} else {
|
|
760
|
-
this.config = new
|
|
760
|
+
this.config = new MicrofrontendChildConfig({ config, overrides, meta });
|
|
761
761
|
}
|
|
762
762
|
}
|
|
763
763
|
isChildConfig() {
|
|
764
|
-
return this.config instanceof
|
|
764
|
+
return this.config instanceof MicrofrontendChildConfig;
|
|
765
765
|
}
|
|
766
766
|
static fromEnv({
|
|
767
767
|
cookies,
|
|
768
768
|
meta
|
|
769
769
|
}) {
|
|
770
|
-
const config =
|
|
770
|
+
const config = MicrofrontendConfigIsomorphic.fromEnv({
|
|
771
771
|
cookies,
|
|
772
772
|
meta
|
|
773
773
|
});
|
|
@@ -775,8 +775,82 @@ var Microfrontends = class {
|
|
|
775
775
|
}
|
|
776
776
|
};
|
|
777
777
|
|
|
778
|
-
// src/config-v2/microfrontends/
|
|
778
|
+
// src/config-v2/microfrontends/utils/find-repository-root.ts
|
|
779
|
+
import fs from "node:fs";
|
|
779
780
|
import path from "node:path";
|
|
781
|
+
var GIT_DIRECTORY = ".git";
|
|
782
|
+
function findRepositoryRoot(startDir) {
|
|
783
|
+
let currentDir = startDir || process.cwd();
|
|
784
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
785
|
+
const gitPath = path.join(currentDir, GIT_DIRECTORY);
|
|
786
|
+
if (fs.existsSync(gitPath) && fs.statSync(gitPath).isDirectory()) {
|
|
787
|
+
return currentDir;
|
|
788
|
+
}
|
|
789
|
+
currentDir = path.dirname(currentDir);
|
|
790
|
+
}
|
|
791
|
+
throw new Error(
|
|
792
|
+
"Repository root not found. Specify the root of the repository with the `repository.root` option."
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// src/config-v2/microfrontends/utils/find-package-path.ts
|
|
797
|
+
import { dirname } from "node:path";
|
|
798
|
+
import { readFileSync } from "node:fs";
|
|
799
|
+
import fg from "fast-glob";
|
|
800
|
+
var configCache = {};
|
|
801
|
+
function findPackagePathWithGlob({
|
|
802
|
+
repositoryRoot,
|
|
803
|
+
name
|
|
804
|
+
}) {
|
|
805
|
+
try {
|
|
806
|
+
const packageJsonPaths = fg.globSync("**/package.json", {
|
|
807
|
+
cwd: repositoryRoot,
|
|
808
|
+
absolute: true,
|
|
809
|
+
onlyFiles: true,
|
|
810
|
+
followSymbolicLinks: false,
|
|
811
|
+
ignore: ["**/node_modules/**", "**/.git/**"]
|
|
812
|
+
});
|
|
813
|
+
const matchingPaths = [];
|
|
814
|
+
for (const packageJsonPath2 of packageJsonPaths) {
|
|
815
|
+
const packageJsonContent = readFileSync(packageJsonPath2, "utf-8");
|
|
816
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
817
|
+
if (packageJson.name === name) {
|
|
818
|
+
matchingPaths.push(packageJsonPath2);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
if (matchingPaths.length > 1) {
|
|
822
|
+
throw new Error(
|
|
823
|
+
`Found multiple packages with the name "${name}" in the repository: ${matchingPaths.join(", ")}`
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
if (matchingPaths.length === 0) {
|
|
827
|
+
throw new Error(
|
|
828
|
+
`Could not find package with the name "${name}" in the repository`
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
const [packageJsonPath] = matchingPaths;
|
|
832
|
+
return dirname(packageJsonPath);
|
|
833
|
+
} catch (error) {
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
function findPackagePath(opts) {
|
|
838
|
+
const cacheKey = `${opts.repositoryRoot}-${opts.name}`;
|
|
839
|
+
if (configCache[cacheKey]) {
|
|
840
|
+
return configCache[cacheKey];
|
|
841
|
+
}
|
|
842
|
+
const result = findPackagePathWithGlob(opts);
|
|
843
|
+
if (!result) {
|
|
844
|
+
throw new Error(
|
|
845
|
+
`Could not find package with the name "${opts.name}" in the repository`
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
configCache[cacheKey] = result;
|
|
849
|
+
return result;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// src/config-v2/microfrontends/server/utils/get-output-file-path.ts
|
|
853
|
+
import path2 from "node:path";
|
|
780
854
|
|
|
781
855
|
// src/config-v2/microfrontends/server/constants.ts
|
|
782
856
|
var MFE_CONFIG_DEFAULT_FILE_PATH = "microfrontends";
|
|
@@ -790,13 +864,13 @@ function isVercel() {
|
|
|
790
864
|
// src/config-v2/microfrontends/server/utils/get-output-file-path.ts
|
|
791
865
|
function getOutputFilePath() {
|
|
792
866
|
if (isVercel()) {
|
|
793
|
-
return
|
|
867
|
+
return path2.join(
|
|
794
868
|
".vercel",
|
|
795
869
|
MFE_CONFIG_DEFAULT_FILE_PATH,
|
|
796
870
|
MFE_CONFIG_DEFAULT_FILE_NAME
|
|
797
871
|
);
|
|
798
872
|
}
|
|
799
|
-
return
|
|
873
|
+
return path2.join(MFE_CONFIG_DEFAULT_FILE_PATH, MFE_CONFIG_DEFAULT_FILE_NAME);
|
|
800
874
|
}
|
|
801
875
|
|
|
802
876
|
// src/config-v2/microfrontends/server/validation.ts
|
|
@@ -804,14 +878,14 @@ import { parse as parse2 } from "jsonc-parser";
|
|
|
804
878
|
import { Ajv } from "ajv";
|
|
805
879
|
|
|
806
880
|
// src/config/errors.ts
|
|
807
|
-
var
|
|
881
|
+
var MicrofrontendError2 = class extends Error {
|
|
808
882
|
constructor(message, opts) {
|
|
809
883
|
super(message);
|
|
810
|
-
this.name = "
|
|
811
|
-
this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/
|
|
884
|
+
this.name = "MicrofrontendsError";
|
|
885
|
+
this.source = (opts == null ? void 0 : opts.source) ?? "@vercel/microfrontends";
|
|
812
886
|
this.type = (opts == null ? void 0 : opts.type) ?? "unknown";
|
|
813
887
|
this.subtype = opts == null ? void 0 : opts.subtype;
|
|
814
|
-
Error.captureStackTrace(this,
|
|
888
|
+
Error.captureStackTrace(this, MicrofrontendError2);
|
|
815
889
|
}
|
|
816
890
|
isKnown() {
|
|
817
891
|
return this.type !== "unknown";
|
|
@@ -820,13 +894,13 @@ var MicroFrontendError2 = class extends Error {
|
|
|
820
894
|
return !this.isKnown();
|
|
821
895
|
}
|
|
822
896
|
/**
|
|
823
|
-
* Converts an error to a
|
|
897
|
+
* Converts an error to a MicrofrontendsError.
|
|
824
898
|
* @param original - The original error to convert.
|
|
825
|
-
* @returns The converted
|
|
899
|
+
* @returns The converted MicrofrontendsError.
|
|
826
900
|
*/
|
|
827
901
|
static convert(original, opts) {
|
|
828
902
|
if (opts == null ? void 0 : opts.fileName) {
|
|
829
|
-
const err =
|
|
903
|
+
const err = MicrofrontendError2.convertFSError(original, opts.fileName);
|
|
830
904
|
if (err) {
|
|
831
905
|
return err;
|
|
832
906
|
}
|
|
@@ -834,25 +908,25 @@ var MicroFrontendError2 = class extends Error {
|
|
|
834
908
|
if (original.message.includes(
|
|
835
909
|
"Code generation from strings disallowed for this context"
|
|
836
910
|
)) {
|
|
837
|
-
return new
|
|
911
|
+
return new MicrofrontendError2(original.message, {
|
|
838
912
|
type: "config",
|
|
839
913
|
subtype: "unsupported_validation_env",
|
|
840
914
|
source: "ajv"
|
|
841
915
|
});
|
|
842
916
|
}
|
|
843
|
-
return new
|
|
917
|
+
return new MicrofrontendError2(original.message);
|
|
844
918
|
}
|
|
845
919
|
static convertFSError(original, fileName) {
|
|
846
920
|
if (original instanceof Error && "code" in original) {
|
|
847
921
|
if (original.code === "ENOENT") {
|
|
848
|
-
return new
|
|
922
|
+
return new MicrofrontendError2(`Could not find "${fileName}"`, {
|
|
849
923
|
type: "config",
|
|
850
924
|
subtype: "unable_to_read_file",
|
|
851
925
|
source: "fs"
|
|
852
926
|
});
|
|
853
927
|
}
|
|
854
928
|
if (original.code === "EACCES") {
|
|
855
|
-
return new
|
|
929
|
+
return new MicrofrontendError2(
|
|
856
930
|
`Permission denied while accessing "${fileName}"`,
|
|
857
931
|
{
|
|
858
932
|
type: "config",
|
|
@@ -863,7 +937,7 @@ var MicroFrontendError2 = class extends Error {
|
|
|
863
937
|
}
|
|
864
938
|
}
|
|
865
939
|
if (original instanceof SyntaxError) {
|
|
866
|
-
return new
|
|
940
|
+
return new MicrofrontendError2(
|
|
867
941
|
`Failed to parse "${fileName}": Invalid JSON format.`,
|
|
868
942
|
{
|
|
869
943
|
type: "config",
|
|
@@ -875,23 +949,23 @@ var MicroFrontendError2 = class extends Error {
|
|
|
875
949
|
return null;
|
|
876
950
|
}
|
|
877
951
|
/**
|
|
878
|
-
* Handles an unknown error and returns a
|
|
952
|
+
* Handles an unknown error and returns a MicrofrontendsError instance.
|
|
879
953
|
* @param err - The error to handle.
|
|
880
|
-
* @returns A
|
|
954
|
+
* @returns A MicrofrontendsError instance.
|
|
881
955
|
*/
|
|
882
956
|
static handle(err, opts) {
|
|
883
|
-
if (err instanceof
|
|
957
|
+
if (err instanceof MicrofrontendError2) {
|
|
884
958
|
return err;
|
|
885
959
|
}
|
|
886
960
|
if (err instanceof Error) {
|
|
887
|
-
return
|
|
961
|
+
return MicrofrontendError2.convert(err, opts);
|
|
888
962
|
}
|
|
889
963
|
if (typeof err === "object" && err !== null) {
|
|
890
964
|
if ("message" in err && typeof err.message === "string") {
|
|
891
|
-
return
|
|
965
|
+
return MicrofrontendError2.convert(new Error(err.message), opts);
|
|
892
966
|
}
|
|
893
967
|
}
|
|
894
|
-
return new
|
|
968
|
+
return new MicrofrontendError2("An unknown error occurred");
|
|
895
969
|
}
|
|
896
970
|
};
|
|
897
971
|
|
|
@@ -1106,10 +1180,6 @@ var schema_v2_default = {
|
|
|
1106
1180
|
type: "string",
|
|
1107
1181
|
description: "flag name that can be used to enable/disable all paths in the group"
|
|
1108
1182
|
},
|
|
1109
|
-
routeToDefaultApplication: {
|
|
1110
|
-
type: "boolean",
|
|
1111
|
-
description: "True to route the request to the default application for this micro-frontends set-up. This must be `true` when using `flag` or when you want to use custom logic to make the routing decision for this group of paths."
|
|
1112
|
-
},
|
|
1113
1183
|
paths: {
|
|
1114
1184
|
type: "array",
|
|
1115
1185
|
items: {
|
|
@@ -1169,7 +1239,7 @@ function validateSchema(configString) {
|
|
|
1169
1239
|
const validate = ajv.compile(SCHEMA);
|
|
1170
1240
|
const isValid = validate(parsedConfig);
|
|
1171
1241
|
if (!isValid) {
|
|
1172
|
-
throw new
|
|
1242
|
+
throw new MicrofrontendError2(
|
|
1173
1243
|
`Invalid config: ${ajv.errorsText(validate.errors)}`,
|
|
1174
1244
|
{ type: "config", subtype: "does_not_match_schema" }
|
|
1175
1245
|
);
|
|
@@ -1186,8 +1256,8 @@ var MicrofrontendsServer = class extends Microfrontends {
|
|
|
1186
1256
|
pretty: true
|
|
1187
1257
|
}) {
|
|
1188
1258
|
const outputPath = getOutputFilePath();
|
|
1189
|
-
|
|
1190
|
-
|
|
1259
|
+
fs2.mkdirSync(dirname2(outputPath), { recursive: true });
|
|
1260
|
+
fs2.writeFileSync(
|
|
1191
1261
|
outputPath,
|
|
1192
1262
|
JSON.stringify(
|
|
1193
1263
|
this.config.toSchemaJson(),
|
|
@@ -1220,7 +1290,7 @@ var MicrofrontendsServer = class extends Microfrontends {
|
|
|
1220
1290
|
meta
|
|
1221
1291
|
});
|
|
1222
1292
|
}
|
|
1223
|
-
throw new
|
|
1293
|
+
throw new MicrofrontendError(
|
|
1224
1294
|
"Invalid config: must be a string or an object",
|
|
1225
1295
|
{ type: "config", subtype: "does_not_match_schema" }
|
|
1226
1296
|
);
|
|
@@ -1255,17 +1325,74 @@ var MicrofrontendsServer = class extends Microfrontends {
|
|
|
1255
1325
|
static fromFile({
|
|
1256
1326
|
filePath,
|
|
1257
1327
|
cookies,
|
|
1258
|
-
meta
|
|
1328
|
+
meta,
|
|
1329
|
+
options
|
|
1259
1330
|
}) {
|
|
1260
1331
|
try {
|
|
1261
|
-
const
|
|
1332
|
+
const configJson = fs2.readFileSync(filePath, "utf-8");
|
|
1333
|
+
const config = MicrofrontendsServer.validate(configJson);
|
|
1334
|
+
if (!isMainConfig(config) && (options == null ? void 0 : options.resolveMainConfig)) {
|
|
1335
|
+
const repositoryRoot = findRepositoryRoot();
|
|
1336
|
+
const packagePath = findPackagePath({
|
|
1337
|
+
repositoryRoot,
|
|
1338
|
+
name: config.partOf
|
|
1339
|
+
});
|
|
1340
|
+
if (!packagePath) {
|
|
1341
|
+
throw new MicrofrontendError(
|
|
1342
|
+
`Could not find default application "${config.partOf}" in the repository`,
|
|
1343
|
+
{ type: "config", subtype: "not_found" }
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
const mainConfigPath = join(packagePath, "microfrontends.json");
|
|
1347
|
+
return MicrofrontendsServer.fromMainConfigFile({
|
|
1348
|
+
filePath: mainConfigPath,
|
|
1349
|
+
overrides: cookies ? parseOverrides(cookies) : void 0
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1262
1352
|
return new MicrofrontendsServer({
|
|
1263
|
-
config
|
|
1353
|
+
config,
|
|
1264
1354
|
overrides: cookies ? parseOverrides(cookies) : void 0,
|
|
1265
1355
|
meta
|
|
1266
1356
|
});
|
|
1267
1357
|
} catch (e) {
|
|
1268
|
-
throw
|
|
1358
|
+
throw MicrofrontendError.handle(e, {
|
|
1359
|
+
fileName: filePath
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
/*
|
|
1364
|
+
* Generates a MicrofrontendMainConfig instance from a file.
|
|
1365
|
+
*/
|
|
1366
|
+
static fromMainConfigFile({
|
|
1367
|
+
filePath,
|
|
1368
|
+
overrides
|
|
1369
|
+
}) {
|
|
1370
|
+
try {
|
|
1371
|
+
const config = fs2.readFileSync(filePath, "utf-8");
|
|
1372
|
+
const validatedConfig = MicrofrontendsServer.validate(config);
|
|
1373
|
+
if (!isMainConfig(validatedConfig)) {
|
|
1374
|
+
throw new MicrofrontendError(
|
|
1375
|
+
`${filePath} is not a main microfrontend config`,
|
|
1376
|
+
{
|
|
1377
|
+
type: "config",
|
|
1378
|
+
subtype: "invalid_main_path"
|
|
1379
|
+
}
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
const [defaultApplication] = Object.entries(validatedConfig.applications).filter(([, app]) => isDefaultApp(app)).map(([name]) => name);
|
|
1383
|
+
if (!defaultApplication) {
|
|
1384
|
+
throw new MicrofrontendError(
|
|
1385
|
+
`No default application found. At least one application needs to be the default by omitting routing.`,
|
|
1386
|
+
{ type: "config", subtype: "no_default_application" }
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
return new MicrofrontendsServer({
|
|
1390
|
+
config: validatedConfig,
|
|
1391
|
+
overrides,
|
|
1392
|
+
meta: { fromApp: defaultApplication }
|
|
1393
|
+
});
|
|
1394
|
+
} catch (e) {
|
|
1395
|
+
throw MicrofrontendError.handle(e, {
|
|
1269
1396
|
fileName: filePath
|
|
1270
1397
|
});
|
|
1271
1398
|
}
|