serve: with NG_HMR_CSTYLES=1, component stylesheets not touched by the last change revert to first-build content after a rebuild
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 52/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- angular, sass, typescript
- Lĩnh vực
- build-system, devtools
Hướng nghiên cứu
Reproduce the issue with the supplied minimal Angular application and edit sequence, then inspect @angular/build/src/builders/application/execute-build.js around externalRuntimeStyles and componentStyleBundler. Trace how incremental results reach the dev-server asset map, including bundler caching and result merging. Done means every served component stylesheet reflects the latest successful source state after each rebuild, with regression coverage.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Command
serve
Is this a regression?
Unknown. I have only tested 22.2.1.
Description
With NG_HMR_CSTYLES=1 (link-based component style hot reloading), ng serve emits component stylesheets as external /<hash>.css?ngcomp=... links. After a rebuild, the dev server serves fresh content only for the stylesheet(s) affected by that change. Every other component stylesheet is served with its content from the first build, dropping earlier edits that are still saved on disk.
Each check below is a fresh request for the page and its ?ngcomp links, so a freshly loaded page receives the stale content too.
Without the flag, the same edit sequence (steps c1 to c5) produces no stale stylesheet.
Hypothesis (unverified, from reading the code, not from debugging): in @angular/build/src/builders/application/execute-build.js, on every rebuild with externalRuntimeStyles the code runs
// TODO: Only attempt rebundling of invalidated styles once incremental build results are supported.
if (rebuildState && options.externalRuntimeStyles) {
componentStyleBundler.invalidate(rebuildState.fileChanges.all);
const componentResults = await componentStyleBundler.bundleAllFiles(true, true);
bundlingIndividualResults.push(...componentResults);
}
so only the invalidated sheets are re-bundled, and the sheets that are not invalidated seem to be served from their initial-build output rather than their last-built output. I have not confirmed which layer (bundler cache, result merging, or the dev server asset map) drops the later content.
Side observation, no claim about impact: with the flag, the SSR HTML contains no inline <style> tags for component styles (links only); without it, it contains one <style> per component.
Minimal Reproduction
pnpm dlx @angular/[email protected] new repro --ssr --style=scss --defaults --skip-git --package-manager=pnpm
cd repro
mkdir src/app/a src/app/b
src/app/_p.scss:
$color: red;
src/app/a/a.ts (and the same for src/app/b/b.ts with b/BComponent/app-b):
import { Component } from '@angular/core';
@Component({
selector: 'app-a',
template: '<p class="a">a</p>',
styleUrl: './style.scss',
})
export class AComponent {}
src/app/a/style.scss (and the same for b with .b/BASELINE-b):
@use '../p';
.a { color: p.$color; }
.BASELINE-a { order: 0; }
src/app/app.html:
<app-a />
<app-b />
src/app/app.ts: import AComponent and BComponent and add them to imports.
Serve with the flag:
NG_HMR_CSTYLES=1 pnpm exec ng serve --port 8094 --no-open
Helper that fetches the page, takes every ?ngcomp link and prints which marker classes each sheet contains (check.sh):
#!/bin/zsh
label=$1
html=$(curl -s http://localhost:8094/)
echo "--- $label"
echo "$html" | grep -oE 'href="[^"]*ngcomp[^"]*"' | sed -E 's/href="//; s/"$//; s/&/\&/g' | while read -r h; do
body=$(curl -s "http://localhost:8094/$h")
who=$(echo "$body" | grep -oE '^\.(a|b) ' | head -1 | tr -d ' .')
markers=$(echo "$body" | grep -oE '(BASELINE|MARK)-[A-Za-z0-9-]+' | tr '\n' ' ')
echo "$h sheet=${who:-empty(app)} markers: $markers"
done
Edit sequence (wait about 4 seconds after each edit for the rebuild, then run ./check.sh <label>):
./check.sh baseline
printf '.MARK-P1 { order: 1; }\n' >> src/app/_p.scss # c1: edit partial
printf '.MARK-P2 { order: 2; }\n' >> src/app/_p.scss # c2: edit partial again
printf '.MARK-A1 { order: 1; }\n' >> src/app/a/style.scss # c3: edit sheet A only
printf '.MARK-P3 { order: 3; }\n' >> src/app/_p.scss # c4: edit partial again
printf '.MARK-B1 { order: 1; }\n' >> src/app/b/style.scss # c5: edit sheet B only
printf '.MARK-A2 { order: 2; }\n' >> src/app/a/style.scss # c6: edit sheet A only
Observed with NG_HMR_CSTYLES=1 (markers present in each served sheet; all edits are saved on disk):
| step | sheet A (a/style.scss) |
sheet B (b/style.scss) |
|---|---|---|
| baseline | BASELINE-a | BASELINE-b |
c1 edit _p.scss |
P1 BASELINE-a | P1 BASELINE-b |
c2 edit _p.scss |
P1 P2 BASELINE-a | P1 P2 BASELINE-b |
| c3 edit A only | P1 P2 BASELINE-a A1 | BASELINE-b (lost P1, P2) |
c4 edit _p.scss |
P1 P2 P3 BASELINE-a A1 | P1 P2 P3 BASELINE-b |
| c5 edit B only | BASELINE-a (lost P1 P2 P3 A1) | P1 P2 P3 BASELINE-b B1 |
| c6 edit A only | P1 P2 P3 BASELINE-a A1 A2 | BASELINE-b (lost P1 P2 P3 B1) |
(Marker names abbreviated: P1 is MARK-P1, etc. At c5 and c6 the partial still contains P1, P2 and P3 on disk.)
Control: steps c1 to c5 without NG_HMR_CSTYLES (component styles inlined in the SSR HTML, no ngcomp links). Every step shows all markers present in both sheets, e.g. after c3 sheet B has MARK-P1 MARK-P2 BASELINE-b, after c5 sheet A has MARK-P1 MARK-P2 MARK-P3 BASELINE-a MARK-A1 and sheet B has MARK-P1 MARK-P2 MARK-P3 BASELINE-b MARK-B1.
Expected: after each rebuild every served component stylesheet reflects the current content of its sources (the latest successful build), not only the stylesheets touched by the latest change.
Actual: untouched sheets revert to their first-build content until they are touched again.
Exception or Error
No error is reported by the dev server. Its log only says Component stylesheet(s) changed. and Stylesheet update sent to client(s)..
Your Environment
Angular CLI : 22.2.1
Angular : 22.2.1
Node.js : 26.7.0
Package Manager : pnpm 10.30.2
Operating System : darwin arm64
@angular/build : 22.2.1
@angular/cli : 22.2.1
@angular/common : 22.2.1
@angular/compiler : 22.2.1
@angular/compiler-cli : 22.2.1
@angular/core : 22.2.1
@angular/platform-browser : 22.2.1
@angular/platform-server : 22.2.1
@angular/router : 22.2.1
@angular/ssr : 22.2.1
rxjs : 7.8.2
typescript : 6.0.3
Anything else relevant?
Stylesheets were checked with curl against the dev server (a fresh request per step), not in a browser, so I have not observed the visual effect in a browser. macOS (Darwin 25.x, arm64).
- Ngôn ngữ chính
- TypeScript
- Star
- 27k
- Fork
- 11.8k
- Merge trung bình
- 1 ngày 2 phút
- Pull request đã merge (30 ngày)
- 168
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của angular/angular-cli
-
Can't use an array of hostnames in --allowedHosts cli parameter in @angular/build:dev-serverĐang mởarea: @angular/build gemini-triaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
angular/angular-cli#33955 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area: @angular/cli gemini-triaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
angular/angular-cli#33055 · 1 bình luận · 3 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
dev-server: es2016 prebundle target for zone.js apps lowers private fields and breaks dependenciesĐang mởarea: @angular/build
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
angular/angular-cli#34280 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Follow-up to issue: SSR: Add a way to configure externalDependencies for the server bundle onlyĐang mởarea: @angular/build
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
angular/angular-cli#34262 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Vite dev server: proxy config normalization reorders glob keys, drops string `context` and misses URLs with a query stringCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mởarea: @angular/build
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 65/100
angular/angular-cli#34257 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của angular/angular-cli
Issue tương tự
-
Flaky: mongodb-memory-server 'Port already in use' when another process starts a mongod concurrentlyĐang mởarea:testing bug effort:S priority:P2
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Maintainer thường phản hồi trong vòng 1 ngày
-
lens:agent lens:process process
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
thebristolsound/birdbrain#1772 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug priority:low ready-for-dev
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Automattic/data-liberation-agent#685 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Business
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
Maintainer thường phản hồi trong vòng 1 ngày