feat(@ngtools/webpack): add option to control lazy route discovery

This commit is contained in:
Filipe Silva 2019-02-28 13:58:23 +00:00 committed by Minko Gechev
parent 7e9297b64d
commit b54a9379a6

View File

@ -103,6 +103,11 @@ export interface AngularCompilerPluginOptions {
nameLazyFiles?: boolean; nameLazyFiles?: boolean;
logger?: logging.Logger; logger?: logging.Logger;
directTemplateLoading?: boolean; directTemplateLoading?: boolean;
// When using the loadChildren string syntax, @ngtools/webpack must query @angular/compiler-cli
// via a private API to know which lazy routes exist. This increases build and rebuild time.
// When using Ivy, the string syntax is not supported at all. Thus we shouldn't attempt that.
// This option is also used for when the compilation doesn't need this sort of processing at all.
discoverLazyRoutes?: boolean;
// added to the list of lazy routes // added to the list of lazy routes
additionalLazyModules?: { [module: string]: string }; additionalLazyModules?: { [module: string]: string };
@ -134,6 +139,7 @@ export class AngularCompilerPlugin {
private _compilerHost: WebpackCompilerHost & CompilerHost; private _compilerHost: WebpackCompilerHost & CompilerHost;
private _moduleResolutionCache: ts.ModuleResolutionCache; private _moduleResolutionCache: ts.ModuleResolutionCache;
private _resourceLoader?: WebpackResourceLoader; private _resourceLoader?: WebpackResourceLoader;
private _discoverLazyRoutes = true;
// Contains `moduleImportPath#exportName` => `fullModulePath`. // Contains `moduleImportPath#exportName` => `fullModulePath`.
private _lazyRoutes: LazyRouteMap = {}; private _lazyRoutes: LazyRouteMap = {};
private _tsConfigPath: string; private _tsConfigPath: string;
@ -292,6 +298,26 @@ export class AngularCompilerPlugin {
this._platformTransformers = options.platformTransformers; this._platformTransformers = options.platformTransformers;
} }
if (options.discoverLazyRoutes !== undefined) {
this._discoverLazyRoutes = options.discoverLazyRoutes;
}
if (this._discoverLazyRoutes === false && this.options.additionalLazyModuleResources
&& this.options.additionalLazyModuleResources.length > 0) {
this._warnings.push(
new Error(`Lazy route discovery is disabled but additional Lazy Module Resources were`
+ ` provided. These will be ignored.`),
);
}
if (this._discoverLazyRoutes === false && this.options.additionalLazyModules
&& Object.keys(this.options.additionalLazyModules).length > 0) {
this._warnings.push(
new Error(`Lazy route discovery is disabled but additional lazy modules were provided.`
+ `These will be ignored.`),
);
}
// Default ContextElementDependency to the one we can import from here. // Default ContextElementDependency to the one we can import from here.
// Failing to use the right ContextElementDependency will throw the error below: // Failing to use the right ContextElementDependency will throw the error below:
// "No module factory available for dependency type: ContextElementDependency" // "No module factory available for dependency type: ContextElementDependency"
@ -411,7 +437,7 @@ export class AngularCompilerPlugin {
this._entryModule = resolveEntryModuleFromMain( this._entryModule = resolveEntryModuleFromMain(
this._mainPath, this._compilerHost, this._getTsProgram() as ts.Program); this._mainPath, this._compilerHost, this._getTsProgram() as ts.Program);
if (!this.entryModule && !this._compilerOptions.enableIvy) { if (this._discoverLazyRoutes && !this.entryModule && !this._compilerOptions.enableIvy) {
this._warnings.push('Lazy routes discovery is not enabled. ' this._warnings.push('Lazy routes discovery is not enabled. '
+ 'Because there is neither an entryModule nor a ' + 'Because there is neither an entryModule nor a '
+ 'statically analyzable bootstrap code in the main file.', + 'statically analyzable bootstrap code in the main file.',
@ -697,6 +723,7 @@ export class AngularCompilerPlugin {
); );
}); });
if (this._discoverLazyRoutes) {
// Add lazy modules to the context module for @angular/core // Add lazy modules to the context module for @angular/core
compiler.hooks.contextModuleFactory.tap('angular-compiler', cmf => { compiler.hooks.contextModuleFactory.tap('angular-compiler', cmf => {
const angularCorePackagePath = require.resolve('@angular/core/package.json'); const angularCorePackagePath = require.resolve('@angular/core/package.json');
@ -706,14 +733,14 @@ export class AngularCompilerPlugin {
// module starts with it. // module starts with it.
// This may be slower but it will be compatible with both APF5, 6 and potential future // This may be slower but it will be compatible with both APF5, 6 and potential future
// versions (until the dynamic import appears outside of core I suppose). // versions (until the dynamic import appears outside of core I suppose).
// We resolve any symbolic links in order to get the real path that would be used in webpack. // We resolve symbolic links in order to get the real path that would be used in webpack.
const angularCoreResourceRoot = fs.realpathSync(path.dirname(angularCorePackagePath)); const angularCoreResourceRoot = fs.realpathSync(path.dirname(angularCorePackagePath));
cmf.hooks.afterResolve.tapPromise('angular-compiler', async result => { cmf.hooks.afterResolve.tapPromise('angular-compiler', async result => {
// Alter only existing request from Angular or one of the additional lazy module resources. // Alter only existing request from Angular or the additional lazy module resources.
const isLazyModuleResource = (resource: string) => const isLazyModuleResource = (resource: string) =>
resource.startsWith(angularCoreResourceRoot) || resource.startsWith(angularCoreResourceRoot) ||
( this.options.additionalLazyModuleResources && (this.options.additionalLazyModuleResources &&
this.options.additionalLazyModuleResources.includes(resource)); this.options.additionalLazyModuleResources.includes(resource));
if (!result || !this.done || !isLazyModuleResource(result.resource)) { if (!result || !this.done || !isLazyModuleResource(result.resource)) {
@ -755,6 +782,7 @@ export class AngularCompilerPlugin {
); );
}); });
}); });
}
// Create and destroy forked type checker on watch mode. // Create and destroy forked type checker on watch mode.
compiler.hooks.watchRun.tap('angular-compiler', () => { compiler.hooks.watchRun.tap('angular-compiler', () => {
@ -922,6 +950,7 @@ export class AngularCompilerPlugin {
// Make a new program and load the Angular structure. // Make a new program and load the Angular structure.
await this._createOrUpdateProgram(); await this._createOrUpdateProgram();
if (this._discoverLazyRoutes) {
// Try to find lazy routes if we have an entry module. // Try to find lazy routes if we have an entry module.
// We need to run the `listLazyRoutes` the first time because it also navigates libraries // We need to run the `listLazyRoutes` the first time because it also navigates libraries
// and other things that we might miss using the (faster) findLazyRoutesInAst. // and other things that we might miss using the (faster) findLazyRoutesInAst.
@ -943,6 +972,7 @@ export class AngularCompilerPlugin {
}; };
this._processLazyRoutes(lazyRouteMap); this._processLazyRoutes(lazyRouteMap);
}
// Emit files. // Emit files.
time('AngularCompilerPlugin._update._emit'); time('AngularCompilerPlugin._update._emit');