diff --git a/packages/angular/build/src/builders/application/execute-build.ts b/packages/angular/build/src/builders/application/execute-build.ts
index 857ef564f52a..21beb57bf478 100644
--- a/packages/angular/build/src/builders/application/execute-build.ts
+++ b/packages/angular/build/src/builders/application/execute-build.ts
@@ -175,10 +175,7 @@ export async function executeBuild(
// Only run if the number of lazy chunks meets the configured threshold.
// This avoids overhead for small projects with few chunks.
-
- // TODO: Remove this log once chunk optimization is supported for server builds as this
- // causes the file to be renamed and thus causes incorrect preloading.
- if (!options.serverEntryPoint && lazyChunksCount >= optimizeChunksThreshold) {
+ if (lazyChunksCount >= optimizeChunksThreshold) {
const { optimizeChunks } = await import('./chunk-optimizer');
const optimizationResult = await profileAsync('OPTIMIZE_CHUNKS', () =>
optimizeChunks(
diff --git a/packages/angular/build/src/builders/application/tests/behavior/chunk-optimization-server_spec.ts b/packages/angular/build/src/builders/application/tests/behavior/chunk-optimization-server_spec.ts
new file mode 100644
index 000000000000..76ecbbc4329e
--- /dev/null
+++ b/packages/angular/build/src/builders/application/tests/behavior/chunk-optimization-server_spec.ts
@@ -0,0 +1,187 @@
+/**
+ * @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 { buildApplication } from '../../index';
+import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setup';
+
+/**
+ * Fixture application with a server entry point and four lazy routes.
+ * Four lazy chunks exceed the default chunk optimization threshold (3),
+ * so the optimization pass runs without requiring the
+ * `NG_BUILD_OPTIMIZE_CHUNKS` environment variable (which is captured at
+ * module load time and cannot be toggled per spec).
+ *
+ * `shared.ts` is imported statically by both `main.ts` and two of the lazy
+ * components. esbuild emits such modules as a separate `chunk-*.js` shared
+ * chunk, while the chunk optimizer merges entry-reachable modules back into
+ * the main chunk. The absence of `chunk-*.js` files is therefore used as a
+ * signal that the optimization pass actually ran.
+ */
+const LAZY_ROUTE_NAMES = ['lazy-a', 'lazy-b', 'lazy-c', 'lazy-d'] as const;
+
+function lazyComponentSource(name: string, useShared: boolean): string {
+ const className = name.replace(/(^|-)(\w)/g, (_, __, c: string) => c.toUpperCase());
+
+ return `
+ import { Component } from '@angular/core';
+ ${useShared ? `import { sharedValue } from '../shared';` : ''}
+
+ @Component({
+ selector: 'app-${name}',
+ template: '