Skip to content

Commit 8bded93

Browse files
Alan Agiusmgechev
authored andcommitted
fix(@ngtools/webpack): import as results in the alias being undefined with Typescript 3.2
When using the `specifier.propertyName` with `typeChecker.getSymbolAtLocation` it will return a more detailed symbol then we originally have in the `usedSymbols` set. We should probably use `symbol.id` to actually check if the symbols are the same, however the `id` is not exposed in the Symbol interface. Using `node.name` will return the same symbol that we have stored in the set. Fixes angular#13212
1 parent ad9dd1f commit 8bded93

2 files changed

Lines changed: 110 additions & 1 deletion

File tree

packages/angular_devkit/build_angular/test/browser/aot_spec_large.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,113 @@ describe('Browser Builder AOT', () => {
3030
}),
3131
).toPromise().then(done, done.fail);
3232
});
33+
34+
it('works with aliased imports', (done) => {
35+
const overrides = { aot: true };
36+
37+
host.writeMultipleFiles({
38+
'src/app/app.component.ts': `import { Component } from '@angular/core';
39+
import { from as fromPromise } from 'rxjs';
40+
41+
@Component({
42+
selector: 'app-root',
43+
templateUrl: './app.component.html',
44+
styleUrls: ['./app.component.css']
45+
})
46+
export class AppComponent {
47+
title = 'app-component';
48+
49+
constructor() {
50+
console.log(fromPromise(Promise.resolve('test')));
51+
}
52+
}`,
53+
});
54+
55+
runTargetSpec(host, browserTargetSpec, overrides).pipe(
56+
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
57+
tap(() => {
58+
const fileName = join(outputPath, 'main.js');
59+
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
60+
// if the aliased import was dropped this won't be rewired to a webpack module.
61+
expect(content).toMatch(/rxjs__WEBPACK_IMPORTED_.+[\"from\"]/);
62+
expect(content).not.toContain('fromPromise');
63+
}),
64+
).toPromise().then(done, done.fail);
65+
});
66+
67+
it('works with aliased imports from an exported object literal', (done) => {
68+
const overrides = { aot: true };
69+
70+
host.writeMultipleFiles({
71+
'src/foo.ts': `
72+
import { from as fromPromise } from 'rxjs';
73+
export { fromPromise };
74+
`,
75+
'src/app/app.component.ts': `
76+
import { Component } from '@angular/core';
77+
import { fromPromise } from '../foo';
78+
79+
@Component({
80+
selector: 'app-root',
81+
templateUrl: './app.component.html',
82+
styleUrls: ['./app.component.css']
83+
})
84+
export class AppComponent {
85+
title = 'app-component';
86+
87+
constructor() {
88+
console.log(fromPromise(Promise.resolve('test')));
89+
}
90+
}`,
91+
});
92+
93+
runTargetSpec(host, browserTargetSpec, overrides).pipe(
94+
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
95+
tap(() => {
96+
const fileName = join(outputPath, 'main.js');
97+
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
98+
// if the aliased import was dropped this won't be rewired to a webpack module.
99+
expect(content).toMatch(/rxjs__WEBPACK_IMPORTED_.+[\"from\"]/);
100+
expect(content).toMatch(/rxjs__WEBPACK_IMPORTED_.+[\"fromPromise\"]/);
101+
}),
102+
).toPromise().then(done, done.fail);
103+
});
104+
105+
it('works with aliased imports from an alias export', (done) => {
106+
const overrides = { aot: true };
107+
108+
host.writeMultipleFiles({
109+
'src/foo.ts': `
110+
export { from as fromPromise } from 'rxjs';
111+
`,
112+
'src/app/app.component.ts': `
113+
import { Component } from '@angular/core';
114+
import { fromPromise } from '../foo';
115+
116+
@Component({
117+
selector: 'app-root',
118+
templateUrl: './app.component.html',
119+
styleUrls: ['./app.component.css']
120+
})
121+
export class AppComponent {
122+
title = 'app-component';
123+
124+
constructor() {
125+
console.log(fromPromise(Promise.resolve('test')));
126+
}
127+
}`,
128+
});
129+
130+
runTargetSpec(host, browserTargetSpec, overrides).pipe(
131+
tap((buildEvent) => expect(buildEvent.success).toBe(true)),
132+
tap(() => {
133+
const fileName = join(outputPath, 'main.js');
134+
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
135+
// if the aliased import was dropped this won't be rewired to a webpack module.
136+
expect(content).toMatch(/rxjs__WEBPACK_IMPORTED_.+[\"from\"]/);
137+
expect(content).toMatch(/rxjs__WEBPACK_IMPORTED_.+[\"fromPromise\"]/);
138+
}),
139+
).toPromise().then(done, done.fail);
140+
});
141+
33142
});

packages/ngtools/webpack/src/transformers/elide_imports.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export function elideImports(
100100
// "import { XYZ, ... } from 'abc';"
101101
const specifierOps = [];
102102
for (const specifier of node.importClause.namedBindings.elements) {
103-
if (isUnused(specifier.propertyName || specifier.name)) {
103+
if (isUnused(specifier.name)) {
104104
specifierOps.push(new RemoveNodeOperation(sourceFile, specifier));
105105
}
106106
}

0 commit comments

Comments
 (0)