What happened?
The frontend production build and dev server run an older Angular build toolchain than the version the frontend manifest pins. The builder comes from a wrapper package that declares its own loose range for the Angular devkit. The lockfile resolves that range to the previous patch release, not the pinned one. So the build loads the older toolchain while the pinned copy sits at the workspace root, reachable only from the CLI's own paths.
Two consequences. Raising the devkit and CLI pins has no effect on the build that produces the shipped bundle. It fails silently: CI stays green, because the older toolchain is internally coherent. And the install tree carries two full copies of the toolchain rather than one.
Expected: the pinned devkit version is the one that compiles the app, and the toolchain is installed once.
This started when the pin moved off the version the wrapper's range had been sharing; before that, one lockfile entry served both. It has survived at least two subsequent Angular updates, so every bump of these two packages since has missed the build path the same way.
How to reproduce?
yarn --cwd frontend install
- Read the version of
frontend/node_modules/@angular-devkit/build-angular — it is the pinned one (currently 21.2.19).
- Read the version of
frontend/node_modules/@angular-builders/custom-webpack/node_modules/@angular-devkit/build-angular — it is 21.2.18.
frontend/angular.json routes both build and serve through @angular-builders/custom-webpack, so the copy from step 3 is the one that runs.
frontend/yarn.lock shows the same split for @angular/build and @ngtools/webpack. Running yarn dedupe in frontend/ collapses the ranges back onto the pinned versions, which confirms the diagnosis.
Version/Branch
1.3.0-incubating-SNAPSHOT (main)
Relevant log output
$ grep -n '^"@angular-devkit/build-angular@\|^"@angular/build@\|^"@ngtools/webpack@' frontend/yarn.lock
310:"@angular-devkit/build-angular@npm:21.2.19":
422:"@angular-devkit/build-angular@npm:^21.0.0": # resolves to 21.2.18
727:"@angular/build@npm:21.2.18, @angular/build@npm:^21.0.0":
808:"@angular/build@npm:21.2.19":
4531:"@ngtools/webpack@npm:21.2.18":
4542:"@ngtools/webpack@npm:21.2.19":
# installed tree
node_modules/@angular-devkit/build-angular 21.2.19
node_modules/@angular-builders/custom-webpack/node_modules/
@angular-devkit/build-angular 21.2.18
node_modules/@angular/build 21.2.18
node_modules/@ngtools/webpack 21.2.18
What happened?
The frontend production build and dev server run an older Angular build toolchain than the version the frontend manifest pins. The builder comes from a wrapper package that declares its own loose range for the Angular devkit. The lockfile resolves that range to the previous patch release, not the pinned one. So the build loads the older toolchain while the pinned copy sits at the workspace root, reachable only from the CLI's own paths.
Two consequences. Raising the devkit and CLI pins has no effect on the build that produces the shipped bundle. It fails silently: CI stays green, because the older toolchain is internally coherent. And the install tree carries two full copies of the toolchain rather than one.
Expected: the pinned devkit version is the one that compiles the app, and the toolchain is installed once.
This started when the pin moved off the version the wrapper's range had been sharing; before that, one lockfile entry served both. It has survived at least two subsequent Angular updates, so every bump of these two packages since has missed the build path the same way.
How to reproduce?
yarn --cwd frontend installfrontend/node_modules/@angular-devkit/build-angular— it is the pinned one (currently 21.2.19).frontend/node_modules/@angular-builders/custom-webpack/node_modules/@angular-devkit/build-angular— it is 21.2.18.frontend/angular.jsonroutes bothbuildandservethrough@angular-builders/custom-webpack, so the copy from step 3 is the one that runs.frontend/yarn.lockshows the same split for@angular/buildand@ngtools/webpack. Runningyarn dedupeinfrontend/collapses the ranges back onto the pinned versions, which confirms the diagnosis.Version/Branch
1.3.0-incubating-SNAPSHOT (main)
Relevant log output