voidzero-dev / voidzero-dev/oxc-angular-compiler
fix(defer): emit lazy dependencies for components used only inside @defer blocks
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Rust
- Star
- 228
- Fork
- 20
- Merge trung bình
- 1 ngày 15 giờ
- Pull request đã merge (30 ngày)
- 36
Mô tả
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
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
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.
Hướng nghiên cứu
Bắt đầu trong crates/oxc_angular_compiler/src/component/defer_resolver.rs và so sánh cách xử lý explicit-deferredImports hiện có với logic collectDeferredSymbols của ngc trong handler.ts:2344-2475. Chạy các trường hợp về dạng import dependency của @defer trong napi/angular-compiler/test/analog-compat/component.spec.ts, bao gồm các trường hợp aliased, default-import và @switch lồng nhau. Hoàn tất có nghĩa là các import chỉ dành cho defer tạo ra deferBlockDependencies với dạng export lazy chính xác, trong khi các dependency thông thường loại trừ chúng.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- angular, rust, typescript
- Lĩnh vực
- compilers, frontend, testing-qa
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Ít trao đổi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 56/100