Skip to content

Commit 6570983

Browse files
committed
fix(@ngtools/webpack): remove compiler workarounds
These issues were fixed in Angular 5.0.0-rc.7. Fix angular#8228
1 parent d2e22b2 commit 6570983

File tree

3 files changed

+123
-140
lines changed

3 files changed

+123
-140
lines changed

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

+61-92
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
createProgram,
4848
createCompilerHost,
4949
formatDiagnostics,
50+
readConfiguration,
5051
} from './ngtools_api';
5152
import { findAstNodes } from './transformers/ast_helpers';
5253

@@ -86,13 +87,11 @@ export class AngularCompilerPlugin implements Tapable {
8687
private _options: AngularCompilerPluginOptions;
8788

8889
// TS compilation.
89-
private _compilerOptions: ts.CompilerOptions;
90-
private _angularCompilerOptions: CompilerOptions;
91-
private _tsFilenames: string[];
90+
private _compilerOptions: CompilerOptions;
91+
private _rootNames: string[];
9292
private _program: (ts.Program | Program);
93-
private _compilerHost: WebpackCompilerHost;
93+
private _compilerHost: WebpackCompilerHost & CompilerHost;
9494
private _moduleResolutionCache: ts.ModuleResolutionCache;
95-
private _angularCompilerHost: WebpackCompilerHost & CompilerHost;
9695
private _resourceLoader: WebpackResourceLoader;
9796
// Contains `moduleImportPath#exportName` => `fullModulePath`.
9897
private _lazyRoutes: LazyRouteMap = Object.create(null);
@@ -214,11 +213,10 @@ export class AngularCompilerPlugin implements Tapable {
214213
}
215214

216215
// Parse the tsconfig contents.
217-
const tsConfig = ts.parseJsonConfigFileContent(
218-
tsConfigJson, ts.sys, basePath, undefined, this._tsConfigPath);
216+
const config = readConfiguration(this._tsConfigPath, tsConfigJson);
219217

220-
this._tsFilenames = tsConfig.fileNames;
221-
this._compilerOptions = tsConfig.options;
218+
this._rootNames = config.rootNames;
219+
this._compilerOptions = config.options;
222220

223221
// Overwrite outDir so we can find generated files next to their .ts origin in compilerHost.
224222
this._compilerOptions.outDir = '';
@@ -250,55 +248,54 @@ export class AngularCompilerPlugin implements Tapable {
250248
// to the webpack dependency tree and rebuilds triggered by file edits.
251249
this._compilerOptions.noEmitOnError = false;
252250

253-
// Compose Angular Compiler Options.
254-
this._angularCompilerOptions = Object.assign(
255-
this._compilerOptions,
256-
tsConfig.raw['angularCompilerOptions'],
257-
{ basePath }
258-
);
259-
260251
// Set JIT (no code generation) or AOT mode.
261252
if (options.skipCodeGeneration !== undefined) {
262253
this._JitMode = options.skipCodeGeneration;
263254
}
264255

265256
// Process i18n options.
266257
if (options.hasOwnProperty('i18nInFile')) {
267-
this._angularCompilerOptions.i18nInFile = options.i18nInFile;
258+
this._compilerOptions.i18nInFile = options.i18nInFile;
268259
}
269260
if (options.hasOwnProperty('i18nInFormat')) {
270-
this._angularCompilerOptions.i18nInFormat = options.i18nInFormat;
261+
this._compilerOptions.i18nInFormat = options.i18nInFormat;
271262
}
272263
if (options.hasOwnProperty('i18nOutFile')) {
273-
this._angularCompilerOptions.i18nOutFile = options.i18nOutFile;
264+
this._compilerOptions.i18nOutFile = options.i18nOutFile;
274265
}
275266
if (options.hasOwnProperty('i18nOutFormat')) {
276-
this._angularCompilerOptions.i18nOutFormat = options.i18nOutFormat;
267+
this._compilerOptions.i18nOutFormat = options.i18nOutFormat;
277268
}
278269
if (options.hasOwnProperty('locale') && options.locale) {
279-
this._angularCompilerOptions.i18nInLocale = this._validateLocale(options.locale);
270+
this._compilerOptions.i18nInLocale = this._validateLocale(options.locale);
280271
}
281272
if (options.hasOwnProperty('missingTranslation')) {
282-
this._angularCompilerOptions.i18nInMissingTranslations =
273+
this._compilerOptions.i18nInMissingTranslations =
283274
options.missingTranslation as 'error' | 'warning' | 'ignore';
284275
}
285276

286277
// Use entryModule if available in options, otherwise resolve it from mainPath after program
287278
// creation.
288279
if (this._options.entryModule) {
289280
this._entryModule = this._options.entryModule;
290-
} else if (this._angularCompilerOptions.entryModule) {
281+
} else if (this._compilerOptions.entryModule) {
291282
this._entryModule = path.resolve(this._basePath,
292-
this._angularCompilerOptions.entryModule);
283+
this._compilerOptions.entryModule);
293284
}
294285

295286
// Create the webpack compiler host.
296-
this._compilerHost = new WebpackCompilerHost(this._compilerOptions, this._basePath);
297-
this._compilerHost.enableCaching();
287+
const webpackCompilerHost = new WebpackCompilerHost(this._compilerOptions, this._basePath);
288+
webpackCompilerHost.enableCaching();
298289

299290
// Create and set a new WebpackResourceLoader.
300291
this._resourceLoader = new WebpackResourceLoader();
301-
this._compilerHost.setResourceLoader(this._resourceLoader);
292+
webpackCompilerHost.setResourceLoader(this._resourceLoader);
293+
294+
// Use the WebpackCompilerHost with a resource loader to create an AngularCompilerHost.
295+
this._compilerHost = createCompilerHost({
296+
options: this._compilerOptions,
297+
tsHost: webpackCompilerHost
298+
}) as CompilerHost & WebpackCompilerHost;
302299

303300
// Override some files in the FileSystem.
304301
if (this._options.hostOverrideFileSystem) {
@@ -342,28 +339,24 @@ export class AngularCompilerPlugin implements Tapable {
342339
private _createOrUpdateProgram() {
343340
return Promise.resolve()
344341
.then(() => {
345-
const changedTsFiles = this._getChangedTsFiles();
346-
347-
changedTsFiles.forEach((file) => {
348-
if (!this._tsFilenames.includes(file)) {
349-
// TODO: figure out if action is needed for files that were removed from the
350-
// compilation.
351-
this._tsFilenames.push(file);
352-
}
353-
});
342+
// Get the root files from the ts config.
343+
// When a new root name (like a lazy route) is added, it won't be available from
344+
// following imports on the existing files, so we need to get the new list of root files.
345+
this._rootNames = readConfiguration(this._tsConfigPath).rootNames;
354346

355-
// Update the forked type checker.
347+
// Update the forked type checker with all changed compilation files.
348+
// This includes templates, that also need to be reloaded on the type checker.
356349
if (this._forkTypeChecker && !this._firstRun) {
357-
this._updateForkedTypeChecker(changedTsFiles);
350+
this._updateForkedTypeChecker(this._rootNames, this._getChangedCompilationFiles());
358351
}
359352

360353
if (this._JitMode) {
361354
// Create the TypeScript program.
362355
time('AngularCompilerPlugin._createOrUpdateProgram.ts.createProgram');
363356
this._program = ts.createProgram(
364-
this._tsFilenames,
365-
this._angularCompilerOptions,
366-
this._angularCompilerHost,
357+
this._rootNames,
358+
this._compilerOptions,
359+
this._compilerHost,
367360
this._program as ts.Program
368361
);
369362
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ts.createProgram');
@@ -372,26 +365,19 @@ export class AngularCompilerPlugin implements Tapable {
372365
} else {
373366
time('AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram');
374367
// Create the Angular program.
375-
try {
376-
this._program = createProgram({
377-
rootNames: this._tsFilenames,
378-
options: this._angularCompilerOptions,
379-
host: this._angularCompilerHost,
380-
oldProgram: this._program as Program
368+
this._program = createProgram({
369+
rootNames: this._rootNames,
370+
options: this._compilerOptions,
371+
host: this._compilerHost,
372+
oldProgram: this._program as Program
373+
});
374+
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram');
375+
376+
time('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync');
377+
return this._program.loadNgStructureAsync()
378+
.then(() => {
379+
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync');
381380
});
382-
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram');
383-
384-
time('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync');
385-
return this._program.loadNgStructureAsync()
386-
.then(() => {
387-
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync');
388-
});
389-
} catch (e) {
390-
// TODO: remove this when the issue is addressed.
391-
// Temporary workaround for https://github.com/angular/angular/issues/19951
392-
this._program = undefined;
393-
throw e;
394-
}
395381
}
396382
})
397383
.then(() => {
@@ -412,7 +398,7 @@ export class AngularCompilerPlugin implements Tapable {
412398
const result = __NGTOOLS_PRIVATE_API_2.listLazyRoutes({
413399
program: this._getTsProgram(),
414400
host: this._compilerHost,
415-
angularCompilerOptions: Object.assign({}, this._angularCompilerOptions, {
401+
angularCompilerOptions: Object.assign({}, this._compilerOptions, {
416402
// genDir seems to still be needed in @angular\compiler-cli\src\compiler_host.js:226.
417403
genDir: ''
418404
}),
@@ -508,8 +494,8 @@ export class AngularCompilerPlugin implements Tapable {
508494
} else {
509495
// Found a new route, add it to the map and read it into the compiler host.
510496
this._lazyRoutes[moduleKey] = modulePath;
511-
this._angularCompilerHost.readFile(lazyRouteTSFile);
512-
this._angularCompilerHost.invalidate(lazyRouteTSFile);
497+
this._compilerHost.readFile(lazyRouteTSFile);
498+
this._compilerHost.invalidate(lazyRouteTSFile);
513499
}
514500
});
515501
}
@@ -545,7 +531,7 @@ export class AngularCompilerPlugin implements Tapable {
545531

546532
this._typeCheckerProcess = fork(path.resolve(__dirname, typeCheckerFile), [], forkOptions);
547533
this._typeCheckerProcess.send(new InitMessage(this._compilerOptions, this._basePath,
548-
this._JitMode, this._tsFilenames));
534+
this._JitMode, this._rootNames));
549535

550536
// Cleanup.
551537
const killTypeCheckerProcess = () => {
@@ -557,8 +543,8 @@ export class AngularCompilerPlugin implements Tapable {
557543
process.once('uncaughtException', killTypeCheckerProcess);
558544
}
559545

560-
private _updateForkedTypeChecker(changedTsFiles: string[]) {
561-
this._typeCheckerProcess.send(new UpdateMessage(changedTsFiles));
546+
private _updateForkedTypeChecker(rootNames: string[], changedCompilationFiles: string[]) {
547+
this._typeCheckerProcess.send(new UpdateMessage(rootNames, changedCompilationFiles));
562548
}
563549

564550

@@ -682,22 +668,12 @@ export class AngularCompilerPlugin implements Tapable {
682668
// Update the resource loader with the new webpack compilation.
683669
this._resourceLoader.update(compilation);
684670

671+
// Create a new process for the type checker on the second build if there isn't one yet.
672+
if (this._forkTypeChecker && !this._firstRun && !this._typeCheckerProcess) {
673+
this._createForkedTypeChecker();
674+
}
675+
685676
this._donePromise = Promise.resolve()
686-
.then(() => {
687-
// Create a new process for the type checker.
688-
if (this._forkTypeChecker && !this._firstRun && !this._typeCheckerProcess) {
689-
this._createForkedTypeChecker();
690-
}
691-
})
692-
.then(() => {
693-
if (this._firstRun) {
694-
// Use the WebpackResourceLoader with a resource loader to create an AngularCompilerHost.
695-
this._angularCompilerHost = createCompilerHost({
696-
options: this._angularCompilerOptions,
697-
tsHost: this._compilerHost
698-
}) as CompilerHost & WebpackCompilerHost;
699-
}
700-
})
701677
.then(() => this._update())
702678
.then(() => {
703679
timeEnd('AngularCompilerPlugin._make');
@@ -731,10 +707,6 @@ export class AngularCompilerPlugin implements Tapable {
731707
const changedTsFiles = this._getChangedTsFiles();
732708
if (this._ngCompilerSupportsNewApi) {
733709
this._processLazyRoutes(this._listLazyRoutesFromProgram());
734-
// TODO: remove this when the issue is addressed.
735-
// Fix for a bug in compiler where the program needs to be updated after
736-
// _listLazyRoutesFromProgram is called.
737-
return this._createOrUpdateProgram();
738710
} else if (this._firstRun) {
739711
this._processLazyRoutes(this._getLazyRoutesFromNgtools());
740712
} else if (changedTsFiles.length > 0) {
@@ -772,11 +744,11 @@ export class AngularCompilerPlugin implements Tapable {
772744
}
773745

774746
// If we have a locale, auto import the locale data file.
775-
if (this._angularCompilerOptions.i18nInLocale) {
747+
if (this._compilerOptions.i18nInLocale) {
776748
transformOps.push(...registerLocaleData(
777749
sf,
778750
this.entryModule,
779-
this._angularCompilerOptions.i18nInLocale
751+
this._compilerOptions.i18nInLocale
780752
));
781753
}
782754
} else if (this._platform === PLATFORM.Server) {
@@ -846,7 +818,7 @@ export class AngularCompilerPlugin implements Tapable {
846818
}
847819

848820
// Write the extracted messages to disk.
849-
const i18nOutFilePath = path.resolve(this._basePath, this._angularCompilerOptions.i18nOutFile);
821+
const i18nOutFilePath = path.resolve(this._basePath, this._compilerOptions.i18nOutFile);
850822
const i18nOutFileContent = this._compilerHost.readFile(i18nOutFilePath);
851823
if (i18nOutFileContent) {
852824
_recursiveMkDir(path.dirname(i18nOutFilePath))
@@ -994,17 +966,14 @@ export class AngularCompilerPlugin implements Tapable {
994966

995967
if (!hasErrors(allDiagnostics)) {
996968
time('AngularCompilerPlugin._emit.ng.emit');
997-
const extractI18n = !!this._angularCompilerOptions.i18nOutFile;
969+
const extractI18n = !!this._compilerOptions.i18nOutFile;
998970
const emitFlags = extractI18n ? EmitFlags.I18nBundle : EmitFlags.Default;
999971
emitResult = angularProgram.emit({ emitFlags, customTransformers });
1000972
allDiagnostics.push(...emitResult.diagnostics);
1001973
if (extractI18n) {
1002974
this.writeI18nOutFile();
1003975
}
1004976
timeEnd('AngularCompilerPlugin._emit.ng.emit');
1005-
} else {
1006-
// Throw away the old program if there was an error.
1007-
this._program = undefined;
1008977
}
1009978
}
1010979
} catch (e) {

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

+11
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ export interface CreateCompilerHostInterface {
112112
export interface FormatDiagnosticsInterface {
113113
(diags: Diagnostics): string;
114114
}
115+
export interface ParsedConfiguration {
116+
project: string;
117+
options: CompilerOptions;
118+
rootNames: string[];
119+
emitFlags: any;
120+
errors: Diagnostics;
121+
}
122+
export interface ReadConfigurationInterface {
123+
(project: string, existingOptions?: ts.CompilerOptions): ParsedConfiguration;
124+
}
115125

116126
// Manually check for Compiler CLI availability and supported version.
117127
// This is needed because @ngtools/webpack does not depend directly on @angular/compiler-cli, since
@@ -173,4 +183,5 @@ try {
173183
export const createProgram: CreateProgramInterface = ngtools2.createProgram;
174184
export const createCompilerHost: CreateCompilerHostInterface = ngtools2.createCompilerHost;
175185
export const formatDiagnostics: FormatDiagnosticsInterface = ngtools2.formatDiagnostics;
186+
export const readConfiguration: ReadConfigurationInterface = compilerCli.readConfiguration;
176187
export const EmitFlags = ngtools2.EmitFlags;

0 commit comments

Comments
 (0)