Skip to content

fix(@ngtools/webpack): elide non-value aliases and type-only AST constructs (20.3.x) - #34667

Merged
dgp1130 merged 3 commits into
angular:20.3.xfrom
alan-agius4:fix/elide-imports-20.3.x
Nov 6, 2026
Merged

dgp1130 merged 3 commits into
angular:20.3.xfrom
alan-agius4:fix/elide-imports-20.3.x

Conversation

@alan-agius4

Copy link
Copy Markdown
Collaborator

Backport of #34582 and #34594 to 20.3.x.

alan-agius4 and others added 3 commits November 6, 2026 13:49
…type declarations

When `elideImports` removes unused import specifiers (such as after
`removeIvyJitSupportCalls` removes `ɵsetClassMetadata`), it previously
walked into `interface` declarations, `type` alias declarations, and
type-only `export` declarations/specifiers (`export type { X }`,
`export { type X }`). This caused it to mark those type-only imported
symbols as used at runtime and rewrite the `ImportDeclaration` while
retaining those specifiers.

Because the `ImportDeclaration` AST node was replaced by a `before`
transformer, TypeScript skipped its own type-only import elision on the
cloned declaration, leaving the type-only specifier in the emitted JS
output. With webpack 5.112.0+, unused import specifiers are still
link-checked against the target module, causing builds with
`strictExportPresence: true` to fail.

Skip pure type declarations (`InterfaceDeclaration`,
`TypeAliasDeclaration`, `TypeParameterDeclaration`) and type-only
exports (`ExportDeclaration` and `ExportSpecifier` with `isTypeOnly`)
when collecting used identifiers in `elideImports`.

Closes angular#34580
…y AST constructs

Follow up to angular#34582 to cover remaining pure-type import elision cases and
partial specifier removal in `replaceBootstrap`:

- Elide imported alias symbols that do not resolve to a runtime value (or
  traverse a type-only alias declaration), handling non-`type` interface
  re-exports (`export { Foo }`) and interface parameter types under
  `emitDecoratorMetadata`.
- Only rewrite a partially elided import declaration when a runtime value
  import must be removed or when the declaration was already replaced by a
  previous transformer. TypeScript skips its own import elision for
  declarations replaced by a transformer, so leaving other declarations
  untouched avoids retaining specifiers that TypeScript would have otherwise
  elided (such as inlined `const enum` imports).
- Skip all non-`ExpressionWithTypeArguments` `TypeNode`s when
  `emitDecoratorMetadata` is disabled, and unconditionally skip
  `TypeQueryNode` (`typeof X`), `ImportTypeNode`,
  `IndexSignatureDeclaration`, ambient `declare` statements, and external
  `export ... from '...'` declarations.
- Recursively visit child AST nodes when applying `elideImports` removals in
  `replaceBootstrap` so individual `ImportSpecifier`s are removed when
  `platformBrowserDynamic` shares an import with other used runtime exports.
…AST constructs

Follow up to angular#34582 to apply the same import elision fixes made to
`@ngtools/webpack` to the `replaceBootstrap` transformer used by the
application builder:

- Elide imported alias symbols that do not resolve to a runtime value (or
  traverse a type-only alias declaration), handling non-`type` interface
  re-exports (`export { Foo }`) and interface parameter types under
  `emitDecoratorMetadata`.
- Only rewrite a partially elided import declaration when a runtime value
  import must be removed or when the declaration was already replaced by a
  previous transformer, so TypeScript's own import elision continues to
  apply to all other declarations.
- Skip all non-`ExpressionWithTypeArguments` `TypeNode`s when
  `emitDecoratorMetadata` is disabled, and unconditionally skip
  `TypeQueryNode` (`typeof X`), `ImportTypeNode`,
  `IndexSignatureDeclaration`, ambient `declare` statements, and external
  `export ... from '...'` declarations.
- Recursively visit child AST nodes when applying import removals in
  `replaceBootstrap` so individual `ImportSpecifier`s are removed when
  `platformBrowserDynamic` shares an import with other used runtime exports.
@alan-agius4 alan-agius4 added area: @ngtools/webpack target: lts This PR is targeting a version currently in long-term support area: @angular/build labels Nov 6, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances the import elision logic in both the Angular build tools and @ngtools/webpack transformers. Specifically, it updates elideImports and replaceBootstrap to more accurately identify and elide type-only imports, non-value aliases, and imports that resolve through type-only re-exports, while ensuring that runtime values are preserved. It also introduces comprehensive unit tests to verify these changes. I have no feedback to provide as there are no review comments.

@alan-agius4 alan-agius4 added the action: review The PR is still awaiting reviews from at least one requested reviewer label Nov 6, 2026
@alan-agius4
alan-agius4 requested a review from clydin November 6, 2026 14:15
@alan-agius4 alan-agius4 linked an issue Nov 6, 2026 that may be closed by this pull request
1 task done
@alan-agius4 alan-agius4 added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Nov 6, 2026
@dgp1130
dgp1130 merged commit 25fed48 into angular:20.3.x Nov 6, 2026
38 of 39 checks passed
@dgp1130

dgp1130 commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

This PR was merged into the repository. The changes were merged into the following branches:

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

Labels

action: merge The PR is ready for merge by the caretaker area: @angular/build area: @ngtools/webpack target: lts This PR is targeting a version currently in long-term support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

'ModuleWithProviders' was not found in '@angular/core' for v21.2.29

3 participants