Command
build
Description
Since upgrading to Angular 21, the new build pipeline leverages beasties to optimize asset loading by automatically processing all <link rel="stylesheet"> tags found in index.html. While this works for standard static assets, it completely breaks setups that rely on runtime stylesheet overrides (e.g., multi-tenant white-labeling via Docker volume mounts or runtime file replacement).
The Technical Failure Mechanism:
-
At Build Time (ng build):
The external customization stylesheet (e.g., custom-theme.css) either does not exist yet or is present only as an empty/dummy placeholder file.
- If the file is missing: The Angular build pipeline throws an error because
beasties attempts to perform static analysis on a non-existent local asset path.
- If the file is an empty placeholder:
beasties processes it, extracts no critical CSS, but mutates the original HTML tag to enforce its asynchronous loading strategy (e.g., altering attributes, changing media="print" with an onload handler, or injecting preprocessors).
-
At Runtime (Docker Deployment):
The administrator mounts or overwrites the actual, populated custom-theme.css into the container's dist folder.
- Because the
<link> tag was mutated/rewritten during the build phase by beasties, the browser handles the runtime-loaded sheet with modified priority or asynchronous wrappers. This introduces severe race conditions, Flash of Unstyled Content (FOUC), or layout shifts, as the runtime styles are no longer parsed synchronously as intended by the developer.
There is currently no granular way to tell @angular/build / beasties to completely ignore a specific <link> tag and leave it completely untouched in the final index.html.
Describe the solution you'd like
We need a granular way to tell beasties / @angular/build to ignore a specific stylesheet.
Ideally, adding a standard or dedicated attribute like ng-skip-inline, data-beasties-skip, or simply respecting a data-inline="false" attribute on the <link> tag should signal the builder to copy the tag exactly as-is without attempting to read, prune, mutate, or inline its contents:
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="custom-override.css" ng-skip-inline>
Describe alternatives you've considered
-
Disabling inlineCritical globally in angular.json: This fixes the Docker override issue but kills Core Web Vitals (FCP/LCP) optimizations for the rest of the application's actual global styles, which we do want beasties to inline.
-
Injecting the <link> tag dynamically via JavaScript:
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'custom-override.css';
document.head.appendChild(link);
While this successfully hides the link from beasties' static analysis during build, it's a runtime workaround for a configuration that should be handled cleanly at the compiler/build tool level.
Command
build
Description
Since upgrading to Angular 21, the new build pipeline leverages
beastiesto optimize asset loading by automatically processing all<link rel="stylesheet">tags found inindex.html. While this works for standard static assets, it completely breaks setups that rely on runtime stylesheet overrides (e.g., multi-tenant white-labeling via Docker volume mounts or runtime file replacement).The Technical Failure Mechanism:
At Build Time (
ng build):The external customization stylesheet (e.g.,
custom-theme.css) either does not exist yet or is present only as an empty/dummy placeholder file.beastiesattempts to perform static analysis on a non-existent local asset path.beastiesprocesses it, extracts no critical CSS, but mutates the original HTML tag to enforce its asynchronous loading strategy (e.g., altering attributes, changingmedia="print"with anonloadhandler, or injecting preprocessors).At Runtime (Docker Deployment):
The administrator mounts or overwrites the actual, populated
custom-theme.cssinto the container's dist folder.<link>tag was mutated/rewritten during the build phase bybeasties, the browser handles the runtime-loaded sheet with modified priority or asynchronous wrappers. This introduces severe race conditions, Flash of Unstyled Content (FOUC), or layout shifts, as the runtime styles are no longer parsed synchronously as intended by the developer.There is currently no granular way to tell
@angular/build/beastiesto completely ignore a specific<link>tag and leave it completely untouched in the finalindex.html.Describe the solution you'd like
We need a granular way to tell
beasties/@angular/buildto ignore a specific stylesheet.Ideally, adding a standard or dedicated attribute like
ng-skip-inline,data-beasties-skip, or simply respecting adata-inline="false"attribute on the<link>tag should signal the builder to copy the tag exactly as-is without attempting to read, prune, mutate, or inline its contents:Describe alternatives you've considered
Disabling
inlineCriticalglobally inangular.json: This fixes the Docker override issue but kills Core Web Vitals (FCP/LCP) optimizations for the rest of the application's actual global styles, which we do wantbeastiesto inline.Injecting the
<link>tag dynamically via JavaScript:While this successfully hides the link from
beasties' static analysis during build, it's a runtime workaround for a configuration that should be handled cleanly at the compiler/build tool level.