Skip to content
This repository was archived by the owner on Nov 22, 2024. It is now read-only.

Commit 6ef0de8

Browse files
committed
feat(@nguniversal/builders): add support for proxy configuration in ssr-dev-server
With this change we added a new `proxyConfig` option to be used to provide custom proxy configurations to the ssr-dev-server builder. Closes #1757
1 parent a80f4c9 commit 6ef0de8

File tree

5 files changed

+89
-1
lines changed

5 files changed

+89
-1
lines changed

modules/builders/src/ssr-dev-server/index.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import { Architect, BuilderRun } from '@angular-devkit/architect';
1010
import * as browserSync from 'browser-sync';
11+
import * as http from 'http';
1112
import * as https from 'https';
1213
import { from, throwError, timer } from 'rxjs';
1314
import { concatMap, debounceTime, mergeMap, retryWhen, take } from 'rxjs/operators';
@@ -137,4 +138,37 @@ describe('Serve SSR Builder', () => {
137138
)
138139
.toPromise();
139140
});
141+
142+
it('proxies requests based on the proxy configuration file provided in the option', async () => {
143+
const proxyServer = http.createServer((request, response) => {
144+
if (request.url?.endsWith('/test')) {
145+
response.writeHead(200);
146+
response.end('TEST_API_RETURN');
147+
} else {
148+
response.writeHead(404);
149+
response.end();
150+
}
151+
});
152+
153+
try {
154+
await new Promise<void>(resolve => proxyServer.listen(0, '127.0.0.1', resolve));
155+
const proxyAddress = proxyServer.address() as import('net').AddressInfo;
156+
157+
host.writeMultipleFiles({
158+
'proxy.config.json': `{ "/api/*": { "logLevel": "debug","target": "http://127.0.0.1:${proxyAddress.port}" } }`,
159+
});
160+
161+
const run = await architect.scheduleTarget(target, { port: 7001, proxyConfig: 'proxy.config.json' });
162+
runs.push(run);
163+
164+
const output = await run.result as SSRDevServerBuilderOutput;
165+
expect(output.success).toBe(true);
166+
expect(output.baseUrl).toBe('http://localhost:7001');
167+
const response = await fetch('http://localhost:7001/api/test');
168+
expect(await response?.text()).toContain('TEST_API_RETURN');
169+
170+
} finally {
171+
await new Promise<void>((resolve) => proxyServer.close(() => resolve()));
172+
}
173+
});
140174
});

modules/builders/src/ssr-dev-server/index.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from '@angular-devkit/architect';
1515
import { json, logging, tags } from '@angular-devkit/core';
1616
import * as browserSync from 'browser-sync';
17+
import { existsSync } from 'fs';
1718
import { createProxyMiddleware } from 'http-proxy-middleware';
1819
import { join, resolve as pathResolve } from 'path';
1920
import {
@@ -212,7 +213,7 @@ async function initBrowserSync(
212213
return browserSyncInstance;
213214
}
214215

215-
const { port: browserSyncPort, open, host, publicHost } = options;
216+
const { port: browserSyncPort, open, host, publicHost, proxyConfig } = options;
216217
const bsPort = browserSyncPort || await getAvailablePort();
217218
const bsOptions: browserSync.Options = {
218219
proxy: {
@@ -284,6 +285,19 @@ async function initBrowserSync(
284285
}
285286
}
286287

288+
if (proxyConfig) {
289+
if (!bsOptions.middleware) {
290+
bsOptions.middleware = [];
291+
} else if (!Array.isArray(bsOptions.middleware)) {
292+
bsOptions.middleware = [bsOptions.middleware];
293+
}
294+
295+
bsOptions.middleware = [
296+
...bsOptions.middleware,
297+
...getProxyConfig(context.workspaceRoot, proxyConfig),
298+
];
299+
}
300+
287301
return new Promise((resolve, reject) => {
288302
browserSyncInstance.init(bsOptions, (error, bs) => {
289303
if (error) {
@@ -322,4 +336,36 @@ function getSslConfig(
322336
return ssl;
323337
}
324338

339+
function getProxyConfig(
340+
root: string,
341+
proxyConfig: string,
342+
): browserSync.MiddlewareHandler[] {
343+
const proxyPath = pathResolve(root, proxyConfig);
344+
let proxySettings: any;
345+
try {
346+
proxySettings = require(proxyPath);
347+
} catch (error) {
348+
if (error.code === 'MODULE_NOT_FOUND') {
349+
throw new Error(`Proxy config file ${proxyPath} does not exist.`);
350+
}
351+
352+
throw error;
353+
}
354+
355+
const proxies = Array.isArray(proxySettings) ? proxySettings : [proxySettings];
356+
357+
return proxies.map(proxy => {
358+
const keys = Object.keys(proxy);
359+
const context = keys[0];
360+
361+
if (keys.length === 1 || typeof context === 'string') {
362+
const normalizedContext = context.replace(/^\*$/, '**').replace(/\/\*$/, '');
363+
364+
return createProxyMiddleware(normalizedContext, proxy[context]) as any;
365+
}
366+
367+
return createProxyMiddleware(proxy) as any;
368+
});
369+
}
370+
325371
export default createBuilder<SSRDevServerBuilderOptions, BuilderOutput>(execute);

modules/builders/src/ssr-dev-server/schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
"sslCert": {
5656
"type": "string",
5757
"description": "SSL certificate to use for serving HTTPS."
58+
},
59+
"proxyConfig": {
60+
"type": "string",
61+
"description": "Proxy configuration file."
5862
}
5963
},
6064
"additionalProperties": false,

modules/builders/src/ssr-dev-server/schema.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,7 @@ export interface Schema {
4242

4343
/** SSL certificate to use for serving HTTPS. */
4444
sslCert?: string;
45+
46+
/** Proxy configuration file */
47+
proxyConfig?: string;
4548
}

tools/defaults.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ def jasmine_node_test(deps = [], **kwargs):
106106

107107
_jasmine_node_test(
108108
deps = local_deps,
109+
templated_args = ["--bazel_patch_module_resolver"],
109110
configuration_env_vars = ["compile"],
110111
**kwargs
111112
)

0 commit comments

Comments
 (0)