Skip to content

Commit 95686a4

Browse files
filipesilvavikerman
authored andcommitted
fix(@ngtools/webpack): find aliased lazy route factories
Fix #14707
1 parent 6b2b51f commit 95686a4

File tree

2 files changed

+90
-2
lines changed

2 files changed

+90
-2
lines changed

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import * as ts from 'typescript';
1010
import { forwardSlashPath } from '../utils';
1111

1212

13+
// Check if a ts.Symbol is an alias.
14+
const isAlias = (symbol: ts.Symbol) => symbol.flags & ts.SymbolFlags.Alias;
15+
1316
/**
1417
* Given this original source code:
1518
*
@@ -193,15 +196,26 @@ function replaceImport(
193196

194197
// Try to resolve the import. It might be a reexport from somewhere and the ngfactory will only
195198
// be present next to the original module.
196-
const exportedSymbol = typeChecker.getSymbolAtLocation(exportNameId);
199+
let exportedSymbol = typeChecker.getSymbolAtLocation(exportNameId);
197200
if (!exportedSymbol) {
198201
return warnAndBail();
199202
}
203+
// Named exports are also a declaration in the re-exporting module so we have to follow the
204+
// re-exports to find the original symbol.
205+
if (isAlias(exportedSymbol)) {
206+
exportedSymbol = typeChecker.getAliasedSymbol(exportedSymbol);
207+
if (!exportedSymbol) {
208+
return warnAndBail();
209+
}
210+
}
211+
212+
// Find declarations of the original symbol so we can get their source file name.
200213
const exportedSymbolDecl = exportedSymbol.getDeclarations();
201214
if (!exportedSymbolDecl || exportedSymbolDecl.length === 0) {
202215
return warnAndBail();
203216
}
204217

218+
// Let's guess the first declaration is the one we want, because we don't have a better criteria.
205219
// Get the relative path from the containing module to the imported module.
206220
const relativePath = relative(dirname(fileName), exportedSymbolDecl[0].getSourceFile().fileName);
207221

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

+75-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe('@ngtools/webpack transformers', () => {
6464
expect(warningCalled).toBeTruthy();
6565
});
6666

67-
it('should support resolving reexports', () => {
67+
it('should support resolving * re-exports', () => {
6868
const additionalFiles: Record<string, string> = {
6969
'shared/index.ts': `
7070
export * from './path/to/lazy/lazy.module';
@@ -97,5 +97,79 @@ describe('@ngtools/webpack transformers', () => {
9797

9898
expect(tags.oneLine`${result}`).toEqual(tags.oneLine`${output}`);
9999
});
100+
101+
it('should support resolving named re-exports', () => {
102+
const additionalFiles: Record<string, string> = {
103+
'shared/index.ts': `
104+
export { LazyModule } from './path/to/lazy/lazy.module';
105+
`,
106+
'shared/path/to/lazy/lazy.module.ts': `
107+
export const LazyModule = {};
108+
`,
109+
};
110+
const input = tags.stripIndent`
111+
const ɵ0 = () => import('./shared').then(m => m.LazyModule);
112+
const routes = [{
113+
path: 'lazy',
114+
loadChildren: ɵ0
115+
}];
116+
`;
117+
118+
const output = tags.stripIndent`
119+
const ɵ0 = () => import("./shared/path/to/lazy/lazy.module.ngfactory").then(m => m.LazyModuleNgFactory);
120+
const routes = [{
121+
path: 'lazy',
122+
loadChildren: ɵ0
123+
}];
124+
`;
125+
126+
const { program, compilerHost } = createTypescriptContext(input, additionalFiles, true);
127+
const transformer = importFactory(() => { }, () => program.getTypeChecker());
128+
const result = transformTypescript(undefined, [transformer], program, compilerHost);
129+
130+
expect(tags.oneLine`${result}`).toEqual(tags.oneLine`${output}`);
131+
});
132+
133+
134+
it('should support resolving re-export chains', () => {
135+
const additionalFiles: Record<string, string> = {
136+
'shared/index.ts': `
137+
export { LazyModule } from './index2';
138+
`,
139+
'shared/index2.ts': `
140+
export * from './index3';
141+
`,
142+
'shared/index3.ts': `
143+
export { LazyModule } from './index4';
144+
`,
145+
'shared/index4.ts': `
146+
export * from './path/to/lazy/lazy.module';
147+
`,
148+
'shared/path/to/lazy/lazy.module.ts': `
149+
export const LazyModule = {};
150+
`,
151+
};
152+
const input = tags.stripIndent`
153+
const ɵ0 = () => import('./shared').then(m => m.LazyModule);
154+
const routes = [{
155+
path: 'lazy',
156+
loadChildren: ɵ0
157+
}];
158+
`;
159+
160+
const output = tags.stripIndent`
161+
const ɵ0 = () => import("./shared/path/to/lazy/lazy.module.ngfactory").then(m => m.LazyModuleNgFactory);
162+
const routes = [{
163+
path: 'lazy',
164+
loadChildren: ɵ0
165+
}];
166+
`;
167+
168+
const { program, compilerHost } = createTypescriptContext(input, additionalFiles, true);
169+
const transformer = importFactory(() => { }, () => program.getTypeChecker());
170+
const result = transformTypescript(undefined, [transformer], program, compilerHost);
171+
172+
expect(tags.oneLine`${result}`).toEqual(tags.oneLine`${output}`);
173+
});
100174
});
101175
});

0 commit comments

Comments
 (0)