diff --git a/package.json b/package.json
index 2a45ab656476..a04ea47beead 100644
--- a/package.json
+++ b/package.json
@@ -169,6 +169,7 @@
}
},
"resolutions": {
- "typescript": "5.9.3"
+ "typescript": "5.9.3",
+ "undici-types": "^7.16.0"
}
}
diff --git a/packages/angular/build/BUILD.bazel b/packages/angular/build/BUILD.bazel
index 05f42e4dcd95..d8f89be1d5cd 100644
--- a/packages/angular/build/BUILD.bazel
+++ b/packages/angular/build/BUILD.bazel
@@ -105,6 +105,7 @@ ts_project(
":node_modules/sass",
":node_modules/source-map-support",
":node_modules/tinyglobby",
+ ":node_modules/undici",
":node_modules/vite",
":node_modules/vitest",
":node_modules/watchpack",
diff --git a/packages/angular/build/package.json b/packages/angular/build/package.json
index 345d83a0b22a..aaefb19bd7b9 100644
--- a/packages/angular/build/package.json
+++ b/packages/angular/build/package.json
@@ -42,6 +42,7 @@
"semver": "7.7.3",
"source-map-support": "0.5.21",
"tinyglobby": "0.2.15",
+ "undici": "7.16.0",
"vite": "7.2.1",
"watchpack": "2.4.4"
},
@@ -49,8 +50,8 @@
"lmdb": "3.4.3"
},
"devDependencies": {
- "@angular/ssr": "workspace:*",
"@angular-devkit/core": "workspace:*",
+ "@angular/ssr": "workspace:*",
"jsdom": "27.1.0",
"less": "4.4.2",
"ng-packagr": "21.0.0-rc.0",
@@ -59,9 +60,9 @@
"vitest": "4.0.7"
},
"peerDependencies": {
- "@angular/core": "0.0.0-ANGULAR-FW-PEER-DEP",
"@angular/compiler": "0.0.0-ANGULAR-FW-PEER-DEP",
"@angular/compiler-cli": "0.0.0-ANGULAR-FW-PEER-DEP",
+ "@angular/core": "0.0.0-ANGULAR-FW-PEER-DEP",
"@angular/localize": "0.0.0-ANGULAR-FW-PEER-DEP",
"@angular/platform-browser": "0.0.0-ANGULAR-FW-PEER-DEP",
"@angular/platform-server": "0.0.0-ANGULAR-FW-PEER-DEP",
diff --git a/packages/angular/build/src/builders/dev-server/vite/server.ts b/packages/angular/build/src/builders/dev-server/vite/server.ts
index f527e41d33d0..9cabeabccfec 100644
--- a/packages/angular/build/src/builders/dev-server/vite/server.ts
+++ b/packages/angular/build/src/builders/dev-server/vite/server.ts
@@ -13,6 +13,7 @@ import type { ComponentStyleRecord } from '../../../tools/vite/middlewares';
import {
ServerSsrMode,
createAngularMemoryPlugin,
+ createAngularServerSideSSLPlugin,
createAngularSetupMiddlewaresPlugin,
createAngularSsrTransformPlugin,
createRemoveIdPrefixPlugin,
@@ -207,16 +208,19 @@ export async function setupServer(
preTransformRequests,
cacheDir,
),
- ssr: createSsrConfig(
- externalMetadata,
- serverOptions,
- prebundleTransformer,
- zoneless,
- target,
- prebundleLoaderExtensions,
- thirdPartySourcemaps,
- define,
- ),
+ ssr:
+ ssrMode === ServerSsrMode.NoSsr
+ ? undefined
+ : createSsrConfig(
+ externalMetadata,
+ serverOptions,
+ prebundleTransformer,
+ zoneless,
+ target,
+ prebundleLoaderExtensions,
+ thirdPartySourcemaps,
+ define,
+ ),
plugins: [
createAngularSetupMiddlewaresPlugin({
outputFiles,
@@ -258,11 +262,15 @@ export async function setupServer(
};
if (serverOptions.ssl) {
+ configuration.plugins ??= [];
if (!serverOptions.sslCert || !serverOptions.sslKey) {
const { default: basicSslPlugin } = await import('@vitejs/plugin-basic-ssl');
- configuration.plugins ??= [];
configuration.plugins.push(basicSslPlugin());
}
+
+ if (ssrMode !== ServerSsrMode.NoSsr) {
+ configuration.plugins?.push(createAngularServerSideSSLPlugin());
+ }
}
return configuration;
diff --git a/packages/angular/build/src/tools/vite/plugins/index.ts b/packages/angular/build/src/tools/vite/plugins/index.ts
index ef697aa7395a..6c4cdd4496e4 100644
--- a/packages/angular/build/src/tools/vite/plugins/index.ts
+++ b/packages/angular/build/src/tools/vite/plugins/index.ts
@@ -10,3 +10,4 @@ export { createAngularMemoryPlugin } from './angular-memory-plugin';
export { createRemoveIdPrefixPlugin } from './id-prefix-plugin';
export { createAngularSetupMiddlewaresPlugin, ServerSsrMode } from './setup-middlewares-plugin';
export { createAngularSsrTransformPlugin } from './ssr-transform-plugin';
+export { createAngularServerSideSSLPlugin } from './ssr-ssl-plugin';
diff --git a/packages/angular/build/src/tools/vite/plugins/ssr-ssl-plugin.ts b/packages/angular/build/src/tools/vite/plugins/ssr-ssl-plugin.ts
new file mode 100644
index 000000000000..c87e0bd112a0
--- /dev/null
+++ b/packages/angular/build/src/tools/vite/plugins/ssr-ssl-plugin.ts
@@ -0,0 +1,46 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.dev/license
+ */
+
+import { rootCertificates } from 'node:tls';
+import type { Plugin } from 'vite';
+
+export function createAngularServerSideSSLPlugin(): Plugin {
+ return {
+ name: 'angular-ssr-ssl-plugin',
+ apply: 'serve',
+ async configureServer({ config, httpServer }) {
+ const {
+ ssr,
+ server: { https },
+ } = config;
+
+ if (!ssr || !https?.cert) {
+ return;
+ }
+
+ // TODO(alanagius): Replace `undici` with `tls.setDefaultCACertificates` once we only support Node.js 22.18.0+ and 24.5.0+.
+ // See: https://nodejs.org/api/tls.html#tlssetdefaultcacertificatescerts
+ const { getGlobalDispatcher, setGlobalDispatcher, Agent } = await import('undici');
+ const originalDispatcher = getGlobalDispatcher();
+ const { cert } = https;
+ const certificates = Array.isArray(cert) ? cert : [cert];
+
+ setGlobalDispatcher(
+ new Agent({
+ connect: {
+ ca: [...rootCertificates, ...certificates],
+ },
+ }),
+ );
+
+ httpServer?.on('close', () => {
+ setGlobalDispatcher(originalDispatcher);
+ });
+ },
+ };
+}
diff --git a/packages/angular_devkit/build_angular/src/builders/dev-server/specs/ssl_spec.ts b/packages/angular_devkit/build_angular/src/builders/dev-server/specs/ssl_spec.ts
index 1f41eba74279..60ed65793c7f 100644
--- a/packages/angular_devkit/build_angular/src/builders/dev-server/specs/ssl_spec.ts
+++ b/packages/angular_devkit/build_angular/src/builders/dev-server/specs/ssl_spec.ts
@@ -8,7 +8,7 @@
import { Architect, BuilderRun } from '@angular-devkit/architect';
import { tags } from '@angular-devkit/core';
-import { Agent, getGlobalDispatcher, setGlobalDispatcher } from 'undici';
+import { Agent } from 'undici';
import { createArchitect, host } from '../../../testing/test-utils';
import { DevServerBuilderOutput } from '../index';
@@ -35,20 +35,12 @@ describe('Dev Server Builder ssl', () => {
expect(output.success).toBe(true);
expect(output.baseUrl).toMatch(/^https:\/\/localhost:\d+\//);
- // The self-signed certificate used by the dev server will cause fetch to fail
- // unless reject unauthorized is disabled.
- const originalDispatcher = getGlobalDispatcher();
- setGlobalDispatcher(
- new Agent({
+ const response = await fetch(output.baseUrl, {
+ dispatcher: new Agent({
connect: { rejectUnauthorized: false },
}),
- );
- try {
- const response = await fetch(output.baseUrl);
- expect(await response.text()).toContain('
HelloWorldApp');
- } finally {
- setGlobalDispatcher(originalDispatcher);
- }
+ });
+ expect(await response.text()).toContain('HelloWorldApp');
});
it('supports key and cert', async () => {
@@ -122,19 +114,11 @@ describe('Dev Server Builder ssl', () => {
expect(output.success).toBe(true);
expect(output.baseUrl).toMatch(/^https:\/\/localhost:\d+\//);
- // The self-signed certificate used by the dev server will cause fetch to fail
- // unless reject unauthorized is disabled.
- const originalDispatcher = getGlobalDispatcher();
- setGlobalDispatcher(
- new Agent({
+ const response = await fetch(output.baseUrl, {
+ dispatcher: new Agent({
connect: { rejectUnauthorized: false },
}),
- );
- try {
- const response = await fetch(output.baseUrl);
- expect(await response.text()).toContain('HelloWorldApp');
- } finally {
- setGlobalDispatcher(originalDispatcher);
- }
+ });
+ expect(await response.text()).toContain('HelloWorldApp');
});
});
diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts
index a67cf0b3c5b5..7651b2387c16 100644
--- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts
+++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts
@@ -9,7 +9,7 @@
import { Architect } from '@angular-devkit/architect';
// eslint-disable-next-line import/no-extraneous-dependencies
import * as browserSync from 'browser-sync';
-import { Agent, getGlobalDispatcher, setGlobalDispatcher } from 'undici';
+import { Agent } from 'undici';
import { createArchitect, host } from '../../../testing/test-utils';
import { SSRDevServerBuilderOutput } from '../index';
@@ -85,20 +85,13 @@ describe('Serve SSR Builder', () => {
expect(output.success).toBe(true);
expect(output.baseUrl).toBe(`https://localhost:${output.port}`);
- // The self-signed certificate used by the dev server will cause fetch to fail
- // unless reject unauthorized is disabled.
- const originalDispatcher = getGlobalDispatcher();
- setGlobalDispatcher(
- new Agent({
+ const response = await fetch(`https://localhost:${output.port}/index.html`, {
+ dispatcher: new Agent({
connect: { rejectUnauthorized: false },
}),
- );
- try {
- const response = await fetch(`https://localhost:${output.port}/index.html`);
- expect(await response.text()).toContain('HelloWorldApp');
- } finally {
- setGlobalDispatcher(originalDispatcher);
- }
+ });
+
+ expect(await response.text()).toContain('HelloWorldApp');
await run.stop();
});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ab1741abe7f8..c1d305ec98a0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6,6 +6,7 @@ settings:
overrides:
typescript: 5.9.3
+ undici-types: ^7.16.0
'@angular/build': workspace:*
packageExtensionsChecksum: sha256-3L73Fw32UVtE6x5BJxJPBtQtH/mgsr31grNpdhHP1IY=
@@ -418,6 +419,9 @@ importers:
tinyglobby:
specifier: 0.2.15
version: 0.2.15
+ undici:
+ specifier: 7.16.0
+ version: 7.16.0
vite:
specifier: 7.2.1
version: 7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)
@@ -8456,9 +8460,6 @@ packages:
unbzip2-stream@1.4.3:
resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==}
- undici-types@6.21.0:
- resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
-
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
@@ -11905,7 +11906,7 @@ snapshots:
'@types/node@22.19.0':
dependencies:
- undici-types: 6.21.0
+ undici-types: 7.16.0
'@types/node@24.10.0':
dependencies:
@@ -17996,8 +17997,6 @@ snapshots:
buffer: 5.7.1
through: 2.3.8
- undici-types@6.21.0: {}
-
undici-types@7.16.0: {}
undici@5.29.0:
diff --git a/tests/legacy-cli/BUILD.bazel b/tests/legacy-cli/BUILD.bazel
index 0b66850c52b2..713bc31b5c82 100644
--- a/tests/legacy-cli/BUILD.bazel
+++ b/tests/legacy-cli/BUILD.bazel
@@ -68,6 +68,7 @@ e2e_suites(
# Extra runtime deps due to bundling issues.
# TODO: Clean this up.
"//:node_modules/express",
+ "//:node_modules/undici",
],
runner = ":runner_entrypoint",
)
diff --git a/tests/legacy-cli/e2e/tests/BUILD.bazel b/tests/legacy-cli/e2e/tests/BUILD.bazel
index 55f5019b568f..0ed3f83428f7 100644
--- a/tests/legacy-cli/e2e/tests/BUILD.bazel
+++ b/tests/legacy-cli/e2e/tests/BUILD.bazel
@@ -13,6 +13,7 @@ ts_project(
"//:node_modules/express",
"//:node_modules/fast-glob",
"//:node_modules/semver",
+ "//:node_modules/undici",
"//tests/legacy-cli/e2e/utils",
],
)
diff --git a/tests/legacy-cli/e2e/tests/commands/serve/ssr-http-requests-assets.ts b/tests/legacy-cli/e2e/tests/commands/serve/ssr-http-requests-assets.ts
index aa7e33089666..19f1208646d6 100644
--- a/tests/legacy-cli/e2e/tests/commands/serve/ssr-http-requests-assets.ts
+++ b/tests/legacy-cli/e2e/tests/commands/serve/ssr-http-requests-assets.ts
@@ -1,5 +1,5 @@
import assert from 'node:assert';
-
+import { Agent } from 'undici';
import { killAllProcesses, ng } from '../../../utils/process';
import { writeMultipleFiles } from '../../../utils/fs';
import { installWorkspacePackages, uninstallPackage } from '../../../utils/packages';
@@ -71,11 +71,120 @@ export default async function () {
await killAllProcesses();
- try {
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
- const sslPort = await ngServe('--ssl');
- assert.match(await (await fetch(`https://localhost:${sslPort}/`)).text(), match);
- } finally {
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
- }
+ const sslPort = await ngServe('--ssl');
+ assert.match(
+ await (
+ await fetch(`https://localhost:${sslPort}/`, {
+ dispatcher: new Agent({
+ connect: {
+ rejectUnauthorized: false,
+ },
+ }),
+ })
+ ).text(),
+ match,
+ );
+
+ await killAllProcesses();
+
+ // With OpenSSl cert+key
+ writeMultipleFiles({
+ 'server.key': `-----BEGIN PRIVATE KEY-----
+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
+xlFXnn9FIQthAEWUhFgqApO+oKBn0hw=
+-----END PRIVATE KEY-----
+`,
+ 'server.crt': `-----BEGIN CERTIFICATE-----
+MIIFCTCCAvGgAwIBAgIUd0CiuFYYUTnnfB/Q6lijpEZJy4wwDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MTEwNzEwMTE0NFoXDTI2MTEw
+NzEwMTE0NFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAzsgZlcutcxKn7KEz0PYE19t9/55a1V7WlBiZGw0eWnLa
+tF/l0LWbiKDuCYEaYmM+f/F4mPAImjHbd9Gm7oDuQIciG7BskMb89rIu8ikPllHR
+fw0U6X06u+hPBF0fFvQSPg06Rv9ZzRgXdZaTGvDTHx6i74baXmx7gXG9QQkXpcvh
+SCx1Qxn/nXwiL0dGb7fAId6iy+r7196cxajPV6131IFiqqW8/i9QXgjyC7B/lGjj
+gs828qy6GOn52sI1JHP4nh1snK6O3QVJbiSf5HBraT2A/4bDBXF8+g+u6myBbnOg
+8/Qq1iGoABTKivdRQLVKcnz+/oy4pEDkk6RQy4CfpJQAxgomegv3b41LGDPuDC/X
+V+kPa4+rEKP6I9A7HY9/SeZlZpJZG0T+aoXjBk8nNPf2pm4mBX81hDDJxHAk/wkv
+69avd6EQxtNgsehdQdOZrUfvwBcQCelMS9rt6DD1WNe/RVo8dvmL2363TaxZ1m/H
+kTIkWSFvDvKbSpK4fiy9UYXqflv9TcXa6YOxNq1j/AFq95nXfnJ2rrxf9sjHnAQy
+1Z5Nzjko3Li3PovZ4Dg9MR3XEXzvPZq8oyHsBCK1EOFNGYMhzIvfaleMMl4XfR80
+1IE9NUKH7IrhfcclX52p7EDo96KjoAkvdlRHqmZy14GlaIf/vvxVe6+Auc8S8y8C
+AwEAAaNTMFEwHQYDVR0OBBYEFCOiC0xvMbfCFzmseoMDht+ydKBbMB8GA1UdIwQY
+MBaAFCOiC0xvMbfCFzmseoMDht+ydKBbMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBAJSiQwcaGVhwUorkb062cyyZOAstEJ5meg6H2g3nL894oWEU
+FLc/S20z2tqO1It4rZB3cRKmB0RvH78eh4aUPAh0lPa/bm/h7WrgdEAJUmlNuZV3
+Hitd/c1d2OVzx6w+CFYd/G5GW3sWblYiH0paIN6s4TqHFY/IAzzZKQB7Ud7FJagM
+KMkEP8RFDm7iRcENuSf51LtZb2NjN1TM5CK5sVXu62dvPYZC6SW052/qd1U+1Tyw
+EX4fCqUgEoGoU6+Ftz3hCdVy3E4uzFBK1e5wmct6HULBZL51PWpf3BgwneZy0itE
+lD6Y0H6m/9KMVcXpAHZK+6YnOOcWxIgfjykjZEO99rx3pVWPw1uSBUJEu1SLknAn
+JDe+WLp+xmB8s62EjixZsEGqoQYYrtZ3vz8u4PSSgYPJjdAkFdLOPitf0U8ZW9/7
+hGyHgqd7WQ3toBwwdnPo6fZqHHyN8rXeWcmx8Uj9oyY1uunkSmq3csITPQg/zKBO
+6RsO3pPj8mHjeAZCDs+Ks68ccPsn+53fJ9CrjiJlHFIP0ywbEBO1snJDit5q3gQI
+/UpClB9Sl+mz4wznOvrKycrxrLEptZeBA5c6M9Qr30YJAb/prxvzSY5FrUGcstkO
+CQVzSwZEUXxSo6K4cJ55vC0p3P3aoMvEpHfM+JqL3lCM9qWrxfkhvn8YS+Gg
+-----END CERTIFICATE-----
+`,
+ });
+
+ const sslPortForCerts = await ngServe('--ssl', '--ssl-cert=server.crt', '--ssl-key="server.key"');
+ assert.match(
+ await (
+ await fetch(`https://localhost:${sslPortForCerts}/`, {
+ dispatcher: new Agent({
+ connect: {
+ rejectUnauthorized: false,
+ },
+ }),
+ })
+ ).text(),
+ match,
+ );
}
diff --git a/tests/legacy-cli/e2e/tests/vite/ssr-with-ssl.ts b/tests/legacy-cli/e2e/tests/vite/ssr-with-ssl.ts
index c4c0fd34ec75..5bb8d9105cf8 100644
--- a/tests/legacy-cli/e2e/tests/vite/ssr-with-ssl.ts
+++ b/tests/legacy-cli/e2e/tests/vite/ssr-with-ssl.ts
@@ -1,3 +1,4 @@
+import { Agent } from 'undici';
import assert from 'node:assert';
import { writeMultipleFiles } from '../../utils/fs';
import { ng, silentNg } from '../../utils/process';
@@ -46,14 +47,16 @@ export default async function () {
await validateResponse('/home', /home works/);
async function validateResponse(pathname: string, match: RegExp): Promise {
- try {
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
- const response = await fetch(new URL(pathname, `https://localhost:${port}`));
- const text = await response.text();
- assert.match(text, match);
- assert.equal(response.status, 200);
- } finally {
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
- }
+ const response = await fetch(new URL(pathname, `https://localhost:${port}`), {
+ dispatcher: new Agent({
+ connect: {
+ rejectUnauthorized: false,
+ },
+ }),
+ });
+
+ const text = await response.text();
+ assert.match(text, match);
+ assert.equal(response.status, 200);
}
}
diff --git a/tests/legacy-cli/rollup.config.mjs b/tests/legacy-cli/rollup.config.mjs
index 0fc2768c5057..208e4cc78c42 100644
--- a/tests/legacy-cli/rollup.config.mjs
+++ b/tests/legacy-cli/rollup.config.mjs
@@ -25,7 +25,7 @@ for (const file of testFiles) {
export default {
input: chunks,
- external: [],
+ external: ['undici'], // This cannot be bundled as `node:sqlite` is experimental in node.js 22. Remove once this feature is no longer behind a flag
plugins: [
nodeResolve({
preferBuiltins: true,