From 0635ef4bc0935037d34dc01057551ae4802f1d62 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Thu, 27 Aug 2026 13:09:16 +0000 Subject: [PATCH] fix(@angular/build): enable code splitting for vitest browser tests Enables code splitting for Vitest browser tests while keeping it disabled for Node-based tests (JSDOM/Happy-DOM). Vitest's Node-based module loading emulation (vite-node) is not fully spec compliant and lacks live ESM bindings across chunk boundaries, which can cause uninitialized exports and break mocking. In browser tests, however, the real browser adheres to the ECMAScript spec, so code splitting can be safely enabled there. --- .../unit-test/runners/vitest/build-options.ts | 12 ++++++------ .../src/tools/esbuild/angular/compiler-plugin.ts | 4 +--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts index 3936f44b09fd..c522d51c2272 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/build-options.ts @@ -256,13 +256,13 @@ export async function getVitestBuildOptions( sourceMap: { scripts: true, vendor: false, styles: false }, outputHashing: adjustOutputHashing(baseBuildOptions.outputHashing), optimization: false, + namedChunks: false, entryPoints, - // Every spec file is its own entry point, so splitting hoists any module shared between two - // specs into a chunk whose exports are then read across a chunk boundary. Those reads rely on - // live ESM bindings, and a module placed in a shared chunk is only assigned its exported value - // when that chunk's lazy initializer runs, so an importing chunk can read `undefined`. Nothing - // downloads these bundles, so there is no benefit to weigh against that. - disableCodeSplitting: true, + // Vitest's Node-based module loading emulation (vite-node) is not fully spec compliant and lacks + // live ESM bindings across chunk boundaries. This can cause uninitialized exports or break mocking. + // In browser tests, however, the real browser adheres to the ECMAScript spec, so code splitting can + // be safely enabled. + disableCodeSplitting: options.browsers?.length ? false : true, // Enable support for vitest browser prebundling. Excludes can be controlled with a runnerConfig // and the `optimizeDeps.exclude` option. externalPackages: true, diff --git a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts index b0ff0593cecc..0cc9d1f499f8 100644 --- a/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts +++ b/packages/angular/build/src/tools/esbuild/angular/compiler-plugin.ts @@ -576,9 +576,7 @@ export function createCompilerPlugin( const replacement = pluginOptions.fileReplacements?.[path.normalize(args.path)]; if (replacement) { return { - contents: await import('node:fs/promises').then(({ readFile }) => - readFile(path.normalize(replacement)), - ), + contents: await readFile(path.normalize(replacement)), loader: 'json' as const, watchFiles: [replacement], };