Skip to content

fix(compiler-cli): record class extends clause references in DeferredSymbolTracker - #70111

Open
mattrbeck wants to merge 1 commit into
angular:mainfrom
mattrbeck:fix-defer-extends-reference
Open

fix(compiler-cli): record class extends clause references in DeferredSymbolTracker#70111
mattrbeck wants to merge 1 commit into
angular:mainfrom
mattrbeck:fix-defer-extends-reference

Conversation

@mattrbeck

Copy link
Copy Markdown
Member

Problem

DeferredSymbolTracker.lookupIdentifiersInSourceFile prunes ts.isTypeNode subtrees so that references appearing exclusively inside type annotations do not prevent static import declarations from being elided in favor of @defer dynamic import()s.

However, ts.isTypeNode returns true for ts.ExpressionWithTypeArguments, which TypeScript's AST uses to represent both extends and implements heritage clauses. An extends clause on a class declaration or class expression is a runtime value position that survives into emitted JavaScript:

import { DeferredComponent, BaseComponent } from './components';

@Component({
  template: `
    @defer {
      <defer-cmp />
    }
  `,
  imports: [DeferredComponent],
})
export class MyComponent extends BaseComponent {}

Because isTypeNode returned true for ts.ExpressionWithTypeArguments, references to BaseComponent were pruned. DeferredSymbolTracker concluded that BaseComponent had zero runtime references, marked the static import as deferrable, and deleted it from the emitted JavaScript output.

At runtime, this results in a fatal ReferenceError: BaseComponent is not defined.

Solution

Ensure that ExpressionWithTypeArguments representing an extends clause on a class declaration or class expression is not treated as an erasable type node in lookupIdentifiersInSourceFile. References within a class extends clause are now properly recorded as active runtime references, preventing the static import from being deleted when a base class is referenced.

Testing

Added a new compliance test case in packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_deferred/:

  • defer_extends_clause verifying that static imports are preserved and the dependency is emitted eagerly when a sibling symbol is referenced in a class extends clause.

@angular-robot angular-robot Bot added the area: compiler Issues related to `ngc`, Angular's template compiler label Aug 7, 2026
@ngbot ngbot Bot added this to the Backlog milestone Aug 7, 2026
…SymbolTracker

`DeferredSymbolTracker.lookupIdentifiersInSourceFile` prunes `ts.isTypeNode`
subtrees so that references appearing exclusively inside type annotations
do not keep static import declarations in the emitted JavaScript.

However, `ts.isTypeNode` returns `true` for `ts.ExpressionWithTypeArguments`,
which TypeScript uses to represent both `extends` and `implements` heritage
clauses. An `extends` clause on a class declaration or class expression is a
value position that survives in the emitted JavaScript output.

Because `isTypeNode` returned `true`, references to base classes imported
alongside deferred dependencies were ignored. As a result, the compiler
erroneously marked the static import statement as deferrable and deleted it
from the emitted JavaScript, leaving the `extends <Base>` clause referencing
an undeclared identifier and causing a runtime `ReferenceError`.

This commit ensures that `ExpressionWithTypeArguments` under a class `extends`
clause is not treated as an erasable type node, preserving the static import
whenever a base class is referenced.
@mattrbeck
mattrbeck force-pushed the fix-defer-extends-reference branch from 4830ee1 to 18d899e Compare August 7, 2026 00:36
@mattrbeck
mattrbeck marked this pull request as ready for review August 7, 2026 00:51
@mattrbeck
mattrbeck requested a review from crisbeto August 7, 2026 00:51
@mattrbeck

Copy link
Copy Markdown
Member Author

Passing g3 tests. Currently running TGP, although expecting this not to be breaking http://test/OCL:960612740:BASE:960633940:1786073167024:52dfa045

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: compiler Issues related to `ngc`, Angular's template compiler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant