Skip to content

Commit 8ccfffd

Browse files
committed
f
1 parent 79ec7c8 commit 8ccfffd

File tree

2 files changed

+109
-3
lines changed

2 files changed

+109
-3
lines changed

packages/angular_devkit/build_angular/src/builders/dev-server/vite-server.ts

+23-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { Schema as BrowserBuilderOptions } from '../browser-esbuild/schema';
3333
import { loadProxyConfiguration } from './load-proxy-config';
3434
import type { NormalizedDevServerOptions } from './options';
3535
import type { DevServerBuilderOutput } from './webpack-server';
36+
import { ConnectionOptions } from 'node:tls';
3637

3738
interface OutputFileRecord {
3839
contents: Uint8Array;
@@ -680,11 +681,11 @@ export async function setupServer(
680681
}
681682

682683
transformIndexHtmlAndAddHeaders(url, rawHtml, res, next, async (html) => {
683-
const protocol = serverOptions.ssl ? 'https' : 'http';
684-
const route = `${protocol}://${req.headers.host}${req.originalUrl}`;
684+
const url = new URL(req.originalUrl ?? '/', server.resolvedUrls?.local[0]);
685+
685686
const { content } = await renderPage({
686687
document: html,
687-
route,
688+
route: url.toString(),
688689
serverContext: 'ssr',
689690
loadBundle: (uri: string) =>
690691
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -799,6 +800,25 @@ export async function setupServer(
799800
configuration.plugins ??= [];
800801
configuration.plugins.push(basicSslPlugin());
801802
}
803+
804+
if (ssr) {
805+
// Patch the TLS module to allow self signed certificate requests when running SSR.
806+
// We cannot use `NODE_EXTRA_CA_CERTS` as this is only read once when launching Node.js
807+
// and using `NODE_TLS_REJECT_UNAUTHORIZED` would apply globally and a warning is shown.
808+
const tls = await import('node:tls');
809+
const originalConnect = tls.connect;
810+
tls.connect = function (...args) {
811+
if (args && typeof args === 'object') {
812+
const options = args[0] as ConnectionOptions;
813+
if (options.host === serverOptions.host && options.port == serverOptions.port) {
814+
options.rejectUnauthorized = false;
815+
}
816+
}
817+
818+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
819+
return originalConnect.apply(this, args as any);
820+
};
821+
}
802822
}
803823

804824
return configuration;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import assert from 'node:assert';
2+
import { setTimeout } from 'node:timers/promises';
3+
import { killAllProcesses, ng } from '../../../utils/process';
4+
import { getGlobalVariable } from '../../../utils/env';
5+
import { rimraf, writeMultipleFiles } from '../../../utils/fs';
6+
import { installWorkspacePackages } from '../../../utils/packages';
7+
import { ngServe, useSha } from '../../../utils/project';
8+
9+
export default async function () {
10+
const useWebpackBuilder = !getGlobalVariable('argv')['esbuild'];
11+
if (useWebpackBuilder) {
12+
// Not supported by the webpack based builder.
13+
return;
14+
}
15+
16+
// Forcibly remove in case another test doesn't clean itself up.
17+
await rimraf('node_modules/@angular/ssr');
18+
await ng('add', '@angular/ssr', '--skip-confirmation');
19+
await useSha();
20+
await installWorkspacePackages();
21+
22+
await writeMultipleFiles({
23+
// Add http client and route
24+
'src/app/app.config.ts': `
25+
import { ApplicationConfig } from '@angular/core';
26+
import { provideRouter } from '@angular/router';
27+
28+
import {HomeComponent} from './home/home.component';
29+
import { provideClientHydration } from '@angular/platform-browser';
30+
import { provideHttpClient, withFetch } from '@angular/common/http';
31+
32+
export const appConfig: ApplicationConfig = {
33+
providers: [
34+
provideRouter([{
35+
path: '',
36+
component: HomeComponent,
37+
}]),
38+
provideClientHydration(),
39+
provideHttpClient(withFetch()),
40+
],
41+
};
42+
`,
43+
// Add asset
44+
'src/assets/media.json': JSON.stringify({ dataFromAssets: true }),
45+
// Update component to do an HTTP call to asset.
46+
'src/app/app.component.ts': `
47+
import { Component, inject } from '@angular/core';
48+
import { CommonModule } from '@angular/common';
49+
import { RouterOutlet } from '@angular/router';
50+
import { HttpClient } from '@angular/common/http';
51+
52+
@Component({
53+
selector: 'app-root',
54+
standalone: true,
55+
imports: [CommonModule, RouterOutlet],
56+
template: \`
57+
<p>{{ data | json }}</p>
58+
<router-outlet></router-outlet>
59+
\`,
60+
})
61+
export class AppComponent {
62+
data: any;
63+
constructor() {
64+
const http = inject(HttpClient);
65+
http.get('/assets/media.json').subscribe((d) => {
66+
this.data = d;
67+
});
68+
}
69+
}
70+
`,
71+
});
72+
73+
await ng('generate', 'component', 'home');
74+
75+
await verifyResponse(await ngServe('--no-ssl'));
76+
77+
await setTimeout(500);
78+
await killAllProcesses();
79+
80+
await verifyResponse(await ngServe('--ssl'));
81+
}
82+
83+
async function verifyResponse(port: number): Promise<void> {
84+
const indexResponse = await fetch(`http://localhost:${port}/`);
85+
assert.match(await indexResponse.text(), /<p>{[\S\s]*"dataFromAssets":[\s\S]*true[\S\s]*}<\/p>/);
86+
}

0 commit comments

Comments
 (0)