Skip to content

Commit 405bfa3

Browse files
aminesbdevalan-agius4
authored andcommitted
fix(@angular/build): keep the order of glob entries in the proxy configuration
Glob keys were converted to regular expressions by adding the new key and deleting the old one, which moved every glob entry to the end of the object. Since Vite proxies a request with the first entry that matches it, a glob written before a broader plain key could never be used. (cherry picked from commit 3871a9d)
1 parent 996e47f commit 405bfa3

2 files changed

Lines changed: 39 additions & 10 deletions

File tree

‎packages/angular/build/src/builders/dev-server/tests/options/proxy-config_spec.ts‎

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,19 +302,47 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
302302
await proxyServer.close();
303303
}
304304
});
305+
306+
it('keeps the order of glob entries relative to other entries', async () => {
307+
harness.useTarget('serve', {
308+
...BASE_OPTIONS,
309+
proxyConfig: 'proxy.config.json',
310+
});
311+
312+
const proxyServer = await createProxyServer();
313+
const otherProxyServer = await createProxyServer('OTHER_API_RETURN');
314+
try {
315+
await harness.writeFiles({
316+
'proxy.config.json': `
317+
{
318+
"/api/test/**": { "target": "http://127.0.0.1:${proxyServer.address.port}" },
319+
"/api": { "target": "http://127.0.0.1:${otherProxyServer.address.port}" }
320+
}
321+
`,
322+
});
323+
324+
const { result, response } = await executeOnceAndFetch(harness, '/api/test');
325+
326+
expect(result?.success).toBeTrue();
327+
expect(await response?.text()).toContain('TEST_API_RETURN');
328+
} finally {
329+
await proxyServer.close();
330+
await otherProxyServer.close();
331+
}
332+
});
305333
});
306334
});
307335

308336
/**
309337
* Creates an HTTP Server used for proxy testing that provides a `/test` endpoint
310-
* that returns a 200 response with a body of `TEST_API_RETURN`. All other requests
311-
* will return a 404 response.
338+
* that returns a 200 response with a body of `body` (`TEST_API_RETURN` by default).
339+
* All other requests will return a 404 response.
312340
*/
313-
async function createProxyServer() {
341+
async function createProxyServer(body = 'TEST_API_RETURN') {
314342
const proxyServer = createServer((request, response) => {
315343
if (request.url?.endsWith('/test')) {
316344
response.writeHead(200);
317-
response.end('TEST_API_RETURN');
345+
response.end(body);
318346
} else {
319347
response.writeHead(404);
320348
response.end();

‎packages/angular/build/src/utils/load-proxy-config.ts‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,14 @@ function normalizeProxyConfiguration(
114114
}
115115

116116
// TODO: Consider upstreaming glob support
117-
for (const key of Object.keys(normalizedProxy)) {
118-
if (key[0] !== '^' && isDynamicPattern(key)) {
119-
const pattern = makeRegExpFromGlob(key).source;
120-
normalizedProxy[pattern] = normalizedProxy[key];
121-
delete normalizedProxy[key];
122-
}
117+
// The object is rebuilt so that converted glob entries keep their original position,
118+
// since Vite proxies a request with the first entry that matches it.
119+
const orderedProxy: Record<string, object> = {};
120+
for (const [key, value] of Object.entries(normalizedProxy)) {
121+
const context = key[0] !== '^' && isDynamicPattern(key) ? makeRegExpFromGlob(key).source : key;
122+
orderedProxy[context] = value;
123123
}
124+
normalizedProxy = orderedProxy;
124125

125126
// Replace `pathRewrite` field with a `rewrite` function
126127
for (const proxyEntry of Object.values(normalizedProxy)) {

0 commit comments

Comments
 (0)