Skip to content

Commit 5d8ccc9

Browse files
committed
fix(@ngtools/webpack): fix tsconfig parsing and rootfile list
Fix angular#8228
1 parent d2e22b2 commit 5d8ccc9

File tree

17 files changed

+234
-300
lines changed

17 files changed

+234
-300
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

+70-153
Large diffs are not rendered by default.

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;

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

+57-54
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ export class InitMessage extends TypeCheckerMessage {
3434
public compilerOptions: ts.CompilerOptions,
3535
public basePath: string,
3636
public jitMode: boolean,
37-
public tsFilenames: string[],
37+
public rootNames: string[],
3838
) {
3939
super(MESSAGE_KIND.Init);
4040
}
4141
}
4242

4343
export class UpdateMessage extends TypeCheckerMessage {
44-
constructor(public changedTsFiles: string[]) {
44+
constructor(public rootNames: string[], public changedCompilationFiles: string[]) {
4545
super(MESSAGE_KIND.Update);
4646
}
4747
}
@@ -51,90 +51,89 @@ let lastCancellationToken: CancellationToken;
5151

5252
process.on('message', (message: TypeCheckerMessage) => {
5353
time('TypeChecker.message');
54-
try {
55-
switch (message.kind) {
56-
case MESSAGE_KIND.Init:
57-
const initMessage = message as InitMessage;
58-
typeChecker = new TypeChecker(
59-
initMessage.compilerOptions,
60-
initMessage.basePath,
61-
initMessage.jitMode,
62-
initMessage.tsFilenames,
63-
);
64-
break;
65-
case MESSAGE_KIND.Update:
66-
if (!typeChecker) {
67-
throw new Error('TypeChecker: update message received before initialization');
68-
}
69-
if (lastCancellationToken) {
70-
// This cancellation token doesn't seem to do much, messages don't seem to be processed
71-
// before the diagnostics finish.
72-
lastCancellationToken.requestCancellation();
73-
}
74-
const updateMessage = message as UpdateMessage;
75-
lastCancellationToken = new CancellationToken();
76-
typeChecker.update(updateMessage.changedTsFiles, lastCancellationToken);
77-
break;
78-
default:
79-
throw new Error(`TypeChecker: Unexpected message received: ${message}.`);
80-
}
81-
} catch (error) {
82-
// Ignore errors in the TypeChecker.
83-
// Anything that would throw here will error out the compilation as well.
54+
switch (message.kind) {
55+
case MESSAGE_KIND.Init:
56+
const initMessage = message as InitMessage;
57+
typeChecker = new TypeChecker(
58+
initMessage.compilerOptions,
59+
initMessage.basePath,
60+
initMessage.jitMode,
61+
initMessage.rootNames,
62+
);
63+
break;
64+
case MESSAGE_KIND.Update:
65+
if (!typeChecker) {
66+
throw new Error('TypeChecker: update message received before initialization');
67+
}
68+
if (lastCancellationToken) {
69+
// This cancellation token doesn't seem to do much, messages don't seem to be processed
70+
// before the diagnostics finish.
71+
lastCancellationToken.requestCancellation();
72+
}
73+
const updateMessage = message as UpdateMessage;
74+
lastCancellationToken = new CancellationToken();
75+
typeChecker.update(updateMessage.rootNames, updateMessage.changedCompilationFiles,
76+
lastCancellationToken);
77+
break;
78+
default:
79+
throw new Error(`TypeChecker: Unexpected message received: ${message}.`);
8480
}
8581
timeEnd('TypeChecker.message');
8682
});
8783

8884

8985
class TypeChecker {
9086
private _program: ts.Program | Program;
91-
private _angularCompilerHost: WebpackCompilerHost & CompilerHost;
87+
private _compilerHost: WebpackCompilerHost & CompilerHost;
9288

9389
constructor(
94-
private _angularCompilerOptions: CompilerOptions,
90+
private _compilerOptions: CompilerOptions,
9591
_basePath: string,
9692
private _JitMode: boolean,
97-
private _tsFilenames: string[],
93+
private _rootNames: string[],
9894
) {
9995
time('TypeChecker.constructor');
100-
const compilerHost = new WebpackCompilerHost(_angularCompilerOptions, _basePath);
96+
const compilerHost = new WebpackCompilerHost(_compilerOptions, _basePath);
10197
compilerHost.enableCaching();
102-
this._angularCompilerHost = createCompilerHost({
103-
options: this._angularCompilerOptions,
98+
// We don't set a async resource loader on the compiler host because we only support
99+
// html templates, which are the only ones that can throw errors, and those can be loaded
100+
// synchronously.
101+
// If we need to also report errors on styles then we'll need to ask the main thread
102+
// for these resources.
103+
this._compilerHost = createCompilerHost({
104+
options: this._compilerOptions,
104105
tsHost: compilerHost
105106
}) as CompilerHost & WebpackCompilerHost;
106107
timeEnd('TypeChecker.constructor');
107108
}
108109

109-
private _updateTsFilenames(changedTsFiles: string[]) {
110-
time('TypeChecker._updateTsFilenames');
111-
changedTsFiles.forEach((fileName) => {
112-
this._angularCompilerHost.invalidate(fileName);
113-
if (!this._tsFilenames.includes(fileName)) {
114-
this._tsFilenames.push(fileName);
115-
}
110+
private _update(rootNames: string[], changedCompilationFiles: string[]) {
111+
time('TypeChecker._update');
112+
this._rootNames = rootNames;
113+
changedCompilationFiles.forEach((fileName) => {
114+
this._compilerHost.invalidate(fileName);
116115
});
117-
timeEnd('TypeChecker._updateTsFilenames');
116+
timeEnd('TypeChecker._update');
118117
}
119118

120119
private _createOrUpdateProgram() {
121120
if (this._JitMode) {
122121
// Create the TypeScript program.
123122
time('TypeChecker._createOrUpdateProgram.ts.createProgram');
124123
this._program = ts.createProgram(
125-
this._tsFilenames,
126-
this._angularCompilerOptions,
127-
this._angularCompilerHost,
124+
this._rootNames,
125+
this._compilerOptions,
126+
this._compilerHost,
128127
this._program as ts.Program
129128
) as ts.Program;
130129
timeEnd('TypeChecker._createOrUpdateProgram.ts.createProgram');
131130
} else {
132131
time('TypeChecker._createOrUpdateProgram.ng.createProgram');
133132
// Create the Angular program.
134133
this._program = createProgram({
135-
rootNames: this._tsFilenames,
136-
options: this._angularCompilerOptions,
137-
host: this._angularCompilerHost,
134+
rootNames: this._rootNames,
135+
options: this._compilerOptions,
136+
host: this._compilerHost,
138137
oldProgram: this._program as Program
139138
}) as Program;
140139
timeEnd('TypeChecker._createOrUpdateProgram.ng.createProgram');
@@ -153,6 +152,9 @@ class TypeChecker {
153152
if (errors.length > 0) {
154153
const message = formatDiagnostics(errors);
155154
console.error(bold(red('ERROR in ' + message)));
155+
} else {
156+
// Reset the changed file tracker only if there are no errors.
157+
this._compilerHost.resetChangedFileTracker();
156158
}
157159

158160
if (warnings.length > 0) {
@@ -162,8 +164,9 @@ class TypeChecker {
162164
}
163165
}
164166

165-
public update(changedTsFiles: string[], cancellationToken: CancellationToken) {
166-
this._updateTsFilenames(changedTsFiles);
167+
public update(rootNames: string[], changedCompilationFiles: string[],
168+
cancellationToken: CancellationToken) {
169+
this._update(rootNames, changedCompilationFiles);
167170
this._createOrUpdateProgram();
168171
this._diagnose(cancellationToken);
169172
}

tests/e2e/assets/webpack/test-app-ng5/package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
"name": "test",
33
"license": "MIT",
44
"dependencies": {
5-
"@angular/common": "^5.0.0-beta.5",
6-
"@angular/compiler": "^5.0.0-beta.5",
7-
"@angular/compiler-cli": "^5.0.0-beta.5",
8-
"@angular/core": "^5.0.0-beta.5",
9-
"@angular/http": "^5.0.0-beta.5",
10-
"@angular/platform-browser": "^5.0.0-beta.5",
11-
"@angular/platform-browser-dynamic": "^5.0.0-beta.5",
12-
"@angular/platform-server": "^5.0.0-beta.5",
13-
"@angular/router": "^5.0.0-beta.5",
5+
"@angular/common": "^5.0.0-rc.8",
6+
"@angular/compiler": "^5.0.0-rc.8",
7+
"@angular/compiler-cli": "^5.0.0-rc.8",
8+
"@angular/core": "^5.0.0-rc.8",
9+
"@angular/http": "^5.0.0-rc.8",
10+
"@angular/platform-browser": "^5.0.0-rc.8",
11+
"@angular/platform-browser-dynamic": "^5.0.0-rc.8",
12+
"@angular/platform-server": "^5.0.0-rc.8",
13+
"@angular/router": "^5.0.0-rc.8",
1414
"@ngtools/webpack": "0.0.0",
1515
"core-js": "^2.4.1",
16-
"rxjs": "^5.4.2",
16+
"rxjs": "^5.5.0",
1717
"zone.js": "^0.8.14"
1818
},
1919
"devDependencies": {

tests/e2e/assets/webpack/test-app-weird-ng5/package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
"name": "test",
33
"license": "MIT",
44
"dependencies": {
5-
"@angular/common": "^5.0.0-beta.5",
6-
"@angular/compiler": "^5.0.0-beta.5",
7-
"@angular/compiler-cli": "^5.0.0-beta.5",
8-
"@angular/core": "^5.0.0-beta.5",
9-
"@angular/http": "^5.0.0-beta.5",
10-
"@angular/platform-browser": "^5.0.0-beta.5",
11-
"@angular/platform-browser-dynamic": "^5.0.0-beta.5",
12-
"@angular/platform-server": "^5.0.0-beta.5",
13-
"@angular/router": "^5.0.0-beta.5",
5+
"@angular/common": "^5.0.0-rc.8",
6+
"@angular/compiler": "^5.0.0-rc.8",
7+
"@angular/compiler-cli": "^5.0.0-rc.8",
8+
"@angular/core": "^5.0.0-rc.8",
9+
"@angular/http": "^5.0.0-rc.8",
10+
"@angular/platform-browser": "^5.0.0-rc.8",
11+
"@angular/platform-browser-dynamic": "^5.0.0-rc.8",
12+
"@angular/platform-server": "^5.0.0-rc.8",
13+
"@angular/router": "^5.0.0-rc.8",
1414
"@ngtools/webpack": "0.0.0",
1515
"core-js": "^2.4.1",
16-
"rxjs": "^5.4.2",
16+
"rxjs": "^5.5.0",
1717
"zone.js": "^0.8.14"
1818
},
1919
"devDependencies": {

tests/e2e/setup/500-create-project.ts

+10
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ export default function() {
5252
.then(() => updateTsConfig(json => {
5353
json['compilerOptions']['sourceRoot'] = '/';
5454
}))
55+
.then(() => updateJsonFile('src/tsconfig.spec.json', json => {
56+
if (argv.nightly) {
57+
// *************************************************************************************
58+
// REMOVE THIS WITH UPDATED NG5 SCHEMATICS
59+
// In ng5 we have to tell users users to update their tsconfig.json.
60+
// `src/tsconfig.spec.json` needs to be updated with `"include": [ "**/*.ts" ]`
61+
// *************************************************************************************
62+
json['include'] = ['**/*.ts'];
63+
}
64+
}))
5565
.then(() => git('config', 'user.email', '[email protected]'))
5666
.then(() => git('config', 'user.name', 'Angular CLI E2e'))
5767
.then(() => git('config', 'commit.gpgSign', 'false'))

tests/e2e/tests/build/aot/angular-compiler.ts

-65
This file was deleted.

tests/e2e/tests/build/aot/aot.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ import {expectFileToMatch} from '../../../utils/fs';
44
export default function() {
55
return ng('build', '--aot')
66
.then(() => expectFileToMatch('dist/main.bundle.js',
7-
/bootstrapModuleFactory.*\/\* AppModuleNgFactory \*\//));
7+
/platformBrowser.*bootstrapModuleFactory.*AppModuleNgFactory/));
88
}

tests/e2e/tests/build/aot/exclude.ts

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ export default function () {
77
// Disable parts of it in webpack tests.
88
const ejected = getGlobalVariable('argv').eject;
99

10+
// Skip this in ng5 tests, it only happens in ng2/4.
11+
// This check should be changed once ng5 because the default.
12+
if (getGlobalVariable('argv').nightly) {
13+
return Promise.resolve();
14+
}
15+
1016
// Check if **/*.spec.ts files are excluded by default.
1117
return Promise.resolve()
1218
// This import would cause aot to fail.

0 commit comments

Comments
 (0)