Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): correctly handle glob negation in…
Browse files Browse the repository at this point in the history
… proxy config when using vite

This commit fixes an issue were negated globs in proxy config were not process correctly when using vite.

Closes #26970
  • Loading branch information
alan-agius4 committed Jan 26, 2024
1 parent 37ffa5e commit dbd3984
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import * as http from 'http';
import { createServer } from 'node:http';
import { executeDevServer } from '../../index';
import { executeOnceAndFetch } from '../execute-fetch';
import { describeServeBuilder } from '../jasmine-helpers';
Expand All @@ -27,21 +27,18 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
proxyConfig: 'proxy.config.json',
});

const proxyServer = createProxyServer();
const proxyServer = await createProxyServer();
try {
await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));
const proxyAddress = proxyServer.address() as import('net').AddressInfo;

await harness.writeFiles({
'proxy.config.json': `{ "/api/*": { "target": "http://127.0.0.1:${proxyAddress.port}" } }`,
'proxy.config.json': `{ "/api/*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }`,
});

const { result, response } = await executeOnceAndFetch(harness, '/api/test');

expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
await proxyServer.close();
}
});

Expand All @@ -51,15 +48,12 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
proxyConfig: 'proxy.config.json',
});

const proxyServer = createProxyServer();
const proxyServer = await createProxyServer();
try {
await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));
const proxyAddress = proxyServer.address() as import('net').AddressInfo;

await harness.writeFiles({
'proxy.config.json': `
// JSON file with comments
{ "/api/*": { "target": "http://127.0.0.1:${proxyAddress.port}" } }
{ "/api/*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }
`,
});

Expand All @@ -68,7 +62,7 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
await proxyServer.close();
}
});

Expand All @@ -77,22 +71,18 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
...BASE_OPTIONS,
proxyConfig: 'proxy.config.js',
});

const proxyServer = createProxyServer();
const proxyServer = await createProxyServer();
try {
await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));
const proxyAddress = proxyServer.address() as import('net').AddressInfo;

await harness.writeFiles({
'proxy.config.js': `module.exports = { "/api/*": { "target": "http://127.0.0.1:${proxyAddress.port}" } }`,
'proxy.config.js': `module.exports = { "/api/*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }`,
});

const { result, response } = await executeOnceAndFetch(harness, '/api/test');

expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
await proxyServer.close();
}
});

Expand All @@ -102,13 +92,10 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
proxyConfig: 'proxy.config.js',
});

const proxyServer = createProxyServer();
const proxyServer = await createProxyServer();
try {
await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));
const proxyAddress = proxyServer.address() as import('net').AddressInfo;

await harness.writeFiles({
'proxy.config.js': `export default { "/api/*": { "target": "http://127.0.0.1:${proxyAddress.port}" } }`,
'proxy.config.js': `export default { "/api/*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }`,
'package.json': '{ "type": "module" }',
});

Expand All @@ -117,7 +104,7 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
await proxyServer.close();
}
});

Expand All @@ -127,10 +114,9 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
proxyConfig: 'proxy.config.cjs',
});

const proxyServer = createProxyServer();
const proxyServer = await createProxyServer();
try {
await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));
const proxyAddress = proxyServer.address() as import('net').AddressInfo;
const proxyAddress = proxyServer.address;

await harness.writeFiles({
'proxy.config.cjs': `module.exports = { "/api/*": { "target": "http://127.0.0.1:${proxyAddress.port}" } }`,
Expand All @@ -141,7 +127,7 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
await proxyServer.close();
}
});

Expand All @@ -151,21 +137,18 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
proxyConfig: 'proxy.config.mjs',
});

const proxyServer = createProxyServer();
const proxyServer = await createProxyServer();
try {
await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));
const proxyAddress = proxyServer.address() as import('net').AddressInfo;

await harness.writeFiles({
'proxy.config.mjs': `export default { "/api/*": { "target": "http://127.0.0.1:${proxyAddress.port}" } }`,
'proxy.config.mjs': `export default { "/api/*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }`,
});

const { result, response } = await executeOnceAndFetch(harness, '/api/test');

expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
await proxyServer.close();
}
});

Expand All @@ -175,21 +158,18 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
proxyConfig: 'proxy.config.json',
});

const proxyServer = createProxyServer();
const proxyServer = await createProxyServer();
try {
await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));
const proxyAddress = proxyServer.address() as import('net').AddressInfo;

await harness.writeFiles({
'proxy.config.json': `[ { "context": ["/api", "/abc"], "target": "http://127.0.0.1:${proxyAddress.port}" } ]`,
'proxy.config.json': `[ { "context": ["/api", "/abc"], "target": "http://127.0.0.1:${proxyServer.address.port}" } ]`,
});

const { result, response } = await executeOnceAndFetch(harness, '/api/test');

expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
await proxyServer.close();
}
});

Expand Down Expand Up @@ -232,18 +212,39 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
}),
);
});

it('supports negation of globs', async () => {
harness.useTarget('serve', {
...BASE_OPTIONS,
proxyConfig: 'proxy.config.json',
});

const proxyServer = await createProxyServer();
try {
await harness.writeFiles({
'proxy.config.json': `
{ "!something/**/*": { "target": "http://127.0.0.1:${proxyServer.address.port}" } }
`,
});

const { result, response } = await executeOnceAndFetch(harness, '/api/test');

expect(result?.success).toBeTrue();
expect(await response?.text()).toContain('TEST_API_RETURN');
} finally {
await proxyServer.close();
}
});
});
});

/**
* Creates an HTTP Server used for proxy testing that provides a `/test` endpoint
* that returns a 200 response with a body of `TEST_API_RETURN`. All other requests
* will return a 404 response.
*
* @returns An HTTP Server instance.
*/
function createProxyServer() {
return http.createServer((request, response) => {
async function createProxyServer() {
const proxyServer = createServer((request, response) => {
if (request.url?.endsWith('/test')) {
response.writeHead(200);
response.end('TEST_API_RETURN');
Expand All @@ -252,4 +253,11 @@ function createProxyServer() {
response.end();
}
});

await new Promise<void>((resolve) => proxyServer.listen(0, '127.0.0.1', resolve));

return {
address: proxyServer.address() as import('net').AddressInfo,
close: () => new Promise<void>((resolve) => proxyServer.close(() => resolve())),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { existsSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { extname, resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
import { parse as parseGlob } from 'picomatch';
import { makeRe as makeRegExpFromGlob } from 'picomatch';
import { assertIsError } from './error';
import { loadEsmModule } from './load-esm';

Expand Down Expand Up @@ -129,8 +129,8 @@ function normalizeProxyConfiguration(
// TODO: Consider upstreaming glob support
for (const key of Object.keys(normalizedProxy)) {
if (isDynamicPattern(key)) {
const { output } = parseGlob(key);
normalizedProxy[`^${output}$`] = normalizedProxy[key];
const pattern = makeRegExpFromGlob(key).source;
normalizedProxy[pattern] = normalizedProxy[key];
delete normalizedProxy[key];
}
}
Expand Down

0 comments on commit dbd3984

Please sign in to comment.