Skip to content

Commit f27be11

Browse files
committed
feat(@nguniversal/builders): add SSL support for dev-server
With this change we add SSL support to the SSR dev-server. We expose 3 new options; - `ssl`: Turn on/off HTTPs - `sslKey`: SSL key to use for serving HTTPS - `sslCert`: SSL certificate to use for serving HTTPS Closes angular#1633
1 parent ece3d9f commit f27be11

File tree

4 files changed

+57
-5
lines changed

4 files changed

+57
-5
lines changed

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

+16-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
import { Architect, BuilderRun } from '@angular-devkit/architect';
1010
import * as browserSync from 'browser-sync';
11-
import { concatMap, debounceTime, mergeMap, retryWhen, take } from 'rxjs/operators';
12-
11+
import * as https from 'https';
1312
import { from, throwError, timer } from 'rxjs';
13+
import { concatMap, debounceTime, mergeMap, retryWhen, take } from 'rxjs/operators';
1414
import { createArchitect, host } from '../../testing/utils';
1515
import { SSRDevServerBuilderOutput } from './index';
1616

@@ -90,6 +90,20 @@ describe('Serve SSR Builder', () => {
9090
expect(output.baseUrl).not.toContain('4200');
9191
});
9292

93+
it('works with SSL', async () => {
94+
const run = await architect.scheduleTarget(target, { ssl: true });
95+
runs.push(run);
96+
const output = await run.result as SSRDevServerBuilderOutput;
97+
expect(output.success).toBe(true);
98+
expect(output.baseUrl).toBe('https://localhost:4200');
99+
100+
const response = await fetch('https://localhost:4200/index.html', {
101+
agent: new https.Agent({ rejectUnauthorized: false }),
102+
});
103+
104+
expect(await response.text()).toContain('<title>App</title>');
105+
});
106+
93107
// todo: alan-agius4: Investigate why this tests passed locally but fails in CI.
94108
// this is currenty disabled but still useful locally
95109
// tslint:disable-next-line: ban

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

+19-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
import { json, logging, tags } from '@angular-devkit/core';
1616
import * as browserSync from 'browser-sync';
1717
import { createProxyMiddleware } from 'http-proxy-middleware';
18-
import { join } from 'path';
18+
import { join, resolve as pathResolve } from 'path';
1919
import {
2020
EMPTY,
2121
Observable,
@@ -62,7 +62,6 @@ export function execute(
6262
const browserTarget = targetFromTargetString(options.browserTarget);
6363
const serverTarget = targetFromTargetString(options.serverTarget);
6464
const getBaseUrl = (bs: browserSync.BrowserSyncInstance) => `${bs.getOption('scheme')}://${bs.getOption('host')}:${bs.getOption('port')}`;
65-
6665
const browserTargetRun = context.scheduleTarget(browserTarget, {
6766
serviceWorker: false,
6867
watch: true,
@@ -136,7 +135,7 @@ export function execute(
136135

137136
return of(builderOutput);
138137
} else {
139-
return from(initBrowserSync(bsInstance, nodeServerPort, options))
138+
return from(initBrowserSync(bsInstance, nodeServerPort, options, context))
140139
.pipe(
141140
tap(bs => {
142141
const baseUrl = getBaseUrl(bs);
@@ -207,6 +206,7 @@ async function initBrowserSync(
207206
browserSyncInstance: browserSync.BrowserSyncInstance,
208207
nodeServerPort: number,
209208
options: SSRDevServerBuilderOptions,
209+
context: BuilderContext,
210210
): Promise<browserSync.BrowserSyncInstance> {
211211
if (browserSyncInstance.active) {
212212
return browserSyncInstance;
@@ -237,6 +237,7 @@ async function initBrowserSync(
237237
ghostMode: false,
238238
logLevel: 'silent',
239239
open,
240+
https: getSslConfig(context.workspaceRoot, options),
240241
};
241242

242243
const publicHostNormalized = publicHost && publicHost.endsWith('/')
@@ -306,4 +307,19 @@ function mapErrorToMessage(error: unknown): string {
306307
return '';
307308
}
308309

310+
function getSslConfig(
311+
root: string,
312+
options: SSRDevServerBuilderOptions,
313+
): browserSync.HttpsOptions | undefined | boolean {
314+
const { ssl, sslCert, sslKey } = options;
315+
if (ssl && sslCert && sslKey) {
316+
return {
317+
key: pathResolve(root, sslKey),
318+
cert: pathResolve(root, sslCert),
319+
};
320+
}
321+
322+
return ssl;
323+
}
324+
309325
export default createBuilder<SSRDevServerBuilderOptions, BuilderOutput>(execute);

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

+13
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@
4242
"type": "boolean",
4343
"description": "Launch the development server in inspector mode and listen on address and port '127.0.0.1:9229'.",
4444
"default": false
45+
},
46+
"ssl": {
47+
"type": "boolean",
48+
"description": "Serve using HTTPS.",
49+
"default": false
50+
},
51+
"sslKey": {
52+
"type": "string",
53+
"description": "SSL key to use for serving HTTPS."
54+
},
55+
"sslCert": {
56+
"type": "string",
57+
"description": "SSL certificate to use for serving HTTPS."
4558
}
4659
},
4760
"additionalProperties": false,

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

+9
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,13 @@ export interface Schema {
3333
* Use for a complex dev server setup, such as one with reverse proxies.
3434
*/
3535
publicHost?: string;
36+
37+
/** Serve using HTTPS. */
38+
ssl?: boolean;
39+
40+
/** SSL key to use for serving HTTPS. */
41+
sslKey?: string;
42+
43+
/** SSL certificate to use for serving HTTPS. */
44+
sslCert?: string;
3645
}

0 commit comments

Comments
 (0)