Skip to content

Commit 2485e64

Browse files
committed
refactor(@angular-devkit/build-angular): move webpack compiler creation to karma builder
Moves the instantiation of the Webpack Compiler from the Karma plugin to the Karma builder (`browser_builder`). This allows the builder to have full ownership of the compiler's lifecycle and configuration, including `singleRun` adjustments and output paths. The Karma plugin now receives the `compiler` instance directly instead of the configuration, reducing its responsibility to just integration logic.
1 parent a69dc95 commit 2485e64

File tree

2 files changed

+29
-32
lines changed

2 files changed

+29
-32
lines changed

packages/angular_devkit/build_angular/src/builders/karma/browser_builder.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { purgeStaleBuildCache } from '@angular/build/private';
1010
import type { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
1111
import type { ConfigOptions, Server } from 'karma';
1212
import * as path from 'node:path';
13-
import type { Configuration } from 'webpack';
13+
import webpack, { Configuration } from 'webpack';
1414
import { getCommonConfig, getStylesConfig } from '../../tools/webpack/configs';
1515
import type { ExecutionTransformer } from '../../transforms';
1616
import { generateBrowserWebpackConfigFromContext } from '../../utils/webpack-browser-config';
@@ -77,9 +77,31 @@ export function execute(
7777
}),
7878
);
7979

80+
const KARMA_APPLICATION_PATH = '_karma_webpack_';
81+
webpackConfig.output ??= {};
82+
webpackConfig.output.path = `/${KARMA_APPLICATION_PATH}/`;
83+
webpackConfig.output.publicPath = `/${KARMA_APPLICATION_PATH}/`;
84+
85+
if (karmaOptions.singleRun) {
86+
webpackConfig.plugins.unshift({
87+
apply: (compiler: webpack.Compiler) => {
88+
compiler.hooks.afterEnvironment.tap('karma', () => {
89+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
90+
compiler.watchFileSystem = { watch: () => {} } as any;
91+
});
92+
},
93+
});
94+
}
95+
96+
// Remove the watch option to avoid the [DEP_WEBPACK_WATCH_WITHOUT_CALLBACK] warning.
97+
// The compiler is initialized in watch mode by webpack-dev-middleware.
98+
delete webpackConfig.watch;
99+
100+
const compiler = webpack(webpackConfig);
101+
80102
karmaOptions.buildWebpack = {
81103
options,
82-
webpackConfig,
104+
compiler,
83105
logger: context.logger,
84106
};
85107

packages/angular_devkit/build_angular/src/tools/webpack/plugins/karma/karma.ts

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@
1010
// TODO: cleanup this file, it's copied as is from Angular CLI.
1111
import * as http from 'node:http';
1212
import * as path from 'node:path';
13-
import webpack from 'webpack';
13+
import type { Compiler } from 'webpack';
1414
import webpackDevMiddleware from 'webpack-dev-middleware';
1515

1616
import { statsErrorsToString } from '../../utils/stats';
1717
import { createConsoleLogger } from '@angular-devkit/core/node';
1818
import { logging } from '@angular-devkit/core';
1919
import { BuildOptions } from '../../../../utils/build-options';
2020
import { normalizeSourceMaps } from '../../../../utils/index';
21-
import assert from 'node:assert';
2221

2322
const KARMA_APPLICATION_PATH = '_karma_webpack_';
2423

@@ -67,16 +66,13 @@ const init: any = (config: any, emitter: any) => {
6766
config.reporters.push('coverage');
6867
}
6968

70-
// Add webpack config.
71-
const webpackConfig = config.buildWebpack.webpackConfig;
69+
const compiler = config.buildWebpack.compiler as Compiler;
7270
const webpackMiddlewareConfig = {
7371
// Hide webpack output because its noisy.
7472
stats: false,
7573
publicPath: `/${KARMA_APPLICATION_PATH}/`,
7674
};
7775

78-
// Use existing config if any.
79-
config.webpack = { ...webpackConfig, ...config.webpack };
8076
config.webpackMiddleware = { ...webpackMiddlewareConfig, ...config.webpackMiddleware };
8177

8278
// Our custom context and debug files list the webpack bundles directly instead of using
@@ -90,29 +86,10 @@ const init: any = (config: any, emitter: any) => {
9086
config.middleware = config.middleware || [];
9187
config.middleware.push('@angular-devkit/build-angular--fallback');
9288

93-
if (config.singleRun) {
94-
// There's no option to turn off file watching in webpack-dev-server, but
95-
// we can override the file watcher instead.
96-
webpackConfig.plugins.unshift({
97-
apply: (compiler: any) => {
98-
compiler.hooks.afterEnvironment.tap('karma', () => {
99-
compiler.watchFileSystem = { watch: () => {} };
100-
});
101-
},
102-
});
103-
}
104-
// Files need to be served from a custom path for Karma.
105-
webpackConfig.output.path = `/${KARMA_APPLICATION_PATH}/`;
106-
webpackConfig.output.publicPath = `/${KARMA_APPLICATION_PATH}/`;
107-
108-
const compiler = webpack(webpackConfig, (error, stats) => {
109-
if (error) {
110-
throw error;
111-
}
112-
113-
if (stats?.hasErrors()) {
89+
compiler.hooks.done.tap('karma', (stats) => {
90+
if (stats.hasErrors()) {
11491
// Only generate needed JSON stats and when needed.
115-
const statsJson = stats?.toJson({
92+
const statsJson = stats.toJson({
11693
all: false,
11794
children: true,
11895
errors: true,
@@ -136,8 +113,6 @@ const init: any = (config: any, emitter: any) => {
136113
callback?.();
137114
}
138115

139-
assert(compiler, 'Webpack compiler factory did not return a compiler instance.');
140-
141116
compiler.hooks.invalid.tap('karma', () => handler());
142117
compiler.hooks.watchRun.tapAsync('karma', (_: any, callback: () => void) => handler(callback));
143118
compiler.hooks.run.tapAsync('karma', (_: any, callback: () => void) => handler(callback));

0 commit comments

Comments
 (0)