Skip to content

Commit 4b0c7a3

Browse files
committed
fix(@ngtools/webpack): fallback to main thread typechecking
This PR will prevent the main thread for exiting when the forked type checker exists unexpectedly. A warning will be logged on the console when this happens: ``` WARNING in AngularCompilerPlugin: Forked Type Checker exited unexpectedly. Falling back to typechecking on main thread. ``` Fix angular#8331
1 parent 78e1395 commit 4b0c7a3

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

packages/@ngtools/webpack/src/angular_compiler_plugin.ts

+41-16
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ export class AngularCompilerPlugin implements Tapable {
106106
// Webpack plugin.
107107
private _firstRun = true;
108108
private _donePromise: Promise<void> | null;
109-
private _compiler: any = null;
110-
private _compilation: any = null;
111109
private _normalizedLocale: string;
110+
private _warnings: (string | Error)[] = [];
111+
private _errors: (string | Error)[] = [];
112112

113113
// TypeChecker process.
114114
private _forkTypeChecker = true;
@@ -447,7 +447,7 @@ export class AngularCompilerPlugin implements Tapable {
447447
if (moduleKey in this._lazyRoutes) {
448448
if (this._lazyRoutes[moduleKey] !== modulePath) {
449449
// Found a duplicate, this is an error.
450-
this._compilation.warnings.push(
450+
this._warnings.push(
451451
new Error(`Duplicated path in loadChildren detected during a rebuild. `
452452
+ `We will take the latest version detected and override it to save rebuild time. `
453453
+ `You should perform a full build to validate that your routes don't overlap.`)
@@ -483,12 +483,32 @@ export class AngularCompilerPlugin implements Tapable {
483483

484484
// Cleanup.
485485
const killTypeCheckerProcess = () => {
486-
treeKill(this._typeCheckerProcess.pid, 'SIGTERM');
486+
if (this._typeCheckerProcess && this._typeCheckerProcess.pid) {
487+
treeKill(this._typeCheckerProcess.pid, 'SIGTERM');
488+
this._typeCheckerProcess = undefined;
489+
this._forkTypeChecker = false;
490+
}
491+
};
492+
493+
// Handle child process exit.
494+
const handleChildProcessExit = () => {
495+
killTypeCheckerProcess();
496+
const msg = 'AngularCompilerPlugin: Forked Type Checker exited unexpectedly. ' +
497+
'Falling back to typechecking on main thread.';
498+
this._warnings.push(msg);
499+
};
500+
this._typeCheckerProcess.once('exit', handleChildProcessExit);
501+
this._typeCheckerProcess.once('SIGINT', handleChildProcessExit);
502+
this._typeCheckerProcess.once('uncaughtException', handleChildProcessExit);
503+
504+
// Handle parent process exit.
505+
const handleParentProcessExit = () => {
506+
killTypeCheckerProcess();
487507
process.exit();
488508
};
489-
process.once('exit', killTypeCheckerProcess);
490-
process.once('SIGINT', killTypeCheckerProcess);
491-
process.once('uncaughtException', killTypeCheckerProcess);
509+
process.once('exit', handleParentProcessExit);
510+
process.once('SIGINT', handleParentProcessExit);
511+
process.once('uncaughtException', handleParentProcessExit);
492512
}
493513

494514
private _updateForkedTypeChecker(rootNames: string[], changedCompilationFiles: string[]) {
@@ -498,8 +518,6 @@ export class AngularCompilerPlugin implements Tapable {
498518

499519
// Registration hook for webpack plugin.
500520
apply(compiler: any) {
501-
this._compiler = compiler;
502-
503521
// Decorate inputFileSystem to serve contents of CompilerHost.
504522
// Use decorated inputFileSystem in watchFileSystem.
505523
compiler.plugin('environment', () => {
@@ -573,7 +591,6 @@ export class AngularCompilerPlugin implements Tapable {
573591
});
574592
compiler.plugin('done', () => {
575593
this._donePromise = null;
576-
this._compilation = null;
577594
});
578595

579596
// TODO: consider if it's better to remove this plugin and instead make it wait on the
@@ -604,14 +621,13 @@ export class AngularCompilerPlugin implements Tapable {
604621

605622
private _make(compilation: any, cb: (err?: any, request?: any) => void) {
606623
time('AngularCompilerPlugin._make');
607-
this._compilation = compilation;
608624
this._emitSkipped = true;
609-
if (this._compilation._ngToolsWebpackPluginInstance) {
625+
if (compilation._ngToolsWebpackPluginInstance) {
610626
return cb(new Error('An @ngtools/webpack plugin already exist for this compilation.'));
611627
}
612628

613629
// Set a private variable for this plugin instance.
614-
this._compilation._ngToolsWebpackPluginInstance = this;
630+
compilation._ngToolsWebpackPluginInstance = this;
615631

616632
// Update the resource loader with the new webpack compilation.
617633
this._resourceLoader.update(compilation);
@@ -624,15 +640,24 @@ export class AngularCompilerPlugin implements Tapable {
624640
this._donePromise = Promise.resolve()
625641
.then(() => this._update())
626642
.then(() => {
643+
this.pushCompilationErrors(compilation);
627644
timeEnd('AngularCompilerPlugin._make');
628645
cb();
629646
}, (err: any) => {
630647
compilation.errors.push(err.stack);
648+
this.pushCompilationErrors(compilation);
631649
timeEnd('AngularCompilerPlugin._make');
632650
cb();
633651
});
634652
}
635653

654+
private pushCompilationErrors(compilation: any) {
655+
compilation.errors.push(...this._errors);
656+
compilation.warnings.push(...this._warnings);
657+
this._errors = [];
658+
this._warnings = [];
659+
}
660+
636661
private _makeTransformers() {
637662

638663
const isAppPath = (fileName: string) =>
@@ -730,18 +755,18 @@ export class AngularCompilerPlugin implements Tapable {
730755

731756
if (errors.length > 0) {
732757
const message = formatDiagnostics(errors);
733-
this._compilation.errors.push(message);
758+
this._errors.push(message);
734759
}
735760

736761
if (warnings.length > 0) {
737762
const message = formatDiagnostics(warnings);
738-
this._compilation.warnings.push(message);
763+
this._warnings.push(message);
739764
}
740765

741766
this._emitSkipped = !emitResult || emitResult.emitSkipped;
742767

743768
// Reset changed files on successful compilation.
744-
if (!this._emitSkipped && this._compilation.errors.length === 0) {
769+
if (!this._emitSkipped && this._errors.length === 0) {
745770
this._compilerHost.resetChangedFileTracker();
746771
}
747772
timeEnd('AngularCompilerPlugin._update');

0 commit comments

Comments
 (0)