Skip to content

Commit 6d7d2eb

Browse files
filipesilvaalexeagle
authored andcommitted
feat(@ngtools/webpack): support loadchildren string syntax in Ivy
1 parent b7dfdb8 commit 6d7d2eb

File tree

4 files changed

+32
-83
lines changed

4 files changed

+32
-83
lines changed

packages/ngtools/webpack/src/angular_compiler_plugin.ts

+15-16
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export class AngularCompilerPlugin {
9595
private _resourceLoader?: WebpackResourceLoader;
9696
private _discoverLazyRoutes = true;
9797
private _importFactories = false;
98+
private _useFactories = false;
9899
// Contains `moduleImportPath#exportName` => `fullModulePath`.
99100
private _lazyRoutes: LazyRouteMap = {};
100101
private _tsConfigPath: string;
@@ -256,11 +257,8 @@ export class AngularCompilerPlugin {
256257
}
257258

258259
// Determine if lazy route discovery via Compiler CLI private API should be attempted.
259-
if (this._compilerOptions.enableIvy) {
260-
// Never try to discover lazy routes with Ivy.
261-
this._discoverLazyRoutes = false;
262-
} else if (options.discoverLazyRoutes !== undefined) {
263-
// The default is to discover routes, but it can be overriden.
260+
// The default is to discover routes, but it can be overriden.
261+
if (options.discoverLazyRoutes !== undefined) {
264262
this._discoverLazyRoutes = options.discoverLazyRoutes;
265263
}
266264

@@ -280,7 +278,12 @@ export class AngularCompilerPlugin {
280278
);
281279
}
282280

283-
if (!this._compilerOptions.enableIvy && options.importFactories === true) {
281+
if (!this._JitMode && !this._compilerOptions.enableIvy) {
282+
// Only attempt to use factories when AOT and not Ivy.
283+
this._useFactories = true;
284+
}
285+
286+
if (this._useFactories && options.importFactories === true) {
284287
// Only transform imports to use factories with View Engine.
285288
this._importFactories = true;
286289
}
@@ -488,18 +491,14 @@ export class AngularCompilerPlugin {
488491
const lazyRouteTSFile = discoveredLazyRoutes[lazyRouteKey].replace(/\\/g, '/');
489492
let modulePath: string, moduleKey: string;
490493

491-
if (this._JitMode ||
492-
// When using Ivy and not using allowEmptyCodegenFiles, factories are not generated.
493-
(this._compilerOptions.enableIvy && !this._compilerOptions.allowEmptyCodegenFiles)
494-
) {
495-
modulePath = lazyRouteTSFile;
496-
moduleKey = `${lazyRouteModule}${moduleName ? '#' + moduleName : ''}`;
497-
} else {
498-
// NgFactories are only used with AOT on ngc (legacy) mode.
494+
if (this._useFactories) {
499495
modulePath = lazyRouteTSFile.replace(/(\.d)?\.tsx?$/, '');
500496
modulePath += '.ngfactory.js';
501497
const factoryModuleName = moduleName ? `#${moduleName}NgFactory` : '';
502498
moduleKey = `${lazyRouteModule}.ngfactory${factoryModuleName}`;
499+
} else {
500+
modulePath = lazyRouteTSFile;
501+
moduleKey = `${lazyRouteModule}${moduleName ? '#' + moduleName : ''}`;
503502
}
504503

505504
modulePath = workaroundResolve(modulePath);
@@ -949,7 +948,7 @@ export class AngularCompilerPlugin {
949948
this._normalizedLocale));
950949
}
951950

952-
if (!this._JitMode) {
951+
if (this._useFactories) {
953952
// Replace bootstrap in browser AOT.
954953
this._transformers.push(replaceBootstrap(
955954
isAppPath,
@@ -960,7 +959,7 @@ export class AngularCompilerPlugin {
960959
}
961960
} else if (this._platform === PLATFORM.Server) {
962961
this._transformers.push(exportLazyModuleMap(isMainPath, getLazyRoutes));
963-
if (!this._JitMode) {
962+
if (this._useFactories) {
964963
this._transformers.push(
965964
exportNgFactory(isMainPath, getEntryModule),
966965
replaceServerBootstrap(isMainPath, getEntryModule, getTypeChecker));

tests/legacy-cli/e2e/tests/basic/rebuild.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
import {writeFile, writeMultipleFiles} from '../../utils/fs';
88
import {wait} from '../../utils/utils';
99
import {request} from '../../utils/http';
10-
import {getGlobalVariable} from '../../utils/env';
1110

1211
const validBundleRegEx = /: Compiled successfully./;
1312

@@ -16,11 +15,6 @@ export default function() {
1615
return Promise.resolve();
1716
}
1817

19-
const argv = getGlobalVariable('argv');
20-
const ivyProject = argv['ivy'];
21-
const lazyImport = ivyProject ? `() => import('./lazy/lazy.module').then(m => m.LazyModule)`
22-
: `'./lazy/lazy.module#LazyModule'`;
23-
2418
return execAndWaitForOutputToMatch('ng', ['serve'], validBundleRegEx)
2519
// Add a lazy module.
2620
.then(() => ng('generate', 'module', 'lazy', '--routing'))
@@ -47,7 +41,7 @@ export default function() {
4741
FormsModule,
4842
HttpClientModule,
4943
RouterModule.forRoot([
50-
{ path: 'lazy', loadChildren: ${lazyImport} }
44+
{ path: 'lazy', loadChildren: './lazy/lazy.module#LazyModule' }
5145
])
5246
],
5347
providers: [],

tests/legacy-cli/e2e/tests/build/lazy-load-syntax.ts

+11-39
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,6 @@ export default async function () {
7474
});
7575
`);
7676

77-
// Set factory shims to false.
78-
await updateJsonFile('tsconfig.app.json', json => {
79-
if (json['angularCompilerOptions'] === undefined) {
80-
json['angularCompilerOptions'] = {};
81-
}
82-
json['angularCompilerOptions']['allowEmptyCodegenFiles'] = false;
83-
});
84-
8577
// Convert the default config to use JIT and prod to just do AOT.
8678
// This way we can use `ng e2e` to test JIT and `ng e2e --prod` to test AOT.
8779
await updateJsonFile('angular.json', json => {
@@ -90,40 +82,20 @@ export default async function () {
9082
buildTarget['configurations']['production'] = { aot: true };
9183
});
9284

93-
// Test string import with factory shims.
94-
await replaceLoadChildren(`'./lazy/lazy.module#LazyModule'`);
95-
await replaceInFile('tsconfig.app.json', `"allowEmptyCodegenFiles": false`,
96-
`"allowEmptyCodegenFiles": true`);
97-
if (ivyProject) {
98-
// Ivy should not support the string syntax.
99-
await expectToFail(() => ng('e2e'));
100-
await expectToFail(() => ng('e2e', '--prod'));
101-
} else {
102-
// View engine should support the string syntax.
103-
await ng('e2e');
104-
await ng('e2e', '--prod');
105-
}
106-
107-
// Test string import without factory shims.
85+
// Test string import.
86+
// Both Ivy and View Engine should support it.
10887
await replaceLoadChildren(`'./lazy/lazy.module#LazyModule'`);
109-
await replaceInFile('tsconfig.app.json', `"allowEmptyCodegenFiles": true`,
110-
`"allowEmptyCodegenFiles": false`);
111-
if (ivyProject) {
112-
// Ivy should not support the string syntax.
113-
await expectToFail(() => ng('e2e'));
114-
await expectToFail(() => ng('e2e', '--prod'));
115-
} else {
116-
// View engine should support the string syntax.
117-
await ng('e2e');
118-
await ng('e2e', '--prod');
119-
}
88+
await ng('e2e');
89+
await ng('e2e', '--prod');
12090

12191
// Test `import()` style lazy load.
122-
await updateJsonFile('angular.json', json => {
123-
// Add the experimental flag to import factories in View Engine.
124-
const buildTarget = json['projects'][projectName]['architect']['build'];
125-
buildTarget['options']['experimentalImportFactories'] = true;
126-
});
92+
if (!ivyProject) {
93+
await updateJsonFile('angular.json', json => {
94+
// Add the experimental flag to import factories in View Engine.
95+
const buildTarget = json['projects'][projectName]['architect']['build'];
96+
buildTarget['options']['experimentalImportFactories'] = true;
97+
});
98+
}
12799
// Both Ivy and View Engine should support it.
128100
await replaceLoadChildren(`() => import('./lazy/lazy.module').then(m => m.LazyModule)`);
129101
await ng('e2e');

tests/legacy-cli/e2e/tests/misc/lazy-module.ts

+5-21
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,9 @@ import {readdirSync} from 'fs';
22

33
import {ng, silentNpm} from '../../utils/process';
44
import {appendToFile, writeFile, prependToFile, replaceInFile} from '../../utils/fs';
5-
import {getGlobalVariable} from '../../utils/env';
65

76

87
export default function() {
9-
const argv = getGlobalVariable('argv');
10-
const ivyProject = argv['ivy'];
11-
const lazyImport = ivyProject ? `() => import('src/app/lazy/lazy.module').then(m => m.LazyModule)`
12-
: `'src/app/lazy/lazy.module#LazyModule'`;
13-
const lazyImport1 = ivyProject ? `() => import('./lazy/lazy.module').then(m => m.LazyModule)`
14-
: `'./lazy/lazy.module#LazyModule'`;
15-
const lazyImport2 = ivyProject ? `() => import('./too/lazy/lazy.module').then(m => m.LazyModule)`
16-
: `'./too/lazy/lazy.module#LazyModule'`;
17-
188
let oldNumberOfFiles = 0;
199
return Promise.resolve()
2010
.then(() => ng('build'))
@@ -25,9 +15,9 @@ export default function() {
2515
import { RouterModule } from '@angular/router';
2616
`))
2717
.then(() => replaceInFile('src/app/app.module.ts', 'imports: [', `imports: [
28-
RouterModule.forRoot([{ path: "lazy", loadChildren: ${lazyImport} }]),
29-
RouterModule.forRoot([{ path: "lazy1", loadChildren: ${lazyImport1} }]),
30-
RouterModule.forRoot([{ path: "lazy2", loadChildren: ${lazyImport2} }]),
18+
RouterModule.forRoot([{ path: "lazy", loadChildren: 'src/app/lazy/lazy.module#LazyModule' }]),
19+
RouterModule.forRoot([{ path: "lazy1", loadChildren: './lazy/lazy.module#LazyModule' }]),
20+
RouterModule.forRoot([{ path: "lazy2", loadChildren: './too/lazy/lazy.module#LazyModule' }]),
3121
`))
3222
.then(() => ng('build', '--named-chunks'))
3323
.then(() => readdirSync('dist/test-project'))
@@ -38,14 +28,8 @@ export default function() {
3828
}
3929
oldNumberOfFiles = currentNumberOfDistFiles;
4030

41-
// Named lazy route chunks are not available with Ivy.
42-
if (!ivyProject) {
43-
if (!distFiles.includes('lazy-lazy-module.js')) {
44-
throw new Error('The lazy module chunk did not have a name.');
45-
}
46-
if (!distFiles.includes('too-lazy-lazy-module.js')) {
47-
throw new Error('The lazy module chunk did not use a unique name.');
48-
}
31+
if (!distFiles.includes('too-lazy-lazy-module.js')) {
32+
throw new Error('The lazy module chunk did not use a unique name.');
4933
}
5034
})
5135
// verify System.import still works

0 commit comments

Comments
 (0)