Skip to content

Commit 53012c8

Browse files
committed
fix(@angular/build): force dev-server to use HTTP/1.1 when using SSR with SSL
When using SSR with SSL, Vite attempts to use HTTP/2 by default. However, the Express server used for SSR does not support HTTP/2, causing requests to fail. This commit forces Vite to use HTTP/1.1 in this scenario by setting the ALPNProtocols to `['http/1.1']`. This is required as now Vite uses HTTP 2 for SSL: vitejs/vite@fc21af7 Closes #31894
1 parent 61a027d commit 53012c8

File tree

3 files changed

+26
-11
lines changed

3 files changed

+26
-11
lines changed

packages/angular/build/src/builders/dev-server/vite/server.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,7 @@ async function createServerConfig(
6060
headers: serverOptions.headers,
6161
// Disable the websocket if live reload is disabled (false/undefined are the only valid values)
6262
ws: serverOptions.liveReload === false && serverOptions.hmr === false ? false : undefined,
63-
// When server-side rendering (SSR) is enabled togather with SSL and Express is being used,
64-
// we must configure Vite to use HTTP/1.1.
65-
// This is necessary because Express does not support HTTP/2.
66-
// We achieve this by defining an empty proxy.
67-
// See: https://github.com/vitejs/vite/blob/c4b532cc900bf988073583511f57bd581755d5e3/packages/vite/src/node/http.ts#L106
68-
proxy:
69-
serverOptions.ssl && ssrMode === ServerSsrMode.ExternalSsrMiddleware ? (proxy ?? {}) : proxy,
63+
proxy,
7064
cors: {
7165
// This will add the header `Access-Control-Allow-Origin: http://example.com`,
7266
// where `http://example.com` is the requesting origin.

packages/angular/build/src/tools/vite/plugins/ssr-ssl-plugin.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ export function createAngularServerSideSSLPlugin(): Plugin {
2323
return;
2424
}
2525

26+
if (httpServer && 'ALPNProtocols' in httpServer) {
27+
// Force Vite to use HTTP/1.1 when SSR and SSL are enabled.
28+
// This is required because the Express server used for SSR does not support HTTP/2.
29+
// See: https://github.com/vitejs/vite/blob/46d3077f2b63771cc50230bc907c48f5773c00fb/packages/vite/src/node/http.ts#L126
30+
31+
// We directly set the `ALPNProtocols` on the HTTP server to override the default behavior.
32+
// Passing `ALPNProtocols` in the TLS options would cause Node.js to automatically include `h2`.
33+
// Additionally, using `ALPNCallback` is not an option as it is mutually exclusive with `ALPNProtocols`.
34+
// See: https://github.com/nodejs/node/blob/b8b4350ed3b73d225eb9e628d69151df56eaf298/lib/internal/http2/core.js#L3351
35+
httpServer.ALPNProtocols = ['http/1.1'];
36+
}
37+
2638
// TODO(alanagius): Replace `undici` with `tls.setDefaultCACertificates` once we only support Node.js 22.18.0+ and 24.5.0+.
2739
// See: https://nodejs.org/api/tls.html#tlssetdefaultcacertificatescerts
2840
const { getGlobalDispatcher, setGlobalDispatcher, Agent } = await import('undici');

tests/legacy-cli/e2e/tests/vite/ssr-with-ssl.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,23 @@ export default async function () {
4242

4343
const port = await ngServe('--ssl');
4444

45-
// Verify the server is running and the API response is correct.
46-
await validateResponse('/main.js', /bootstrapApplication/);
47-
await validateResponse('/home', /home works/);
45+
// http 2
46+
await validateResponse('/main.js', /bootstrapApplication/, true);
47+
await validateResponse('/home', /home works/, true);
4848

49-
async function validateResponse(pathname: string, match: RegExp): Promise<void> {
49+
// http 1.1
50+
await validateResponse('/main.js', /bootstrapApplication/, false);
51+
await validateResponse('/home', /home works/, false);
52+
53+
async function validateResponse(
54+
pathname: string,
55+
match: RegExp,
56+
allowH2: boolean,
57+
): Promise<void> {
5058
const response = await fetch(new URL(pathname, `https://localhost:${port}`), {
5159
dispatcher: new Agent({
5260
connect: {
61+
allowH2,
5362
rejectUnauthorized: false,
5463
},
5564
}),

0 commit comments

Comments
 (0)