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], };