Skip to content

Commit 0f8b332

Browse files
filipesilvavikerman
authored andcommitted
fix(@ngtools/webpack): find aliased lazy route factories
Fix #14707
1 parent d1a2527 commit 0f8b332

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';
@@ -95,5 +95,79 @@ describe('@ngtools/webpack transformers', () => {
9595

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

0 commit comments

Comments
 (0)