Skip to content

Commit 26f13b4

Browse files
committed
fix(@angular/build): Providing a DI token to dev server for SSR
Add configuration for add custom DI token. issue: #26323
1 parent fbc6eb3 commit 26f13b4

File tree

8 files changed

+44
-7
lines changed

8 files changed

+44
-7
lines changed

packages/angular/build/src/builders/application/options.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,11 @@ export async function normalizeOptions(
216216
if (options.ssr === true) {
217217
ssrOptions = {};
218218
} else if (typeof options.ssr === 'object') {
219-
const { entry } = options.ssr;
219+
const { entry, providers } = options.ssr;
220220

221221
ssrOptions = {
222222
entry: entry && path.join(workspaceRoot, entry),
223+
providers: providers && path.join(workspaceRoot, providers),
223224
};
224225
}
225226

packages/angular/build/src/builders/application/schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,10 @@
518518
"entry": {
519519
"type": "string",
520520
"description": "The server entry-point that when executed will spawn the web server."
521+
},
522+
"providers": {
523+
"type": "string",
524+
"description": "Path to providers for server application"
521525
}
522526
},
523527
"additionalProperties": false

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ export async function* serveWithVite(
9494
browserOptions.prerender = false;
9595

9696
// Avoid bundling and processing the ssr entry-point as this is not used by the dev-server.
97-
browserOptions.ssr = true;
9897

9998
// https://nodejs.org/api/process.html#processsetsourcemapsenabledval
10099
process.setSourceMapsEnabled(true);
@@ -286,7 +285,7 @@ export async function* serveWithVite(
286285
assetFiles,
287286
browserOptions.preserveSymlinks,
288287
externalMetadata,
289-
!!browserOptions.ssr,
288+
browserOptions.ssr,
290289
prebundleTransformer,
291290
target,
292291
isZonelessApp(polyfills),
@@ -465,7 +464,7 @@ export async function setupServer(
465464
assets: Map<string, string>,
466465
preserveSymlinks: boolean | undefined,
467466
externalMetadata: ExternalResultMetadata,
468-
ssr: boolean,
467+
ssr: boolean | { entry: string; providers: string; },
469468
prebundleTransformer: JavaScriptTransformer,
470469
target: string[],
471470
zoneless: boolean,

packages/angular/build/src/tools/esbuild/application-code-bundle.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ export function createServerCodeBundleOptions(
185185
if (ssrEntryPoint) {
186186
entryPoints['server'] = ssrEntryPoint;
187187
}
188+
const providersEntryPoint = ssrOptions?.providers;
189+
if (providersEntryPoint) {
190+
entryPoints['providers'] = providersEntryPoint;
191+
}
188192

189193
const buildOptions: BuildOptions = {
190194
...getEsBuildCommonOptions(options),

packages/angular/build/src/tools/vite/angular-memory-plugin.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ import { ServerResponse } from 'node:http';
1414
import { dirname, extname, join, relative } from 'node:path';
1515
import type { Connect, Plugin } from 'vite';
1616
import { renderPage } from '../../utils/server-rendering/render-page';
17+
import { loadEsmModuleFromMemory } from '../../utils/server-rendering/load-esm-from-memory';
1718

1819
export interface AngularMemoryPluginOptions {
1920
workspaceRoot: string;
2021
virtualProjectRoot: string;
2122
outputFiles: Map<string, { contents: Uint8Array; servable: boolean }>;
2223
assets: Map<string, string>;
23-
ssr: boolean;
24+
ssr: boolean | {entry: string, providers: string};
2425
external?: string[];
2526
extensionMiddleware?: Connect.NextHandleFunction[];
2627
extraHeaders?: Record<string, string>;
@@ -221,6 +222,18 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
221222
transformIndexHtmlAndAddHeaders(req.url, rawHtml, res, next, async (html) => {
222223
const resolvedUrls = server.resolvedUrls;
223224
const baseUrl = resolvedUrls?.local[0] ?? resolvedUrls?.network[0];
225+
const providers: [] = [];
226+
if (ssr && typeof ssr === 'object' && ssr.providers){
227+
const providersModule = await server.ssrLoadModule('/providers.mjs')
228+
if (providersModule && providersModule.default) {
229+
try {
230+
const result = providersModule.default(req, res)
231+
if (result && Array.isArray(result)) providers.push(...result as [])
232+
} catch (e) {
233+
throw new Error('Should be export default function which return array of provider')
234+
}
235+
}
236+
}
224237

225238
const { content } = await renderPage({
226239
document: html,
@@ -233,6 +246,7 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
233246
outputFiles: {},
234247
// TODO: add support for critical css inlining.
235248
inlineCriticalCss: false,
249+
providers
236250
});
237251

238252
return indexHtmlTransformer && content ? await indexHtmlTransformer(content) : content;

packages/angular/build/src/utils/server-rendering/load-esm-from-memory.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,18 @@
88

99
import { assertIsError } from '../error';
1010
import { loadEsmModule } from '../load-esm';
11-
import { MainServerBundleExports, RenderUtilsServerBundleExports } from './main-bundle-exports';
11+
import {
12+
MainProvidersBundleExports,
13+
MainServerBundleExports,
14+
RenderUtilsServerBundleExports
15+
} from './main-bundle-exports';
1216

1317
export function loadEsmModuleFromMemory(
1418
path: './main.server.mjs',
1519
): Promise<MainServerBundleExports>;
20+
export function loadEsmModuleFromMemory(
21+
path: './providers.mjs',
22+
): Promise<MainProvidersBundleExports>;
1623
export function loadEsmModuleFromMemory(
1724
path: './render-utils.server.mjs',
1825
): Promise<RenderUtilsServerBundleExports>;

packages/angular/build/src/utils/server-rendering/main-bundle-exports.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import type { ApplicationRef, Type, ɵConsole } from '@angular/core';
9+
import type { ApplicationRef, Type, ɵConsole, ApplicationConfig } from '@angular/core';
1010
import type { renderApplication, renderModule, ɵSERVER_CONTEXT } from '@angular/platform-server';
1111
import type { extractRoutes } from '../routes-extractor/extractor';
12+
import type { ServerResponse } from 'node:http';
1213

1314
export interface MainServerBundleExports {
1415
/** Standalone application bootstrapping function. */
1516
default: (() => Promise<ApplicationRef>) | Type<unknown>;
1617
}
1718

19+
export interface MainProvidersBundleExports {
20+
default: <Req, Res>(req: Req, res: Res) => ApplicationConfig['providers'];
21+
}
22+
1823
export interface RenderUtilsServerBundleExports {
1924
/** An internal token that allows providing extra information about the server context. */
2025
ɵSERVER_CONTEXT: typeof ɵSERVER_CONTEXT;

packages/angular/build/src/utils/server-rendering/render-page.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export interface RenderOptions {
2020
inlineCriticalCss?: boolean;
2121
loadBundle?: ((path: './main.server.mjs') => Promise<MainServerBundleExports>) &
2222
((path: './render-utils.server.mjs') => Promise<RenderUtilsServerBundleExports>);
23+
providers: StaticProvider[]
2324
}
2425

2526
export interface RenderResult {
@@ -40,6 +41,7 @@ export async function renderPage({
4041
inlineCriticalCss,
4142
outputFiles,
4243
loadBundle = loadEsmModuleFromMemory,
44+
providers
4345
}: RenderOptions): Promise<RenderResult> {
4446
const { default: bootstrapAppFnOrModule } = await loadBundle('./main.server.mjs');
4547
const { ɵSERVER_CONTEXT, renderModule, renderApplication, ɵresetCompiledComponents, ɵConsole } =
@@ -71,6 +73,7 @@ export async function renderPage({
7173
return new Console();
7274
},
7375
},
76+
...providers
7477
];
7578

7679
assert(

0 commit comments

Comments
 (0)