@vercel/microfrontends 2.2.0 → 2.2.2
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 +25 -0
- package/cli/index.cjs +0 -1
- package/dist/bin/cli.cjs +551 -381
- package/dist/config.cjs +191 -169
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.ts +3 -2
- package/dist/config.js +192 -170
- package/dist/config.js.map +1 -1
- package/dist/experimental/sveltekit.cjs +643 -489
- package/dist/experimental/sveltekit.cjs.map +1 -1
- package/dist/experimental/sveltekit.js +645 -491
- package/dist/experimental/sveltekit.js.map +1 -1
- package/dist/experimental/vite.cjs +671 -519
- package/dist/experimental/vite.cjs.map +1 -1
- package/dist/experimental/vite.js +669 -517
- package/dist/experimental/vite.js.map +1 -1
- package/dist/microfrontends/server.cjs +661 -509
- package/dist/microfrontends/server.cjs.map +1 -1
- package/dist/microfrontends/server.d.ts +2 -2
- package/dist/microfrontends/server.js +663 -511
- package/dist/microfrontends/server.js.map +1 -1
- package/dist/microfrontends/utils.cjs +117 -23
- package/dist/microfrontends/utils.cjs.map +1 -1
- package/dist/microfrontends/utils.d.ts +4 -4
- package/dist/microfrontends/utils.js +118 -24
- 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.d.ts +8 -8
- package/dist/next/client.js +1 -1
- package/dist/next/client.js.map +1 -1
- package/dist/next/config.cjs +784 -626
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +782 -624
- package/dist/next/config.js.map +1 -1
- package/dist/next/middleware.cjs +244 -222
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.js +245 -223
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +192 -170
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.d.ts +1 -1
- package/dist/next/testing.js +193 -171
- package/dist/next/testing.js.map +1 -1
- package/dist/overrides.cjs +5 -5
- package/dist/overrides.cjs.map +1 -1
- package/dist/overrides.d.ts +9 -9
- package/dist/overrides.js +5 -5
- package/dist/overrides.js.map +1 -1
- package/dist/utils/mfe-port.cjs +689 -522
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.d.ts +9 -1
- package/dist/utils/mfe-port.js +687 -521
- package/dist/utils/mfe-port.js.map +1 -1
- package/dist/validation.cjs +8 -24
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.js +8 -24
- package/dist/validation.js.map +1 -1
- package/package.json +4 -6
|
@@ -37,38 +37,27 @@ module.exports = __toCommonJS(server_exports);
|
|
|
37
37
|
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
38
38
|
var import_node_path8 = require("path");
|
|
39
39
|
|
|
40
|
-
// src/
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
function isOverrideCookie(cookie) {
|
|
46
|
-
return Boolean(cookie.name?.startsWith(OVERRIDES_COOKIE_PREFIX));
|
|
40
|
+
// src/bin/logger.ts
|
|
41
|
+
function debug(...args) {
|
|
42
|
+
if (process.env.MFE_DEBUG) {
|
|
43
|
+
console.log(...args);
|
|
44
|
+
}
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function getOverrideFromCookie(cookie) {
|
|
51
|
-
if (!isOverrideCookie(cookie) || !cookie.value)
|
|
52
|
-
return;
|
|
53
|
-
return {
|
|
54
|
-
application: cookie.name.replace(OVERRIDES_ENV_COOKIE_PREFIX, ""),
|
|
55
|
-
host: cookie.value
|
|
56
|
-
};
|
|
46
|
+
function info(...args) {
|
|
47
|
+
console.log(...args);
|
|
57
48
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const override = getOverrideFromCookie(cookie);
|
|
64
|
-
if (!override)
|
|
65
|
-
return;
|
|
66
|
-
overridesConfig.applications[override.application] = {
|
|
67
|
-
environment: { host: override.host }
|
|
68
|
-
};
|
|
69
|
-
});
|
|
70
|
-
return overridesConfig;
|
|
49
|
+
function warn(...args) {
|
|
50
|
+
console.warn(...args);
|
|
51
|
+
}
|
|
52
|
+
function error(...args) {
|
|
53
|
+
console.error(...args);
|
|
71
54
|
}
|
|
55
|
+
var logger = {
|
|
56
|
+
debug,
|
|
57
|
+
info,
|
|
58
|
+
warn,
|
|
59
|
+
error
|
|
60
|
+
};
|
|
72
61
|
|
|
73
62
|
// src/config/errors.ts
|
|
74
63
|
var MicrofrontendError = class extends Error {
|
|
@@ -162,277 +151,47 @@ var MicrofrontendError = class extends Error {
|
|
|
162
151
|
}
|
|
163
152
|
};
|
|
164
153
|
|
|
165
|
-
// src/config/microfrontends-config/
|
|
166
|
-
function getConfigStringFromEnv() {
|
|
167
|
-
const config = process.env.MFE_CONFIG;
|
|
168
|
-
if (!config) {
|
|
169
|
-
throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
|
|
170
|
-
type: "config",
|
|
171
|
-
subtype: "not_found_in_env"
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
return config;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// src/config/schema/utils/is-default-app.ts
|
|
178
|
-
function isDefaultApp(a) {
|
|
179
|
-
return !("routing" in a);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// src/config/microfrontends/utils/find-repository-root.ts
|
|
183
|
-
var import_node_fs = __toESM(require("fs"), 1);
|
|
184
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
185
|
-
var GIT_DIRECTORY = ".git";
|
|
186
|
-
function hasGitDirectory(dir) {
|
|
187
|
-
const gitPath = import_node_path.default.join(dir, GIT_DIRECTORY);
|
|
188
|
-
return import_node_fs.default.existsSync(gitPath) && import_node_fs.default.statSync(gitPath).isDirectory();
|
|
189
|
-
}
|
|
190
|
-
function hasPnpmWorkspaces(dir) {
|
|
191
|
-
return import_node_fs.default.existsSync(import_node_path.default.join(dir, "pnpm-workspace.yaml"));
|
|
192
|
-
}
|
|
193
|
-
function hasPackageJson(dir) {
|
|
194
|
-
return import_node_fs.default.existsSync(import_node_path.default.join(dir, "package.json"));
|
|
195
|
-
}
|
|
196
|
-
function findRepositoryRoot(startDir) {
|
|
197
|
-
if (process.env.NX_WORKSPACE_ROOT) {
|
|
198
|
-
return process.env.NX_WORKSPACE_ROOT;
|
|
199
|
-
}
|
|
200
|
-
let currentDir = startDir || process.cwd();
|
|
201
|
-
let lastPackageJsonDir = null;
|
|
202
|
-
while (currentDir !== import_node_path.default.parse(currentDir).root) {
|
|
203
|
-
if (hasGitDirectory(currentDir) || hasPnpmWorkspaces(currentDir)) {
|
|
204
|
-
return currentDir;
|
|
205
|
-
}
|
|
206
|
-
if (hasPackageJson(currentDir)) {
|
|
207
|
-
lastPackageJsonDir = currentDir;
|
|
208
|
-
}
|
|
209
|
-
currentDir = import_node_path.default.dirname(currentDir);
|
|
210
|
-
}
|
|
211
|
-
if (lastPackageJsonDir) {
|
|
212
|
-
return lastPackageJsonDir;
|
|
213
|
-
}
|
|
214
|
-
throw new Error(
|
|
215
|
-
`Could not find the root of the repository for ${startDir}. Please ensure that the directory is part of a Git repository. If you suspect that this should work, please file an issue to the Vercel team.`
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// src/config/microfrontends/utils/infer-microfrontends-location.ts
|
|
220
|
-
var import_node_path2 = require("path");
|
|
221
|
-
var import_node_fs2 = require("fs");
|
|
154
|
+
// src/config/microfrontends-config/isomorphic/index.ts
|
|
222
155
|
var import_jsonc_parser = require("jsonc-parser");
|
|
223
|
-
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
224
|
-
|
|
225
|
-
// src/config/microfrontends/utils/get-config-file-name.ts
|
|
226
|
-
var DEFAULT_CONFIGURATION_FILENAMES = [
|
|
227
|
-
"microfrontends.json",
|
|
228
|
-
"microfrontends.jsonc"
|
|
229
|
-
];
|
|
230
|
-
function getPossibleConfigurationFilenames({
|
|
231
|
-
customConfigFilename
|
|
232
|
-
}) {
|
|
233
|
-
if (customConfigFilename) {
|
|
234
|
-
if (!customConfigFilename.endsWith(".json") && !customConfigFilename.endsWith(".jsonc")) {
|
|
235
|
-
throw new Error(
|
|
236
|
-
`Found VC_MICROFRONTENDS_CONFIG_FILE_NAME but the name is invalid. Received: ${customConfigFilename}. The file name must end with '.json' or '.jsonc'. It's also possible for the env var to include the path, eg microfrontends-dev.json or /path/to/microfrontends-dev.json.`
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
return Array.from(
|
|
240
|
-
/* @__PURE__ */ new Set([customConfigFilename, ...DEFAULT_CONFIGURATION_FILENAMES])
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
return DEFAULT_CONFIGURATION_FILENAMES;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// src/config/microfrontends/utils/infer-microfrontends-location.ts
|
|
247
|
-
var configCache = {};
|
|
248
|
-
function findPackageWithMicrofrontendsConfig({
|
|
249
|
-
repositoryRoot,
|
|
250
|
-
applicationContext,
|
|
251
|
-
customConfigFilename
|
|
252
|
-
}) {
|
|
253
|
-
const applicationName = applicationContext.name;
|
|
254
|
-
try {
|
|
255
|
-
const microfrontendsJsonPaths = import_fast_glob.default.globSync(
|
|
256
|
-
`**/{${getPossibleConfigurationFilenames({ customConfigFilename }).join(",")}}`,
|
|
257
|
-
{
|
|
258
|
-
cwd: repositoryRoot,
|
|
259
|
-
absolute: true,
|
|
260
|
-
onlyFiles: true,
|
|
261
|
-
followSymbolicLinks: false,
|
|
262
|
-
ignore: ["**/node_modules/**", "**/.git/**"]
|
|
263
|
-
}
|
|
264
|
-
);
|
|
265
|
-
const matchingPaths = [];
|
|
266
|
-
for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
|
|
267
|
-
try {
|
|
268
|
-
const microfrontendsJsonContent = (0, import_node_fs2.readFileSync)(
|
|
269
|
-
microfrontendsJsonPath,
|
|
270
|
-
"utf-8"
|
|
271
|
-
);
|
|
272
|
-
const microfrontendsJson = (0, import_jsonc_parser.parse)(microfrontendsJsonContent);
|
|
273
|
-
if (microfrontendsJson.applications[applicationName]) {
|
|
274
|
-
matchingPaths.push(microfrontendsJsonPath);
|
|
275
|
-
} else {
|
|
276
|
-
for (const [_, app] of Object.entries(
|
|
277
|
-
microfrontendsJson.applications
|
|
278
|
-
)) {
|
|
279
|
-
if (app.packageName === applicationName) {
|
|
280
|
-
matchingPaths.push(microfrontendsJsonPath);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
} catch (error2) {
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
if (matchingPaths.length > 1) {
|
|
288
|
-
throw new MicrofrontendError(
|
|
289
|
-
`Found multiple \`microfrontends.json\` files in the repository referencing the application "${applicationName}", but only one is allowed.
|
|
290
|
-
${matchingPaths.join("\n \u2022 ")}`,
|
|
291
|
-
{ type: "config", subtype: "inference_failed" }
|
|
292
|
-
);
|
|
293
|
-
}
|
|
294
|
-
if (matchingPaths.length === 0) {
|
|
295
|
-
let additionalErrorMessage = "";
|
|
296
|
-
if (microfrontendsJsonPaths.length > 0) {
|
|
297
|
-
if (!applicationContext.projectName) {
|
|
298
|
-
additionalErrorMessage = `
|
|
299
|
-
|
|
300
|
-
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.`;
|
|
301
|
-
} else {
|
|
302
|
-
additionalErrorMessage = `
|
|
303
|
-
|
|
304
|
-
Names of applications in \`microfrontends.json\` must match the Vercel Project name (${applicationContext.projectName}).`;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
throw new MicrofrontendError(
|
|
308
|
-
`Could not find a \`microfrontends.json\` file in the repository that contains the "${applicationName}" application.${additionalErrorMessage}
|
|
309
|
-
|
|
310
|
-
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.
|
|
311
|
-
|
|
312
|
-
If your Vercel Microfrontends configuration has a custom name, ensure the VC_MICROFRONTENDS_CONFIG_FILE_NAME environment variable is set, you can pull the vercel project environment variables using the "vercel env pull" command.
|
|
313
|
-
|
|
314
|
-
If you suspect this is thrown in error, please reach out to the Vercel team.`,
|
|
315
|
-
{ type: "config", subtype: "inference_failed" }
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
const [packageJsonPath] = matchingPaths;
|
|
319
|
-
return (0, import_node_path2.dirname)(packageJsonPath);
|
|
320
|
-
} catch (error2) {
|
|
321
|
-
if (error2 instanceof MicrofrontendError) {
|
|
322
|
-
throw error2;
|
|
323
|
-
}
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
function inferMicrofrontendsLocation(opts) {
|
|
328
|
-
const cacheKey = `${opts.repositoryRoot}-${opts.applicationContext.name}${opts.customConfigFilename ? `-${opts.customConfigFilename}` : ""}`;
|
|
329
|
-
if (configCache[cacheKey]) {
|
|
330
|
-
return configCache[cacheKey];
|
|
331
|
-
}
|
|
332
|
-
const result = findPackageWithMicrofrontendsConfig(opts);
|
|
333
|
-
if (!result) {
|
|
334
|
-
throw new MicrofrontendError(
|
|
335
|
-
`Could not infer the location of the \`microfrontends.json\` file for application "${opts.applicationContext.name}" starting in directory "${opts.repositoryRoot}".`,
|
|
336
|
-
{ type: "config", subtype: "inference_failed" }
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
configCache[cacheKey] = result;
|
|
340
|
-
return result;
|
|
341
|
-
}
|
|
342
156
|
|
|
343
|
-
// src/config/
|
|
344
|
-
var
|
|
345
|
-
var
|
|
157
|
+
// src/config/overrides/constants.ts
|
|
158
|
+
var OVERRIDES_COOKIE_PREFIX = "vercel-micro-frontends-override";
|
|
159
|
+
var OVERRIDES_ENV_COOKIE_PREFIX = `${OVERRIDES_COOKIE_PREFIX}:env:`;
|
|
346
160
|
|
|
347
|
-
// src/
|
|
348
|
-
function
|
|
349
|
-
|
|
350
|
-
console.log(...args);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
function info(...args) {
|
|
354
|
-
console.log(...args);
|
|
355
|
-
}
|
|
356
|
-
function warn(...args) {
|
|
357
|
-
console.warn(...args);
|
|
358
|
-
}
|
|
359
|
-
function error(...args) {
|
|
360
|
-
console.error(...args);
|
|
161
|
+
// src/config/overrides/is-override-cookie.ts
|
|
162
|
+
function isOverrideCookie(cookie) {
|
|
163
|
+
return Boolean(cookie.name?.startsWith(OVERRIDES_COOKIE_PREFIX));
|
|
361
164
|
}
|
|
362
|
-
var logger = {
|
|
363
|
-
debug,
|
|
364
|
-
info,
|
|
365
|
-
warn,
|
|
366
|
-
error
|
|
367
|
-
};
|
|
368
165
|
|
|
369
|
-
// src/config/
|
|
370
|
-
function
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (import_node_fs3.default.existsSync(import_node_path3.default.join(repositoryRoot, "vlt-workspaces.json"))) {
|
|
378
|
-
return true;
|
|
379
|
-
}
|
|
380
|
-
if (process.env.NX_WORKSPACE_ROOT === import_node_path3.default.resolve(repositoryRoot)) {
|
|
381
|
-
return true;
|
|
382
|
-
}
|
|
383
|
-
const packageJsonPath = import_node_path3.default.join(repositoryRoot, "package.json");
|
|
384
|
-
if (!import_node_fs3.default.existsSync(packageJsonPath)) {
|
|
385
|
-
return false;
|
|
386
|
-
}
|
|
387
|
-
const packageJson = JSON.parse(
|
|
388
|
-
import_node_fs3.default.readFileSync(packageJsonPath, "utf-8")
|
|
389
|
-
);
|
|
390
|
-
return packageJson.workspaces !== void 0;
|
|
391
|
-
} catch (error2) {
|
|
392
|
-
logger.error("Error determining if repository is a monorepo", error2);
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
166
|
+
// src/config/overrides/get-override-from-cookie.ts
|
|
167
|
+
function getOverrideFromCookie(cookie) {
|
|
168
|
+
if (!isOverrideCookie(cookie) || !cookie.value)
|
|
169
|
+
return;
|
|
170
|
+
return {
|
|
171
|
+
application: cookie.name.replace(OVERRIDES_ENV_COOKIE_PREFIX, ""),
|
|
172
|
+
host: cookie.value
|
|
173
|
+
};
|
|
395
174
|
}
|
|
396
175
|
|
|
397
|
-
// src/config/
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
410
|
-
throw new Error(
|
|
411
|
-
`The root of the package that contains the \`package.json\` file for the \`${startDir}\` directory could not be found.`
|
|
412
|
-
);
|
|
176
|
+
// src/config/overrides/parse-overrides.ts
|
|
177
|
+
function parseOverrides(cookies) {
|
|
178
|
+
const overridesConfig = { applications: {} };
|
|
179
|
+
cookies.forEach((cookie) => {
|
|
180
|
+
const override = getOverrideFromCookie(cookie);
|
|
181
|
+
if (!override)
|
|
182
|
+
return;
|
|
183
|
+
overridesConfig.applications[override.application] = {
|
|
184
|
+
environment: { host: override.host }
|
|
185
|
+
};
|
|
186
|
+
});
|
|
187
|
+
return overridesConfig;
|
|
413
188
|
}
|
|
414
189
|
|
|
415
|
-
// src/config/
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
function findConfig({
|
|
419
|
-
dir,
|
|
420
|
-
customConfigFilename
|
|
421
|
-
}) {
|
|
422
|
-
for (const filename of getPossibleConfigurationFilenames({
|
|
423
|
-
customConfigFilename
|
|
424
|
-
})) {
|
|
425
|
-
const maybeConfig = (0, import_node_path5.join)(dir, filename);
|
|
426
|
-
if (import_node_fs5.default.existsSync(maybeConfig)) {
|
|
427
|
-
return maybeConfig;
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return null;
|
|
190
|
+
// src/config/schema/utils/is-default-app.ts
|
|
191
|
+
function isDefaultApp(a) {
|
|
192
|
+
return !("routing" in a);
|
|
431
193
|
}
|
|
432
194
|
|
|
433
|
-
// src/config/microfrontends-config/isomorphic/index.ts
|
|
434
|
-
var import_jsonc_parser2 = require("jsonc-parser");
|
|
435
|
-
|
|
436
195
|
// src/config/microfrontends-config/client/index.ts
|
|
437
196
|
var import_path_to_regexp = require("path-to-regexp");
|
|
438
197
|
var regexpCache = /* @__PURE__ */ new Map();
|
|
@@ -488,49 +247,226 @@ var MicrofrontendConfigClient = class {
|
|
|
488
247
|
static fromEnv(config) {
|
|
489
248
|
if (!config) {
|
|
490
249
|
throw new Error(
|
|
491
|
-
"Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`? Is the local proxy running and this application is being accessed via the proxy port? See https://vercel.com/docs/microfrontends/local-development#setting-up-microfrontends-proxy"
|
|
250
|
+
"Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`? Is the local proxy running and this application is being accessed via the proxy port? See https://vercel.com/docs/microfrontends/local-development#setting-up-microfrontends-proxy"
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
return new MicrofrontendConfigClient(JSON.parse(config));
|
|
254
|
+
}
|
|
255
|
+
isEqual(other) {
|
|
256
|
+
return this === other || JSON.stringify(this.applications) === JSON.stringify(other.applications);
|
|
257
|
+
}
|
|
258
|
+
getApplicationNameForPath(path6) {
|
|
259
|
+
if (!path6.startsWith("/")) {
|
|
260
|
+
throw new Error(`Path must start with a /`);
|
|
261
|
+
}
|
|
262
|
+
if (this.pathCache[path6]) {
|
|
263
|
+
return this.pathCache[path6];
|
|
264
|
+
}
|
|
265
|
+
const pathname = new URL(path6, "https://example.com").pathname;
|
|
266
|
+
for (const [name, application] of Object.entries(this.applications)) {
|
|
267
|
+
if (application.routing) {
|
|
268
|
+
for (const group of application.routing) {
|
|
269
|
+
for (const childPath of group.paths) {
|
|
270
|
+
const regexp = getRegexp(childPath);
|
|
271
|
+
if (regexp.test(pathname)) {
|
|
272
|
+
this.pathCache[path6] = name;
|
|
273
|
+
return name;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const defaultApplication = Object.entries(this.applications).find(
|
|
280
|
+
([, application]) => application.default
|
|
281
|
+
);
|
|
282
|
+
if (!defaultApplication) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
this.pathCache[path6] = defaultApplication[0];
|
|
286
|
+
return defaultApplication[0];
|
|
287
|
+
}
|
|
288
|
+
serialize() {
|
|
289
|
+
return this.serialized;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// src/config/microfrontends-config/utils/get-config-from-env.ts
|
|
294
|
+
function getConfigStringFromEnv() {
|
|
295
|
+
const config = process.env.MFE_CONFIG;
|
|
296
|
+
if (!config) {
|
|
297
|
+
throw new MicrofrontendError(`Missing "MFE_CONFIG" in environment.`, {
|
|
298
|
+
type: "config",
|
|
299
|
+
subtype: "not_found_in_env"
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return config;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// src/config/microfrontends-config/isomorphic/constants.ts
|
|
306
|
+
var DEFAULT_LOCAL_PROXY_PORT = 3024;
|
|
307
|
+
var MFE_APP_PORT_ENV = "MFE_APP_PORT";
|
|
308
|
+
var MFE_LOCAL_PROXY_PORT_ENV = "MFE_LOCAL_PROXY_PORT";
|
|
309
|
+
|
|
310
|
+
// src/config/microfrontends-config/isomorphic/utils/generate-port.ts
|
|
311
|
+
function generatePortFromName({
|
|
312
|
+
name,
|
|
313
|
+
minPort = 3e3,
|
|
314
|
+
maxPort = 8e3
|
|
315
|
+
}) {
|
|
316
|
+
if (!name) {
|
|
317
|
+
throw new Error("Name is required to generate a port");
|
|
318
|
+
}
|
|
319
|
+
let hash = 0;
|
|
320
|
+
for (let i = 0; i < name.length; i++) {
|
|
321
|
+
hash = (hash << 5) - hash + name.charCodeAt(i);
|
|
322
|
+
hash |= 0;
|
|
323
|
+
}
|
|
324
|
+
hash = Math.abs(hash);
|
|
325
|
+
const range = maxPort - minPort;
|
|
326
|
+
const port = minPort + hash % range;
|
|
327
|
+
return port;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/config/microfrontends-config/isomorphic/host.ts
|
|
331
|
+
var Host = class {
|
|
332
|
+
constructor(hostConfig, options) {
|
|
333
|
+
if (typeof hostConfig === "string") {
|
|
334
|
+
({
|
|
335
|
+
protocol: this.protocol,
|
|
336
|
+
host: this.host,
|
|
337
|
+
port: this.port
|
|
338
|
+
} = Host.parseUrl(hostConfig));
|
|
339
|
+
} else {
|
|
340
|
+
const { protocol = "https", host, port } = hostConfig;
|
|
341
|
+
this.protocol = protocol;
|
|
342
|
+
this.host = host;
|
|
343
|
+
this.port = port;
|
|
344
|
+
}
|
|
345
|
+
this.local = options?.isLocal;
|
|
346
|
+
}
|
|
347
|
+
static parseUrl(url, defaultProtocol = "https") {
|
|
348
|
+
let hostToParse = url;
|
|
349
|
+
if (!/^https?:\/\//.exec(hostToParse)) {
|
|
350
|
+
hostToParse = `${defaultProtocol}://${hostToParse}`;
|
|
351
|
+
}
|
|
352
|
+
const parsed = new URL(hostToParse);
|
|
353
|
+
if (!parsed.hostname) {
|
|
354
|
+
throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
|
|
355
|
+
}
|
|
356
|
+
if (parsed.hash) {
|
|
357
|
+
throw new Error(
|
|
358
|
+
Host.getMicrofrontendsError(url, "cannot have a fragment")
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
if (parsed.username || parsed.password) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
Host.getMicrofrontendsError(
|
|
364
|
+
url,
|
|
365
|
+
"cannot have authentication credentials (username and/or password)"
|
|
366
|
+
)
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
if (parsed.pathname !== "/") {
|
|
370
|
+
throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
|
|
371
|
+
}
|
|
372
|
+
if (parsed.search) {
|
|
373
|
+
throw new Error(
|
|
374
|
+
Host.getMicrofrontendsError(url, "cannot have query parameters")
|
|
492
375
|
);
|
|
493
376
|
}
|
|
494
|
-
|
|
377
|
+
const protocol = parsed.protocol.slice(0, -1);
|
|
378
|
+
return {
|
|
379
|
+
protocol,
|
|
380
|
+
host: parsed.hostname,
|
|
381
|
+
port: parsed.port ? Number.parseInt(parsed.port, 10) : void 0
|
|
382
|
+
};
|
|
495
383
|
}
|
|
496
|
-
|
|
497
|
-
return
|
|
384
|
+
static getMicrofrontendsError(url, message) {
|
|
385
|
+
return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
|
|
498
386
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
387
|
+
isLocal() {
|
|
388
|
+
return this.local || this.host === "localhost" || this.host === "127.0.0.1";
|
|
389
|
+
}
|
|
390
|
+
toString() {
|
|
391
|
+
const url = this.toUrl();
|
|
392
|
+
return url.toString().replace(/\/$/, "");
|
|
393
|
+
}
|
|
394
|
+
toUrl() {
|
|
395
|
+
const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
|
|
396
|
+
return new URL(url);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
var LocalHost = class extends Host {
|
|
400
|
+
constructor({
|
|
401
|
+
appName,
|
|
402
|
+
local
|
|
403
|
+
}) {
|
|
404
|
+
const portOverride = process.env[MFE_APP_PORT_ENV];
|
|
405
|
+
if (portOverride) {
|
|
406
|
+
const overridePort = Number.parseInt(portOverride, 10);
|
|
407
|
+
if (!Number.isNaN(overridePort) && overridePort > 0 && overridePort < 65536) {
|
|
408
|
+
super({
|
|
409
|
+
protocol: "http",
|
|
410
|
+
host: "localhost",
|
|
411
|
+
port: overridePort
|
|
412
|
+
});
|
|
413
|
+
return;
|
|
518
414
|
}
|
|
519
415
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
if (
|
|
524
|
-
|
|
416
|
+
let protocol;
|
|
417
|
+
let host;
|
|
418
|
+
let port;
|
|
419
|
+
if (typeof local === "number") {
|
|
420
|
+
port = local;
|
|
421
|
+
} else if (typeof local === "string") {
|
|
422
|
+
if (/^\d+$/.test(local)) {
|
|
423
|
+
port = Number.parseInt(local, 10);
|
|
424
|
+
} else {
|
|
425
|
+
const parsed = Host.parseUrl(local, "http");
|
|
426
|
+
protocol = parsed.protocol;
|
|
427
|
+
host = parsed.host;
|
|
428
|
+
port = parsed.port;
|
|
429
|
+
}
|
|
430
|
+
} else if (local) {
|
|
431
|
+
protocol = local.protocol;
|
|
432
|
+
host = local.host;
|
|
433
|
+
port = local.port;
|
|
525
434
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
435
|
+
super({
|
|
436
|
+
protocol: protocol ?? "http",
|
|
437
|
+
host: host ?? "localhost",
|
|
438
|
+
port: port ?? generatePortFromName({ name: appName })
|
|
439
|
+
});
|
|
531
440
|
}
|
|
532
441
|
};
|
|
533
442
|
|
|
443
|
+
// src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
|
|
444
|
+
var import_md5 = __toESM(require("md5"), 1);
|
|
445
|
+
function hashApplicationName(name) {
|
|
446
|
+
if (!name) {
|
|
447
|
+
throw new Error("Application name is required to generate hash");
|
|
448
|
+
}
|
|
449
|
+
return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
|
|
453
|
+
var PREFIX = "vc-ap";
|
|
454
|
+
function generateAssetPrefixFromName({
|
|
455
|
+
name
|
|
456
|
+
}) {
|
|
457
|
+
if (!name) {
|
|
458
|
+
throw new Error("Name is required to generate an asset prefix");
|
|
459
|
+
}
|
|
460
|
+
return `${PREFIX}-${hashApplicationName(name)}`;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
|
|
464
|
+
function generateAutomationBypassEnvVarName({
|
|
465
|
+
name
|
|
466
|
+
}) {
|
|
467
|
+
return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
|
|
468
|
+
}
|
|
469
|
+
|
|
534
470
|
// src/config/microfrontends-config/isomorphic/validation.ts
|
|
535
471
|
var import_path_to_regexp2 = require("path-to-regexp");
|
|
536
472
|
var LIST_FORMATTER = new Intl.ListFormat("en", {
|
|
@@ -707,159 +643,11 @@ var validateConfigDefaultApplication = (applicationConfigsById) => {
|
|
|
707
643
|
);
|
|
708
644
|
throw new MicrofrontendError(
|
|
709
645
|
`All applications except for the default app must contain the "routing" field. Applications that are missing routing: ${LIST_FORMATTER.format(applicationNamesMissingRouting)}.`,
|
|
710
|
-
{ type: "config", subtype: "multiple_default_applications" }
|
|
711
|
-
);
|
|
712
|
-
}
|
|
713
|
-
};
|
|
714
|
-
|
|
715
|
-
// src/config/microfrontends-config/isomorphic/utils/hash-application-name.ts
|
|
716
|
-
var import_md5 = __toESM(require("md5"), 1);
|
|
717
|
-
function hashApplicationName(name) {
|
|
718
|
-
if (!name) {
|
|
719
|
-
throw new Error("Application name is required to generate hash");
|
|
720
|
-
}
|
|
721
|
-
return (0, import_md5.default)(name).substring(0, 6).padStart(6, "0");
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
// src/config/microfrontends-config/isomorphic/utils/generate-asset-prefix.ts
|
|
725
|
-
var PREFIX = "vc-ap";
|
|
726
|
-
function generateAssetPrefixFromName({
|
|
727
|
-
name
|
|
728
|
-
}) {
|
|
729
|
-
if (!name) {
|
|
730
|
-
throw new Error("Name is required to generate an asset prefix");
|
|
731
|
-
}
|
|
732
|
-
return `${PREFIX}-${hashApplicationName(name)}`;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// src/config/microfrontends-config/isomorphic/utils/generate-port.ts
|
|
736
|
-
function generatePortFromName({
|
|
737
|
-
name,
|
|
738
|
-
minPort = 3e3,
|
|
739
|
-
maxPort = 8e3
|
|
740
|
-
}) {
|
|
741
|
-
if (!name) {
|
|
742
|
-
throw new Error("Name is required to generate a port");
|
|
743
|
-
}
|
|
744
|
-
let hash = 0;
|
|
745
|
-
for (let i = 0; i < name.length; i++) {
|
|
746
|
-
hash = (hash << 5) - hash + name.charCodeAt(i);
|
|
747
|
-
hash |= 0;
|
|
748
|
-
}
|
|
749
|
-
hash = Math.abs(hash);
|
|
750
|
-
const range = maxPort - minPort;
|
|
751
|
-
const port = minPort + hash % range;
|
|
752
|
-
return port;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
// src/config/microfrontends-config/isomorphic/host.ts
|
|
756
|
-
var Host = class {
|
|
757
|
-
constructor(hostConfig, options) {
|
|
758
|
-
if (typeof hostConfig === "string") {
|
|
759
|
-
({
|
|
760
|
-
protocol: this.protocol,
|
|
761
|
-
host: this.host,
|
|
762
|
-
port: this.port
|
|
763
|
-
} = Host.parseUrl(hostConfig));
|
|
764
|
-
} else {
|
|
765
|
-
const { protocol = "https", host, port } = hostConfig;
|
|
766
|
-
this.protocol = protocol;
|
|
767
|
-
this.host = host;
|
|
768
|
-
this.port = port;
|
|
769
|
-
}
|
|
770
|
-
this.local = options?.isLocal;
|
|
771
|
-
}
|
|
772
|
-
static parseUrl(url, defaultProtocol = "https") {
|
|
773
|
-
let hostToParse = url;
|
|
774
|
-
if (!/^https?:\/\//.exec(hostToParse)) {
|
|
775
|
-
hostToParse = `${defaultProtocol}://${hostToParse}`;
|
|
776
|
-
}
|
|
777
|
-
const parsed = new URL(hostToParse);
|
|
778
|
-
if (!parsed.hostname) {
|
|
779
|
-
throw new Error(Host.getMicrofrontendsError(url, "requires a host"));
|
|
780
|
-
}
|
|
781
|
-
if (parsed.hash) {
|
|
782
|
-
throw new Error(
|
|
783
|
-
Host.getMicrofrontendsError(url, "cannot have a fragment")
|
|
784
|
-
);
|
|
785
|
-
}
|
|
786
|
-
if (parsed.username || parsed.password) {
|
|
787
|
-
throw new Error(
|
|
788
|
-
Host.getMicrofrontendsError(
|
|
789
|
-
url,
|
|
790
|
-
"cannot have authentication credentials (username and/or password)"
|
|
791
|
-
)
|
|
792
|
-
);
|
|
793
|
-
}
|
|
794
|
-
if (parsed.pathname !== "/") {
|
|
795
|
-
throw new Error(Host.getMicrofrontendsError(url, "cannot have a path"));
|
|
796
|
-
}
|
|
797
|
-
if (parsed.search) {
|
|
798
|
-
throw new Error(
|
|
799
|
-
Host.getMicrofrontendsError(url, "cannot have query parameters")
|
|
800
|
-
);
|
|
801
|
-
}
|
|
802
|
-
const protocol = parsed.protocol.slice(0, -1);
|
|
803
|
-
return {
|
|
804
|
-
protocol,
|
|
805
|
-
host: parsed.hostname,
|
|
806
|
-
port: parsed.port ? Number.parseInt(parsed.port) : void 0
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
static getMicrofrontendsError(url, message) {
|
|
810
|
-
return `Microfrontends configuration error: the URL ${url} in your microfrontends.json ${message}.`;
|
|
811
|
-
}
|
|
812
|
-
isLocal() {
|
|
813
|
-
return this.local || this.host === "localhost" || this.host === "127.0.0.1";
|
|
814
|
-
}
|
|
815
|
-
toString() {
|
|
816
|
-
const url = this.toUrl();
|
|
817
|
-
return url.toString().replace(/\/$/, "");
|
|
818
|
-
}
|
|
819
|
-
toUrl() {
|
|
820
|
-
const url = `${this.protocol}://${this.host}${this.port ? `:${this.port}` : ""}`;
|
|
821
|
-
return new URL(url);
|
|
822
|
-
}
|
|
823
|
-
};
|
|
824
|
-
var LocalHost = class extends Host {
|
|
825
|
-
constructor({
|
|
826
|
-
appName,
|
|
827
|
-
local
|
|
828
|
-
}) {
|
|
829
|
-
let protocol;
|
|
830
|
-
let host;
|
|
831
|
-
let port;
|
|
832
|
-
if (typeof local === "number") {
|
|
833
|
-
port = local;
|
|
834
|
-
} else if (typeof local === "string") {
|
|
835
|
-
if (/^\d+$/.test(local)) {
|
|
836
|
-
port = Number.parseInt(local);
|
|
837
|
-
} else {
|
|
838
|
-
const parsed = Host.parseUrl(local, "http");
|
|
839
|
-
protocol = parsed.protocol;
|
|
840
|
-
host = parsed.host;
|
|
841
|
-
port = parsed.port;
|
|
842
|
-
}
|
|
843
|
-
} else if (local) {
|
|
844
|
-
protocol = local.protocol;
|
|
845
|
-
host = local.host;
|
|
846
|
-
port = local.port;
|
|
847
|
-
}
|
|
848
|
-
super({
|
|
849
|
-
protocol: protocol ?? "http",
|
|
850
|
-
host: host ?? "localhost",
|
|
851
|
-
port: port ?? generatePortFromName({ name: appName })
|
|
852
|
-
});
|
|
646
|
+
{ type: "config", subtype: "multiple_default_applications" }
|
|
647
|
+
);
|
|
853
648
|
}
|
|
854
649
|
};
|
|
855
650
|
|
|
856
|
-
// src/config/microfrontends-config/isomorphic/utils/generate-automation-bypass-env-var-name.ts
|
|
857
|
-
function generateAutomationBypassEnvVarName({
|
|
858
|
-
name
|
|
859
|
-
}) {
|
|
860
|
-
return `AUTOMATION_BYPASS_${name.toUpperCase().replace(/[^a-zA-Z0-9]/g, "_")}`;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
651
|
// src/config/microfrontends-config/isomorphic/application.ts
|
|
864
652
|
var Application = class {
|
|
865
653
|
constructor(name, {
|
|
@@ -940,9 +728,6 @@ var ChildApplication = class extends Application {
|
|
|
940
728
|
}
|
|
941
729
|
};
|
|
942
730
|
|
|
943
|
-
// src/config/microfrontends-config/isomorphic/constants.ts
|
|
944
|
-
var DEFAULT_LOCAL_PROXY_PORT = 3024;
|
|
945
|
-
|
|
946
731
|
// src/config/microfrontends-config/isomorphic/index.ts
|
|
947
732
|
var MicrofrontendConfigIsomorphic = class {
|
|
948
733
|
constructor({
|
|
@@ -986,7 +771,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
986
771
|
};
|
|
987
772
|
}
|
|
988
773
|
static validate(config) {
|
|
989
|
-
const c = typeof config === "string" ? (0,
|
|
774
|
+
const c = typeof config === "string" ? (0, import_jsonc_parser.parse)(config) : config;
|
|
990
775
|
validateConfigPaths(c.applications);
|
|
991
776
|
validateConfigDefaultApplication(c.applications);
|
|
992
777
|
return c;
|
|
@@ -995,7 +780,7 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
995
780
|
cookies
|
|
996
781
|
}) {
|
|
997
782
|
return new MicrofrontendConfigIsomorphic({
|
|
998
|
-
config: (0,
|
|
783
|
+
config: (0, import_jsonc_parser.parse)(getConfigStringFromEnv()),
|
|
999
784
|
overrides: parseOverrides(cookies ?? [])
|
|
1000
785
|
});
|
|
1001
786
|
}
|
|
@@ -1061,9 +846,17 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
1061
846
|
return this.defaultApplication;
|
|
1062
847
|
}
|
|
1063
848
|
/**
|
|
1064
|
-
* Returns the configured port for the local proxy
|
|
849
|
+
* Returns the configured port for the local proxy.
|
|
850
|
+
* Can be overridden via MFE_LOCAL_PROXY_PORT environment variable.
|
|
1065
851
|
*/
|
|
1066
852
|
getLocalProxyPort() {
|
|
853
|
+
const portOverride = process.env[MFE_LOCAL_PROXY_PORT_ENV];
|
|
854
|
+
if (portOverride) {
|
|
855
|
+
const port = Number.parseInt(portOverride, 10);
|
|
856
|
+
if (!Number.isNaN(port) && port > 0 && port < 65536) {
|
|
857
|
+
return port;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
1067
860
|
return this.config.options?.localProxyPort ?? DEFAULT_LOCAL_PROXY_PORT;
|
|
1068
861
|
}
|
|
1069
862
|
toClientConfig(options) {
|
|
@@ -1101,32 +894,144 @@ var MicrofrontendConfigIsomorphic = class {
|
|
|
1101
894
|
}
|
|
1102
895
|
};
|
|
1103
896
|
|
|
897
|
+
// src/config/microfrontends/utils/find-config.ts
|
|
898
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
899
|
+
var import_node_path = require("path");
|
|
900
|
+
|
|
901
|
+
// src/config/microfrontends/utils/get-config-file-name.ts
|
|
902
|
+
var DEFAULT_CONFIGURATION_FILENAMES = [
|
|
903
|
+
"microfrontends.json",
|
|
904
|
+
"microfrontends.jsonc"
|
|
905
|
+
];
|
|
906
|
+
function getPossibleConfigurationFilenames({
|
|
907
|
+
customConfigFilename
|
|
908
|
+
}) {
|
|
909
|
+
if (customConfigFilename) {
|
|
910
|
+
if (!customConfigFilename.endsWith(".json") && !customConfigFilename.endsWith(".jsonc")) {
|
|
911
|
+
throw new Error(
|
|
912
|
+
`Found VC_MICROFRONTENDS_CONFIG_FILE_NAME but the name is invalid. Received: ${customConfigFilename}. The file name must end with '.json' or '.jsonc'. It's also possible for the env var to include the path, eg microfrontends-dev.json or /path/to/microfrontends-dev.json.`
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
return Array.from(
|
|
916
|
+
/* @__PURE__ */ new Set([customConfigFilename, ...DEFAULT_CONFIGURATION_FILENAMES])
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
return DEFAULT_CONFIGURATION_FILENAMES;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// src/config/microfrontends/utils/find-config.ts
|
|
923
|
+
function findConfig({
|
|
924
|
+
dir,
|
|
925
|
+
customConfigFilename
|
|
926
|
+
}) {
|
|
927
|
+
for (const filename of getPossibleConfigurationFilenames({
|
|
928
|
+
customConfigFilename
|
|
929
|
+
})) {
|
|
930
|
+
const maybeConfig = (0, import_node_path.join)(dir, filename);
|
|
931
|
+
if (import_node_fs.default.existsSync(maybeConfig)) {
|
|
932
|
+
return maybeConfig;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// src/config/microfrontends/utils/find-package-root.ts
|
|
939
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
940
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
941
|
+
var PACKAGE_JSON = "package.json";
|
|
942
|
+
function findPackageRoot(startDir) {
|
|
943
|
+
let currentDir = startDir || process.cwd();
|
|
944
|
+
while (currentDir !== import_node_path2.default.parse(currentDir).root) {
|
|
945
|
+
const pkgJsonPath = import_node_path2.default.join(currentDir, PACKAGE_JSON);
|
|
946
|
+
if (import_node_fs2.default.existsSync(pkgJsonPath)) {
|
|
947
|
+
return currentDir;
|
|
948
|
+
}
|
|
949
|
+
currentDir = import_node_path2.default.dirname(currentDir);
|
|
950
|
+
}
|
|
951
|
+
throw new Error(
|
|
952
|
+
`The root of the package that contains the \`package.json\` file for the \`${startDir}\` directory could not be found.`
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// src/config/microfrontends/utils/find-repository-root.ts
|
|
957
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
958
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
959
|
+
var GIT_DIRECTORY = ".git";
|
|
960
|
+
function hasGitDirectory(dir) {
|
|
961
|
+
const gitPath = import_node_path3.default.join(dir, GIT_DIRECTORY);
|
|
962
|
+
return import_node_fs3.default.existsSync(gitPath) && import_node_fs3.default.statSync(gitPath).isDirectory();
|
|
963
|
+
}
|
|
964
|
+
function hasPnpmWorkspaces(dir) {
|
|
965
|
+
return import_node_fs3.default.existsSync(import_node_path3.default.join(dir, "pnpm-workspace.yaml"));
|
|
966
|
+
}
|
|
967
|
+
function hasPackageJson(dir) {
|
|
968
|
+
return import_node_fs3.default.existsSync(import_node_path3.default.join(dir, "package.json"));
|
|
969
|
+
}
|
|
970
|
+
function findRepositoryRoot(startDir) {
|
|
971
|
+
if (process.env.NX_WORKSPACE_ROOT) {
|
|
972
|
+
return process.env.NX_WORKSPACE_ROOT;
|
|
973
|
+
}
|
|
974
|
+
let currentDir = startDir || process.cwd();
|
|
975
|
+
let lastPackageJsonDir = null;
|
|
976
|
+
while (currentDir !== import_node_path3.default.parse(currentDir).root) {
|
|
977
|
+
if (hasGitDirectory(currentDir) || hasPnpmWorkspaces(currentDir)) {
|
|
978
|
+
return currentDir;
|
|
979
|
+
}
|
|
980
|
+
if (hasPackageJson(currentDir)) {
|
|
981
|
+
lastPackageJsonDir = currentDir;
|
|
982
|
+
}
|
|
983
|
+
currentDir = import_node_path3.default.dirname(currentDir);
|
|
984
|
+
}
|
|
985
|
+
if (lastPackageJsonDir) {
|
|
986
|
+
return lastPackageJsonDir;
|
|
987
|
+
}
|
|
988
|
+
throw new Error(
|
|
989
|
+
`Could not find the root of the repository for ${startDir}. Please ensure that the directory is part of a Git repository. If you suspect that this should work, please file an issue to the Vercel team.`
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
|
|
1104
993
|
// src/config/microfrontends/utils/get-application-context.ts
|
|
1105
|
-
var
|
|
1106
|
-
var
|
|
994
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
995
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
1107
996
|
function getApplicationContext(opts) {
|
|
1108
997
|
if (opts?.appName) {
|
|
998
|
+
logger.debug(
|
|
999
|
+
"[MFE Config] Application name from appName parameter:",
|
|
1000
|
+
opts.appName
|
|
1001
|
+
);
|
|
1109
1002
|
return { name: opts.appName };
|
|
1110
1003
|
}
|
|
1111
1004
|
if (process.env.VERCEL_PROJECT_NAME) {
|
|
1005
|
+
logger.debug(
|
|
1006
|
+
"[MFE Config] Application name from VERCEL_PROJECT_NAME:",
|
|
1007
|
+
process.env.VERCEL_PROJECT_NAME
|
|
1008
|
+
);
|
|
1112
1009
|
return {
|
|
1113
1010
|
name: process.env.VERCEL_PROJECT_NAME,
|
|
1114
1011
|
projectName: process.env.VERCEL_PROJECT_NAME
|
|
1115
1012
|
};
|
|
1116
1013
|
}
|
|
1117
1014
|
if (process.env.NX_TASK_TARGET_PROJECT) {
|
|
1015
|
+
logger.debug(
|
|
1016
|
+
"[MFE Config] Application name from NX_TASK_TARGET_PROJECT:",
|
|
1017
|
+
process.env.NX_TASK_TARGET_PROJECT
|
|
1018
|
+
);
|
|
1118
1019
|
return {
|
|
1119
1020
|
name: process.env.NX_TASK_TARGET_PROJECT,
|
|
1120
1021
|
packageJsonName: process.env.NX_TASK_TARGET_PROJECT
|
|
1121
1022
|
};
|
|
1122
1023
|
}
|
|
1123
1024
|
try {
|
|
1124
|
-
const vercelProjectJsonPath =
|
|
1125
|
-
|
|
1025
|
+
const vercelProjectJsonPath = import_node_fs4.default.readFileSync(
|
|
1026
|
+
import_node_path4.default.join(opts?.packageRoot || ".", ".vercel", "project.json"),
|
|
1126
1027
|
"utf-8"
|
|
1127
1028
|
);
|
|
1128
1029
|
const projectJson = JSON.parse(vercelProjectJsonPath);
|
|
1129
1030
|
if (projectJson.projectName) {
|
|
1031
|
+
logger.debug(
|
|
1032
|
+
"[MFE Config] Application name from .vercel/project.json:",
|
|
1033
|
+
projectJson.projectName
|
|
1034
|
+
);
|
|
1130
1035
|
return {
|
|
1131
1036
|
name: projectJson.projectName,
|
|
1132
1037
|
projectName: projectJson.projectName
|
|
@@ -1135,8 +1040,8 @@ function getApplicationContext(opts) {
|
|
|
1135
1040
|
} catch (_) {
|
|
1136
1041
|
}
|
|
1137
1042
|
try {
|
|
1138
|
-
const packageJsonString =
|
|
1139
|
-
|
|
1043
|
+
const packageJsonString = import_node_fs4.default.readFileSync(
|
|
1044
|
+
import_node_path4.default.join(opts?.packageRoot || ".", "package.json"),
|
|
1140
1045
|
"utf-8"
|
|
1141
1046
|
);
|
|
1142
1047
|
const packageJson = JSON.parse(packageJsonString);
|
|
@@ -1150,6 +1055,10 @@ function getApplicationContext(opts) {
|
|
|
1150
1055
|
}
|
|
1151
1056
|
);
|
|
1152
1057
|
}
|
|
1058
|
+
logger.debug(
|
|
1059
|
+
"[MFE Config] Application name from package.json:",
|
|
1060
|
+
packageJson.name
|
|
1061
|
+
);
|
|
1153
1062
|
return { name: packageJson.name, packageJsonName: packageJson.name };
|
|
1154
1063
|
} catch (err) {
|
|
1155
1064
|
throw MicrofrontendError.handle(err, {
|
|
@@ -1158,6 +1067,209 @@ function getApplicationContext(opts) {
|
|
|
1158
1067
|
}
|
|
1159
1068
|
}
|
|
1160
1069
|
|
|
1070
|
+
// src/config/microfrontends/utils/infer-microfrontends-location.ts
|
|
1071
|
+
var import_node_fs5 = require("fs");
|
|
1072
|
+
var import_node_path5 = require("path");
|
|
1073
|
+
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
1074
|
+
var import_jsonc_parser2 = require("jsonc-parser");
|
|
1075
|
+
var configCache = {};
|
|
1076
|
+
function findPackageWithMicrofrontendsConfig({
|
|
1077
|
+
repositoryRoot,
|
|
1078
|
+
applicationContext,
|
|
1079
|
+
customConfigFilename
|
|
1080
|
+
}) {
|
|
1081
|
+
const applicationName = applicationContext.name;
|
|
1082
|
+
logger.debug(
|
|
1083
|
+
"[MFE Config] Searching repository for configs containing application:",
|
|
1084
|
+
applicationName
|
|
1085
|
+
);
|
|
1086
|
+
try {
|
|
1087
|
+
const microfrontendsJsonPaths = import_fast_glob.default.globSync(
|
|
1088
|
+
`**/{${getPossibleConfigurationFilenames({ customConfigFilename }).join(",")}}`,
|
|
1089
|
+
{
|
|
1090
|
+
cwd: repositoryRoot,
|
|
1091
|
+
absolute: true,
|
|
1092
|
+
onlyFiles: true,
|
|
1093
|
+
followSymbolicLinks: false,
|
|
1094
|
+
ignore: ["**/node_modules/**", "**/.git/**"]
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
logger.debug(
|
|
1098
|
+
"[MFE Config] Found",
|
|
1099
|
+
microfrontendsJsonPaths.length,
|
|
1100
|
+
"config file(s) in repository"
|
|
1101
|
+
);
|
|
1102
|
+
const matchingPaths = [];
|
|
1103
|
+
for (const microfrontendsJsonPath of microfrontendsJsonPaths) {
|
|
1104
|
+
if (doesApplicationExistInConfig(microfrontendsJsonPath, applicationName)) {
|
|
1105
|
+
matchingPaths.push(microfrontendsJsonPath);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
logger.debug(
|
|
1109
|
+
"[MFE Config] Total matching config files:",
|
|
1110
|
+
matchingPaths.length
|
|
1111
|
+
);
|
|
1112
|
+
if (matchingPaths.length > 1) {
|
|
1113
|
+
throw new MicrofrontendError(
|
|
1114
|
+
`Found multiple \`microfrontends.json\` files in the repository referencing the application "${applicationName}", but only one is allowed.
|
|
1115
|
+
${matchingPaths.join("\n \u2022 ")}`,
|
|
1116
|
+
{ type: "config", subtype: "inference_failed" }
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
if (matchingPaths.length === 0) {
|
|
1120
|
+
if (repositoryRoot && doesMisplacedConfigExist(
|
|
1121
|
+
repositoryRoot,
|
|
1122
|
+
applicationName,
|
|
1123
|
+
customConfigFilename
|
|
1124
|
+
)) {
|
|
1125
|
+
logger.debug(
|
|
1126
|
+
"[MFE Config] Found misplaced config in wrong .vercel directory in repository"
|
|
1127
|
+
);
|
|
1128
|
+
const misplacedConfigPath = (0, import_node_path5.join)(
|
|
1129
|
+
repositoryRoot,
|
|
1130
|
+
".vercel",
|
|
1131
|
+
customConfigFilename || "microfrontends.json"
|
|
1132
|
+
);
|
|
1133
|
+
throw new MicrofrontendError(
|
|
1134
|
+
`Unable to automatically infer the location of the \`microfrontends.json\` file.
|
|
1135
|
+
|
|
1136
|
+
A microfrontends config was found in the \`.vercel\` directory at the repository root: ${misplacedConfigPath}
|
|
1137
|
+
However, in a monorepo, the config file should be placed in the \`.vercel\` directory in your application directory instead.
|
|
1138
|
+
|
|
1139
|
+
To fix this:
|
|
1140
|
+
1. If using \`vercel link\`, run it with \`vercel link --repo\` to handle monorepos, or run \`vercel microfrontends pull --cwd=<application-directory>\` to make sure it pulls the \`microfrontends.json\` file to the correct location
|
|
1141
|
+
2. If manually defined, move the config file to the \`.vercel\` directory in your application
|
|
1142
|
+
3. Alternatively, set the VC_MICROFRONTENDS_CONFIG environment variable to the correct path
|
|
1143
|
+
|
|
1144
|
+
For more information, see: https://vercel.com/docs/cli/project-linking`,
|
|
1145
|
+
{ type: "config", subtype: "inference_failed" }
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
let additionalErrorMessage = "";
|
|
1149
|
+
if (microfrontendsJsonPaths.length > 0) {
|
|
1150
|
+
if (!applicationContext.projectName) {
|
|
1151
|
+
additionalErrorMessage = `
|
|
1152
|
+
|
|
1153
|
+
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.`;
|
|
1154
|
+
} else {
|
|
1155
|
+
additionalErrorMessage = `
|
|
1156
|
+
|
|
1157
|
+
Names of applications in \`microfrontends.json\` must match the Vercel Project name (${applicationContext.projectName}).`;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
throw new MicrofrontendError(
|
|
1161
|
+
`Could not find a \`microfrontends.json\` file in the repository that contains the "${applicationName}" application.${additionalErrorMessage}
|
|
1162
|
+
|
|
1163
|
+
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.
|
|
1164
|
+
|
|
1165
|
+
If your Vercel Microfrontends configuration has a custom name, ensure the VC_MICROFRONTENDS_CONFIG_FILE_NAME environment variable is set, you can pull the vercel project environment variables using the "vercel env pull" command.
|
|
1166
|
+
|
|
1167
|
+
If you suspect this is thrown in error, please reach out to the Vercel team.`,
|
|
1168
|
+
{ type: "config", subtype: "inference_failed" }
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
const [packageJsonPath] = matchingPaths;
|
|
1172
|
+
return (0, import_node_path5.dirname)(packageJsonPath);
|
|
1173
|
+
} catch (error2) {
|
|
1174
|
+
if (error2 instanceof MicrofrontendError) {
|
|
1175
|
+
throw error2;
|
|
1176
|
+
}
|
|
1177
|
+
return null;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
function inferMicrofrontendsLocation(opts) {
|
|
1181
|
+
const cacheKey = `${opts.repositoryRoot}-${opts.applicationContext.name}${opts.customConfigFilename ? `-${opts.customConfigFilename}` : ""}`;
|
|
1182
|
+
if (configCache[cacheKey]) {
|
|
1183
|
+
return configCache[cacheKey];
|
|
1184
|
+
}
|
|
1185
|
+
const result = findPackageWithMicrofrontendsConfig(opts);
|
|
1186
|
+
if (!result) {
|
|
1187
|
+
throw new MicrofrontendError(
|
|
1188
|
+
`Could not infer the location of the \`microfrontends.json\` file for application "${opts.applicationContext.name}" starting in directory "${opts.repositoryRoot}".`,
|
|
1189
|
+
{ type: "config", subtype: "inference_failed" }
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
configCache[cacheKey] = result;
|
|
1193
|
+
return result;
|
|
1194
|
+
}
|
|
1195
|
+
function existsSync(path6) {
|
|
1196
|
+
try {
|
|
1197
|
+
(0, import_node_fs5.statSync)(path6);
|
|
1198
|
+
return true;
|
|
1199
|
+
} catch (_) {
|
|
1200
|
+
return false;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
function doesMisplacedConfigExist(repositoryRoot, applicationName, customConfigFilename) {
|
|
1204
|
+
logger.debug(
|
|
1205
|
+
"[MFE Config] Looking for misplaced config in wrong .vercel directory"
|
|
1206
|
+
);
|
|
1207
|
+
const misplacedConfigPath = (0, import_node_path5.join)(
|
|
1208
|
+
repositoryRoot,
|
|
1209
|
+
".vercel",
|
|
1210
|
+
customConfigFilename || "microfrontends.json"
|
|
1211
|
+
);
|
|
1212
|
+
return existsSync(misplacedConfigPath) && doesApplicationExistInConfig(misplacedConfigPath, applicationName);
|
|
1213
|
+
}
|
|
1214
|
+
function doesApplicationExistInConfig(microfrontendsJsonPath, applicationName) {
|
|
1215
|
+
try {
|
|
1216
|
+
const microfrontendsJsonContent = (0, import_node_fs5.readFileSync)(
|
|
1217
|
+
microfrontendsJsonPath,
|
|
1218
|
+
"utf-8"
|
|
1219
|
+
);
|
|
1220
|
+
const microfrontendsJson = (0, import_jsonc_parser2.parse)(microfrontendsJsonContent);
|
|
1221
|
+
if (microfrontendsJson.applications[applicationName]) {
|
|
1222
|
+
logger.debug(
|
|
1223
|
+
"[MFE Config] Found application in config:",
|
|
1224
|
+
microfrontendsJsonPath
|
|
1225
|
+
);
|
|
1226
|
+
return true;
|
|
1227
|
+
}
|
|
1228
|
+
for (const [_, app] of Object.entries(microfrontendsJson.applications)) {
|
|
1229
|
+
if (app.packageName === applicationName) {
|
|
1230
|
+
logger.debug(
|
|
1231
|
+
"[MFE Config] Found application via packageName in config:",
|
|
1232
|
+
microfrontendsJsonPath
|
|
1233
|
+
);
|
|
1234
|
+
return true;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
} catch (error2) {
|
|
1238
|
+
logger.debug("[MFE Config] Error checking application in config:", error2);
|
|
1239
|
+
}
|
|
1240
|
+
return false;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
// src/config/microfrontends/utils/is-monorepo.ts
|
|
1244
|
+
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
1245
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
1246
|
+
function isMonorepo({
|
|
1247
|
+
repositoryRoot
|
|
1248
|
+
}) {
|
|
1249
|
+
try {
|
|
1250
|
+
if (import_node_fs6.default.existsSync(import_node_path6.default.join(repositoryRoot, "pnpm-workspace.yaml"))) {
|
|
1251
|
+
return true;
|
|
1252
|
+
}
|
|
1253
|
+
if (import_node_fs6.default.existsSync(import_node_path6.default.join(repositoryRoot, "vlt-workspaces.json"))) {
|
|
1254
|
+
return true;
|
|
1255
|
+
}
|
|
1256
|
+
if (process.env.NX_WORKSPACE_ROOT === import_node_path6.default.resolve(repositoryRoot)) {
|
|
1257
|
+
return true;
|
|
1258
|
+
}
|
|
1259
|
+
const packageJsonPath = import_node_path6.default.join(repositoryRoot, "package.json");
|
|
1260
|
+
if (!import_node_fs6.default.existsSync(packageJsonPath)) {
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
const packageJson = JSON.parse(
|
|
1264
|
+
import_node_fs6.default.readFileSync(packageJsonPath, "utf-8")
|
|
1265
|
+
);
|
|
1266
|
+
return packageJson.workspaces !== void 0;
|
|
1267
|
+
} catch (error2) {
|
|
1268
|
+
logger.error("Error determining if repository is a monorepo", error2);
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1161
1273
|
// src/config/microfrontends/server/utils/get-output-file-path.ts
|
|
1162
1274
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
1163
1275
|
|
|
@@ -1171,8 +1283,8 @@ function getOutputFilePath() {
|
|
|
1171
1283
|
}
|
|
1172
1284
|
|
|
1173
1285
|
// src/config/microfrontends/server/validation.ts
|
|
1174
|
-
var import_jsonc_parser3 = require("jsonc-parser");
|
|
1175
1286
|
var import_ajv = require("ajv");
|
|
1287
|
+
var import_jsonc_parser3 = require("jsonc-parser");
|
|
1176
1288
|
|
|
1177
1289
|
// schema/schema.json
|
|
1178
1290
|
var schema_default = {
|
|
@@ -1200,9 +1312,7 @@ var schema_default = {
|
|
|
1200
1312
|
description: "Optional configuration options for the microfrontend."
|
|
1201
1313
|
}
|
|
1202
1314
|
},
|
|
1203
|
-
required: [
|
|
1204
|
-
"applications"
|
|
1205
|
-
],
|
|
1315
|
+
required: ["applications"],
|
|
1206
1316
|
additionalProperties: false,
|
|
1207
1317
|
description: "The microfrontends configuration schema. See https://vercel.com/docs/microfrontends/configuration."
|
|
1208
1318
|
},
|
|
@@ -1239,19 +1349,14 @@ var schema_default = {
|
|
|
1239
1349
|
description: "Development configuration for the default application."
|
|
1240
1350
|
}
|
|
1241
1351
|
},
|
|
1242
|
-
required: [
|
|
1243
|
-
"development"
|
|
1244
|
-
],
|
|
1352
|
+
required: ["development"],
|
|
1245
1353
|
additionalProperties: false
|
|
1246
1354
|
},
|
|
1247
1355
|
DefaultDevelopment: {
|
|
1248
1356
|
type: "object",
|
|
1249
1357
|
properties: {
|
|
1250
1358
|
local: {
|
|
1251
|
-
type: [
|
|
1252
|
-
"number",
|
|
1253
|
-
"string"
|
|
1254
|
-
],
|
|
1359
|
+
type: ["number", "string"],
|
|
1255
1360
|
description: "A local port number or host that this application runs on when it is running locally. If passing a string, include the protocol (optional), host (required) and port (optional).\n\nExamples of valid values: 8080, my.localhost.me, my.localhost.me:8080, https://my.localhost.me, https://my.localhost.me:8080.\n\nThe default value is http://localhost:<port> where port is a stable, unique port number (based on the application name).\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1256
1361
|
},
|
|
1257
1362
|
task: {
|
|
@@ -1263,9 +1368,7 @@ var schema_default = {
|
|
|
1263
1368
|
description: "Fallback for local development, could point to any environment. This is required for the default app. This value is used as the fallback for child apps as well if they do not have a fallback.\n\nIf passing a string, include the protocol (optional), host (required) and port (optional). For example: `https://this.ismyhost:8080`. If omitted, the protocol defaults to HTTPS. If omitted, the port defaults to `80` for HTTP and `443` for HTTPS.\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1264
1369
|
}
|
|
1265
1370
|
},
|
|
1266
|
-
required: [
|
|
1267
|
-
"fallback"
|
|
1268
|
-
],
|
|
1371
|
+
required: ["fallback"],
|
|
1269
1372
|
additionalProperties: false
|
|
1270
1373
|
},
|
|
1271
1374
|
ChildApplication: {
|
|
@@ -1288,19 +1391,14 @@ var schema_default = {
|
|
|
1288
1391
|
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.\n\nThe default value is the auto-generated asset prefix of the form `vc-ap-<hash>`.\n\nSee https://vercel.com/docs/microfrontends/path-routing#asset-prefix."
|
|
1289
1392
|
}
|
|
1290
1393
|
},
|
|
1291
|
-
required: [
|
|
1292
|
-
"routing"
|
|
1293
|
-
],
|
|
1394
|
+
required: ["routing"],
|
|
1294
1395
|
additionalProperties: false
|
|
1295
1396
|
},
|
|
1296
1397
|
ChildDevelopment: {
|
|
1297
1398
|
type: "object",
|
|
1298
1399
|
properties: {
|
|
1299
1400
|
local: {
|
|
1300
|
-
type: [
|
|
1301
|
-
"number",
|
|
1302
|
-
"string"
|
|
1303
|
-
],
|
|
1401
|
+
type: ["number", "string"],
|
|
1304
1402
|
description: "A local port number or host that this application runs on when it is running locally. If passing a string, include the protocol (optional), host (required) and port (optional).\n\nExamples of valid values: 8080, my.localhost.me, my.localhost.me:8080, https://my.localhost.me, https://my.localhost.me:8080.\n\nThe default value is http://localhost:<port> where port is a stable, unique port number (based on the application name).\n\nSee https://vercel.com/docs/microfrontends/local-development."
|
|
1305
1403
|
},
|
|
1306
1404
|
task: {
|
|
@@ -1340,9 +1438,7 @@ var schema_default = {
|
|
|
1340
1438
|
description: "A list of path expressions that are routed to this application. See https://vercel.com/docs/microfrontends/path-routing#supported-path-expressions."
|
|
1341
1439
|
}
|
|
1342
1440
|
},
|
|
1343
|
-
required: [
|
|
1344
|
-
"paths"
|
|
1345
|
-
],
|
|
1441
|
+
required: ["paths"],
|
|
1346
1442
|
additionalProperties: false,
|
|
1347
1443
|
description: "A group of paths that is routed to this application."
|
|
1348
1444
|
},
|
|
@@ -1521,7 +1617,13 @@ var MicrofrontendsServer = class {
|
|
|
1521
1617
|
filePath,
|
|
1522
1618
|
cookies
|
|
1523
1619
|
} = {}) {
|
|
1620
|
+
logger.debug("[MFE Config] Starting config inference", {
|
|
1621
|
+
appName,
|
|
1622
|
+
directory: directory || process.cwd(),
|
|
1623
|
+
filePath
|
|
1624
|
+
});
|
|
1524
1625
|
if (filePath) {
|
|
1626
|
+
logger.debug("[MFE Config] Using explicit filePath:", filePath);
|
|
1525
1627
|
return MicrofrontendsServer.fromFile({
|
|
1526
1628
|
filePath,
|
|
1527
1629
|
cookies
|
|
@@ -1529,16 +1631,25 @@ var MicrofrontendsServer = class {
|
|
|
1529
1631
|
}
|
|
1530
1632
|
try {
|
|
1531
1633
|
const packageRoot = findPackageRoot(directory);
|
|
1634
|
+
logger.debug("[MFE Config] Package root:", packageRoot);
|
|
1532
1635
|
const applicationContext = getApplicationContext({
|
|
1533
1636
|
appName,
|
|
1534
1637
|
packageRoot
|
|
1535
1638
|
});
|
|
1639
|
+
logger.debug("[MFE Config] Application context:", applicationContext);
|
|
1536
1640
|
const customConfigFilename = process.env.VC_MICROFRONTENDS_CONFIG_FILE_NAME;
|
|
1641
|
+
if (customConfigFilename) {
|
|
1642
|
+
logger.debug(
|
|
1643
|
+
"[MFE Config] Custom config filename from VC_MICROFRONTENDS_CONFIG_FILE_NAME:",
|
|
1644
|
+
customConfigFilename
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1537
1647
|
const maybeConfig = findConfig({
|
|
1538
1648
|
dir: packageRoot,
|
|
1539
1649
|
customConfigFilename
|
|
1540
1650
|
});
|
|
1541
1651
|
if (maybeConfig) {
|
|
1652
|
+
logger.debug("[MFE Config] Config found at package root:", maybeConfig);
|
|
1542
1653
|
return MicrofrontendsServer.fromFile({
|
|
1543
1654
|
filePath: maybeConfig,
|
|
1544
1655
|
cookies
|
|
@@ -1546,42 +1657,78 @@ var MicrofrontendsServer = class {
|
|
|
1546
1657
|
}
|
|
1547
1658
|
const repositoryRoot = findRepositoryRoot();
|
|
1548
1659
|
const isMonorepo2 = isMonorepo({ repositoryRoot });
|
|
1660
|
+
logger.debug(
|
|
1661
|
+
"[MFE Config] Repository root:",
|
|
1662
|
+
repositoryRoot,
|
|
1663
|
+
"Is monorepo:",
|
|
1664
|
+
isMonorepo2
|
|
1665
|
+
);
|
|
1549
1666
|
const configFromEnv = process.env.VC_MICROFRONTENDS_CONFIG;
|
|
1550
1667
|
if (typeof configFromEnv === "string") {
|
|
1668
|
+
logger.debug(
|
|
1669
|
+
"[MFE Config] Checking VC_MICROFRONTENDS_CONFIG:",
|
|
1670
|
+
configFromEnv
|
|
1671
|
+
);
|
|
1551
1672
|
const maybeConfigFromEnv = (0, import_node_path8.resolve)(packageRoot, configFromEnv);
|
|
1552
1673
|
if (maybeConfigFromEnv) {
|
|
1674
|
+
logger.debug(
|
|
1675
|
+
"[MFE Config] Config loaded from VC_MICROFRONTENDS_CONFIG:",
|
|
1676
|
+
maybeConfigFromEnv
|
|
1677
|
+
);
|
|
1553
1678
|
return MicrofrontendsServer.fromFile({
|
|
1554
1679
|
filePath: maybeConfigFromEnv,
|
|
1555
1680
|
cookies
|
|
1556
1681
|
});
|
|
1557
1682
|
}
|
|
1558
1683
|
} else {
|
|
1684
|
+
const vercelDir = (0, import_node_path8.join)(packageRoot, ".vercel");
|
|
1685
|
+
logger.debug(
|
|
1686
|
+
"[MFE Config] Searching for config in .vercel directory:",
|
|
1687
|
+
vercelDir
|
|
1688
|
+
);
|
|
1559
1689
|
const maybeConfigFromVercel = findConfig({
|
|
1560
|
-
dir:
|
|
1690
|
+
dir: vercelDir,
|
|
1561
1691
|
customConfigFilename
|
|
1562
1692
|
});
|
|
1563
1693
|
if (maybeConfigFromVercel) {
|
|
1694
|
+
logger.debug(
|
|
1695
|
+
"[MFE Config] Config found in .vercel directory:",
|
|
1696
|
+
maybeConfigFromVercel
|
|
1697
|
+
);
|
|
1564
1698
|
return MicrofrontendsServer.fromFile({
|
|
1565
1699
|
filePath: maybeConfigFromVercel,
|
|
1566
1700
|
cookies
|
|
1567
1701
|
});
|
|
1568
1702
|
}
|
|
1569
1703
|
if (isMonorepo2) {
|
|
1704
|
+
logger.debug(
|
|
1705
|
+
"[MFE Config] Inferring microfrontends location in monorepo for application:",
|
|
1706
|
+
applicationContext.name
|
|
1707
|
+
);
|
|
1570
1708
|
const defaultPackage = inferMicrofrontendsLocation({
|
|
1571
1709
|
repositoryRoot,
|
|
1572
1710
|
applicationContext,
|
|
1573
1711
|
customConfigFilename
|
|
1574
1712
|
});
|
|
1713
|
+
logger.debug(
|
|
1714
|
+
"[MFE Config] Inferred package location:",
|
|
1715
|
+
defaultPackage
|
|
1716
|
+
);
|
|
1575
1717
|
const maybeConfigFromDefault = findConfig({
|
|
1576
1718
|
dir: defaultPackage,
|
|
1577
1719
|
customConfigFilename
|
|
1578
1720
|
});
|
|
1579
1721
|
if (maybeConfigFromDefault) {
|
|
1722
|
+
logger.debug(
|
|
1723
|
+
"[MFE Config] Config found in inferred package:",
|
|
1724
|
+
maybeConfigFromDefault
|
|
1725
|
+
);
|
|
1580
1726
|
return MicrofrontendsServer.fromFile({
|
|
1581
1727
|
filePath: maybeConfigFromDefault,
|
|
1582
1728
|
cookies
|
|
1583
1729
|
});
|
|
1584
1730
|
}
|
|
1731
|
+
logger.debug("[MFE Config] No config found in inferred package");
|
|
1585
1732
|
}
|
|
1586
1733
|
}
|
|
1587
1734
|
throw new MicrofrontendError(
|
|
@@ -1607,8 +1754,13 @@ var MicrofrontendsServer = class {
|
|
|
1607
1754
|
cookies
|
|
1608
1755
|
}) {
|
|
1609
1756
|
try {
|
|
1757
|
+
logger.debug("[MFE Config] Reading config from file:", filePath);
|
|
1610
1758
|
const configJson = import_node_fs7.default.readFileSync(filePath, "utf-8");
|
|
1611
1759
|
const config = MicrofrontendsServer.validate(configJson);
|
|
1760
|
+
logger.debug(
|
|
1761
|
+
"[MFE Config] Config loaded with applications:",
|
|
1762
|
+
Object.keys(config.applications)
|
|
1763
|
+
);
|
|
1612
1764
|
return new MicrofrontendsServer({
|
|
1613
1765
|
config,
|
|
1614
1766
|
overrides: cookies ? parseOverrides(cookies) : void 0
|