@vercel/microfrontends 0.14.0 → 0.16.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/dist/bin/cli.cjs +392 -1620
- package/dist/config.cjs +478 -1001
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.ts +4 -25
- package/dist/config.js +474 -980
- package/dist/config.js.map +1 -1
- package/dist/{v2/microfrontends → microfrontends}/server.cjs +91 -150
- package/dist/microfrontends/server.cjs.map +1 -0
- package/dist/{v2/microfrontends → microfrontends}/server.d.ts +4 -4
- package/dist/{v2/microfrontends → microfrontends}/server.js +91 -150
- package/dist/microfrontends/server.js.map +1 -0
- package/dist/{v2/microfrontends.cjs → microfrontends.cjs} +49 -28
- package/dist/microfrontends.cjs.map +1 -0
- package/dist/{v2/microfrontends.d.ts → microfrontends.d.ts} +4 -4
- package/dist/{v2/microfrontends.js → microfrontends.js} +48 -27
- package/dist/microfrontends.js.map +1 -0
- 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 +1344 -1024
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.d.ts +1 -1
- package/dist/next/config.js +1343 -1023
- package/dist/next/config.js.map +1 -1
- package/dist/next/endpoints.cjs +77 -18
- package/dist/next/endpoints.cjs.map +1 -1
- package/dist/next/endpoints.d.ts +13 -2
- package/dist/next/endpoints.js +77 -18
- package/dist/next/endpoints.js.map +1 -1
- package/dist/next/middleware.cjs +765 -395
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.d.ts +10 -5
- package/dist/next/middleware.js +765 -395
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +615 -1031
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.d.ts +14 -12
- package/dist/next/testing.js +609 -1015
- package/dist/next/testing.js.map +1 -1
- package/dist/overrides.cjs +40 -108
- package/dist/overrides.cjs.map +1 -1
- package/dist/overrides.d.ts +24 -2
- package/dist/overrides.js +36 -106
- package/dist/overrides.js.map +1 -1
- package/dist/{v2/routing.cjs → routing.cjs} +3 -3
- package/dist/routing.cjs.map +1 -0
- package/dist/{v2/schema.cjs → schema.cjs} +1 -1
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.ts +1 -0
- package/dist/utils/mfe-port.cjs +237 -1338
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.js +230 -1331
- package/dist/utils/mfe-port.js.map +1 -1
- package/dist/validation.cjs +31 -361
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.ts +3 -146
- package/dist/validation.js +30 -359
- package/dist/validation.js.map +1 -1
- package/package.json +29 -92
- package/schema/schema.json +174 -244
- package/dist/config/client.cjs +0 -54
- package/dist/config/client.cjs.map +0 -1
- package/dist/config/client.d.ts +0 -23
- package/dist/config/client.js +0 -28
- package/dist/config/client.js.map +0 -1
- package/dist/config/edge.cjs +0 -508
- package/dist/config/edge.cjs.map +0 -1
- package/dist/config/edge.d.ts +0 -20
- package/dist/config/edge.js +0 -481
- package/dist/config/edge.js.map +0 -1
- package/dist/microfrontend-config-983a5139.d.ts +0 -154
- package/dist/schema-2922d49e.d.ts +0 -182
- package/dist/v2/config.cjs +0 -709
- package/dist/v2/config.cjs.map +0 -1
- package/dist/v2/config.d.ts +0 -4
- package/dist/v2/config.js +0 -684
- package/dist/v2/config.js.map +0 -1
- package/dist/v2/microfrontends/server.cjs.map +0 -1
- package/dist/v2/microfrontends/server.js.map +0 -1
- package/dist/v2/microfrontends.cjs.map +0 -1
- package/dist/v2/microfrontends.js.map +0 -1
- package/dist/v2/next/client.cjs +0 -3
- package/dist/v2/next/client.cjs.map +0 -1
- package/dist/v2/next/client.d.ts +0 -45
- package/dist/v2/next/client.js +0 -3
- package/dist/v2/next/client.js.map +0 -1
- package/dist/v2/next/config.cjs +0 -2178
- package/dist/v2/next/config.cjs.map +0 -1
- package/dist/v2/next/config.d.ts +0 -22
- package/dist/v2/next/config.js +0 -2143
- package/dist/v2/next/config.js.map +0 -1
- package/dist/v2/next/endpoints.cjs +0 -141
- package/dist/v2/next/endpoints.cjs.map +0 -1
- package/dist/v2/next/endpoints.d.ts +0 -26
- package/dist/v2/next/endpoints.js +0 -116
- package/dist/v2/next/endpoints.js.map +0 -1
- package/dist/v2/next/middleware.cjs +0 -1099
- package/dist/v2/next/middleware.cjs.map +0 -1
- package/dist/v2/next/middleware.d.ts +0 -34
- package/dist/v2/next/middleware.js +0 -1071
- package/dist/v2/next/middleware.js.map +0 -1
- package/dist/v2/next/testing.cjs +0 -992
- package/dist/v2/next/testing.cjs.map +0 -1
- package/dist/v2/next/testing.d.ts +0 -55
- package/dist/v2/next/testing.js +0 -961
- package/dist/v2/next/testing.js.map +0 -1
- package/dist/v2/overrides.cjs +0 -75
- package/dist/v2/overrides.cjs.map +0 -1
- package/dist/v2/overrides.d.ts +0 -24
- package/dist/v2/overrides.js +0 -45
- package/dist/v2/overrides.js.map +0 -1
- package/dist/v2/routing.cjs.map +0 -1
- package/dist/v2/schema.cjs.map +0 -1
- package/dist/v2/schema.d.ts +0 -1
- package/schema/schema-v2.json +0 -266
- /package/dist/{v2/routing.d.ts → routing.d.ts} +0 -0
- /package/dist/{v2/routing.js → routing.js} +0 -0
- /package/dist/{v2/routing.js.map → routing.js.map} +0 -0
- /package/dist/{v2/schema.js → schema.js} +0 -0
- /package/dist/{v2/schema.js.map → schema.js.map} +0 -0
package/dist/next/middleware.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/next/middleware/middleware.ts
|
|
2
2
|
import { NextResponse } from "next/server";
|
|
3
|
-
import { pathToRegexp } from "path-to-regexp";
|
|
3
|
+
import { pathToRegexp as pathToRegexp3 } from "path-to-regexp";
|
|
4
4
|
|
|
5
|
-
// src/config/
|
|
5
|
+
// src/config/microfrontends-config/isomorphic/index.ts
|
|
6
6
|
import { parse } from "jsonc-parser";
|
|
7
7
|
|
|
8
8
|
// src/config/errors.ts
|
|
@@ -97,131 +97,320 @@ var MicrofrontendError = class extends Error {
|
|
|
97
97
|
}
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
-
// src/
|
|
101
|
-
function
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
100
|
+
// src/config/microfrontends-config/utils/get-config-from-env.ts
|
|
101
|
+
function getConfigStringFromEnv() {
|
|
102
|
+
const config = process.env.MFE_CONFIG;
|
|
103
|
+
if (!config) {
|
|
104
|
+
throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
|
|
105
|
+
type: "config",
|
|
106
|
+
subtype: "not_found_in_env"
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return config;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/config/schema/utils/is-main-config.ts
|
|
113
|
+
function isMainConfig(c) {
|
|
114
|
+
return !("partOf" in c);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/config/schema/utils/is-default-app.ts
|
|
118
|
+
function isDefaultApp(a) {
|
|
119
|
+
return !("routing" in a);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/config/microfrontends-config/client/index.ts
|
|
123
|
+
import { pathToRegexp } from "path-to-regexp";
|
|
124
|
+
var MicrofrontendConfigClient = class {
|
|
125
|
+
constructor(config, opts) {
|
|
126
|
+
this.pathCache = {};
|
|
127
|
+
this.serialized = config;
|
|
128
|
+
if (opts == null ? void 0 : opts.removeFlaggedPaths) {
|
|
129
|
+
for (const app of Object.values(config.applications)) {
|
|
130
|
+
if (app.routing) {
|
|
131
|
+
app.routing = app.routing.filter((match) => !match.flag);
|
|
132
|
+
}
|
|
116
133
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
134
|
+
}
|
|
135
|
+
this.applications = config.applications;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create a new `MicrofrontendConfigClient` from a JSON string.
|
|
139
|
+
* Config must be passed in to remain framework agnostic
|
|
140
|
+
*/
|
|
141
|
+
static fromEnv(config, opts) {
|
|
142
|
+
if (!config) {
|
|
143
|
+
throw new Error("No microfrontends configuration found");
|
|
144
|
+
}
|
|
145
|
+
return new MicrofrontendConfigClient(
|
|
146
|
+
JSON.parse(config),
|
|
147
|
+
opts
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
isEqual(other) {
|
|
151
|
+
return JSON.stringify(this.applications) === JSON.stringify(other.applications);
|
|
152
|
+
}
|
|
153
|
+
getApplicationNameForPath(path) {
|
|
154
|
+
if (!path.startsWith("/")) {
|
|
155
|
+
throw new Error(`Path must start with a /`);
|
|
156
|
+
}
|
|
157
|
+
if (this.pathCache[path]) {
|
|
158
|
+
return this.pathCache[path];
|
|
159
|
+
}
|
|
160
|
+
const pathname = new URL(path, "https://example.com").pathname;
|
|
161
|
+
for (const [name, application] of Object.entries(this.applications)) {
|
|
162
|
+
if (application.routing) {
|
|
163
|
+
for (const group of application.routing) {
|
|
164
|
+
for (const childPath of group.paths) {
|
|
165
|
+
const regexp = pathToRegexp(childPath);
|
|
166
|
+
if (regexp.test(pathname)) {
|
|
167
|
+
this.pathCache[path] = name;
|
|
168
|
+
return name;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
123
171
|
}
|
|
124
172
|
}
|
|
125
|
-
tag = args.join(options.joinString);
|
|
126
|
-
tag = tag.replace(/\s/g, options.joinString);
|
|
127
|
-
if (options.lowercaseOnly)
|
|
128
|
-
tag = tag.toLowerCase();
|
|
129
|
-
tag = tag.replace(options.regexRemovePattern, (match) => {
|
|
130
|
-
if (match === options.joinString)
|
|
131
|
-
return match;
|
|
132
|
-
return "";
|
|
133
|
-
});
|
|
134
|
-
if (tag.length > options.maxLen)
|
|
135
|
-
tag = tag.substring(0, options.maxLen);
|
|
136
|
-
tag = tag.replace(reJoinString, options.joinString);
|
|
137
|
-
return tag;
|
|
138
173
|
}
|
|
174
|
+
const defaultApplication = Object.entries(this.applications).find(
|
|
175
|
+
([, application]) => application.default
|
|
176
|
+
);
|
|
177
|
+
if (!defaultApplication) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
this.pathCache[path] = defaultApplication[0];
|
|
181
|
+
return defaultApplication[0];
|
|
182
|
+
}
|
|
183
|
+
serialize() {
|
|
184
|
+
return this.serialized;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// src/config/overrides/constants.ts
|
|
189
|
+
var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
|
|
190
|
+
var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
|
|
191
|
+
|
|
192
|
+
// src/config/overrides/is-override-cookie.ts
|
|
193
|
+
function isOverrideCookie(cookie) {
|
|
194
|
+
var _a;
|
|
195
|
+
return Boolean((_a = cookie.name) == null ? void 0 : _a.startsWith(OVERRIDES_COOKIE_PREFIX));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/config/overrides/get-override-from-cookie.ts
|
|
199
|
+
function getOverrideFromCookie(cookie) {
|
|
200
|
+
if (!isOverrideCookie(cookie) || !cookie.value)
|
|
201
|
+
return;
|
|
202
|
+
return {
|
|
203
|
+
application: cookie.name.replace(OVERRIDES_ENV_COOKIE_PREFIX, ""),
|
|
204
|
+
host: cookie.value
|
|
139
205
|
};
|
|
140
206
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
207
|
+
|
|
208
|
+
// src/config/overrides/parse-overrides.ts
|
|
209
|
+
function parseOverrides(cookies) {
|
|
210
|
+
const overridesConfig = { applications: {} };
|
|
211
|
+
cookies.forEach((cookie) => {
|
|
212
|
+
const override = getOverrideFromCookie(cookie);
|
|
213
|
+
if (!override)
|
|
214
|
+
return;
|
|
215
|
+
overridesConfig.applications[override.application] = {
|
|
216
|
+
environment: { host: override.host }
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
return overridesConfig;
|
|
144
220
|
}
|
|
145
221
|
|
|
146
|
-
// src/config/
|
|
147
|
-
|
|
148
|
-
var
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
222
|
+
// src/config/microfrontends-config/isomorphic/validation.ts
|
|
223
|
+
import { pathToRegexp as pathToRegexp2, parse as parsePathRegexp } from "path-to-regexp";
|
|
224
|
+
var SUPPORTED_VERSIONS = ["2"];
|
|
225
|
+
var validateConfigVersion = (version) => {
|
|
226
|
+
if (!SUPPORTED_VERSIONS.includes(version)) {
|
|
227
|
+
throw new MicrofrontendError(
|
|
228
|
+
`Unsupported version: ${version}. Supported versions are: ${SUPPORTED_VERSIONS.join(
|
|
229
|
+
", "
|
|
230
|
+
)}`,
|
|
231
|
+
{ type: "config", subtype: "unsupported_version" }
|
|
232
|
+
);
|
|
154
233
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
234
|
+
};
|
|
235
|
+
var validateConfigPaths = (applicationConfigsById) => {
|
|
236
|
+
if (!applicationConfigsById) {
|
|
237
|
+
return;
|
|
158
238
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
239
|
+
const pathsByApplicationId = /* @__PURE__ */ new Map();
|
|
240
|
+
const errors = [];
|
|
241
|
+
for (const [id, app] of Object.entries(applicationConfigsById)) {
|
|
242
|
+
if (isDefaultApp(app)) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
for (const pathMatch of app.routing) {
|
|
246
|
+
for (const path of pathMatch.paths) {
|
|
247
|
+
const maybeError = validatePathExpression(path);
|
|
248
|
+
if (maybeError) {
|
|
249
|
+
errors.push(maybeError);
|
|
250
|
+
}
|
|
251
|
+
const existing = pathsByApplicationId.get(path);
|
|
252
|
+
if (existing) {
|
|
253
|
+
existing.applications.push(id);
|
|
254
|
+
} else {
|
|
255
|
+
pathsByApplicationId.set(path, {
|
|
256
|
+
applications: [id],
|
|
257
|
+
matcher: pathToRegexp2(path),
|
|
258
|
+
applicationId: id
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
166
263
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
264
|
+
const entries = Array.from(pathsByApplicationId.entries());
|
|
265
|
+
entries.forEach(([path, { applications: ids, matcher, applicationId }]) => {
|
|
266
|
+
if (ids.length > 1) {
|
|
267
|
+
errors.push(
|
|
268
|
+
`Duplicate path "${path}" for applications "${ids.join(", ")}"`
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
entries.forEach(
|
|
272
|
+
([
|
|
273
|
+
matchPath,
|
|
274
|
+
{ applications: matchIds, applicationId: matchApplicationId }
|
|
275
|
+
]) => {
|
|
276
|
+
if (path === matchPath) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (applicationId === matchApplicationId) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (matcher.test(matchPath)) {
|
|
283
|
+
const source = `"${path}" of application${ids.length > 0 ? "s" : ""} ${ids.join(", ")}`;
|
|
284
|
+
const destination = `"${matchPath}" of application${matchIds.length > 0 ? "s" : ""} ${matchIds.join(", ")}`;
|
|
285
|
+
errors.push(
|
|
286
|
+
`Overlapping path detected between ${source} and ${destination}`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
if (errors.length) {
|
|
293
|
+
throw new MicrofrontendError(`Invalid paths: ${errors.join(", ")}`, {
|
|
294
|
+
type: "config",
|
|
295
|
+
subtype: "conflicting_paths"
|
|
176
296
|
});
|
|
177
|
-
return overridesConfig;
|
|
178
297
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
298
|
+
};
|
|
299
|
+
var PATH_DEFAULT_PATTERN = "[^\\/#\\?]+?";
|
|
300
|
+
function validatePathExpression(path) {
|
|
301
|
+
const tokens = parsePathRegexp(path);
|
|
302
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
303
|
+
const token = tokens[i];
|
|
304
|
+
if (token === void 0) {
|
|
305
|
+
return `token ${i} in ${path} is undefined, this shouldn't happen`;
|
|
184
306
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
307
|
+
if (typeof token !== "string") {
|
|
308
|
+
if (token.pattern !== PATH_DEFAULT_PATTERN) {
|
|
309
|
+
return `Path ${path} cannot use a regular expression wildcard`;
|
|
310
|
+
}
|
|
311
|
+
if (token.prefix !== "/") {
|
|
312
|
+
return `Wildcard :${token.name} must be immediately after a / in ${path}`;
|
|
313
|
+
}
|
|
314
|
+
if (token.suffix) {
|
|
315
|
+
return `Wildcard suffix on :${token.name} is not allowed. Suffixes are not supported`;
|
|
316
|
+
}
|
|
317
|
+
if (token.modifier && i !== tokens.length - 1) {
|
|
318
|
+
return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path}. Modifiers are only allowed in the last path component`;
|
|
319
|
+
}
|
|
190
320
|
}
|
|
191
|
-
const suffix = previewDeploymentSuffix ? `.${previewDeploymentSuffix}` : `-${teamSlug}.vercel.app`;
|
|
192
|
-
return [
|
|
193
|
-
`${parsedProjectName}-git-([a-zA-Z0-9-]+)${suffix}`,
|
|
194
|
-
microfrontendConfig.getZone(zone).production.host
|
|
195
|
-
];
|
|
196
321
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
322
|
+
return void 0;
|
|
323
|
+
}
|
|
324
|
+
var validateAppPaths = (name, app) => {
|
|
325
|
+
for (const group of app.routing) {
|
|
326
|
+
for (const p of group.paths) {
|
|
327
|
+
if (p === "/") {
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (p.endsWith("/")) {
|
|
331
|
+
throw new MicrofrontendError(
|
|
332
|
+
`Invalid path for application "${name}". ${p} must not end with a slash.`,
|
|
333
|
+
{ type: "application", subtype: "invalid_path" }
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
if (!p.startsWith("/")) {
|
|
337
|
+
throw new MicrofrontendError(
|
|
338
|
+
`Invalid path for application "${name}". ${p} must start with a slash.`,
|
|
339
|
+
{ type: "application", subtype: "invalid_path" }
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
203
343
|
}
|
|
204
|
-
|
|
205
|
-
|
|
344
|
+
};
|
|
345
|
+
var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
346
|
+
if (!applicationConfigsById) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const applicationsWithRouting = Object.entries(applicationConfigsById).filter(
|
|
350
|
+
([, app]) => !isDefaultApp(app)
|
|
351
|
+
);
|
|
352
|
+
const applicationsWithRoutingNames = applicationsWithRouting.map(
|
|
353
|
+
([key]) => key
|
|
354
|
+
);
|
|
355
|
+
const numApplications = Object.keys(applicationConfigsById).length;
|
|
356
|
+
const numApplicationsWithRouting = applicationsWithRoutingNames.length;
|
|
357
|
+
const numApplicationsWithoutRouting = numApplications - numApplicationsWithRouting;
|
|
358
|
+
if (numApplicationsWithoutRouting === 0) {
|
|
359
|
+
throw new MicrofrontendError(
|
|
360
|
+
`No default application found. At least one application needs to be the default by omitting routing.`,
|
|
361
|
+
{ type: "config", subtype: "no_default_application" }
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
if (numApplicationsWithoutRouting > 1) {
|
|
365
|
+
throw new MicrofrontendError(
|
|
366
|
+
`Only one application can omit "routing". Found ${applicationsWithRoutingNames.length - Object.keys(applicationConfigsById).length > 1}.`,
|
|
367
|
+
{ type: "config", subtype: "multiple_default_applications" }
|
|
368
|
+
);
|
|
206
369
|
}
|
|
207
370
|
};
|
|
208
|
-
var Overrides = _Overrides;
|
|
209
|
-
Overrides.overrideEnvCookiePrefix = `${OVERRIDES_COOKIE_PREFIX}:env:`;
|
|
210
371
|
|
|
211
|
-
// src/config/
|
|
372
|
+
// src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
|
|
373
|
+
var PREFIX = "vc-ap";
|
|
374
|
+
function generateAssetPrefixFromName({
|
|
375
|
+
name
|
|
376
|
+
}) {
|
|
377
|
+
if (!name) {
|
|
378
|
+
throw new Error("Name is required to generate an asset prefix");
|
|
379
|
+
}
|
|
380
|
+
return `${PREFIX}-${name}`;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/config/microfrontends-config/isomorphic/utils/generate-port.ts
|
|
384
|
+
function generatePortFromName({
|
|
385
|
+
name,
|
|
386
|
+
minPort = 3e3,
|
|
387
|
+
maxPort = 8e3
|
|
388
|
+
}) {
|
|
389
|
+
if (!name) {
|
|
390
|
+
throw new Error("Name is required to generate a port");
|
|
391
|
+
}
|
|
392
|
+
let hash = 0;
|
|
393
|
+
for (let i = 0; i < name.length; i++) {
|
|
394
|
+
hash = (hash << 5) - hash + name.charCodeAt(i);
|
|
395
|
+
hash |= 0;
|
|
396
|
+
}
|
|
397
|
+
hash = Math.abs(hash);
|
|
398
|
+
const range = maxPort - minPort;
|
|
399
|
+
const port = minPort + hash % range;
|
|
400
|
+
return port;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/config/microfrontends-config/isomorphic/host.ts
|
|
212
404
|
var Host = class {
|
|
213
|
-
constructor(
|
|
214
|
-
|
|
405
|
+
constructor(hostConfig, options) {
|
|
406
|
+
const { protocol = "https", host, port } = hostConfig;
|
|
407
|
+
this.protocol = protocol;
|
|
215
408
|
this.host = host;
|
|
216
409
|
this.port = Host.getPort({ port, protocol: this.protocol });
|
|
217
|
-
this.
|
|
218
|
-
protocol,
|
|
219
|
-
host,
|
|
220
|
-
...port ? { port } : void 0
|
|
221
|
-
};
|
|
410
|
+
this.local = options == null ? void 0 : options.isLocal;
|
|
222
411
|
}
|
|
223
412
|
isLocal() {
|
|
224
|
-
return this.host === "localhost" || this.host === "127.0.0.1";
|
|
413
|
+
return this.local || this.host === "localhost" || this.host === "127.0.0.1";
|
|
225
414
|
}
|
|
226
415
|
static getPort({
|
|
227
416
|
protocol,
|
|
@@ -247,176 +436,234 @@ var Host = class {
|
|
|
247
436
|
const url = `${this.protocol}://${this.host}${this.isDefaultPort() && !includeDefaultPort ? "" : `:${this.port}`}`;
|
|
248
437
|
return new URL(url);
|
|
249
438
|
}
|
|
250
|
-
|
|
251
|
-
|
|
439
|
+
};
|
|
440
|
+
var LocalHost = class extends Host {
|
|
441
|
+
constructor({
|
|
442
|
+
appName,
|
|
443
|
+
...hostConfig
|
|
444
|
+
}) {
|
|
445
|
+
const host = hostConfig.host ?? "localhost";
|
|
446
|
+
const port = hostConfig.port ?? generatePortFromName({ name: appName });
|
|
447
|
+
const protocol = hostConfig.protocol ?? "http";
|
|
448
|
+
super({ protocol, host, port });
|
|
252
449
|
}
|
|
253
450
|
};
|
|
254
451
|
|
|
255
|
-
// src/config/
|
|
452
|
+
// src/config/microfrontends-config/isomorphic/application.ts
|
|
256
453
|
var Application = class {
|
|
257
454
|
constructor(name, {
|
|
258
455
|
app,
|
|
259
|
-
overrides
|
|
456
|
+
overrides,
|
|
457
|
+
isDefault
|
|
260
458
|
}) {
|
|
261
|
-
|
|
459
|
+
var _a, _b;
|
|
262
460
|
this.name = name;
|
|
263
|
-
this.default = app.default;
|
|
264
|
-
this.routing = app.routing;
|
|
265
461
|
this.development = {
|
|
266
|
-
local: new
|
|
267
|
-
|
|
462
|
+
local: new LocalHost({
|
|
463
|
+
appName: name,
|
|
464
|
+
...(_a = app.development) == null ? void 0 : _a.local
|
|
465
|
+
}),
|
|
466
|
+
fallback: ((_b = app.development) == null ? void 0 : _b.fallback) ? new Host(app.development.fallback) : void 0
|
|
268
467
|
};
|
|
269
|
-
this.production = new Host(app.production);
|
|
468
|
+
this.production = app.production ? new Host(app.production) : void 0;
|
|
270
469
|
this.vercel = app.vercel;
|
|
271
470
|
this.overrides = (overrides == null ? void 0 : overrides.environment) ? {
|
|
272
471
|
environment: new Host(overrides.environment)
|
|
273
472
|
} : void 0;
|
|
473
|
+
this.default = isDefault ?? false;
|
|
474
|
+
this.serialized = app;
|
|
274
475
|
}
|
|
275
476
|
isDefault() {
|
|
276
477
|
return this.default;
|
|
277
478
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (((_b = (_a = app.routing) == null ? void 0 : _a.assetPrefix) == null ? void 0 : _b.startsWith("/")) || ((_d = (_c = app.routing) == null ? void 0 : _c.assetPrefix) == null ? void 0 : _d.endsWith("/"))) {
|
|
281
|
-
throw new MicrofrontendError(
|
|
282
|
-
`Invalid assetPrefix for application "${name}". Must not start or end with a slash.`,
|
|
283
|
-
{ type: "zone", subtype: "invalid_asset_prefix" }
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
for (const group of ((_e = app.routing) == null ? void 0 : _e.matches) ?? []) {
|
|
287
|
-
for (const p of group.paths) {
|
|
288
|
-
if (p === "/") {
|
|
289
|
-
continue;
|
|
290
|
-
}
|
|
291
|
-
if (p.endsWith("/")) {
|
|
292
|
-
throw new MicrofrontendError(
|
|
293
|
-
`Invalid path for application "${name}". ${p} must not end with a slash.`,
|
|
294
|
-
{ type: "zone", subtype: "invalid_path" }
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
if (!p.startsWith("/")) {
|
|
298
|
-
throw new MicrofrontendError(
|
|
299
|
-
`Invalid path for application "${name}". ${p} must start with a slash.`,
|
|
300
|
-
{ type: "zone", subtype: "invalid_path" }
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
479
|
+
getAssetPrefix() {
|
|
480
|
+
return generateAssetPrefixFromName({ name: this.name });
|
|
305
481
|
}
|
|
306
482
|
serialize() {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
483
|
+
return this.serialized;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
var DefaultApplication = class extends Application {
|
|
487
|
+
constructor(name, {
|
|
488
|
+
app,
|
|
489
|
+
overrides
|
|
490
|
+
}) {
|
|
491
|
+
super(name, {
|
|
492
|
+
app,
|
|
493
|
+
overrides,
|
|
494
|
+
isDefault: true
|
|
495
|
+
});
|
|
496
|
+
this.default = true;
|
|
497
|
+
this.production = new Host(app.production);
|
|
498
|
+
}
|
|
499
|
+
getAssetPrefix() {
|
|
500
|
+
return "";
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
var ChildApplication = class extends Application {
|
|
504
|
+
constructor(name, {
|
|
505
|
+
app,
|
|
506
|
+
overrides
|
|
507
|
+
}) {
|
|
508
|
+
ChildApplication.validate(name, app);
|
|
509
|
+
super(name, {
|
|
510
|
+
app,
|
|
511
|
+
overrides,
|
|
512
|
+
isDefault: false
|
|
513
|
+
});
|
|
514
|
+
this.default = false;
|
|
515
|
+
this.routing = app.routing;
|
|
516
|
+
}
|
|
517
|
+
static validate(name, app) {
|
|
518
|
+
validateAppPaths(name, app);
|
|
329
519
|
}
|
|
330
520
|
};
|
|
331
521
|
|
|
332
|
-
// src/config/
|
|
333
|
-
var SUPPORTED_VERSIONS = ["1"];
|
|
522
|
+
// src/config/microfrontends-config/isomorphic/constants.ts
|
|
334
523
|
var DEFAULT_LOCAL_PROXY_PORT = 3024;
|
|
335
|
-
|
|
524
|
+
|
|
525
|
+
// src/config/microfrontends-config/isomorphic/index.ts
|
|
526
|
+
var MicrofrontendConfigIsomorphic = class {
|
|
336
527
|
constructor({
|
|
337
528
|
config,
|
|
338
|
-
overrides
|
|
529
|
+
overrides,
|
|
530
|
+
meta
|
|
339
531
|
}) {
|
|
340
|
-
this.
|
|
341
|
-
var _a, _b, _c;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
532
|
+
this.childApplications = {};
|
|
533
|
+
var _a, _b, _c, _d;
|
|
534
|
+
MicrofrontendConfigIsomorphic.validate(config);
|
|
535
|
+
const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
|
|
536
|
+
this.overrides = overrides && !disableOverrides ? overrides : void 0;
|
|
537
|
+
this.isMainConfig = isMainConfig(config);
|
|
538
|
+
if (isMainConfig(config)) {
|
|
539
|
+
for (const [appId, appConfig] of Object.entries(config.applications)) {
|
|
540
|
+
const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
|
|
541
|
+
if (isDefaultApp(appConfig)) {
|
|
542
|
+
this.defaultApplication = new DefaultApplication(appId, {
|
|
543
|
+
app: appConfig,
|
|
544
|
+
overrides: appOverrides
|
|
545
|
+
});
|
|
546
|
+
} else {
|
|
547
|
+
this.childApplications[appId] = new ChildApplication(appId, {
|
|
548
|
+
app: appConfig,
|
|
549
|
+
overrides: appOverrides
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
} else {
|
|
554
|
+
this.partOf = config.partOf;
|
|
555
|
+
const appOverrides = !disableOverrides ? (_d = this.overrides) == null ? void 0 : _d.applications[meta.fromApp] : void 0;
|
|
556
|
+
this.childApplications[meta.fromApp] = new ChildApplication(
|
|
557
|
+
meta.fromApp,
|
|
558
|
+
{
|
|
559
|
+
// we don't know routing because we're not in the main config
|
|
560
|
+
app: { routing: [] },
|
|
561
|
+
overrides: appOverrides
|
|
562
|
+
}
|
|
348
563
|
);
|
|
349
564
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
565
|
+
if (isMainConfig(config) && !this.defaultApplication) {
|
|
566
|
+
throw new MicrofrontendError(
|
|
567
|
+
`Could not find default application in microfrontends configuration`,
|
|
568
|
+
{
|
|
569
|
+
type: "application",
|
|
570
|
+
subtype: "not_found"
|
|
571
|
+
}
|
|
572
|
+
);
|
|
357
573
|
}
|
|
358
574
|
this.config = config;
|
|
359
|
-
this.name = config.name;
|
|
360
|
-
this.version = config.version;
|
|
361
575
|
this.options = config.options;
|
|
362
|
-
this
|
|
576
|
+
this.serialized = {
|
|
577
|
+
config,
|
|
578
|
+
overrides,
|
|
579
|
+
meta
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
static validate(config) {
|
|
583
|
+
const c = typeof config === "string" ? parse(config) : config;
|
|
584
|
+
if (isMainConfig(c)) {
|
|
585
|
+
validateConfigVersion(c.version);
|
|
586
|
+
validateConfigPaths(c.applications);
|
|
587
|
+
validateConfigDefaultApplication(c.applications);
|
|
588
|
+
}
|
|
589
|
+
return c;
|
|
590
|
+
}
|
|
591
|
+
static fromEnv({
|
|
592
|
+
meta,
|
|
593
|
+
cookies
|
|
594
|
+
}) {
|
|
595
|
+
return new MicrofrontendConfigIsomorphic({
|
|
596
|
+
config: parse(getConfigStringFromEnv()),
|
|
597
|
+
overrides: parseOverrides(cookies ?? []),
|
|
598
|
+
meta
|
|
599
|
+
});
|
|
363
600
|
}
|
|
364
601
|
isOverridesDisabled() {
|
|
365
602
|
var _a, _b;
|
|
366
603
|
return ((_b = (_a = this.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
|
|
367
604
|
}
|
|
368
|
-
static getConfigFromEnv() {
|
|
369
|
-
const config = process.env.MFE_CONFIG;
|
|
370
|
-
if (!config) {
|
|
371
|
-
throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
|
|
372
|
-
type: "config",
|
|
373
|
-
subtype: "not_found_in_env"
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
return config;
|
|
377
|
-
}
|
|
378
|
-
static fromEnv(_) {
|
|
379
|
-
throw new Error("Not implemented");
|
|
380
|
-
}
|
|
381
605
|
getConfig() {
|
|
382
606
|
return this.config;
|
|
383
607
|
}
|
|
608
|
+
getApplicationsByType() {
|
|
609
|
+
return {
|
|
610
|
+
defaultApplication: this.defaultApplication,
|
|
611
|
+
applications: Object.values(this.childApplications)
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
getChildApplications() {
|
|
615
|
+
return Object.values(this.childApplications);
|
|
616
|
+
}
|
|
384
617
|
getAllApplications() {
|
|
385
|
-
return
|
|
618
|
+
return [
|
|
619
|
+
this.defaultApplication,
|
|
620
|
+
...Object.values(this.childApplications)
|
|
621
|
+
].filter(Boolean);
|
|
386
622
|
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if (
|
|
623
|
+
getApplication(name) {
|
|
624
|
+
var _a;
|
|
625
|
+
if (((_a = this.defaultApplication) == null ? void 0 : _a.name) === name) {
|
|
626
|
+
return this.defaultApplication;
|
|
627
|
+
}
|
|
628
|
+
const app = this.childApplications[name];
|
|
629
|
+
if (!app) {
|
|
390
630
|
throw new MicrofrontendError(
|
|
391
631
|
`Could not find microfrontends configuration for application "${name}"`,
|
|
392
632
|
{
|
|
393
|
-
type: "
|
|
633
|
+
type: "application",
|
|
394
634
|
subtype: "not_found"
|
|
395
635
|
}
|
|
396
636
|
);
|
|
397
637
|
}
|
|
398
|
-
return
|
|
638
|
+
return app;
|
|
399
639
|
}
|
|
400
640
|
getApplicationByProjectId(projectId) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
641
|
+
var _a, _b;
|
|
642
|
+
if (((_b = (_a = this.defaultApplication) == null ? void 0 : _a.vercel) == null ? void 0 : _b.projectId) === projectId) {
|
|
643
|
+
return this.defaultApplication;
|
|
644
|
+
}
|
|
645
|
+
return Object.values(this.childApplications).find(
|
|
646
|
+
(app) => {
|
|
647
|
+
var _a2;
|
|
648
|
+
return ((_a2 = app.vercel) == null ? void 0 : _a2.projectId) === projectId;
|
|
405
649
|
}
|
|
406
650
|
);
|
|
407
651
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
652
|
+
/**
|
|
653
|
+
* Returns the default application. This can throw if the default application
|
|
654
|
+
* is undefined ( )
|
|
655
|
+
*/
|
|
656
|
+
getDefaultApplication() {
|
|
657
|
+
if (!this.defaultApplication) {
|
|
411
658
|
throw new MicrofrontendError(
|
|
412
|
-
`Could not find default
|
|
659
|
+
`Could not find default application in microfrontends configuration`,
|
|
413
660
|
{
|
|
414
|
-
type: "
|
|
661
|
+
type: "application",
|
|
415
662
|
subtype: "not_found"
|
|
416
663
|
}
|
|
417
664
|
);
|
|
418
665
|
}
|
|
419
|
-
return
|
|
666
|
+
return this.defaultApplication;
|
|
420
667
|
}
|
|
421
668
|
/**
|
|
422
669
|
* Returns the configured port for the local proxy
|
|
@@ -431,55 +678,147 @@ var MicrofrontendConfigCommon = class {
|
|
|
431
678
|
* NOTE: This is used when writing the config to disk and must always match the input Schema
|
|
432
679
|
*/
|
|
433
680
|
toSchemaJson() {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
681
|
+
return this.serialized.config;
|
|
682
|
+
}
|
|
683
|
+
toClientConfig() {
|
|
684
|
+
const applications = Object.fromEntries(
|
|
685
|
+
Object.entries(this.childApplications).map(([name, application]) => [
|
|
686
|
+
name,
|
|
687
|
+
{
|
|
688
|
+
default: false,
|
|
689
|
+
routing: application.routing
|
|
690
|
+
}
|
|
691
|
+
])
|
|
692
|
+
);
|
|
693
|
+
if (this.defaultApplication) {
|
|
694
|
+
applications[this.defaultApplication.name] = {
|
|
695
|
+
default: true
|
|
696
|
+
};
|
|
437
697
|
}
|
|
438
|
-
return {
|
|
439
|
-
$schema: this.$schema,
|
|
440
|
-
name: this.name,
|
|
441
|
-
version: this.version,
|
|
442
|
-
options: this.options,
|
|
698
|
+
return new MicrofrontendConfigClient({
|
|
443
699
|
applications
|
|
444
|
-
};
|
|
700
|
+
});
|
|
445
701
|
}
|
|
446
702
|
serialize() {
|
|
447
|
-
|
|
448
|
-
const applications = {};
|
|
449
|
-
for (const [name, zone] of Object.entries(this.zones)) {
|
|
450
|
-
applications[name] = zone.serialize();
|
|
451
|
-
}
|
|
452
|
-
return {
|
|
453
|
-
config: {
|
|
454
|
-
name: this.name,
|
|
455
|
-
version: this.version,
|
|
456
|
-
applications,
|
|
457
|
-
options: this.options,
|
|
458
|
-
$schema: this.$schema
|
|
459
|
-
},
|
|
460
|
-
overrides: (_a = this.overrides) == null ? void 0 : _a.serialize()
|
|
461
|
-
};
|
|
703
|
+
return this.serialized;
|
|
462
704
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
// src/config/microfrontends-config/isomorphic/child.ts
|
|
708
|
+
var MicrofrontendChildConfig = class extends MicrofrontendConfigIsomorphic {
|
|
709
|
+
constructor({
|
|
710
|
+
config,
|
|
711
|
+
overrides,
|
|
712
|
+
meta
|
|
713
|
+
}) {
|
|
714
|
+
super({ config, overrides, meta });
|
|
715
|
+
this.isMainConfig = false;
|
|
716
|
+
this.partOf = config.partOf;
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
// src/config/microfrontends-config/isomorphic/main.ts
|
|
721
|
+
var MicrofrontendMainConfig = class extends MicrofrontendConfigIsomorphic {
|
|
722
|
+
constructor({
|
|
723
|
+
config,
|
|
724
|
+
overrides,
|
|
725
|
+
meta
|
|
726
|
+
}) {
|
|
727
|
+
var _a, _b, _c;
|
|
728
|
+
super({ config, overrides, meta });
|
|
729
|
+
this.isMainConfig = true;
|
|
730
|
+
const disableOverrides = ((_b = (_a = config.options) == null ? void 0 : _a.vercel) == null ? void 0 : _b.disableOverrides) ?? false;
|
|
731
|
+
let defaultApplication;
|
|
732
|
+
for (const [appId, appConfig] of Object.entries(config.applications)) {
|
|
733
|
+
const appOverrides = !disableOverrides ? (_c = this.overrides) == null ? void 0 : _c.applications[appId] : void 0;
|
|
734
|
+
if (isDefaultApp(appConfig)) {
|
|
735
|
+
defaultApplication = new DefaultApplication(appId, {
|
|
736
|
+
app: appConfig,
|
|
737
|
+
overrides: appOverrides
|
|
738
|
+
});
|
|
739
|
+
} else {
|
|
740
|
+
this.childApplications[appId] = new ChildApplication(appId, {
|
|
741
|
+
app: appConfig,
|
|
742
|
+
overrides: appOverrides
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (!defaultApplication) {
|
|
747
|
+
throw new MicrofrontendError(
|
|
748
|
+
`Could not find default application in microfrontends configuration`,
|
|
749
|
+
{
|
|
750
|
+
type: "application",
|
|
751
|
+
subtype: "not_found"
|
|
752
|
+
}
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
this.defaultApplication = defaultApplication;
|
|
468
756
|
}
|
|
469
757
|
};
|
|
470
758
|
|
|
471
|
-
// src/config/
|
|
472
|
-
var
|
|
759
|
+
// src/config/microfrontends/isomorphic/index.ts
|
|
760
|
+
var Microfrontends = class {
|
|
761
|
+
constructor({
|
|
762
|
+
config,
|
|
763
|
+
overrides,
|
|
764
|
+
meta
|
|
765
|
+
}) {
|
|
766
|
+
if (isMainConfig(config)) {
|
|
767
|
+
this.config = new MicrofrontendMainConfig({ config, overrides, meta });
|
|
768
|
+
} else {
|
|
769
|
+
this.config = new MicrofrontendChildConfig({ config, overrides, meta });
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
isChildConfig() {
|
|
773
|
+
return this.config instanceof MicrofrontendChildConfig;
|
|
774
|
+
}
|
|
473
775
|
static fromEnv({
|
|
474
|
-
cookies
|
|
776
|
+
cookies,
|
|
777
|
+
meta
|
|
475
778
|
}) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
779
|
+
const config = MicrofrontendConfigIsomorphic.fromEnv({
|
|
780
|
+
cookies,
|
|
781
|
+
meta
|
|
479
782
|
});
|
|
783
|
+
return new Microfrontends(config.serialize());
|
|
480
784
|
}
|
|
481
785
|
};
|
|
482
786
|
|
|
787
|
+
// src/routing/get-domain-from-environment.ts
|
|
788
|
+
function getDomainFromEnvironment({
|
|
789
|
+
app,
|
|
790
|
+
target
|
|
791
|
+
}) {
|
|
792
|
+
var _a;
|
|
793
|
+
const mfeProjects = JSON.parse(
|
|
794
|
+
process.env.VERCEL_MICROFRONTENDS_PROJECTS ?? "[]"
|
|
795
|
+
);
|
|
796
|
+
if (mfeProjects.length === 0) {
|
|
797
|
+
throw new Error("Missing related microfrontends project information");
|
|
798
|
+
}
|
|
799
|
+
if (!((_a = app.vercel) == null ? void 0 : _a.projectId)) {
|
|
800
|
+
throw new Error(`Missing applications[${app.name}].vercel.projectId`);
|
|
801
|
+
}
|
|
802
|
+
const vercelProject = mfeProjects.find(
|
|
803
|
+
(p) => {
|
|
804
|
+
var _a2;
|
|
805
|
+
return p.project.id === ((_a2 = app.vercel) == null ? void 0 : _a2.projectId);
|
|
806
|
+
}
|
|
807
|
+
);
|
|
808
|
+
if (!vercelProject) {
|
|
809
|
+
throw new Error(
|
|
810
|
+
`Missing related microfrontends project information for application "${app.name}"`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
const domain = target === "preview" && vercelProject.preview.branch ? vercelProject.preview.branch : vercelProject.production.alias ?? vercelProject.production.url;
|
|
814
|
+
if (!domain) {
|
|
815
|
+
throw new Error(
|
|
816
|
+
`Missing domain for target "${target}" in application "${app.name}"`
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
return domain.startsWith("https://") ? domain : `https://${domain}`;
|
|
820
|
+
}
|
|
821
|
+
|
|
483
822
|
// src/routing/get-domain-for-current-environment.ts
|
|
484
823
|
function debugDomains(zone, env, domain) {
|
|
485
824
|
if (process.env.MFE_DEBUG === "true") {
|
|
@@ -493,34 +832,45 @@ ${line}
|
|
|
493
832
|
`);
|
|
494
833
|
}
|
|
495
834
|
}
|
|
496
|
-
function
|
|
835
|
+
function getCurrentEnvironment() {
|
|
836
|
+
const isDevelopment = !process.env.VERCEL_ENV || process.env.VERCEL_ENV === "development";
|
|
837
|
+
const isPreview = process.env.VERCEL_ENV === "preview";
|
|
838
|
+
const isProduction = process.env.VERCEL_ENV === "production";
|
|
839
|
+
if (isDevelopment) {
|
|
840
|
+
return { group: "development" };
|
|
841
|
+
} else if (isProduction) {
|
|
842
|
+
return { group: "production" };
|
|
843
|
+
} else if (isPreview) {
|
|
844
|
+
return { group: "preview" };
|
|
845
|
+
}
|
|
846
|
+
return { group: "custom", name: process.env.VERCEL_ENV };
|
|
847
|
+
}
|
|
848
|
+
function getDomainForCurrentEnvironment(config, appName, opts = {}) {
|
|
497
849
|
var _a;
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
return domain;
|
|
510
|
-
} else if (process.env.VERCEL_ENV === "preview") {
|
|
511
|
-
const MFE_PREVIEW_DOMAINS = JSON.parse(
|
|
512
|
-
process.env.MFE_PREVIEW_DOMAINS ?? "{}"
|
|
513
|
-
);
|
|
514
|
-
if (MFE_PREVIEW_DOMAINS[zoneName]) {
|
|
515
|
-
debugDomains(zoneName, "preview", MFE_PREVIEW_DOMAINS[zoneName]);
|
|
516
|
-
return MFE_PREVIEW_DOMAINS[zoneName];
|
|
850
|
+
const app = config.getApplication(appName);
|
|
851
|
+
if (!opts.ignoreOverride && ((_a = app.overrides) == null ? void 0 : _a.environment)) {
|
|
852
|
+
return app.overrides.environment.toString();
|
|
853
|
+
}
|
|
854
|
+
const { group } = getCurrentEnvironment();
|
|
855
|
+
const productionHost = config.getDefaultApplication().production.toString();
|
|
856
|
+
switch (group) {
|
|
857
|
+
case "development": {
|
|
858
|
+
const domain = ["test", "development"].includes(process.env.NODE_ENV) ? app.development.local.toString() : productionHost;
|
|
859
|
+
debugDomains(appName, "development", domain);
|
|
860
|
+
return domain;
|
|
517
861
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
862
|
+
case "preview": {
|
|
863
|
+
return getDomainFromEnvironment({ app, target: "preview" });
|
|
864
|
+
}
|
|
865
|
+
case "production": {
|
|
866
|
+
return getDomainFromEnvironment({ app, target: "production" });
|
|
867
|
+
}
|
|
868
|
+
case "custom":
|
|
869
|
+
console.warn(
|
|
870
|
+
`Custom environments are not supported in getDomainForCurrentEnvironment`
|
|
871
|
+
);
|
|
872
|
+
return productionHost;
|
|
521
873
|
}
|
|
522
|
-
debugDomains(zoneName, process.env.VERCEL_ENV, zone.production.toString());
|
|
523
|
-
return zone.production.toString();
|
|
524
874
|
}
|
|
525
875
|
|
|
526
876
|
// src/next/middleware/middleware.ts
|
|
@@ -544,167 +894,187 @@ async function verifyPreviewDomain(req, rewriteDomain) {
|
|
|
544
894
|
return !(previewResponse.status === 404 && (vercelError === "DEPLOYMENT_NOT_FOUND" || vercelError === "NOT_FOUND"));
|
|
545
895
|
}
|
|
546
896
|
function getHandler({
|
|
897
|
+
config,
|
|
547
898
|
application,
|
|
548
899
|
flagFn,
|
|
549
|
-
pattern
|
|
900
|
+
pattern,
|
|
901
|
+
production
|
|
550
902
|
}) {
|
|
551
903
|
return async (req) => {
|
|
552
|
-
var _a, _b
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
callback
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
904
|
+
var _a, _b;
|
|
905
|
+
try {
|
|
906
|
+
const pathname = req.nextUrl.pathname;
|
|
907
|
+
const search = req.nextUrl.search;
|
|
908
|
+
const proxyRouting = req.headers.get("X-Vercel-Mfe-Proxy") === "1";
|
|
909
|
+
let rewriteDomain = proxyRouting ? null : getDomainForCurrentEnvironment(config, application.name);
|
|
910
|
+
const patchedHeaders = new Headers(req.headers);
|
|
911
|
+
const responseCallbacks = [];
|
|
912
|
+
const onRewrite = (response) => {
|
|
913
|
+
for (const callback of responseCallbacks) {
|
|
914
|
+
callback(response);
|
|
915
|
+
}
|
|
916
|
+
return response;
|
|
917
|
+
};
|
|
918
|
+
if (process.env.VERCEL_ENV === "preview" && rewriteDomain) {
|
|
919
|
+
const zoneFallbackCookieName = `__zone_${application.name}_production_fallback`;
|
|
920
|
+
const assetPrefix = application.getAssetPrefix();
|
|
921
|
+
if (assetPrefix && pathname.startsWith(`/${assetPrefix}`) && ((_a = req.cookies.get(zoneFallbackCookieName)) == null ? void 0 : _a.value) === "1") {
|
|
922
|
+
rewriteDomain = production.toString();
|
|
923
|
+
} else {
|
|
924
|
+
try {
|
|
925
|
+
let deploymentFound;
|
|
926
|
+
if (req.headers.get("x-vercel-skip-deployment-existence-check")) {
|
|
927
|
+
deploymentFound = true;
|
|
928
|
+
} else {
|
|
929
|
+
deploymentFound = await verifyPreviewDomain(req, rewriteDomain);
|
|
930
|
+
}
|
|
931
|
+
if (!deploymentFound) {
|
|
932
|
+
rewriteDomain = production.toString();
|
|
933
|
+
responseCallbacks.push((response) => {
|
|
934
|
+
response.cookies.set(zoneFallbackCookieName, "1", {
|
|
935
|
+
httpOnly: true,
|
|
936
|
+
sameSite: "lax",
|
|
937
|
+
secure: true,
|
|
938
|
+
maxAge: 60
|
|
939
|
+
// 1 minute
|
|
940
|
+
});
|
|
587
941
|
});
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
942
|
+
try {
|
|
943
|
+
const existingCookie = patchedHeaders.get("cookie");
|
|
944
|
+
if (!(existingCookie == null ? void 0 : existingCookie.includes("__vercel_toolbar"))) {
|
|
945
|
+
patchedHeaders.set(
|
|
946
|
+
"cookie",
|
|
947
|
+
[`__vercel_toolbar=1`, existingCookie].join("; ")
|
|
948
|
+
);
|
|
949
|
+
responseCallbacks.push((response) => {
|
|
950
|
+
response.cookies.set("__vercel_toolbar", "1", {
|
|
951
|
+
httpOnly: false,
|
|
952
|
+
sameSite: "lax",
|
|
953
|
+
secure: true,
|
|
954
|
+
maxAge: 29030400
|
|
955
|
+
});
|
|
602
956
|
});
|
|
603
|
-
}
|
|
957
|
+
}
|
|
958
|
+
} catch (error) {
|
|
604
959
|
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
maxAge: 0
|
|
960
|
+
} else if (((_b = req.cookies.get(zoneFallbackCookieName)) == null ? void 0 : _b.value) === "1") {
|
|
961
|
+
responseCallbacks.push((response) => {
|
|
962
|
+
response.cookies.set(zoneFallbackCookieName, "", {
|
|
963
|
+
httpOnly: true,
|
|
964
|
+
sameSite: "lax",
|
|
965
|
+
secure: true,
|
|
966
|
+
maxAge: 0
|
|
967
|
+
});
|
|
614
968
|
});
|
|
615
|
-
}
|
|
969
|
+
}
|
|
970
|
+
} catch {
|
|
616
971
|
}
|
|
617
|
-
} catch {
|
|
618
972
|
}
|
|
619
973
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
974
|
+
const isFlagEnabled = async () => flagFn ? flagFn() : true;
|
|
975
|
+
if (pattern.test(pathname) && await isFlagEnabled()) {
|
|
976
|
+
if (proxyRouting) {
|
|
977
|
+
const headers = new Headers(req.headers);
|
|
978
|
+
headers.set("x-vercel-mfe-zone", application.name);
|
|
979
|
+
return onRewrite(
|
|
980
|
+
NextResponse.next({
|
|
981
|
+
request: {
|
|
982
|
+
headers
|
|
983
|
+
},
|
|
984
|
+
headers: {
|
|
985
|
+
// temporary, can delete when proxyRouting flag is removed
|
|
986
|
+
"x-vercel-mfe-middleware-sent-proxy": application.name
|
|
987
|
+
}
|
|
988
|
+
})
|
|
989
|
+
);
|
|
990
|
+
}
|
|
626
991
|
return onRewrite(
|
|
627
|
-
NextResponse.
|
|
992
|
+
NextResponse.rewrite(`${rewriteDomain}${pathname}${search}`, {
|
|
628
993
|
request: {
|
|
629
|
-
headers
|
|
630
|
-
},
|
|
631
|
-
headers: {
|
|
632
|
-
// temporary, can delete when proxyRouting flag is removed
|
|
633
|
-
"x-vercel-mfe-middleware-sent-proxy": application.name
|
|
994
|
+
headers: patchedHeaders
|
|
634
995
|
}
|
|
635
996
|
})
|
|
636
997
|
);
|
|
637
998
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
headers: patchedHeaders
|
|
642
|
-
}
|
|
643
|
-
})
|
|
644
|
-
);
|
|
999
|
+
} catch (e) {
|
|
1000
|
+
console.error("An error occured in the microfrontends middleware:", e);
|
|
1001
|
+
throw e;
|
|
645
1002
|
}
|
|
646
1003
|
};
|
|
647
1004
|
}
|
|
648
1005
|
function getMicrofrontendsMiddleware({
|
|
649
1006
|
request,
|
|
650
|
-
flagValues
|
|
1007
|
+
flagValues,
|
|
1008
|
+
fromApp
|
|
651
1009
|
}) {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
1010
|
+
const microfrontends = Microfrontends.fromEnv({
|
|
1011
|
+
cookies: request.cookies.getAll(),
|
|
1012
|
+
meta: {
|
|
1013
|
+
fromApp
|
|
1014
|
+
}
|
|
655
1015
|
});
|
|
656
1016
|
const middlewares = [];
|
|
657
|
-
|
|
1017
|
+
if (microfrontends.config instanceof MicrofrontendChildConfig) {
|
|
1018
|
+
return middlewares;
|
|
1019
|
+
}
|
|
1020
|
+
const config = microfrontends.config;
|
|
1021
|
+
const production = config.defaultApplication.production;
|
|
1022
|
+
for (const application of config.getChildApplications()) {
|
|
658
1023
|
if (application.name === process.env.NEXT_PUBLIC_MFE_CURRENT_APPLICATION) {
|
|
659
1024
|
continue;
|
|
660
1025
|
}
|
|
661
|
-
if (
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
for (const path of pathGroup.paths) {
|
|
687
|
-
const pattern = pathToRegexp(path);
|
|
688
|
-
middlewares.push({
|
|
689
|
-
src: pattern,
|
|
690
|
-
fn: getHandler({
|
|
691
|
-
application,
|
|
692
|
-
flagFn,
|
|
693
|
-
pattern
|
|
694
|
-
})
|
|
695
|
-
});
|
|
1026
|
+
if (process.env.VERCEL_ENV === "preview") {
|
|
1027
|
+
const pattern = pathToRegexp3(`/${application.getAssetPrefix()}/:path+`);
|
|
1028
|
+
middlewares.push({
|
|
1029
|
+
src: pattern,
|
|
1030
|
+
fn: getHandler({
|
|
1031
|
+
config,
|
|
1032
|
+
application,
|
|
1033
|
+
pattern,
|
|
1034
|
+
production
|
|
1035
|
+
})
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
for (const pathGroup of application.routing) {
|
|
1039
|
+
if (process.env.VERCEL_ENV === "preview" || pathGroup.flag) {
|
|
1040
|
+
const flagName = pathGroup.flag;
|
|
1041
|
+
let flagFn;
|
|
1042
|
+
if (flagName) {
|
|
1043
|
+
flagFn = flagValues == null ? void 0 : flagValues[flagName];
|
|
1044
|
+
if (!flagFn) {
|
|
1045
|
+
throw new Error(
|
|
1046
|
+
`Flag "${flagName}" was specified to control routing for path group "${pathGroup.group}" in application ${application.name} but not found in provided flag values.`
|
|
1047
|
+
);
|
|
696
1048
|
}
|
|
697
1049
|
}
|
|
1050
|
+
for (const path of pathGroup.paths) {
|
|
1051
|
+
const pattern = pathToRegexp3(path);
|
|
1052
|
+
middlewares.push({
|
|
1053
|
+
src: pattern,
|
|
1054
|
+
fn: getHandler({
|
|
1055
|
+
config,
|
|
1056
|
+
application,
|
|
1057
|
+
flagFn,
|
|
1058
|
+
pattern,
|
|
1059
|
+
production
|
|
1060
|
+
})
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
698
1063
|
}
|
|
699
1064
|
}
|
|
700
1065
|
}
|
|
701
1066
|
return middlewares;
|
|
702
1067
|
}
|
|
703
|
-
async function runMicrofrontendsMiddleware(
|
|
1068
|
+
async function runMicrofrontendsMiddleware({
|
|
1069
|
+
request,
|
|
1070
|
+
fromApp,
|
|
1071
|
+
flagValues
|
|
1072
|
+
}) {
|
|
704
1073
|
const pathname = request.nextUrl.pathname;
|
|
705
1074
|
const middlewares = getMicrofrontendsMiddleware({
|
|
706
1075
|
request,
|
|
707
|
-
flagValues
|
|
1076
|
+
flagValues,
|
|
1077
|
+
fromApp
|
|
708
1078
|
});
|
|
709
1079
|
for (const mware of middlewares) {
|
|
710
1080
|
if (typeof mware.src === "string" ? pathname === mware.src : mware.src.test(pathname)) {
|