voidzero-dev / voidzero-dev/oxc-angular-compiler
fix(defer): emit lazy dependencies for components used only inside @defer blocks
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Rust
- Sterne
- 228
- Forks
- 20
- Ø Merge
- 1 T. 15 Std.
- Gemergte PRs (30 T.)
- 36
Beschreibung
Summary
Angular's @defer block is supposed to lazy-load any standalone component that appears only inside it — the user gets import().then(m => m.X) instead of an eager import at the top of the file. OXC currently emits these references through the regular dependencies factory, so @defer parses correctly but does not actually defer: the deferred component lands in the initial bundle and the lazy boundary is lost.
This is the default ngc behavior and is not opt-in via @Component.deferredImports — the recent bb2735b commit added the explicit-deferredImports path but the implicit detection is still missing.
Reference behavior
ngc at packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts:2344-2475 (collectDeferredSymbols / surrounding logic):
- Walks the component's template AST and collects every standalone import (
scope.directives,scope.pipes). - For each import, checks whether all references appear inside
DeferredBlocknodes — if so, the import is added toallDeferredDecls. - Routes those imports through
DeferBlockDepsEmitMode.PerComponent(orPerBlockfor fine-grained mode), producing lazyimport().then(...)resolvers instead of regular dependency entries. - The normal
dependenciesfactory is built from the non-deferred imports only.
Test that demonstrates the gap (in napi/angular-compiler/test/analog-compat/component.spec.ts:3262):
import { Component } from '@angular/core';
import { LazyCmp } from './lazy';
@Component({
selector: 'app-parent',
imports: [LazyCmp],
template: '@defer { <app-lazy/> }',
})
export class Parent {}
Expected output (matching ngc):
ɵcmp = ɵɵdefineComponent({
...,
dependencies: ɵɵgetComponentDepsFactory(Parent, []),
deferBlockDependencies: [() => import('./lazy').then(m => m.LazyCmp)],
});
Current OXC output:
ɵcmp = ɵɵdefineComponent({
...,
dependencies: ɵɵgetComponentDepsFactory(Parent, [LazyCmp]), // eager
});
Required work
- Defer-only detection — extend the existing template walk in
crates/oxc_angular_compiler/src/component/defer_resolver.rsto flag eachimports: [...]entry that is referenced only insideDeferredBlockAST nodes. - Route to lazy emit — currently
defer_resolver.rsonly handles@Component.deferredImports. Generalize it to also accept implicitly-deferred imports from step 1. - Emit
deferBlockDependencies— wire the lazyimport().then(m => m.X)resolver into thedefineComponentemit. Use original export name (not local alias) — seenapi/angular-compiler/test/analog-compat/component.spec.ts:3284for the aliased-import case. - Default-import shape —
m.defaultrather thanm.Xfor default-imported components — covered bynapi/angular-compiler/test/analog-compat/component.spec.ts:3312.
Tests
The four currently-failing tests under @defer dependency import shape in component.spec.ts (3262, 3284, 3312, plus the @defer inside @switch/@case cases at 1764-area) cover the matrix.
Reference
- ngc impl:
packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts:1312(DeferBlockDepsEmitMode.PerComponent),:2344-2475(allDeferredDeclscollection) - DefersBlock AST:
packages/compiler/src/render3/r3_ast.ts - OXC defer entry:
crates/oxc_angular_compiler/src/component/defer_resolver.rs(added in #307) - Related upstream commit:
bb2735b feat(defer): emit lazy resolver and async metadata for @Component.deferredImports (#307)— explicit-deferredImports path; this issue covers the implicit case
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne in crates/oxc_angular_compiler/src/component/defer_resolver.rs und vergleiche die dort bestehende Behandlung von explicit-deferredImports mit der collectDeferredSymbols-Logik von ngc in handler.ts:2344-2475. Führe die Fälle zur Form von @defer-Abhängigkeitsimporten in napi/angular-compiler/test/analog-compat/component.spec.ts aus, einschließlich der Fälle mit Aliases, Default-Imports und verschachtelten @switch-Blöcken. Als abgeschlossen gilt die Arbeit, wenn ausschließlich verzögerte Imports deferBlockDependencies mit der korrekten Lazy-Exportform erzeugen, während reguläre Abhängigkeiten sie ausschließen.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- angular, rust, typescript
- Bereich
- compilers, frontend, testing-qa
- Issue-Typ
- Bug
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Ruhig
- Klarheit
- Klar beschrieben
- Anfängerfreundlichkeit
- 56/100