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,