@vercel/microfrontends 2.0.0-canary.2 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -11
- package/dist/bin/cli.cjs +180 -63
- package/dist/config.cjs +5 -4
- package/dist/config.cjs.map +1 -1
- package/dist/config.js +5 -4
- package/dist/config.js.map +1 -1
- package/dist/experimental/sveltekit.cjs +5 -4
- package/dist/experimental/sveltekit.cjs.map +1 -1
- package/dist/experimental/sveltekit.js +5 -4
- package/dist/experimental/sveltekit.js.map +1 -1
- package/dist/experimental/vite.cjs +5 -4
- package/dist/experimental/vite.cjs.map +1 -1
- package/dist/experimental/vite.js +5 -4
- package/dist/experimental/vite.js.map +1 -1
- package/dist/microfrontends/server.cjs +5 -4
- package/dist/microfrontends/server.cjs.map +1 -1
- package/dist/microfrontends/server.js +5 -4
- package/dist/microfrontends/server.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 +15 -1
- package/dist/next/client.js +1 -1
- package/dist/next/client.js.map +1 -1
- package/dist/next/config.cjs +5 -4
- package/dist/next/config.cjs.map +1 -1
- package/dist/next/config.js +5 -4
- package/dist/next/config.js.map +1 -1
- package/dist/next/middleware.cjs +5 -4
- package/dist/next/middleware.cjs.map +1 -1
- package/dist/next/middleware.js +5 -4
- package/dist/next/middleware.js.map +1 -1
- package/dist/next/testing.cjs +5 -4
- package/dist/next/testing.cjs.map +1 -1
- package/dist/next/testing.js +5 -4
- package/dist/next/testing.js.map +1 -1
- package/dist/utils/mfe-port.cjs +20 -24
- package/dist/utils/mfe-port.cjs.map +1 -1
- package/dist/utils/mfe-port.js +20 -24
- package/dist/utils/mfe-port.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,28 +1,33 @@
|
|
|
1
1
|
# @vercel/microfrontends
|
|
2
2
|
|
|
3
|
-
## 2.0.
|
|
3
|
+
## 2.0.1
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
### Patch Changes
|
|
12
|
-
|
|
13
|
-
- Support old and new asset prefixes in local development proxy.
|
|
7
|
+
- 8c11bdc:
|
|
8
|
+
- Support hyphens and escaped special characters in supported path matching regex https://vercel.com/docs/microfrontends/path-routing#supported-path-expressions
|
|
9
|
+
- Improve error message for when local development proxy can't determine the port
|
|
10
|
+
- Update local proxy double slash routing behaviour to match the production proxy
|
|
14
11
|
|
|
15
|
-
## 2.0.0
|
|
12
|
+
## 2.0.0
|
|
16
13
|
|
|
17
|
-
> **Check out our [Public Beta](https://vercel.com/changelog/microfrontends-
|
|
14
|
+
> **Check out our [Public Beta](https://vercel.com/changelog/microfrontends-support-is-now-in-public-beta) changelog to learn more about this release.**
|
|
18
15
|
|
|
19
16
|
### Major Changes
|
|
20
17
|
|
|
21
18
|
- This release removes the project name and flag names from being visible to client side code.
|
|
22
19
|
- Modify the auto-generated asset prefix to use a hash of the project name instead of the project name itself.
|
|
23
|
-
- Allow users to specify a custom asset prefix in
|
|
20
|
+
- Allow users to specify a custom asset prefix in `microfrontends.json`.
|
|
24
21
|
- Remove project names and flag names from the Microfrontends client configuration.
|
|
25
22
|
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- Use user-provided appName when inferring the location of microfrontends.json.
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Improve error messages when the name in `package.json` does not match the Vercel project name.
|
|
30
|
+
|
|
26
31
|
## 1.5.0
|
|
27
32
|
|
|
28
33
|
### Minor Changes
|
package/dist/bin/cli.cjs
CHANGED
|
@@ -30,7 +30,7 @@ var import_env = require("@next/env");
|
|
|
30
30
|
// package.json
|
|
31
31
|
var package_default = {
|
|
32
32
|
name: "@vercel/microfrontends",
|
|
33
|
-
version: "2.0.
|
|
33
|
+
version: "2.0.1",
|
|
34
34
|
private: false,
|
|
35
35
|
description: "Defines configuration and utilities for microfrontends development",
|
|
36
36
|
keywords: [
|
|
@@ -169,11 +169,11 @@ var package_default = {
|
|
|
169
169
|
typecheck: "tsc --noEmit"
|
|
170
170
|
},
|
|
171
171
|
dependencies: {
|
|
172
|
-
"@next/env": "15.4
|
|
172
|
+
"@next/env": "15.5.4",
|
|
173
173
|
"@types/md5": "^2.3.5",
|
|
174
174
|
ajv: "^8.17.1",
|
|
175
175
|
commander: "^12.1.0",
|
|
176
|
-
cookie: "0.
|
|
176
|
+
cookie: "1.0.2",
|
|
177
177
|
"fast-glob": "^3.3.2",
|
|
178
178
|
"http-proxy": "^1.18.1",
|
|
179
179
|
"jsonc-parser": "^3.3.1",
|
|
@@ -198,7 +198,7 @@ var package_default = {
|
|
|
198
198
|
"eslint-config-custom": "workspace:*",
|
|
199
199
|
jest: "^29.7.0",
|
|
200
200
|
"jest-environment-jsdom": "29.2.2",
|
|
201
|
-
next: "15.4
|
|
201
|
+
next: "15.5.4",
|
|
202
202
|
react: "19.0.0",
|
|
203
203
|
"react-dom": "19.0.0",
|
|
204
204
|
"ts-config": "workspace:*",
|
|
@@ -452,7 +452,7 @@ var MicrofrontendConfigClient = class {
|
|
|
452
452
|
static fromEnv(config) {
|
|
453
453
|
if (!config) {
|
|
454
454
|
throw new Error(
|
|
455
|
-
"Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
|
|
455
|
+
"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"
|
|
456
456
|
);
|
|
457
457
|
}
|
|
458
458
|
return new MicrofrontendConfigClient(JSON.parse(config));
|
|
@@ -592,10 +592,11 @@ function validatePathExpression(path7) {
|
|
|
592
592
|
}
|
|
593
593
|
if (token.pattern !== PATH_DEFAULT_PATTERN && // Allows (a|b|c) and ((?!a|b|c).*) regex
|
|
594
594
|
// Only limited regex is supported for now, due to performance considerations
|
|
595
|
-
|
|
596
|
-
|
|
595
|
+
// Allows all letters, numbers, and hyphens. Other characters must be escaped.
|
|
596
|
+
!/^(?<allowed>[\w-~]+(?:\|[^:|()]+)+)$|^\(\?!(?<disallowed>[\w-~]+(?:\|[^:|()]+)*)\)\.\*$/.test(
|
|
597
|
+
token.pattern.replace(/\\./g, "")
|
|
597
598
|
)) {
|
|
598
|
-
return `Path ${path7} cannot use unsupported regular expression wildcard`;
|
|
599
|
+
return `Path ${path7} cannot use unsupported regular expression wildcard. If the path includes special characters, they must be escaped with backslash (e.g. '\\(')`;
|
|
599
600
|
}
|
|
600
601
|
if (token.modifier && i !== tokens.length - 1) {
|
|
601
602
|
return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path7}. Modifiers are only allowed in the last path component`;
|
|
@@ -2112,12 +2113,6 @@ var localAuthHtml = ({
|
|
|
2112
2113
|
var MFE_LOCAL_PROXY_HEADER = "x-vercel-mfe-local-proxy-origin";
|
|
2113
2114
|
var MFE_FLAG_VALUE = "vercel-mfe-flag-value";
|
|
2114
2115
|
var MFE_FLAG_VALUE_HEADER = `x-${MFE_FLAG_VALUE}`;
|
|
2115
|
-
var MFE_DEBUG = process.env.MFE_DEBUG;
|
|
2116
|
-
var mfeDebug = (message) => {
|
|
2117
|
-
if (MFE_DEBUG === "true" || MFE_DEBUG === "1") {
|
|
2118
|
-
console.log(message);
|
|
2119
|
-
}
|
|
2120
|
-
};
|
|
2121
2116
|
var ProxyRequestRouter = class {
|
|
2122
2117
|
constructor(config, {
|
|
2123
2118
|
localApps
|
|
@@ -2130,8 +2125,10 @@ var ProxyRequestRouter = class {
|
|
|
2130
2125
|
return this.getApplicationTarget(defaultApp);
|
|
2131
2126
|
}
|
|
2132
2127
|
getApplicationTarget(application) {
|
|
2133
|
-
const useDev =
|
|
2134
|
-
|
|
2128
|
+
const useDev = Boolean(
|
|
2129
|
+
this.localApps.find(
|
|
2130
|
+
(name) => name === application.name || name === application.packageName
|
|
2131
|
+
)
|
|
2135
2132
|
);
|
|
2136
2133
|
let applicationName = application.name;
|
|
2137
2134
|
let host = useDev ? application.development.local : application.fallback;
|
|
@@ -2151,7 +2148,9 @@ var ProxyRequestRouter = class {
|
|
|
2151
2148
|
protocol,
|
|
2152
2149
|
hostname,
|
|
2153
2150
|
port,
|
|
2154
|
-
application: applicationName
|
|
2151
|
+
application: applicationName,
|
|
2152
|
+
isLocal: useDev,
|
|
2153
|
+
originalApplication: application.name
|
|
2155
2154
|
};
|
|
2156
2155
|
}
|
|
2157
2156
|
/**
|
|
@@ -2225,8 +2224,8 @@ var ProxyRequestRouter = class {
|
|
|
2225
2224
|
if (target)
|
|
2226
2225
|
return target;
|
|
2227
2226
|
const defaultHost = this.getDefaultHost(config);
|
|
2228
|
-
|
|
2229
|
-
`
|
|
2227
|
+
console.log(
|
|
2228
|
+
` ${path7} - Did not match any routes. Routing to default app: ${formatProxyTarget(defaultHost)}`
|
|
2230
2229
|
);
|
|
2231
2230
|
return { path: path7, ...defaultHost };
|
|
2232
2231
|
}
|
|
@@ -2242,8 +2241,8 @@ var ProxyRequestRouter = class {
|
|
|
2242
2241
|
const target = this.getApplicationTarget(application);
|
|
2243
2242
|
if (middlewareMfeZone) {
|
|
2244
2243
|
if (middlewareMfeZone === application.name) {
|
|
2245
|
-
|
|
2246
|
-
`
|
|
2244
|
+
console.log(
|
|
2245
|
+
` ${path7} - Routing to ${formatProxyTarget(target)} according to 'x-vercel-mfe-zone' header`
|
|
2247
2246
|
);
|
|
2248
2247
|
return { path: path7, ...target };
|
|
2249
2248
|
}
|
|
@@ -2262,15 +2261,12 @@ var ProxyRequestRouter = class {
|
|
|
2262
2261
|
for (const childPath of group.paths) {
|
|
2263
2262
|
const regexp = (0, import_path_to_regexp3.pathToRegexp)(childPath);
|
|
2264
2263
|
if (regexp.test(url.pathname)) {
|
|
2265
|
-
mfeDebug(
|
|
2266
|
-
`routing ${path7} to '${target.application}' at ${target.hostname}`
|
|
2267
|
-
);
|
|
2268
2264
|
if (group.flag) {
|
|
2269
2265
|
if (mfeFlagValue === true) {
|
|
2270
2266
|
} else if (mfeFlagValue === false) {
|
|
2271
2267
|
continue;
|
|
2272
2268
|
} else {
|
|
2273
|
-
|
|
2269
|
+
console.log(
|
|
2274
2270
|
"Routing group is behind flag. Routing to default app to check flag via middleware."
|
|
2275
2271
|
);
|
|
2276
2272
|
if (!this.isDefaultAppLocal()) {
|
|
@@ -2282,6 +2278,9 @@ var ProxyRequestRouter = class {
|
|
|
2282
2278
|
return null;
|
|
2283
2279
|
}
|
|
2284
2280
|
}
|
|
2281
|
+
console.log(
|
|
2282
|
+
` ${path7} - Matched ${childPath}. Routing to ${formatProxyTarget(target)}`
|
|
2283
|
+
);
|
|
2285
2284
|
return { path: path7, ...target };
|
|
2286
2285
|
}
|
|
2287
2286
|
}
|
|
@@ -2310,8 +2309,8 @@ var ProxyRequestRouter = class {
|
|
|
2310
2309
|
for (const rewrite of rewrites) {
|
|
2311
2310
|
for (const assetPrefix of assetPrefixes) {
|
|
2312
2311
|
if ((0, import_path_to_regexp3.pathToRegexp)(`/${assetPrefix}${rewrite}`).test(pathname)) {
|
|
2313
|
-
|
|
2314
|
-
`
|
|
2312
|
+
console.log(
|
|
2313
|
+
` ${pathname} - Matched asset prefix. Routing to ${formatProxyTarget(target)}`
|
|
2315
2314
|
);
|
|
2316
2315
|
return {
|
|
2317
2316
|
path: path7,
|
|
@@ -2339,13 +2338,16 @@ var ProxyRequestRouter = class {
|
|
|
2339
2338
|
url: refererURL,
|
|
2340
2339
|
applications
|
|
2341
2340
|
});
|
|
2342
|
-
|
|
2343
|
-
|
|
2341
|
+
if (!refererApp) {
|
|
2342
|
+
return null;
|
|
2343
|
+
}
|
|
2344
|
+
console.log(
|
|
2345
|
+
` ${refererURL.pathname} - Routing nextjs stack frame request to ${formatProxyTarget(refererApp)}`
|
|
2344
2346
|
);
|
|
2345
|
-
return
|
|
2347
|
+
return {
|
|
2346
2348
|
...refererApp,
|
|
2347
2349
|
path: `${url.pathname}${url.search}`
|
|
2348
|
-
}
|
|
2350
|
+
};
|
|
2349
2351
|
}
|
|
2350
2352
|
checkNextSourceMap({ url }) {
|
|
2351
2353
|
const isSourceMap = (0, import_path_to_regexp3.pathToRegexp)("/__nextjs_source-map").test(url.pathname);
|
|
@@ -2354,11 +2356,15 @@ var ProxyRequestRouter = class {
|
|
|
2354
2356
|
}
|
|
2355
2357
|
const localApp = this.getArbitraryLocalApp();
|
|
2356
2358
|
if (!localApp) {
|
|
2357
|
-
|
|
2359
|
+
console.error(
|
|
2360
|
+
` ${url.pathname} - No locally running application to route request to`
|
|
2361
|
+
);
|
|
2358
2362
|
return null;
|
|
2359
2363
|
}
|
|
2360
2364
|
const target = this.getApplicationTarget(localApp);
|
|
2361
|
-
|
|
2365
|
+
console.log(
|
|
2366
|
+
` ${url.pathname} - Routing nextjs source map request to randomly selected local application: ${formatProxyTarget(target)}`
|
|
2367
|
+
);
|
|
2362
2368
|
return {
|
|
2363
2369
|
...target,
|
|
2364
2370
|
path: `${url.pathname}${url.search}`
|
|
@@ -2374,7 +2380,9 @@ var ProxyRequestRouter = class {
|
|
|
2374
2380
|
}
|
|
2375
2381
|
const imageUrl = url.searchParams.get("url");
|
|
2376
2382
|
if (!imageUrl) {
|
|
2377
|
-
|
|
2383
|
+
console.error(
|
|
2384
|
+
` ${url.pathname}?${url.search} - No url parameter found in _next/image request`
|
|
2385
|
+
);
|
|
2378
2386
|
return null;
|
|
2379
2387
|
}
|
|
2380
2388
|
const decodedPath = decodeURIComponent(imageUrl);
|
|
@@ -2384,11 +2392,16 @@ var ProxyRequestRouter = class {
|
|
|
2384
2392
|
url: imageURL,
|
|
2385
2393
|
applications
|
|
2386
2394
|
});
|
|
2387
|
-
|
|
2388
|
-
|
|
2395
|
+
if (!imageApp) {
|
|
2396
|
+
return null;
|
|
2397
|
+
}
|
|
2398
|
+
console.log(
|
|
2399
|
+
` ${url.pathname}?${url.search} - Routing nextjs image request to ${formatProxyTarget(imageApp)}`
|
|
2400
|
+
);
|
|
2401
|
+
return {
|
|
2389
2402
|
...imageApp,
|
|
2390
2403
|
path: `${url.pathname}${url.search}`
|
|
2391
|
-
}
|
|
2404
|
+
};
|
|
2392
2405
|
}
|
|
2393
2406
|
isDefaultAppLocal() {
|
|
2394
2407
|
const defaultApp = this.config.getDefaultApplication();
|
|
@@ -2410,10 +2423,12 @@ var ProxyRequestRouter = class {
|
|
|
2410
2423
|
var LocalProxy = class {
|
|
2411
2424
|
constructor(config, {
|
|
2412
2425
|
localApps,
|
|
2413
|
-
proxyPort
|
|
2426
|
+
proxyPort,
|
|
2427
|
+
configFilePath
|
|
2414
2428
|
}) {
|
|
2415
2429
|
this.router = new ProxyRequestRouter(config, { localApps });
|
|
2416
2430
|
this.proxyPort = proxyPort ?? this.router.config.getLocalProxyPort();
|
|
2431
|
+
this.configFilePath = configFilePath;
|
|
2417
2432
|
this.proxy = import_http_proxy.default.createProxyServer({ secure: true });
|
|
2418
2433
|
this.proxy.on("error", (err, req, res) => {
|
|
2419
2434
|
if (res instanceof http.ServerResponse) {
|
|
@@ -2423,9 +2438,12 @@ var LocalProxy = class {
|
|
|
2423
2438
|
}
|
|
2424
2439
|
const target = this.router.getTarget(req);
|
|
2425
2440
|
res.end(
|
|
2426
|
-
`Error proxying request to ${target
|
|
2441
|
+
`Error proxying request to ${formatProxyTarget(target)}. Is the server running locally on port ${target.port}?`
|
|
2442
|
+
);
|
|
2443
|
+
console.error(
|
|
2444
|
+
`Error proxying request for ${formatProxyTarget(target)}: `,
|
|
2445
|
+
err
|
|
2427
2446
|
);
|
|
2428
|
-
console.error(`Error proxying request for ${target.application}: `, err);
|
|
2429
2447
|
});
|
|
2430
2448
|
}
|
|
2431
2449
|
static fromFile(filePath, {
|
|
@@ -2441,7 +2459,11 @@ var LocalProxy = class {
|
|
|
2441
2459
|
microfrontends = MicrofrontendsServer.infer();
|
|
2442
2460
|
}
|
|
2443
2461
|
LocalProxy.validateLocalApps(localApps, microfrontends.config);
|
|
2444
|
-
return new LocalProxy(microfrontends.config, {
|
|
2462
|
+
return new LocalProxy(microfrontends.config, {
|
|
2463
|
+
localApps,
|
|
2464
|
+
proxyPort,
|
|
2465
|
+
configFilePath: filePath
|
|
2466
|
+
});
|
|
2445
2467
|
}
|
|
2446
2468
|
static validateLocalApps(localApps, config) {
|
|
2447
2469
|
const unknownApps = [];
|
|
@@ -2478,13 +2500,37 @@ var LocalProxy = class {
|
|
|
2478
2500
|
}
|
|
2479
2501
|
});
|
|
2480
2502
|
httpServer.listen(this.proxyPort, () => {
|
|
2481
|
-
|
|
2503
|
+
this.displayStartupMessage();
|
|
2482
2504
|
});
|
|
2483
2505
|
}
|
|
2484
2506
|
handleRequest(req, res) {
|
|
2485
2507
|
if (this.handleProxyInfoRequest(req.url, res)) {
|
|
2486
2508
|
return;
|
|
2487
2509
|
}
|
|
2510
|
+
if (req.url?.includes("//")) {
|
|
2511
|
+
const originalUrl = req.url;
|
|
2512
|
+
if (originalUrl) {
|
|
2513
|
+
const normalizedUrl = originalUrl.replaceAll(/\/[\\/]+/g, "/");
|
|
2514
|
+
if (normalizedUrl !== originalUrl) {
|
|
2515
|
+
res.writeHead(307, {
|
|
2516
|
+
Location: normalizedUrl,
|
|
2517
|
+
// Copy incoming request headers except hop-by-hop headers and Location
|
|
2518
|
+
...Object.fromEntries(
|
|
2519
|
+
Object.entries(req.headers).filter(
|
|
2520
|
+
([key]) => ![
|
|
2521
|
+
"connection",
|
|
2522
|
+
"content-length",
|
|
2523
|
+
"transfer-encoding",
|
|
2524
|
+
"location"
|
|
2525
|
+
].includes(key.toLowerCase())
|
|
2526
|
+
)
|
|
2527
|
+
)
|
|
2528
|
+
});
|
|
2529
|
+
res.end();
|
|
2530
|
+
return;
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2488
2534
|
const target = this.router.getTarget(req);
|
|
2489
2535
|
const { req: strippedReq, mfeFlagValue } = removeMfeFlagQuery(req);
|
|
2490
2536
|
if (target.protocol === "https") {
|
|
@@ -2518,7 +2564,7 @@ var LocalProxy = class {
|
|
|
2518
2564
|
})
|
|
2519
2565
|
);
|
|
2520
2566
|
}
|
|
2521
|
-
if (realRes.statusCode === 307) {
|
|
2567
|
+
if (realRes.statusCode === 307 || realRes.statusCode === 308 || realRes.statusCode === 302 || realRes.statusCode === 301) {
|
|
2522
2568
|
const locationHeader = realRes.headers.location;
|
|
2523
2569
|
if (locationHeader) {
|
|
2524
2570
|
const redirectUrl = new import_node_url.URL(
|
|
@@ -2579,6 +2625,79 @@ var LocalProxy = class {
|
|
|
2579
2625
|
}
|
|
2580
2626
|
return false;
|
|
2581
2627
|
}
|
|
2628
|
+
displayStartupMessage() {
|
|
2629
|
+
const allApps = this.router.config.getAllApplications();
|
|
2630
|
+
const localApps = [];
|
|
2631
|
+
const fallbackApps = [];
|
|
2632
|
+
const defaultApp = this.router.config.getDefaultApplication();
|
|
2633
|
+
const defaultFallback = defaultApp.fallback.host;
|
|
2634
|
+
for (const app of allApps) {
|
|
2635
|
+
const isLocal = this.router.localApps.find(
|
|
2636
|
+
(name) => name === app.name || name === app.packageName
|
|
2637
|
+
);
|
|
2638
|
+
if (isLocal) {
|
|
2639
|
+
localApps.push({
|
|
2640
|
+
name: app.name,
|
|
2641
|
+
port: app.development.local.port
|
|
2642
|
+
});
|
|
2643
|
+
} else {
|
|
2644
|
+
const target = this.router.getApplicationTarget(app);
|
|
2645
|
+
let fallbackHost = target.hostname;
|
|
2646
|
+
if (!app.fallback) {
|
|
2647
|
+
fallbackHost = defaultFallback;
|
|
2648
|
+
}
|
|
2649
|
+
fallbackApps.push({
|
|
2650
|
+
name: app.name,
|
|
2651
|
+
fallback: fallbackHost
|
|
2652
|
+
});
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
console.log(`
|
|
2656
|
+
\u25B2 Microfrontends Proxy (${package_default.version}) Started`);
|
|
2657
|
+
console.log(` - Proxy URL: http://localhost:${this.proxyPort}`);
|
|
2658
|
+
if (this.configFilePath) {
|
|
2659
|
+
console.log(` - Config: ${this.configFilePath}`);
|
|
2660
|
+
}
|
|
2661
|
+
if (localApps.length > 0) {
|
|
2662
|
+
console.log(" - Local Applications:");
|
|
2663
|
+
const displayLocalApps = localApps.length > 5 ? [
|
|
2664
|
+
...localApps.slice(0, 5),
|
|
2665
|
+
{ name: `... and ${localApps.length - 5} more`, port: void 0 }
|
|
2666
|
+
] : localApps;
|
|
2667
|
+
for (const app of displayLocalApps) {
|
|
2668
|
+
if (app.port !== void 0) {
|
|
2669
|
+
console.log(` \u2022 ${app.name} (port ${app.port})`);
|
|
2670
|
+
} else {
|
|
2671
|
+
console.log(` \u2022 ${app.name}`);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
if (fallbackApps.length > 0) {
|
|
2676
|
+
console.log(" - Fallback Applications:");
|
|
2677
|
+
const displayFallbackApps = fallbackApps.length > 5 ? [
|
|
2678
|
+
...fallbackApps.slice(0, 5),
|
|
2679
|
+
{ name: `... and ${fallbackApps.length - 5} more`, fallback: "" }
|
|
2680
|
+
] : fallbackApps;
|
|
2681
|
+
for (const app of displayFallbackApps) {
|
|
2682
|
+
if (app.fallback) {
|
|
2683
|
+
console.log(` \u2022 ${app.name} \u2192 ${app.fallback}`);
|
|
2684
|
+
} else {
|
|
2685
|
+
console.log(` \u2022 ${app.name}`);
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
if (localApps.length === 0 && fallbackApps.length === 0) {
|
|
2690
|
+
console.log(" - No applications configured\n");
|
|
2691
|
+
}
|
|
2692
|
+
if (localApps.length > 0) {
|
|
2693
|
+
console.log(
|
|
2694
|
+
"\nRequests directly to the ports of these applications may be automatically\nredirected to this proxy. Set the MFE_DISABLE_LOCAL_PROXY_REWRITE=1\nenvironment variable to disable this behavior."
|
|
2695
|
+
);
|
|
2696
|
+
}
|
|
2697
|
+
console.log(`
|
|
2698
|
+
${"\u2500".repeat(50)}
|
|
2699
|
+
`);
|
|
2700
|
+
}
|
|
2582
2701
|
};
|
|
2583
2702
|
function extractMfeFlagValue(path7) {
|
|
2584
2703
|
const host = "http://example.com";
|
|
@@ -2608,6 +2727,9 @@ function removeMfeFlagQuery(req) {
|
|
|
2608
2727
|
req.url = path7;
|
|
2609
2728
|
return { req, mfeFlagValue };
|
|
2610
2729
|
}
|
|
2730
|
+
function formatProxyTarget(target) {
|
|
2731
|
+
return `${target.originalApplication} (${target.isLocal ? "local" : "fallback"})`;
|
|
2732
|
+
}
|
|
2611
2733
|
|
|
2612
2734
|
// src/bin/port.ts
|
|
2613
2735
|
var import_node_process = require("process");
|
|
@@ -2617,19 +2739,19 @@ var import_node_path9 = __toESM(require("path"), 1);
|
|
|
2617
2739
|
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
2618
2740
|
function mfePort(packageDir) {
|
|
2619
2741
|
const { name: appName, version } = getPackageJson(packageDir);
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2742
|
+
try {
|
|
2743
|
+
const result = loadConfig({ packageDir, appName });
|
|
2744
|
+
const { port } = result;
|
|
2745
|
+
return {
|
|
2746
|
+
name: appName,
|
|
2747
|
+
version,
|
|
2748
|
+
port
|
|
2749
|
+
};
|
|
2750
|
+
} catch (e) {
|
|
2751
|
+
throw new Error(`Unable to determine configured port for ${appName}`, {
|
|
2752
|
+
cause: e
|
|
2753
|
+
});
|
|
2626
2754
|
}
|
|
2627
|
-
const { port } = result;
|
|
2628
|
-
return {
|
|
2629
|
-
name: appName,
|
|
2630
|
-
version,
|
|
2631
|
-
port
|
|
2632
|
-
};
|
|
2633
2755
|
}
|
|
2634
2756
|
function getPackageJson(packageDir) {
|
|
2635
2757
|
const filePath = import_node_path9.default.join(packageDir, "package.json");
|
|
@@ -2639,14 +2761,9 @@ function loadConfig({
|
|
|
2639
2761
|
packageDir,
|
|
2640
2762
|
appName
|
|
2641
2763
|
}) {
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
directory: packageDir
|
|
2646
|
-
});
|
|
2647
|
-
} catch (e) {
|
|
2648
|
-
return void 0;
|
|
2649
|
-
}
|
|
2764
|
+
const config = MicrofrontendsServer.infer({
|
|
2765
|
+
directory: packageDir
|
|
2766
|
+
});
|
|
2650
2767
|
const app = config.config.getApplication(appName);
|
|
2651
2768
|
const port = app.development.local.port ?? (app.development.local.protocol === "https" ? 443 : 80);
|
|
2652
2769
|
return { port };
|
package/dist/config.cjs
CHANGED
|
@@ -232,7 +232,7 @@ var MicrofrontendConfigClient = class {
|
|
|
232
232
|
static fromEnv(config) {
|
|
233
233
|
if (!config) {
|
|
234
234
|
throw new Error(
|
|
235
|
-
"Could not construct MicrofrontendConfigClient: configuration is empty or undefined. Did you set up your application with `withMicrofrontends`?"
|
|
235
|
+
"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"
|
|
236
236
|
);
|
|
237
237
|
}
|
|
238
238
|
return new MicrofrontendConfigClient(JSON.parse(config));
|
|
@@ -372,10 +372,11 @@ function validatePathExpression(path) {
|
|
|
372
372
|
}
|
|
373
373
|
if (token.pattern !== PATH_DEFAULT_PATTERN && // Allows (a|b|c) and ((?!a|b|c).*) regex
|
|
374
374
|
// Only limited regex is supported for now, due to performance considerations
|
|
375
|
-
|
|
376
|
-
|
|
375
|
+
// Allows all letters, numbers, and hyphens. Other characters must be escaped.
|
|
376
|
+
!/^(?<allowed>[\w-~]+(?:\|[^:|()]+)+)$|^\(\?!(?<disallowed>[\w-~]+(?:\|[^:|()]+)*)\)\.\*$/.test(
|
|
377
|
+
token.pattern.replace(/\\./g, "")
|
|
377
378
|
)) {
|
|
378
|
-
return `Path ${path} cannot use unsupported regular expression wildcard`;
|
|
379
|
+
return `Path ${path} cannot use unsupported regular expression wildcard. If the path includes special characters, they must be escaped with backslash (e.g. '\\(')`;
|
|
379
380
|
}
|
|
380
381
|
if (token.modifier && i !== tokens.length - 1) {
|
|
381
382
|
return `Modifier ${token.modifier} is not allowed on wildcard :${token.name} in ${path}. Modifiers are only allowed in the last path component`;
|