Tracking
Environment
| Question |
Answer |
| Tailwind version |
@tailwindcss/vite v4.2.2 |
| Build tool / framework |
Analog.js on Vite 8.0.3 with Angular 21 component stylesheets |
| Node.js |
v25.8.2 locally for investigation |
| Browser |
Chrome |
| Operating system |
macOS |
Reproduction
| Item |
Value |
| Public repro |
Branch-based repro harness: https://github.com/benpsnyder/analog/tree/fix/tailwind |
| Private repro characteristics |
Vite 8, @tailwindcss/vite 4.2.2, Analog.js / Angular component stylesheet HMR |
| Trigger |
edit a component .css file |
| Actual result |
targeted css-update is preceded by an earlier full-reload |
| Expected result |
no full page reload when a later plugin can handle the stylesheet through CSS HMR |
Manual branch-based repro:
git clone https://github.com/benpsnyder/analog.git
cd analog
git checkout fix/tailwind
pnpm install
pnpm exec nx serve tailwind-debug-app
Then edit apps/tailwind-debug-app/src/app/probes/style-probe.component.css and watch the captured HMR traffic in tmp/debug/tailwind-debug-app.vite-ws.log. On the failing path described here, the stylesheet save emits {"type":"full-reload"} before the later css-update payload(s).
Problem Statement
@tailwindcss/vite is forcing a full page reload for an Angular component stylesheet edit even though another plugin later handles the same file with targeted CSS HMR.
Investigation Summary
| Signal |
Finding |
| Outbound HMR payloads |
full-reload is emitted before the later CSS HMR updates |
| Filesystem timing |
only the component stylesheet changes in the relevant save window |
| Angular/Analog diagnostics |
the framework-side stylesheet path reports css-update, not reload fallback |
| Sender stack |
the full-reload originates in @tailwindcss/vite |
Evidence
App-side Vite wiretap
for (const [environmentName, environment] of Object.entries(server.environments)) {
const originalHotSend = environment.hot.send.bind(environment.hot)
environment.hot.send = ((payload: unknown) => {
const stack =
typeof payload === 'object' &&
payload !== null &&
'type' in payload &&
(payload as { type?: unknown }).type === 'full-reload'
? new Error(`[Adastra ENV HOT] ${environmentName} full-reload`).stack
: undefined
writeLog(wsLogPath, {
environmentName,
payload,
source: 'environment.hot.send',
stack,
})
return originalHotSend(payload as never)
}) as typeof environment.hot.send
}
Captured sender stack
Error: [Adastra ENV HOT] client full-reload
at Object.send (...vite.config.mts...mjs:101:136)
at MinimalPluginContext.hotUpdate (.../@tailwindcss/vite/dist/index.mjs:1:3436)
at handleHMRUpdate (.../vite/dist/node/chunks/node.js:26576:67)
at onHMRUpdate (.../vite/dist/node/chunks/node.js:26113:41)
at FSWatcher.<anonymous> (.../vite/dist/node/chunks/node.js:26138:9)
HMR sequence for one stylesheet save
| Order |
Event |
| 1 |
{"type":"full-reload"} from environment.hot.send |
| 2 |
browser receives full-reload |
| 3 |
browser then receives update payload(s) containing css-update |
Representative log excerpt:
2026-04-05T00:14:55.220Z {"environmentName":"client","payload":{"type":"full-reload"},"source":"environment.hot.send", ...}
2026-04-05T00:14:55.220Z {"type":"full-reload"}
2026-04-05T00:14:55.227Z {"environmentName":"client","payload":{"type":"update","updates":[{"type":"css-update", ...}]}}
2026-04-05T00:14:55.228Z {"environmentName":"client","payload":{"type":"update","updates":[{"type":"css-update", ...}]}}
File-level evidence
| Observation |
Value |
| changed file |
call-to-action.component.css |
| generated route files in same save window |
none observed |
| conclusion |
the reload is not being triggered by route generation or another generated application file |
Relevant Tailwind code path
let isExternalFile =
modules.length > 0 &&
modules.every((mod) => mod.type === 'asset' || mod.id === undefined)
if (!isExternalFile) return
if (!isScannedFile(file, modules, roots)) {
continue
}
if (env === this.environment.name) {
this.environment.hot.send({ type: 'full-reload' })
} else if (server.hot.send) {
server.hot.send({ type: 'full-reload' })
} else if (server.ws.send) {
server.ws.send({ type: 'full-reload' })
}
Why This Looks Upstream
| Observation |
Why it matters |
| Tailwind treats asset-only / missing-id modules as evidence that no plugin handles the file |
that assumption is false for this Angular component stylesheet pipeline |
Analog later emits a valid css-update for the same file |
proves the file is still in a handled stylesheet HMR path |
Analog diagnostics report outcome: 'css-update' |
the framework-side branch is not choosing reload as the preferred result |
Framework-side references:
Representative Analog diagnostic:
analog:angular:hmr:v component stylesheet hmr outcome {
file: '.../call-to-action.component.css',
outcome: 'css-update',
encapsulation: 'emulated',
preferredPath: 'css-update',
pitfalls: ['tracked-wrapper-missing-from-module-graph', 'no-owner-modules']
}
Expected vs Actual
|
Expected |
Actual |
| Angular component stylesheet edit |
preserve targeted CSS HMR when another plugin can handle it |
immediate full-reload from @tailwindcss/vite, then later css-update |
Likely Fix Direction
| Direction |
Reason |
narrow the isExternalFile full-reload branch |
reserve reloads for true non-module scanned files like HTML / PHP / template changes |
avoid forcing full-reload for CSS source files solely because modules are asset-only / missing-id |
CSS-like files may still be handled by another plugin's stylesheet HMR pipeline |
If useful, I can follow up with a minimal public reproduction repo and a proposed patch.
Tracking
Environment
@tailwindcss/vitev4.2.2Reproduction
@tailwindcss/vite4.2.2, Analog.js / Angular component stylesheet HMR.cssfilecss-updateis preceded by an earlierfull-reloadManual branch-based repro:
Then edit
apps/tailwind-debug-app/src/app/probes/style-probe.component.cssand watch the captured HMR traffic intmp/debug/tailwind-debug-app.vite-ws.log. On the failing path described here, the stylesheet save emits{"type":"full-reload"}before the latercss-updatepayload(s).Problem Statement
@tailwindcss/viteis forcing a full page reload for an Angular component stylesheet edit even though another plugin later handles the same file with targeted CSS HMR.Investigation Summary
full-reloadis emitted before the later CSS HMR updatescss-update, not reload fallbackfull-reloadoriginates in@tailwindcss/viteEvidence
App-side Vite wiretap
Captured sender stack
Error: [Adastra ENV HOT] client full-reload at Object.send (...vite.config.mts...mjs:101:136) at MinimalPluginContext.hotUpdate (.../@tailwindcss/vite/dist/index.mjs:1:3436) at handleHMRUpdate (.../vite/dist/node/chunks/node.js:26576:67) at onHMRUpdate (.../vite/dist/node/chunks/node.js:26113:41) at FSWatcher.<anonymous> (.../vite/dist/node/chunks/node.js:26138:9)HMR sequence for one stylesheet save
{"type":"full-reload"}fromenvironment.hot.sendfull-reloadupdatepayload(s) containingcss-updateRepresentative log excerpt:
2026-04-05T00:14:55.220Z {"environmentName":"client","payload":{"type":"full-reload"},"source":"environment.hot.send", ...} 2026-04-05T00:14:55.220Z {"type":"full-reload"} 2026-04-05T00:14:55.227Z {"environmentName":"client","payload":{"type":"update","updates":[{"type":"css-update", ...}]}} 2026-04-05T00:14:55.228Z {"environmentName":"client","payload":{"type":"update","updates":[{"type":"css-update", ...}]}}File-level evidence
call-to-action.component.cssRelevant Tailwind code path
Why This Looks Upstream
css-updatefor the same fileoutcome: 'css-update'Framework-side references:
css-update/ reload fallback loggingRepresentative Analog diagnostic:
analog:angular:hmr:v component stylesheet hmr outcome { file: '.../call-to-action.component.css', outcome: 'css-update', encapsulation: 'emulated', preferredPath: 'css-update', pitfalls: ['tracked-wrapper-missing-from-module-graph', 'no-owner-modules'] }Expected vs Actual
full-reloadfrom@tailwindcss/vite, then latercss-updateLikely Fix Direction
isExternalFilefull-reload branchfull-reloadfor CSS source files solely because modules are asset-only / missing-idIf useful, I can follow up with a minimal public reproduction repo and a proposed patch.