Skip to content

Commit 263e84b

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 263e84b

File tree

6 files changed

+145
-182
lines changed

6 files changed

+145
-182
lines changed

packages/@angular/cli/models/webpack-configs/typescript.ts

-3
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,6 @@ function _createAotPlugin(wco: WebpackConfigOptions, options: any) {
9292
missingTranslation: buildOptions.missingTranslation,
9393
hostReplacementPaths,
9494
sourceMap: buildOptions.sourcemaps,
95-
// If we don't explicitely list excludes, it will default to `['**/*.spec.ts']`.
96-
exclude: [],
97-
include: options.include,
9895
}, options);
9996
return new AngularCompilerPlugin(pluginOptions);
10097
} else {

packages/@ngtools/webpack/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ The loader works with webpack plugin to compile your TypeScript. It's important
6666
* `mainPath`. Optional if `entryModule` is specified. The `main.ts` file containing the bootstrap code. The plugin will use AST to determine the `entryModule`.
6767
* `skipCodeGeneration`. Optional, defaults to false. Disable code generation and do not refactor the code to bootstrap. This replaces `templateUrl: "string"` with `template: require("string")` (and similar for styles) to allow for webpack to properly link the resources. Only available in `AotPlugin`.
6868
* `typeChecking`. Optional, defaults to true. Enable type checking through your application. This will slow down compilation, but show syntactic and semantic errors in webpack. Only available in `AotPlugin`.
69-
* `exclude`. Optional. Extra files to exclude from TypeScript compilation.
69+
* `exclude`. Optional. Extra files to exclude from TypeScript compilation. Not supported with `AngularCompilerPlugin`.
7070
* `sourceMap`. Optional. Include sourcemaps.
7171
* `compilerOptions`. Optional. Override options in `tsconfig.json`.
7272

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

+71-119
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

@@ -72,8 +73,6 @@ export interface AngularCompilerPluginOptions {
7273
platform?: PLATFORM;
7374

7475
// Use tsconfig to include path globs.
75-
exclude?: string | string[];
76-
include?: string[];
7776
compilerOptions?: ts.CompilerOptions;
7877
}
7978

@@ -86,13 +85,11 @@ export class AngularCompilerPlugin implements Tapable {
8685
private _options: AngularCompilerPluginOptions;
8786

8887
// TS compilation.
89-
private _compilerOptions: ts.CompilerOptions;
90-
private _angularCompilerOptions: CompilerOptions;
91-
private _tsFilenames: string[];
88+
private _compilerOptions: CompilerOptions;
89+
private _rootNames: string[];
9290
private _program: (ts.Program | Program);
93-
private _compilerHost: WebpackCompilerHost;
91+
private _compilerHost: WebpackCompilerHost & CompilerHost;
9492
private _moduleResolutionCache: ts.ModuleResolutionCache;
95-
private _angularCompilerHost: WebpackCompilerHost & CompilerHost;
9693
private _resourceLoader: WebpackResourceLoader;
9794
// Contains `moduleImportPath#exportName` => `fullModulePath`.
9895
private _lazyRoutes: LazyRouteMap = Object.create(null);
@@ -186,39 +183,11 @@ export class AngularCompilerPlugin implements Tapable {
186183
);
187184
}
188185

189-
// Default exclude to **/*.spec.ts files.
190-
if (!options.hasOwnProperty('exclude')) {
191-
options['exclude'] = ['**/*.spec.ts'];
192-
}
193-
194-
// Add custom excludes to default TypeScript excludes.
195-
if (options.hasOwnProperty('exclude')) {
196-
// If the tsconfig doesn't contain any excludes, we must add the default ones before adding
197-
// any extra ones (otherwise we'd include all of these which can cause unexpected errors).
198-
// This is the same logic as present in TypeScript.
199-
if (!tsConfigJson.exclude) {
200-
tsConfigJson['exclude'] = ['node_modules', 'bower_components', 'jspm_packages'];
201-
if (tsConfigJson.compilerOptions && tsConfigJson.compilerOptions.outDir) {
202-
tsConfigJson.exclude.push(tsConfigJson.compilerOptions.outDir);
203-
}
204-
}
205-
206-
// Join our custom excludes with the existing ones.
207-
tsConfigJson.exclude = tsConfigJson.exclude.concat(options.exclude);
208-
}
209-
210-
// Add extra includes.
211-
if (options.hasOwnProperty('include') && Array.isArray(options.include)) {
212-
tsConfigJson.include = tsConfigJson.include || [];
213-
tsConfigJson.include.push(...options.include);
214-
}
215-
216186
// Parse the tsconfig contents.
217-
const tsConfig = ts.parseJsonConfigFileContent(
218-
tsConfigJson, ts.sys, basePath, undefined, this._tsConfigPath);
187+
const config = readConfiguration(this._tsConfigPath, tsConfigJson.compilerOptions);
219188

220-
this._tsFilenames = tsConfig.fileNames;
221-
this._compilerOptions = tsConfig.options;
189+
this._rootNames = config.rootNames;
190+
this._compilerOptions = config.options;
222191

223192
// Overwrite outDir so we can find generated files next to their .ts origin in compilerHost.
224193
this._compilerOptions.outDir = '';
@@ -250,55 +219,54 @@ export class AngularCompilerPlugin implements Tapable {
250219
// to the webpack dependency tree and rebuilds triggered by file edits.
251220
this._compilerOptions.noEmitOnError = false;
252221

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

265227
// Process i18n options.
266228
if (options.hasOwnProperty('i18nInFile')) {
267-
this._angularCompilerOptions.i18nInFile = options.i18nInFile;
229+
this._compilerOptions.i18nInFile = options.i18nInFile;
268230
}
269231
if (options.hasOwnProperty('i18nInFormat')) {
270-
this._angularCompilerOptions.i18nInFormat = options.i18nInFormat;
232+
this._compilerOptions.i18nInFormat = options.i18nInFormat;
271233
}
272234
if (options.hasOwnProperty('i18nOutFile')) {
273-
this._angularCompilerOptions.i18nOutFile = options.i18nOutFile;
235+
this._compilerOptions.i18nOutFile = options.i18nOutFile;
274236
}
275237
if (options.hasOwnProperty('i18nOutFormat')) {
276-
this._angularCompilerOptions.i18nOutFormat = options.i18nOutFormat;
238+
this._compilerOptions.i18nOutFormat = options.i18nOutFormat;
277239
}
278240
if (options.hasOwnProperty('locale') && options.locale) {
279-
this._angularCompilerOptions.i18nInLocale = this._validateLocale(options.locale);
241+
this._compilerOptions.i18nInLocale = this._validateLocale(options.locale);
280242
}
281243
if (options.hasOwnProperty('missingTranslation')) {
282-
this._angularCompilerOptions.i18nInMissingTranslations =
244+
this._compilerOptions.i18nInMissingTranslations =
283245
options.missingTranslation as 'error' | 'warning' | 'ignore';
284246
}
285247

286248
// Use entryModule if available in options, otherwise resolve it from mainPath after program
287249
// creation.
288250
if (this._options.entryModule) {
289251
this._entryModule = this._options.entryModule;
290-
} else if (this._angularCompilerOptions.entryModule) {
252+
} else if (this._compilerOptions.entryModule) {
291253
this._entryModule = path.resolve(this._basePath,
292-
this._angularCompilerOptions.entryModule);
254+
this._compilerOptions.entryModule);
293255
}
294256

295257
// Create the webpack compiler host.
296-
this._compilerHost = new WebpackCompilerHost(this._compilerOptions, this._basePath);
297-
this._compilerHost.enableCaching();
258+
const webpackCompilerHost = new WebpackCompilerHost(this._compilerOptions, this._basePath);
259+
webpackCompilerHost.enableCaching();
298260

299261
// Create and set a new WebpackResourceLoader.
300262
this._resourceLoader = new WebpackResourceLoader();
301-
this._compilerHost.setResourceLoader(this._resourceLoader);
263+
webpackCompilerHost.setResourceLoader(this._resourceLoader);
264+
265+
// Use the WebpackCompilerHost with a resource loader to create an AngularCompilerHost.
266+
this._compilerHost = createCompilerHost({
267+
options: this._compilerOptions,
268+
tsHost: webpackCompilerHost
269+
}) as CompilerHost & WebpackCompilerHost;
302270

303271
// Override some files in the FileSystem.
304272
if (this._options.hostOverrideFileSystem) {
@@ -342,28 +310,38 @@ export class AngularCompilerPlugin implements Tapable {
342310
private _createOrUpdateProgram() {
343311
return Promise.resolve()
344312
.then(() => {
345-
const changedTsFiles = this._getChangedTsFiles();
346-
347-
changedTsFiles.forEach((file) => {
348-
if (!this._tsFilenames.includes(file)) {
313+
// Get the root files from the ts config.
314+
// When a new root name (like a lazy route) is added, it won't be available from
315+
// following imports on the existing files, so we need to get the new list of root files.
316+
this._rootNames = readConfiguration(this._tsConfigPath).rootNames;
317+
318+
// *************************************************************************************
319+
// REMOVE THIS WITH UPDATED NG5 SCHEMATICS
320+
// Doing this is EXTREMELY wrong and we have to tell users to update their package.json
321+
// instead.
322+
// `src/tsconfig.spec.json` needs to be updated with `"include": [ "**/*.ts" ]`
323+
// *************************************************************************************
324+
this._getChangedTsFiles().forEach((file) => {
325+
if (!this._rootNames.includes(file)) {
349326
// TODO: figure out if action is needed for files that were removed from the
350327
// compilation.
351-
this._tsFilenames.push(file);
328+
this._rootNames.push(file);
352329
}
353330
});
354331

355-
// Update the forked type checker.
332+
// Update the forked type checker with all changed compilation files.
333+
// This includes templates, that also need to be reloaded on the type checker.
356334
if (this._forkTypeChecker && !this._firstRun) {
357-
this._updateForkedTypeChecker(changedTsFiles);
335+
this._updateForkedTypeChecker(this._rootNames, this._getChangedCompilationFiles());
358336
}
359337

360338
if (this._JitMode) {
361339
// Create the TypeScript program.
362340
time('AngularCompilerPlugin._createOrUpdateProgram.ts.createProgram');
363341
this._program = ts.createProgram(
364-
this._tsFilenames,
365-
this._angularCompilerOptions,
366-
this._angularCompilerHost,
342+
this._rootNames,
343+
this._compilerOptions,
344+
this._compilerHost,
367345
this._program as ts.Program
368346
);
369347
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ts.createProgram');
@@ -372,26 +350,19 @@ export class AngularCompilerPlugin implements Tapable {
372350
} else {
373351
time('AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram');
374352
// 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
353+
this._program = createProgram({
354+
rootNames: this._rootNames,
355+
options: this._compilerOptions,
356+
host: this._compilerHost,
357+
oldProgram: this._program as Program
358+
});
359+
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram');
360+
361+
time('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync');
362+
return this._program.loadNgStructureAsync()
363+
.then(() => {
364+
timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync');
381365
});
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-
}
395366
}
396367
})
397368
.then(() => {
@@ -412,7 +383,7 @@ export class AngularCompilerPlugin implements Tapable {
412383
const result = __NGTOOLS_PRIVATE_API_2.listLazyRoutes({
413384
program: this._getTsProgram(),
414385
host: this._compilerHost,
415-
angularCompilerOptions: Object.assign({}, this._angularCompilerOptions, {
386+
angularCompilerOptions: Object.assign({}, this._compilerOptions, {
416387
// genDir seems to still be needed in @angular\compiler-cli\src\compiler_host.js:226.
417388
genDir: ''
418389
}),
@@ -506,10 +477,8 @@ export class AngularCompilerPlugin implements Tapable {
506477
);
507478
}
508479
} else {
509-
// Found a new route, add it to the map and read it into the compiler host.
480+
// Found a new route, add it to the map.
510481
this._lazyRoutes[moduleKey] = modulePath;
511-
this._angularCompilerHost.readFile(lazyRouteTSFile);
512-
this._angularCompilerHost.invalidate(lazyRouteTSFile);
513482
}
514483
});
515484
}
@@ -545,7 +514,7 @@ export class AngularCompilerPlugin implements Tapable {
545514

546515
this._typeCheckerProcess = fork(path.resolve(__dirname, typeCheckerFile), [], forkOptions);
547516
this._typeCheckerProcess.send(new InitMessage(this._compilerOptions, this._basePath,
548-
this._JitMode, this._tsFilenames));
517+
this._JitMode, this._rootNames));
549518

550519
// Cleanup.
551520
const killTypeCheckerProcess = () => {
@@ -557,8 +526,8 @@ export class AngularCompilerPlugin implements Tapable {
557526
process.once('uncaughtException', killTypeCheckerProcess);
558527
}
559528

560-
private _updateForkedTypeChecker(changedTsFiles: string[]) {
561-
this._typeCheckerProcess.send(new UpdateMessage(changedTsFiles));
529+
private _updateForkedTypeChecker(rootNames: string[], changedCompilationFiles: string[]) {
530+
this._typeCheckerProcess.send(new UpdateMessage(rootNames, changedCompilationFiles));
562531
}
563532

564533

@@ -682,22 +651,12 @@ export class AngularCompilerPlugin implements Tapable {
682651
// Update the resource loader with the new webpack compilation.
683652
this._resourceLoader.update(compilation);
684653

654+
// Create a new process for the type checker on the second build if there isn't one yet.
655+
if (this._forkTypeChecker && !this._firstRun && !this._typeCheckerProcess) {
656+
this._createForkedTypeChecker();
657+
}
658+
685659
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-
})
701660
.then(() => this._update())
702661
.then(() => {
703662
timeEnd('AngularCompilerPlugin._make');
@@ -731,18 +690,14 @@ export class AngularCompilerPlugin implements Tapable {
731690
const changedTsFiles = this._getChangedTsFiles();
732691
if (this._ngCompilerSupportsNewApi) {
733692
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();
738693
} else if (this._firstRun) {
739694
this._processLazyRoutes(this._getLazyRoutesFromNgtools());
740695
} else if (changedTsFiles.length > 0) {
741696
this._processLazyRoutes(this._findLazyRoutesInAst(changedTsFiles));
742697
}
743698
})
744699
.then(() => {
745-
// Build transforms, emit and report errorsn.
700+
// Build transforms, emit and report errors.
746701

747702
// We now have the final list of changed TS files.
748703
// Go through each changed file and add transforms as needed.
@@ -772,11 +727,11 @@ export class AngularCompilerPlugin implements Tapable {
772727
}
773728

774729
// If we have a locale, auto import the locale data file.
775-
if (this._angularCompilerOptions.i18nInLocale) {
730+
if (this._compilerOptions.i18nInLocale) {
776731
transformOps.push(...registerLocaleData(
777732
sf,
778733
this.entryModule,
779-
this._angularCompilerOptions.i18nInLocale
734+
this._compilerOptions.i18nInLocale
780735
));
781736
}
782737
} else if (this._platform === PLATFORM.Server) {
@@ -846,7 +801,7 @@ export class AngularCompilerPlugin implements Tapable {
846801
}
847802

848803
// Write the extracted messages to disk.
849-
const i18nOutFilePath = path.resolve(this._basePath, this._angularCompilerOptions.i18nOutFile);
804+
const i18nOutFilePath = path.resolve(this._basePath, this._compilerOptions.i18nOutFile);
850805
const i18nOutFileContent = this._compilerHost.readFile(i18nOutFilePath);
851806
if (i18nOutFileContent) {
852807
_recursiveMkDir(path.dirname(i18nOutFilePath))
@@ -994,17 +949,14 @@ export class AngularCompilerPlugin implements Tapable {
994949

995950
if (!hasErrors(allDiagnostics)) {
996951
time('AngularCompilerPlugin._emit.ng.emit');
997-
const extractI18n = !!this._angularCompilerOptions.i18nOutFile;
952+
const extractI18n = !!this._compilerOptions.i18nOutFile;
998953
const emitFlags = extractI18n ? EmitFlags.I18nBundle : EmitFlags.Default;
999954
emitResult = angularProgram.emit({ emitFlags, customTransformers });
1000955
allDiagnostics.push(...emitResult.diagnostics);
1001956
if (extractI18n) {
1002957
this.writeI18nOutFile();
1003958
}
1004959
timeEnd('AngularCompilerPlugin._emit.ng.emit');
1005-
} else {
1006-
// Throw away the old program if there was an error.
1007-
this._program = undefined;
1008960
}
1009961
}
1010962
} catch (e) {

0 commit comments

Comments
 (0)