Repository navigation
Compiler roots and lifecycle handoffs fail across Angular compilation modes and Vite versions #2518
Description
Please provide the environment you discovered this bug in.
- Analog:
3.0.0-alpha.86, upstreamalphaat4225f45090a4cf4bdfb562a788e908787b6ec73c. - Reproduced locally on Linux with Node
24.15.0and pnpm10.33.0. - Base workspace: Angular compiler
22.0.0, Vite8.0.8, Vitest4.1.4. - Reproduction commit containing tests against the unchanged implementation.
git clone --branch fix/compiler-vite-compat https://github.com/benpsnyder/analog.git analog-compiler-repro
cd analog-compiler-repro
git checkout 5277af9f7547e95cc4cebaec9cb05085a23e8647
pnpm install --frozen-lockfile --ignore-scripts
NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx test vite-plugin-angular --testFiles=src/lib/compiler-roots.spec.ts --watch=false --skipNxCacheUse Node 24.15.0 for these commands. --ignore-scripts avoids the workspace-wide prepare build; the focused test builds its own temporary library. No hosted application or credentials are required.
Which area/package is the issue in?
vite-plugin-angular, with the shared package declaration emitter as supporting build infrastructure.
Description
This is the dedicated compiler workstream requested in Brandon's review of analogjs/analog#2516. It separates compiler behavior and compatibility from the workspace/Vitest upgrade, platform SSR, server-function transport, Query lifetimes, and streaming work.
The smallest consumer example is a Vite library that replaces a component file with one outside the original TypeScript roots:
angular({
tsconfig: 'tsconfig.json',
jit: false,
fileReplacements: [
{ replace: 'src/original.ts', with: 'src/replacement.ts' },
],
});When tsconfig.json includes only the original configured entry, the replacement must still be part of Angular's program. The real-build regression instead receives JavaScript with __decorate and the original Component decorator, without defineComponent: compilation fell through to a generic TypeScript transform. The experimental Compilation API also loses integration-provided roots.
The focused tests expose related handoff failures:
| Trigger | Observed behavior | Expected behavior |
|---|---|---|
A third source of compiler roots is passed to union |
Replacement or integration files are dropped because union accepts two arrays |
Preserve and deduplicate every configured source of roots |
| Production dependency optimization on the Rolldown path | Lifecycle ownership occupies the isTest argument, disabling transformation |
Treat test mode and transformer ownership separately |
| Transform arrives before initial compilation settles | Transform returns undefined instead of emitted Angular output |
Wait for the in-flight compilation |
| Experimental HMR updates a Vite 8 mixed module | Writing the getter-only isSelfAccepting property throws |
Update the client environment's module |
| Library compilation enables declarations inside Angular's Compilation API | Invalid inline-source options or declaration text replacing JavaScript output | Retain usable JavaScript; run library declaration generation separately |
| Plugin setup or stylesheet processing throws | The contextual error loses its original cause |
Preserve cause identity along with plugin/file context |
| A type-only source changes between package builds | The existing declaration is retained with the old interface member | Refresh declarations on every build |
Additional focused tests can be selected with:
NX_DAEMON=false NX_NO_CLOUD=true pnpm exec nx test vite-plugin-angular --testFiles=src/lib/compilation-api/compilation-api-plugin.spec.ts,src/lib/analog-plugin-interop.spec.ts,src/lib/oxc-dts-plugin.spec.ts --watch=false --skipNxCachePlease provide the exception or error you saw
TypeError: Cannot set property isSelfAccepting of #<Object> which has only a getter
AssertionError: expected undefined to match object { code: 'export const value = 1;' }
AssertionError: expected declaration output containing 'first?: boolean' to contain 'second?: string'
TS5051: Option 'inlineSources' can only be used when either '--inlineSourceMap' or '--sourceMap' is provided.
Other information
Implementation is published in analogjs/analog#2520, targeting alpha. Current head e767273de6e3b8589b39c815ccdae4db1a6b7e62 passes the compiler/conformance matrix, nine installed Angular/Vite consumer jobs, browser HMR, Windows, and main CI. The PR documents its tested compilation modes, examples, and shared route-policy prerequisite. The reproduction above remains pinned to the original failing implementation; this issue stays open pending merge.
Acceptance criteria for the focused PR:
- Preserve normal compilation and explicitly test the experimental option enabled and disabled.
- Verify test/watch behavior and externally owned Astro transformer cleanup.
- Exercise actual installed packages with Vite 6, 7, and 8 and supported Angular versions, alongside compiler conformance/API tests.
- Verify normal and fast full/partial compilation, compiler roots, emitted JavaScript, and repeated declaration builds.
- Make unavailable experimental APIs fail during configuration with an actionable diagnostic; do not infer availability from the Angular version alone.
- Include the reproduction, package typecheck/build/lint tests, compatibility CI, and concise documentation in this PR.
The workspace/Vitest 5 migration continues separately in analogjs/analog#2508. The environment and failure evidence above describe the pinned baseline; current compatibility results are recorded in the linked compiler PR.
I would be willing to submit a PR to fix this issue
- Yes
Prepared with OpenAI Codex; findings were checked against local source and executable regressions.
Activity
fix(vite-plugin-angular): preserve compiler roots and lifecycle acros…