From 12e4c4275946f7489fc1e327bf28f0ee60bc3f3c Mon Sep 17 00:00:00 2001 From: Jeb Date: Sun, 31 May 2026 21:18:42 +0200 Subject: [PATCH] feat(custom-webpack)!: remove Karma builder and tests (Angular 22 removes Karma) Angular 22 removes the Karma test builder entirely. The custom-webpack `:karma` builder wraps `@angular-devkit/build-angular:karma`, which will not exist in v22, so it is removed here along with its example-app test fixtures, integration tests, and documentation. BREAKING CHANGE: The `@angular-builders/custom-webpack:karma` builder has been removed. Angular 22 no longer ships a Karma builder. Migrate your `ng test` target to a supported test runner (e.g. Vitest / Web Test Runner or `@angular-builders/jest`). --- examples/AGENTS.md | 2 +- .../custom-webpack/full-cycle-app/README.md | 4 -- .../full-cycle-app/angular.json | 20 ------ .../full-cycle-app/karma.conf.js | 60 ---------------- .../full-cycle-app/package.json | 9 --- .../custom-webpack/sanity-app-esm/README.md | 4 -- .../sanity-app-esm/angular.json | 20 ------ .../sanity-app-esm/karma.conf.cjs | 56 --------------- .../sanity-app-esm/package.json | 9 --- examples/custom-webpack/sanity-app/README.md | 4 -- .../custom-webpack/sanity-app/angular.json | 20 ------ .../custom-webpack/sanity-app/karma.conf.js | 60 ---------------- .../custom-webpack/sanity-app/package.json | 9 --- packages/custom-webpack/.gitignore | 1 - packages/custom-webpack/AGENTS.md | 13 ++-- packages/custom-webpack/README.md | 60 +--------------- packages/custom-webpack/builders.json | 5 -- .../e2e/custom-webpack-karma-schema.spec.ts | 25 ------- packages/custom-webpack/src/index.ts | 1 - packages/custom-webpack/src/karma/index.ts | 23 ------ .../custom-webpack/src/karma/schema.ext.json | 5 -- packages/custom-webpack/src/schemes.ts | 5 -- packages/custom-webpack/tests/integration.js | 26 +------ yarn.lock | 70 ++----------------- 24 files changed, 15 insertions(+), 496 deletions(-) delete mode 100644 examples/custom-webpack/full-cycle-app/karma.conf.js delete mode 100644 examples/custom-webpack/sanity-app-esm/karma.conf.cjs delete mode 100644 examples/custom-webpack/sanity-app/karma.conf.js delete mode 100644 packages/custom-webpack/e2e/custom-webpack-karma-schema.spec.ts delete mode 100644 packages/custom-webpack/src/karma/index.ts delete mode 100644 packages/custom-webpack/src/karma/schema.ext.json diff --git a/examples/AGENTS.md b/examples/AGENTS.md index c5151025d0..ac3f9bf120 100644 --- a/examples/AGENTS.md +++ b/examples/AGENTS.md @@ -45,7 +45,7 @@ examples/ sanity-esbuild-app/ -- CJS/ESM/TS plugin variants, vitest builder sanity-esbuild-app-esm/ -- Same tests in an ESM-type package custom-webpack/ - sanity-app/ -- Basic browser + dev-server + karma tests + sanity-app/ -- Basic browser + dev-server tests sanity-app-esm/ -- Same tests in an ESM-type package full-cycle-app/ -- Full webpack customization + indexTransform tests jest/ diff --git a/examples/custom-webpack/full-cycle-app/README.md b/examples/custom-webpack/full-cycle-app/README.md index 04ce17f70c..36d7862f21 100644 --- a/examples/custom-webpack/full-cycle-app/README.md +++ b/examples/custom-webpack/full-cycle-app/README.md @@ -14,10 +14,6 @@ Run `ng generate component component-name` to generate a new component. You can Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - ## Running end-to-end tests Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). diff --git a/examples/custom-webpack/full-cycle-app/angular.json b/examples/custom-webpack/full-cycle-app/angular.json index e3b4c8a090..ba299e9457 100644 --- a/examples/custom-webpack/full-cycle-app/angular.json +++ b/examples/custom-webpack/full-cycle-app/angular.json @@ -107,26 +107,6 @@ "buildTarget": "full-cycle-app:build" } }, - "test": { - "builder": "@angular-builders/custom-webpack:karma", - "options": { - "polyfills": [ - "zone.js", - "zone.js/testing" - ], - "tsConfig": "tsconfig.spec.json", - "inlineStyleLanguage": "scss", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.scss" - ], - "scripts": [] - } - }, "e2e": { "builder": "@cypress/schematic:cypress", "options": { diff --git a/examples/custom-webpack/full-cycle-app/karma.conf.js b/examples/custom-webpack/full-cycle-app/karma.conf.js deleted file mode 100644 index bf6cc86657..0000000000 --- a/examples/custom-webpack/full-cycle-app/karma.conf.js +++ /dev/null @@ -1,60 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -const path = require('path'); -const fs = require('fs'); -// Prefer the system Chrome (preinstalled and library-matched on CI runners); fall back to -// Puppeteer's bundled Chrome for local dev. Puppeteer's bundled binary stopped launching on -// updated CI runner images ("Cannot start ChromeHeadless"), so system Chrome is more robust. -process.env.CHROME_BIN = - [ - '/usr/bin/google-chrome', - '/usr/bin/google-chrome-stable', - '/usr/bin/chromium-browser', - '/usr/bin/chromium', - ].find(p => fs.existsSync(p)) || require('puppeteer').executablePath(); - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - client: { - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - coverageReporter: { - dir: path.join(__dirname, 'coverage', 'append-webpack-plugins'), - subdir: '.', - reporters: [ - { type: 'text-summary' }, - { type: 'html', subdir: 'html' }, - { type: 'lcovonly' }, - { type: 'json' }, - ], - }, - reporters: ['progress', 'kjhtml', 'coverage'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - flags: ['--disable-translate', '--disable-extensions'], - browsers: ['Chrome'], - browserConsoleLogOptions: { - terminal: false, - }, - customLaunchers: { - ChromeHeadlessCI: { - base: 'ChromeHeadless', - flags: ['--no-sandbox', '--disable-gpu', '--disable-translate', '--disable-extensions'], - }, - }, - singleRun: true, - restartOnFileChange: true, - }); -}; diff --git a/examples/custom-webpack/full-cycle-app/package.json b/examples/custom-webpack/full-cycle-app/package.json index 3cf3f91890..b25731a6db 100644 --- a/examples/custom-webpack/full-cycle-app/package.json +++ b/examples/custom-webpack/full-cycle-app/package.json @@ -4,7 +4,6 @@ "scripts": { "start": "ng serve", "build": "ng build", - "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", "cypress:open": "cypress open", @@ -32,19 +31,11 @@ "@angular/compiler-cli": "21.2.15", "@angular/language-service": "21.2.15", "@eslint/js": "10.0.1", - "@types/jasmine": "6.0.0", "@types/node": "24.12.4", "angular-eslint": "21.4.0", "cypress": "15.16.0", "eslint": "10.4.1", "html-webpack-plugin": "5.6.7", - "jasmine-core": "6.2.0", - "karma": "6.4.4", - "karma-chrome-launcher": "3.2.0", - "karma-coverage": "2.2.1", - "karma-jasmine": "5.1.0", - "karma-jasmine-html-reporter": "2.2.0", - "puppeteer": "24.43.1", "ts-node": "10.9.2", "typescript": "5.9.3", "typescript-eslint": "8.60.0" diff --git a/examples/custom-webpack/sanity-app-esm/README.md b/examples/custom-webpack/sanity-app-esm/README.md index 4f60da2687..622fa0ecc3 100644 --- a/examples/custom-webpack/sanity-app-esm/README.md +++ b/examples/custom-webpack/sanity-app-esm/README.md @@ -14,10 +14,6 @@ Run `ng generate component component-name` to generate a new component. You can Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - ## Running end-to-end tests Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. diff --git a/examples/custom-webpack/sanity-app-esm/angular.json b/examples/custom-webpack/sanity-app-esm/angular.json index 573d3148d7..bc398c2c26 100644 --- a/examples/custom-webpack/sanity-app-esm/angular.json +++ b/examples/custom-webpack/sanity-app-esm/angular.json @@ -118,26 +118,6 @@ "buildTarget": "sanity-app-esm:build" } }, - "test": { - "builder": "@angular-builders/custom-webpack:karma", - "options": { - "polyfills": [ - "zone.js", - "zone.js/testing" - ], - "tsConfig": "tsconfig.spec.json", - "inlineStyleLanguage": "scss", - "karmaConfig": "karma.conf.cjs", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.css" - ], - "scripts": [] - } - }, "cypress-run": { "builder": "@cypress/schematic:cypress", "options": { diff --git a/examples/custom-webpack/sanity-app-esm/karma.conf.cjs b/examples/custom-webpack/sanity-app-esm/karma.conf.cjs deleted file mode 100644 index 6c4d3a0323..0000000000 --- a/examples/custom-webpack/sanity-app-esm/karma.conf.cjs +++ /dev/null @@ -1,56 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -const fs = require('fs'); -// Prefer the system Chrome (preinstalled and library-matched on CI runners); fall back to -// Puppeteer's bundled Chrome for local dev. Puppeteer's bundled binary stopped launching on -// updated CI runner images ("Cannot start ChromeHeadless"), so system Chrome is more robust. -process.env.CHROME_BIN = - ['/usr/bin/google-chrome', '/usr/bin/google-chrome-stable', '/usr/bin/chromium-browser', '/usr/bin/chromium'].find( - p => fs.existsSync(p) - ) || require('puppeteer').executablePath(); - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - client: { - jasmine: { - // you can add configuration options for Jasmine here - // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html - // for example, you can disable the random execution with `random: false` - // or set a specific seed with `seed: 4321` - }, - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - jasmineHtmlReporter: { - suppressAll: true, // removes the duplicated traces - }, - coverageReporter: { - dir: require('path').join(__dirname, './coverage/sanity-app-esm'), - subdir: '.', - reporters: [{ type: 'html' }, { type: 'text-summary' }], - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - customLaunchers: { - ChromeHeadlessCI: { - base: 'ChromeHeadless', - flags: ['--no-sandbox', '--disable-gpu', '--disable-translate', '--disable-extensions'], - }, - }, - singleRun: true, - restartOnFileChange: true, - }); -}; diff --git a/examples/custom-webpack/sanity-app-esm/package.json b/examples/custom-webpack/sanity-app-esm/package.json index 4d6ee159d3..eb679f7150 100644 --- a/examples/custom-webpack/sanity-app-esm/package.json +++ b/examples/custom-webpack/sanity-app-esm/package.json @@ -9,7 +9,6 @@ "build": "ng build", "build-ts": "TS_NODE_PROJECT=tsconfig.app.json NODE_OPTIONS='--loader ts-node/esm' ng build", "watch": "ng build --watch --configuration development", - "test": "ng test", "e2e": "ng e2e", "cypress:open": "cypress open", "cypress:run": "cypress run" @@ -34,16 +33,8 @@ "@angular/cli": "21.2.13", "@angular/compiler-cli": "21.2.15", "@cypress/schematic": "5.0.0", - "@types/jasmine": "6.0.0", "@types/node": "24.12.4", "cypress": "15.16.0", - "jasmine-core": "6.2.0", - "karma": "6.4.4", - "karma-chrome-launcher": "3.2.0", - "karma-coverage": "2.2.1", - "karma-jasmine": "5.1.0", - "karma-jasmine-html-reporter": "2.2.0", - "puppeteer": "24.43.1", "typescript": "5.9.3" } } diff --git a/examples/custom-webpack/sanity-app/README.md b/examples/custom-webpack/sanity-app/README.md index 764f92dae7..948659281d 100644 --- a/examples/custom-webpack/sanity-app/README.md +++ b/examples/custom-webpack/sanity-app/README.md @@ -14,10 +14,6 @@ Run `ng generate component component-name` to generate a new component. You can Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. -## Running unit tests - -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). - ## Running end-to-end tests Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). diff --git a/examples/custom-webpack/sanity-app/angular.json b/examples/custom-webpack/sanity-app/angular.json index bd10e5d1a6..40a6cff3be 100644 --- a/examples/custom-webpack/sanity-app/angular.json +++ b/examples/custom-webpack/sanity-app/angular.json @@ -96,26 +96,6 @@ "buildTarget": "sanity-app:build" } }, - "test": { - "builder": "@angular-builders/custom-webpack:karma", - "options": { - "polyfills": [ - "zone.js", - "zone.js/testing" - ], - "tsConfig": "tsconfig.spec.json", - "inlineStyleLanguage": "scss", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/assets" - ], - "styles": [ - "src/styles.scss" - ], - "scripts": [] - } - }, "e2e": { "builder": "@cypress/schematic:cypress", "options": { diff --git a/examples/custom-webpack/sanity-app/karma.conf.js b/examples/custom-webpack/sanity-app/karma.conf.js deleted file mode 100644 index bf6cc86657..0000000000 --- a/examples/custom-webpack/sanity-app/karma.conf.js +++ /dev/null @@ -1,60 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -const path = require('path'); -const fs = require('fs'); -// Prefer the system Chrome (preinstalled and library-matched on CI runners); fall back to -// Puppeteer's bundled Chrome for local dev. Puppeteer's bundled binary stopped launching on -// updated CI runner images ("Cannot start ChromeHeadless"), so system Chrome is more robust. -process.env.CHROME_BIN = - [ - '/usr/bin/google-chrome', - '/usr/bin/google-chrome-stable', - '/usr/bin/chromium-browser', - '/usr/bin/chromium', - ].find(p => fs.existsSync(p)) || require('puppeteer').executablePath(); - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - client: { - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - coverageReporter: { - dir: path.join(__dirname, 'coverage', 'append-webpack-plugins'), - subdir: '.', - reporters: [ - { type: 'text-summary' }, - { type: 'html', subdir: 'html' }, - { type: 'lcovonly' }, - { type: 'json' }, - ], - }, - reporters: ['progress', 'kjhtml', 'coverage'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - flags: ['--disable-translate', '--disable-extensions'], - browsers: ['Chrome'], - browserConsoleLogOptions: { - terminal: false, - }, - customLaunchers: { - ChromeHeadlessCI: { - base: 'ChromeHeadless', - flags: ['--no-sandbox', '--disable-gpu', '--disable-translate', '--disable-extensions'], - }, - }, - singleRun: true, - restartOnFileChange: true, - }); -}; diff --git a/examples/custom-webpack/sanity-app/package.json b/examples/custom-webpack/sanity-app/package.json index 3832bf7ace..5bdb90515f 100644 --- a/examples/custom-webpack/sanity-app/package.json +++ b/examples/custom-webpack/sanity-app/package.json @@ -4,7 +4,6 @@ "scripts": { "start": "ng serve", "build": "ng build", - "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", "cypress:open": "cypress open", @@ -32,18 +31,10 @@ "@angular/compiler-cli": "21.2.15", "@angular/language-service": "21.2.15", "@eslint/js": "10.0.1", - "@types/jasmine": "6.0.0", "@types/node": "24.12.4", "angular-eslint": "21.4.0", "cypress": "15.16.0", "eslint": "10.4.1", - "jasmine-core": "6.2.0", - "karma": "6.4.4", - "karma-chrome-launcher": "3.2.0", - "karma-coverage": "2.2.1", - "karma-jasmine": "5.1.0", - "karma-jasmine-html-reporter": "2.2.0", - "puppeteer": "24.43.1", "ts-node": "10.9.2", "typescript": "5.9.3", "typescript-eslint": "8.60.0" diff --git a/packages/custom-webpack/.gitignore b/packages/custom-webpack/.gitignore index de75b46351..b7f8d48dfa 100644 --- a/packages/custom-webpack/.gitignore +++ b/packages/custom-webpack/.gitignore @@ -13,7 +13,6 @@ package dist **/schema.json *.js -!karma.conf.js !*webpack.config.js !*index-html.transform.js *.js.map diff --git a/packages/custom-webpack/AGENTS.md b/packages/custom-webpack/AGENTS.md index 45914f8a3b..cee824adc5 100644 --- a/packages/custom-webpack/AGENTS.md +++ b/packages/custom-webpack/AGENTS.md @@ -7,7 +7,7 @@ | | | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Type** | Self-contained Package | -| **Owns** | `@angular-builders/custom-webpack` -- browser, server, dev-server, karma, and extract-i18n builders with webpack config injection | +| **Owns** | `@angular-builders/custom-webpack` -- browser, server, dev-server, and extract-i18n builders with webpack config injection | | **Does NOT own** | The webpack build pipeline itself (delegated to `@angular-devkit/build-angular`), esbuild-based builds | | **Lifecycle** | Maintained as long as Angular supports webpack builders. When Angular drops webpack, this package follows suit. (Source: SME interview, Jeb, 2026-02-16) | | **Users** | Angular developers who need custom webpack configuration without ejecting from the CLI | @@ -20,11 +20,10 @@ ## Entry Points & Contracts -Five builders registered in `builders.json`: +Four builders registered in `builders.json`: - **`browser`** (`src/browser/index.ts`) -- Wraps `executeBrowserBuilder`. - **`server`** (`src/server/index.ts`) -- Wraps `executeServerBuilder`. -- **`karma`** (`src/karma/index.ts`) -- Wraps `executeKarmaBuilder`. - **`extract-i18n`** (`src/extract-i18n/index.ts`) -- Wraps `executeExtractI18nBuilder`. - **`dev-server`** (`src/dev-server/index.ts`) -- Wraps `executeDevServerBuilder` via `executeBrowserBasedBuilder`. @@ -51,8 +50,8 @@ The `dev-server` and `extract-i18n` builders use `executeBrowserBasedBuilder` -- This package extends Angular's base builder schemas with custom properties. During build: 1. `tsc` compiles TypeScript -2. `merge-schemes.ts` (repo root) reads `src/schemes.ts` which defines five schema merge operations -3. Each merge takes an Angular base schema (from `@angular-devkit/build-angular`), applies extensions (including the shared `src/schema.ext.json` for browser/server/karma), and writes merged schemas to `dist/*/schema.json` +2. `merge-schemes.ts` (repo root) reads `src/schemes.ts` which defines four schema merge operations +3. Each merge takes an Angular base schema (from `@angular-devkit/build-angular`), applies extensions (including the shared `src/schema.ext.json` for browser/server), and writes merged schemas to `dist/*/schema.json` Unlike `custom-esbuild`, this package resolves schemas directly via Node resolution (no `originalSchemaPackage` needed) because `@angular-devkit/build-angular` exports its schema files. @@ -64,7 +63,7 @@ Unlike `custom-esbuild`, this package resolves schemas directly via Node resolut **MUST:** Plugin merging uses lodash `merge` by default (deep merge matching plugins by `constructor.name` string equality). Three methods exist (see `src/webpack-config-merger.ts` lines 26-39): (1) **Default merge** -- plugins of the same class have options deep-merged. (2) **Complete replacement** -- set `replaceDuplicatePlugins: true`; user plugin replaces the matching base plugin entirely. (3) **Factory function** -- bypasses merge entirely, user has full programmatic control. Spec tests at lines 6-33 and 77-118 confirm these behaviors. (Source: code investigation, 2026-02-16) -**MUST NEVER:** Add custom properties to schema extensions without also adding them to the shared `src/schema.ext.json` (for properties shared across browser/server/karma) or the builder-specific `src/{builder}/schema.ext.json`. +**MUST NEVER:** Add custom properties to schema extensions without also adding them to the shared `src/schema.ext.json` (for properties shared across browser/server) or the builder-specific `src/{builder}/schema.ext.json`. **MUST NEVER:** Accidentally clobber Angular's critical webpack plugins during merge -- this breaks builds silently. Duplicate or conflicting loader rules cause subtle compilation issues. These are the two most dangerous merge failure modes. (Source: SME interview, Jeb, 2026-02-16) @@ -128,5 +127,5 @@ Verify: `webpack-config-merger.spec.ts` covers merge rules, plugin replacement, ## Dependencies -**Breaks if changed:** Users' `angular.json` referencing `@angular-builders/custom-webpack:browser`, `:server`, `:dev-server`, `:karma`, `:extract-i18n` +**Breaks if changed:** Users' `angular.json` referencing `@angular-builders/custom-webpack:browser`, `:server`, `:dev-server`, `:extract-i18n` **Breaks us if changed:** `@angular-devkit/build-angular` (builder functions + schema structure), `@angular/build` (`IndexHtmlTransform` type), `@angular-builders/common` (module loading), `webpack-merge`, `lodash`, `@angular-devkit/architect` diff --git a/packages/custom-webpack/README.md b/packages/custom-webpack/README.md index 16af93d76f..f8930be5cc 100644 --- a/packages/custom-webpack/README.md +++ b/packages/custom-webpack/README.md @@ -13,7 +13,6 @@ Allow customizing build configuration without ejecting webpack configuration (`n - [Custom Webpack `dev-server`](#custom-webpack-dev-server) - [Example](#example) - [Custom Webpack `server`](#custom-webpack-server) - - [Custom Webpack `karma`](#custom-webpack-karma) - [Custom Webpack `extract-i18n`](#custom-webpack-extract-i18n) - [Example](#example-1) - [Custom Webpack Config Object](#custom-webpack-config-object) @@ -30,7 +29,6 @@ Allow customizing build configuration without ejecting webpack configuration (`n > ⚠️ **Version alignment:** The major version of `@angular-builders/custom-webpack` must match the major version of `@angular/core` in your project. For example, Angular 19 requires `@angular-builders/custom-webpack@19.x`, Angular 20 requires `@angular-builders/custom-webpack@20.x`, etc. Using a mismatched version is the most common source of issues. - ## Previous versions
@@ -71,7 +69,7 @@ Allow customizing build configuration without ejecting webpack configuration (`n "architect": { ... "[architect-target]": { - "builder": "@angular-builders/custom-webpack:[browser|server|karma|dev-server|extract-i18n]", + "builder": "@angular-builders/custom-webpack:[browser|server|dev-server|extract-i18n]", "options": { ... } @@ -79,7 +77,7 @@ Allow customizing build configuration without ejecting webpack configuration (`n Where: - [project] is the name of the project to which you want to add the builder - [architect-target] is the name of build target you want to run (build, serve, test etc. or any custom target) - - [browser|server|karma|dev-server|extract-i18n] one of the supported builders - [browser](#Custom-webpack-browser), [server](#Custom-webpack-server), [karma](#Custom-webpack-Karma), [dev-server](#Custom-webpack-dev-server) or [extract-i18n](#Custom-webpack-extract-i18n) + - [browser|server|dev-server|extract-i18n] one of the supported builders - [browser](#Custom-webpack-browser), [server](#Custom-webpack-server), [dev-server](#Custom-webpack-dev-server) or [extract-i18n](#Custom-webpack-extract-i18n) 3. If `[architect-target]` is not one of the predefined targets (like build, serve, test etc.) then run it like this: `ng run [project]:[architect-target]` If it is one of the predefined targets, you can run it with `ng [architect-target]` @@ -106,7 +104,6 @@ Allow customizing build configuration without ejecting webpack configuration (`n - [@angular-builders/custom-webpack:browser](#Custom-webpack-browser) - [@angular-builders/custom-webpack:server](#Custom-webpack-server) -- [@angular-builders/custom-webpack:karma](#Custom-webpack-Karma) - [@angular-builders/custom-webpack:dev-server](#Custom-webpack-dev-server) - [@angular-builders/custom-webpack:extract-i18n](#Custom-webpack-extract-i18n) @@ -216,58 +213,6 @@ Builder options: In this example `module.rules` entry from `extra-webpack.config.js` will be prepended to `module.rules` entry from Angular CLI underlying webpack config while all the rest will be appended. Since loaders are evaluated [from right to left](https://webpack.js.org/concepts/loaders/#configuration) this will effectively mean that the loaders you define in your custom configuration will be applied **after** the loaders defined by Angular CLI. -## Custom Webpack `karma` - -Extended `@angular-devkit/build-angular:karma` builder that allows to specify additional webpack configuration (on top of the existing under the hood) and `index.html` transformations. -The builder will run the same build as `@angular-devkit/build-angular:karma` does with extra parameters that are specified in the provided webpack configuration. - -Builder options: - -- All the `@angular-devkit/build-angular:karma` options -- `customWebpackConfig`: [see below](#custom-webpack-config-object) - -`angular.json` Example: - -```js -"architect": { - ... - "test": { - "builder": "@angular-builders/custom-webpack:karma", - "options": { - "customWebpackConfig": { - "path": "./extra-webpack.config.js" - }, - "main": "src/test.ts", - "polyfills": ["zone.js"], - "tsConfig": "src/tsconfig.spec.json", - "karmaConfig": "src/karma.conf.js", - } -``` - -External `karma.conf.js` configuration: - -Starting with Angular v20, generating an [external karma config](https://angular.dev/guide/testing#configuration) will cause tests to hang while utilizing `@angular-builders/custom-webpack:karma`. - -Fix this by: -- adding `'@angular-devkit/build-angular'` to the `frameworks` array -- adding `'@angular-devkit/build-angular/plugins/karma'` to the `plugins` array - -`karma.conf.js` example: -```js -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - // ... -``` - ## Custom Webpack `extract-i18n` Enhanced `@angular-devkit/build-angular:extract-i18n` builder that leverages the custom webpack builder to get webpack configuration. @@ -416,7 +361,6 @@ You can check out an example for plugins merge in the [unit tests](./src/webpack > > For full control over the merge, use a [function export](#custom-webpack-config-function) — you receive the full base config and return a new one, bypassing automatic merge entirely. - ## Custom Webpack Promisified Config Webpack config can also export a `Promise` object that resolves custom config. Given the following example: diff --git a/packages/custom-webpack/builders.json b/packages/custom-webpack/builders.json index aab29e079a..5b617f7070 100644 --- a/packages/custom-webpack/builders.json +++ b/packages/custom-webpack/builders.json @@ -16,11 +16,6 @@ "schema": "./dist/dev-server/schema.json", "description": "Dev server extended with custom webpack config" }, - "karma": { - "implementation": "./dist/karma", - "schema": "./dist/karma/schema.json", - "description": "Karma server extended with custom webpack config" - }, "extract-i18n": { "implementation": "./dist/extract-i18n", "schema": "./dist/extract-i18n/schema.json", diff --git a/packages/custom-webpack/e2e/custom-webpack-karma-schema.spec.ts b/packages/custom-webpack/e2e/custom-webpack-karma-schema.spec.ts deleted file mode 100644 index 0a27a1fec2..0000000000 --- a/packages/custom-webpack/e2e/custom-webpack-karma-schema.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { customWebpackConfig, indexTransform } from './custom-webpack-config-schema'; - -describe('custom webpack karma builder test', () => { - let customWebpackBrowserSchema: any; - - beforeEach(() => { - jest.resetModules(); - customWebpackBrowserSchema = require('../dist/karma/schema.json'); - }); - - it('Should fit the schema of @angular-devkit/build-angular:karma', () => { - const originalBrowserSchema = require('@angular-devkit/build-angular/src/builders/karma/schema.json'); - customWebpackBrowserSchema.properties['customWebpackConfig'] = undefined; - customWebpackBrowserSchema.properties['indexTransform'] = undefined; - expect(originalBrowserSchema.properties).toEqual(customWebpackBrowserSchema.properties); - }); - - it('Should contain customWebpackConfig', () => { - expect(customWebpackBrowserSchema.properties.customWebpackConfig).toEqual(customWebpackConfig); - }); - - it('Should contain indexTransform', () => { - expect(customWebpackBrowserSchema.properties.indexTransform).toEqual(indexTransform); - }); -}); diff --git a/packages/custom-webpack/src/index.ts b/packages/custom-webpack/src/index.ts index 7d627ba864..ebefdea986 100644 --- a/packages/custom-webpack/src/index.ts +++ b/packages/custom-webpack/src/index.ts @@ -2,7 +2,6 @@ * Created by Evgeny Barabanov on 01/07/2018. */ export * from './browser'; -export * from './karma'; export * from './server'; export * from './dev-server'; export * from './extract-i18n'; diff --git a/packages/custom-webpack/src/karma/index.ts b/packages/custom-webpack/src/karma/index.ts deleted file mode 100644 index 6e962e9aee..0000000000 --- a/packages/custom-webpack/src/karma/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Created by Evgeny Barabanov on 05/10/2018. - */ - -import { BuilderContext, createBuilder } from '@angular-devkit/architect'; -import { executeKarmaBuilder, KarmaBuilderOptions } from '@angular-devkit/build-angular'; -import { json } from '@angular-devkit/core'; -import { customWebpackConfigTransformFactory } from '../transform-factories'; -import { CustomWebpackSchema } from '../custom-webpack-schema'; - -export type CustomWebpackKarmaBuildSchema = KarmaBuilderOptions & CustomWebpackSchema; - -export const buildCustomWebpackKarma = ( - options: CustomWebpackKarmaBuildSchema, - context: BuilderContext -): ReturnType => - executeKarmaBuilder(options, context, { - webpackConfiguration: customWebpackConfigTransformFactory(options, context), - }); - -export default createBuilder( - buildCustomWebpackKarma -); diff --git a/packages/custom-webpack/src/karma/schema.ext.json b/packages/custom-webpack/src/karma/schema.ext.json deleted file mode 100644 index 50b65a7b13..0000000000 --- a/packages/custom-webpack/src/karma/schema.ext.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$id": "BuildCustomWebpackKarmaSchema", - "title": "Custom webpack karma schema for Build Facade", - "description": "Karma target options" -} diff --git a/packages/custom-webpack/src/schemes.ts b/packages/custom-webpack/src/schemes.ts index ed40aed70d..4fde5a86c2 100644 --- a/packages/custom-webpack/src/schemes.ts +++ b/packages/custom-webpack/src/schemes.ts @@ -10,11 +10,6 @@ module.exports = [ schemaExtensionPaths: [`${__dirname}/server/schema.ext.json`, `${__dirname}/schema.ext.json`], newSchemaPath: `${__dirname}/../dist/server/schema.json`, }, - { - originalSchemaPath: '@angular-devkit/build-angular/src/builders/karma/schema.json', - schemaExtensionPaths: [`${__dirname}/karma/schema.ext.json`, `${__dirname}/schema.ext.json`], - newSchemaPath: `${__dirname}/../dist/karma/schema.json`, - }, { originalSchemaPath: '@angular-devkit/build-angular/src/builders/dev-server/schema.json', schemaExtensionPaths: [`${__dirname}/dev-server/schema.ext.json`], diff --git a/packages/custom-webpack/tests/integration.js b/packages/custom-webpack/tests/integration.js index c16f6a56b0..c3a8ec8a1f 100644 --- a/packages/custom-webpack/tests/integration.js +++ b/packages/custom-webpack/tests/integration.js @@ -1,27 +1,4 @@ module.exports = [ - // Karma builder tests - { - id: 'karma-builder-sanity-app', - name: 'custom-webpack: Karma unit tests', - purpose: 'Karma builder executes unit tests with custom webpack config', - app: 'examples/custom-webpack/sanity-app', - command: 'yarn test --browsers=ChromeHeadlessCI', - }, - { - id: 'karma-builder-sanity-app-esm', - name: 'custom-webpack: Karma ESM package', - purpose: 'Karma builder works in ESM package', - app: 'examples/custom-webpack/sanity-app-esm', - command: 'yarn test --browsers=ChromeHeadlessCI', - }, - { - id: 'karma-builder-full-cycle', - name: 'custom-webpack: Karma full customization', - purpose: 'Karma builder works with full webpack customization', - app: 'examples/custom-webpack/full-cycle-app', - command: 'yarn test --browsers=ChromeHeadlessCI', - }, - // Browser/dev-server builder tests { id: 'browser-builder-basic', @@ -100,7 +77,8 @@ module.exports = [ { id: 'ts-config-bundler-module-resolution', name: 'custom-webpack: TS config with moduleResolution:bundler imports', - purpose: 'Builder loads TypeScript webpack config that uses subpath exports requiring moduleResolution:bundler (regression for #2025)', + purpose: + 'Builder loads TypeScript webpack config that uses subpath exports requiring moduleResolution:bundler (regression for #2025)', app: 'examples/custom-webpack/full-cycle-app', command: 'yarn build -c bundler-resolution-ts', }, diff --git a/yarn.lock b/yarn.lock index ecca52a911..819b8148ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1226,7 +1226,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.27.4": +"@babel/core@npm:^7.23.9, @babel/core@npm:^7.27.4": version: 7.28.5 resolution: "@babel/core@npm:7.28.5" dependencies: @@ -1609,7 +1609,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.3, @babel/parser@npm:^7.28.4, @babel/parser@npm:^7.28.5": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.3, @babel/parser@npm:^7.28.4, @babel/parser@npm:^7.28.5": version: 7.28.5 resolution: "@babel/parser@npm:7.28.5" dependencies: @@ -13565,19 +13565,11 @@ __metadata: "@angular/platform-browser-dynamic": 21.2.15 "@angular/router": 21.2.15 "@eslint/js": 10.0.1 - "@types/jasmine": 6.0.0 "@types/node": 24.12.4 angular-eslint: 21.4.0 cypress: 15.16.0 eslint: 10.4.1 html-webpack-plugin: 5.6.7 - jasmine-core: 6.2.0 - karma: 6.4.4 - karma-chrome-launcher: 3.2.0 - karma-coverage: 2.2.1 - karma-jasmine: 5.1.0 - karma-jasmine-html-reporter: 2.2.0 - puppeteer: 24.43.1 rxjs: 7.8.2 ts-node: 10.9.2 tslib: 2.8.1 @@ -14902,19 +14894,6 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-instrument@npm:^5.1.0": - version: 5.2.1 - resolution: "istanbul-lib-instrument@npm:5.2.1" - dependencies: - "@babel/core": ^7.12.3 - "@babel/parser": ^7.14.7 - "@istanbuljs/schema": ^0.1.2 - istanbul-lib-coverage: ^3.2.0 - semver: ^6.3.0 - checksum: bf16f1803ba5e51b28bbd49ed955a736488381e09375d830e42ddeb403855b2006f850711d95ad726f2ba3f1ae8e7366de7e51d2b9ac67dc4d80191ef7ddf272 - languageName: node - linkType: hard - "istanbul-lib-report@npm:^3.0.0": version: 3.0.1 resolution: "istanbul-lib-report@npm:3.0.1" @@ -14939,17 +14918,6 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-source-maps@npm:^4.0.1": - version: 4.0.1 - resolution: "istanbul-lib-source-maps@npm:4.0.1" - dependencies: - debug: ^4.1.1 - istanbul-lib-coverage: ^3.0.0 - source-map: ^0.6.1 - checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 - languageName: node - linkType: hard - "istanbul-lib-source-maps@npm:^5.0.0": version: 5.0.6 resolution: "istanbul-lib-source-maps@npm:5.0.6" @@ -14961,7 +14929,7 @@ __metadata: languageName: node linkType: hard -"istanbul-reports@npm:^3.0.2, istanbul-reports@npm:^3.0.5, istanbul-reports@npm:^3.1.3": +"istanbul-reports@npm:^3.0.2, istanbul-reports@npm:^3.1.3": version: 3.2.0 resolution: "istanbul-reports@npm:3.2.0" dependencies: @@ -15910,20 +15878,6 @@ __metadata: languageName: node linkType: hard -"karma-coverage@npm:2.2.1": - version: 2.2.1 - resolution: "karma-coverage@npm:2.2.1" - dependencies: - istanbul-lib-coverage: ^3.2.0 - istanbul-lib-instrument: ^5.1.0 - istanbul-lib-report: ^3.0.0 - istanbul-lib-source-maps: ^4.0.1 - istanbul-reports: ^3.0.5 - minimatch: ^3.0.4 - checksum: 72ba4363507a0fee7e5b67d9293f54d64d33f25ad20d39c63a14098a7f67890fbada67433743bedf71e0ccbf6a074013867410e542f7438149a9576eb36ee1f8 - languageName: node - linkType: hard - "karma-jasmine-html-reporter@npm:2.2.0": version: 2.2.0 resolution: "karma-jasmine-html-reporter@npm:2.2.0" @@ -19769,16 +19723,8 @@ __metadata: "@angular/platform-browser-dynamic": 21.2.15 "@angular/router": 21.2.15 "@cypress/schematic": 5.0.0 - "@types/jasmine": 6.0.0 "@types/node": 24.12.4 cypress: 15.16.0 - jasmine-core: 6.2.0 - karma: 6.4.4 - karma-chrome-launcher: 3.2.0 - karma-coverage: 2.2.1 - karma-jasmine: 5.1.0 - karma-jasmine-html-reporter: 2.2.0 - puppeteer: 24.43.1 rxjs: 7.8.2 tslib: 2.8.1 typescript: 5.9.3 @@ -19805,18 +19751,10 @@ __metadata: "@angular/platform-browser-dynamic": 21.2.15 "@angular/router": 21.2.15 "@eslint/js": 10.0.1 - "@types/jasmine": 6.0.0 "@types/node": 24.12.4 angular-eslint: 21.4.0 cypress: 15.16.0 eslint: 10.4.1 - jasmine-core: 6.2.0 - karma: 6.4.4 - karma-chrome-launcher: 3.2.0 - karma-coverage: 2.2.1 - karma-jasmine: 5.1.0 - karma-jasmine-html-reporter: 2.2.0 - puppeteer: 24.43.1 rxjs: 7.8.2 ts-node: 10.9.2 tslib: 2.8.1 @@ -20079,7 +20017,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.3.0, semver@npm:^6.3.1": +"semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: