Skip to content

Commit afced59

Browse files
committed
perf(@ngtools/webpack): avoid full compiler lazy route analysis on JIT rebuilds
The deprecated lazy route string form requires code analysis prior to each build to locate any lazy routes and connect them with Webpack. This change uses the previous fast but less accurate AST based lazy route discovery for JIT rebuilds. The first build will still perform a full Angular compiler analysis to ensure an accurate list of all initial deprecated string form lazy routes.
1 parent 754a4d5 commit afced59

File tree

1 file changed

+53
-29
lines changed

1 file changed

+53
-29
lines changed

packages/ngtools/webpack/src/ivy/plugin.ts

+53-29
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
NormalModuleReplacementPlugin,
1717
compilation,
1818
} from 'webpack';
19+
import { findLazyRoutes } from '../lazy_routes';
1920
import { NgccProcessor } from '../ngcc_processor';
2021
import { TypeScriptPathsPlugin } from '../paths-plugin';
2122
import { WebpackResourceLoader } from '../resource_loader';
@@ -229,7 +230,7 @@ export class AngularWebpackPlugin {
229230

230231
// Create the file emitter used by the webpack loader
231232
const { fileEmitter, builder, internalFiles } = this.pluginOptions.jitMode
232-
? this.updateJitProgram(compilerOptions, rootNames, host, diagnosticsReporter)
233+
? this.updateJitProgram(compilerOptions, rootNames, host, diagnosticsReporter, changedFiles)
233234
: this.updateAotProgram(
234235
compilerOptions,
235236
rootNames,
@@ -523,6 +524,7 @@ export class AngularWebpackPlugin {
523524
rootNames: readonly string[],
524525
host: CompilerHost,
525526
diagnosticsReporter: DiagnosticsReporter,
527+
changedFiles: Set<string> | undefined,
526528
) {
527529
const builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
528530
rootNames,
@@ -547,39 +549,61 @@ export class AngularWebpackPlugin {
547549

548550
const transformers = createJitTransformers(builder, this.pluginOptions);
549551

550-
// Required to support asynchronous resource loading
551-
// Must be done before listing lazy routes
552-
// NOTE: This can be removed once support for the deprecated lazy route string format is removed
553-
const angularProgram = new NgtscProgram(
554-
rootNames,
555-
compilerOptions,
556-
host,
557-
this.ngtscNextProgram,
558-
);
559-
const angularCompiler = angularProgram.compiler;
560-
const pendingAnalysis = angularCompiler.analyzeAsync().then(() => {
561-
for (const lazyRoute of angularCompiler.listLazyRoutes()) {
562-
const [routeKey] = lazyRoute.route.split('#');
563-
this.lazyRouteMap[routeKey] = lazyRoute.referencedModule.filePath;
552+
// Only do a full, expensive Angular compiler string lazy route analysis on the first build
553+
// `changedFiles` will be undefined on a first build
554+
if (!changedFiles) {
555+
// Required to support asynchronous resource loading
556+
// Must be done before listing lazy routes
557+
// NOTE: This can be removed once support for the deprecated lazy route string format is removed
558+
const angularProgram = new NgtscProgram(
559+
rootNames,
560+
compilerOptions,
561+
host,
562+
this.ngtscNextProgram,
563+
);
564+
const angularCompiler = angularProgram.compiler;
565+
const pendingAnalysis = angularCompiler.analyzeAsync().then(() => {
566+
for (const lazyRoute of angularCompiler.listLazyRoutes()) {
567+
const [routeKey] = lazyRoute.route.split('#');
568+
this.lazyRouteMap[routeKey] = lazyRoute.referencedModule.filePath;
569+
}
570+
571+
return this.createFileEmitter(builder, transformers, () => []);
572+
});
573+
const analyzingFileEmitter: FileEmitter = async (file) => {
574+
const innerFileEmitter = await pendingAnalysis;
575+
576+
return innerFileEmitter(file);
577+
};
578+
579+
if (this.watchMode) {
580+
this.ngtscNextProgram = angularProgram;
564581
}
565582

566-
return this.createFileEmitter(builder, transformers, () => []);
567-
});
568-
const analyzingFileEmitter: FileEmitter = async (file) => {
569-
const innerFileEmitter = await pendingAnalysis;
583+
return {
584+
fileEmitter: analyzingFileEmitter,
585+
builder,
586+
internalFiles: undefined,
587+
};
588+
} else {
589+
// Update lazy route map for changed files using fast but less accurate method
590+
for (const changedFile of changedFiles) {
591+
if (!builder.getSourceFile(changedFile)) {
592+
continue;
593+
}
570594

571-
return innerFileEmitter(file);
572-
};
595+
const routes = findLazyRoutes(changedFile, host, builder.getProgram());
596+
for (const [routeKey, filePath] of Object.entries(routes)) {
597+
this.lazyRouteMap[routeKey] = filePath;
598+
}
599+
}
573600

574-
if (this.watchMode) {
575-
this.ngtscNextProgram = angularProgram;
601+
return {
602+
fileEmitter: this.createFileEmitter(builder, transformers, () => []),
603+
builder,
604+
internalFiles: undefined,
605+
};
576606
}
577-
578-
return {
579-
fileEmitter: analyzingFileEmitter,
580-
builder,
581-
internalFiles: undefined,
582-
};
583607
}
584608

585609
private createFileEmitter(

0 commit comments

Comments
 (0)