Debug ID changes the bytes of an optimized chunk but not its file name, so cached files fail the SRI check
Les mainteneurs répondent en général sous 1 jour
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 55/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- angular, typescript
- Domaine
- build-system
Piste de recherche
Start in execute-post-bundle.ts, where injectDebugIds changes output bytes, and chunk-optimizer.ts, where Rolldown assigns hashed chunk names. Trace how the chunk hash is computed and how debug IDs are injected, then check the build tests for optimized chunks and source maps. Done means a changed chunk byte sequence gets a different filename, including when only its source map changes.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Command
build
Is this a regression?
- Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
22.0.x
Description
Since 22.1.0 (#33110), the application builder adds a //# debugId=<uuid> line to each browser JS file when script source maps are enabled. The ID comes from the bytes of the source map.
When the chunk optimizer runs (by default when the build has 3 or more lazy chunks), Rolldown gives the chunks their final file names. The [hash] in these names covers the code of the chunk only. It does not cover the source map. The debugId line is added after that.
A change that keeps the JS code of a chunk the same but changes its source map (for example, a change to a TypeScript type or to a comment) gives this result for a chunk that does not import other chunks:
- The file name stays the same.
- The debugId changes, because the source map changed.
- The file bytes change, because the debugId line changed.
- The SRI hash in
index.htmlchanges to match the new bytes.
In one build, the HTML and the files match. Across two builds, the rule "same hashed file name means same content" is no longer true.
Hosting setups depend on this rule: they cache hashed files as immutable. Any cache can keep the file from the previous build: a CDN such as Cloudflare, the browser cache, or a proxy. That cache then serves the old bytes together with the new index.html. The integrity check fails, the browser blocks the file, and the modules in it do not load.
Before 22.1.0 there was no debugId line, so the bytes of a hashed file changed only when its name changed.
Expected behavior: if the bytes of a hashed output file change, its file name changes too.
Minimal Reproduction
Repository: https://github.com/virgiliojr/angular-debugid-sri-repro
The app is a plain ng new app (Angular CLI 22.2.2) with 3 lazy routes, so the chunk optimizer runs. lazy-a and lazy-b use src/app/shared/label.ts. This module has no imports, so it becomes its own chunk.
- Run
npm ci. - Run
npx ng build --source-map --subresource-integrity. - In
dist/repro/browser/, find the chunk that containslabel:. Write down its file name and its SHA-384. - In
src/app/shared/label.ts, addextra?: number;to theLabelInputinterface. This is a type-only change: the JS output oflabel.tsstays the same. - Run
npx ng build --source-map --subresource-integrityagain. - Find the chunk that contains
label:again.
bash compare-builds.sh in the repository does steps 2 to 6 and prints the result below.
Actual result:
Build 1
file name: chunk-z-ytF2G0.js
sha384 of bytes: sha384-Y7f5K4V0FTCrXc6JQ2tGE+VllRWg501EixeFEPMjNMboDgwfeRc9E6l8oHlqTbX5
debugId line: //# debugId=105cedd6-2603-584f-8e8d-7801d6020b96
sha in index.html: yes
Build 2
file name: chunk-z-ytF2G0.js
sha384 of bytes: sha384-bgCbCJmJexbhKCHeS4kpofe2lKBPWJ1f3JpK9668+/jD2mfiEYADUy5xD1Usr1dZ
debugId line: //# debugId=9c547775-c029-5af8-ba7e-25c70949f1b6
sha in index.html: yes
Diff of the chunk between the two builds:
2c2
< //# debugId=105cedd6-2603-584f-8e8d-7801d6020b96
---
> //# debugId=9c547775-c029-5af8-ba7e-25c70949f1b6
The file name is the same, but the bytes and the SRI hash in index.html are different.
Expected result: if the bytes are different, the file name is different too.
To see the failure in a browser, serve the output of build 2, but serve chunk-z-ytF2G0.js from build 1. This is what a cache does after a deployment.
Exception or Error
Failed to find a valid digest in the 'integrity' attribute for resource 'https://<host>/chunk-z-ytF2G0.js' with computed SHA-384 integrity '<hash>'. The resource has been blocked.
Your Environment
Angular CLI : 22.2.5
Angular : 22.2.3
Node.js : 24.18.0
Package Manager : npm 11.16.0
Operating System : darwin arm64
┌───────────────────────────┬───────────────────┬───────────────────┐
│ Package │ Installed Version │ Requested Version │
├───────────────────────────┼───────────────────┼───────────────────┤
│ @angular/build │ 22.2.5 │ ^22.2.2 │
│ @angular/cli │ 22.2.5 │ ^22.2.2 │
│ @angular/common │ 22.2.3 │ ^22.2.0 │
│ @angular/compiler │ 22.2.3 │ ^22.2.0 │
│ @angular/compiler-cli │ 22.2.3 │ ^22.2.0 │
│ @angular/core │ 22.2.3 │ ^22.2.0 │
│ @angular/forms │ 22.2.3 │ ^22.2.0 │
│ @angular/platform-browser │ 22.2.3 │ ^22.2.0 │
│ @angular/router │ 22.2.3 │ ^22.2.0 │
│ rxjs │ 7.8.2 │ ~7.8.0 │
│ typescript │ 6.0.3 │ ~6.0.2 │
└───────────────────────────┴───────────────────┴───────────────────┘
Anything else relevant?
This does not depend on the browser. Any cache in front of the hashed files can cause it.
The defect needs the chunk optimizer. With NG_BUILD_OPTIMIZE_CHUNKS=false, the same type change gives a new esbuild file name for the chunk (for example chunk-P54LQIKA.js to chunk-5HS55H7R.js), so the name and the bytes change together.
A chunk that imports other chunks usually gets a new name anyway, because the names of the chunks it imports change. A chunk without such imports keeps its name.
Related: #33108, #33110, #33572. The current main still has this behavior: injectDebugIds (called from execute-post-bundle.ts when sourcemapOptions.scripts is true) changes the file contents but does not change the file name. The Rolldown pass in chunk-optimizer.ts uses chunkFileNames: '<name>-[hash].js'.
- Langage dominant
- TypeScript
- Étoiles
- 27k
- Forks
- 11.8k
- Merge moyen
- 1 j 5 h
- PR mergées (30 j)
- 280
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de angular/angular-cli
-
Can't use an array of hostnames in --allowedHosts cli parameter in @angular/build:dev-serverPeut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouvertearea: @angular/build gemini-triaged
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
angular/angular-cli#33955 ·
Les mainteneurs répondent en général sous 1 jour
-
Allow tests to pass without any test files (e.g. via Vitest `passWithNoTests`)Peut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouvertearea: @angular/cli gemini-triaged
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
angular/angular-cli#33055 · 1 commentaire · 3 réactions ·
Les mainteneurs répondent en général sous 1 jour
-
@angular/build: source-map comment scanner corrupts valid JS containing a regex literalPeut-être pris @alan-agius4 l’a pris aujourd’hui. Ouvertearea: @angular/build
Difficulté 3/5 1-2 jours Accessibilité débutants 76/100
angular/angular-cli#34590 ·
Les mainteneurs répondent en général sous 1 jour
-
Angular SSR prerender params allow build-time SSRF, credential leaks, and open redirectsPeut-être pris @SkyZeroZx l’a pris il y a 1 jour. Ouvertearea: @angular/ssr
Difficulté 4/5 3-5 jours Accessibilité débutants 35/100
angular/angular-cli#34569 ·
Les mainteneurs répondent en général sous 1 jour
-
build: ERR_REQUIRE_CYCLE_MODULE when loading oxc-parser in StackBlitz / WebContainerPeut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouvertearea: @angular/build
Difficulté 3/5 1-2 jours Accessibilité débutants 55/100
angular/angular-cli#34524 · 5 commentaires · 2 réactions ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de angular/angular-cli
Issues similaires
-
b:minor bug
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
software-mansion/argent#1698 ·
Les mainteneurs répondent en général sous 1 jour
-
e2e-failure ready-to-code
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
redhat-developer/rhdh-plugin-export-overlays#4624 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
better-auth/better-auth#12132 · 1 réaction ·
Les mainteneurs répondent en général sous 1 jour
-
automation missing-model model-sync provider:tinfoil
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
anomalyco/models.dev#12053 ·
Les mainteneurs répondent en général sous 1 jour
-
o8 next debug build aborts on Glass to Dark appearance switch (nil identifier messaged before check)Ouvertebug
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
hurttlocker/o8#5112 ·