Skip to content

Commit 1e07a11

Browse files
alxhubthePunderWoman
authored andcommitted
fix(compiler-cli): use existing imports for standalone dependencies (#46029)
This commit fixes a small issue in the logic around the calculation of template scopes for standalone components. These scopes include a `Reference` for each dependency of a standalone component, which is used to generate references to that dependency in various contexts. Previously, the `Reference` used for a dependency was the one generated from its own metadata. For example, a referenced directive used the `Reference` that was created when analyzing the directive declaration itself. This still works, as the compiler is always able to emit a reference to any valid `Reference`. However, it's not optimal. The `Reference` which should be used instead is the one generated from analyzing the standalone component's `imports` array, which has knowledge of how the dependency is referenced from within the standalone component's file itself. This allows the compiler to skip creating a new import for the dependency when emitting the standalone component, and use the existing, user-authored import instead. This saves on code size and avoids taxing the bundler with unnecessary imports. PR Close #46029
1 parent 91ce543 commit 1e07a11

2 files changed

Lines changed: 33 additions & 4 deletions

File tree

packages/compiler-cli/src/ngtsc/scope/src/standalone.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,21 @@ export class StandaloneComponentScopeReader implements ComponentScopeReader {
5050

5151
const dirMeta = this.metaReader.getDirectiveMetadata(ref);
5252
if (dirMeta !== null) {
53-
dependencies.add(dirMeta);
53+
dependencies.add({...dirMeta, ref});
5454
isPoisoned = isPoisoned || dirMeta.isPoisoned || !dirMeta.isStandalone;
5555
continue;
5656
}
5757

5858
const pipeMeta = this.metaReader.getPipeMetadata(ref);
5959
if (pipeMeta !== null) {
60-
dependencies.add(pipeMeta);
60+
dependencies.add({...pipeMeta, ref});
6161
isPoisoned = isPoisoned || !pipeMeta.isStandalone;
6262
continue;
6363
}
6464

6565
const ngModuleMeta = this.metaReader.getNgModuleMetadata(ref);
6666
if (ngModuleMeta !== null) {
67-
dependencies.add(ngModuleMeta);
67+
dependencies.add({...ngModuleMeta, ref});
6868

6969
let ngModuleScope: ExportScope|null;
7070
if (ref.node.getSourceFile().isDeclarationFile) {

packages/compiler-cli/test/ngtsc/standalone_spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,35 @@ runInEachFileSystem(() => {
9393
expect(dtsCode).toContain('i0.ɵɵPipeDeclaration<TestPipe, "test", true>');
9494
});
9595

96+
it('should use existing imports for dependencies', () => {
97+
env.write('dep.ts', `
98+
import {Directive} from '@angular/core';
99+
100+
@Directive({
101+
standalone: true,
102+
selector: '[dir]',
103+
})
104+
export class TestDir {}
105+
`);
106+
env.write('test.ts', `
107+
import {Component} from '@angular/core';
108+
import {TestDir} from './dep';
109+
110+
@Component({
111+
standalone: true,
112+
imports: [TestDir],
113+
selector: 'test-cmp',
114+
template: '<div dir></div>',
115+
})
116+
export class TestCmp {}
117+
`);
118+
119+
env.driveMain();
120+
121+
const jsContents = env.getContents('test.js');
122+
expect(jsContents).toContain('dependencies: [TestDir]');
123+
});
124+
96125
it('should compile a standalone component even in the presence of cycles', () => {
97126
env.write('dep.ts', `
98127
import {Directive, Input} from '@angular/core';
@@ -128,7 +157,7 @@ runInEachFileSystem(() => {
128157
env.driveMain();
129158

130159
const jsContents = env.getContents('test.js');
131-
expect(jsContents).toContain('dependencies: [i1.TestDir]');
160+
expect(jsContents).toContain('dependencies: [TestDir]');
132161
});
133162

134163
it('should error when a non-standalone component tries to use imports', () => {

0 commit comments

Comments
 (0)