@@ -49,6 +49,9 @@ interface TSInstances {
49
49
50
50
var instances = < TSInstances > { } ;
51
51
52
+ // Take TypeScript errors, parse them and "pretty-print" to a passed-in function
53
+ // The passed-in function can either console.log them or add them to webpack's
54
+ // list of errors
52
55
function handleErrors ( diagnostics : typescript . Diagnostic [ ] , compiler : typeof typescript , outputFn : ( prettyMessage : string , rawMessage : string , loc : { line : number , character : number } ) => any ) {
53
56
diagnostics . forEach ( diagnostic => {
54
57
var messageText = compiler . flattenDiagnosticMessageText ( diagnostic . messageText , os . EOL ) ;
@@ -66,6 +69,8 @@ function handleErrors(diagnostics: typescript.Diagnostic[], compiler: typeof typ
66
69
} ) ;
67
70
}
68
71
72
+ // The tsconfig.json is found using the same method as `tsc`, starting in the current directory
73
+ // and continuing up the parent directory chain.
69
74
function findConfigFile ( compiler : typeof typescript , searchPath : string , configFileName : string ) : string {
70
75
while ( true ) {
71
76
var fileName = path . join ( searchPath , configFileName ) ;
@@ -81,6 +86,11 @@ function findConfigFile(compiler: typeof typescript, searchPath: string, configF
81
86
return undefined ;
82
87
}
83
88
89
+ // The loader is executed once for each file seen by webpack. However, we need to keep
90
+ // a persistent instance of TypeScript that contains all of the files in the program
91
+ // along with definition files and options. This function either creates an instance
92
+ // or returns the existing one. Multiple instances are possible by using the
93
+ // `instance` property.
84
94
function ensureTypeScriptInstance ( options : Options , loader : any ) : TSInstance {
85
95
86
96
function log ( ...messages : string [ ] ) : void {
@@ -104,6 +114,7 @@ function ensureTypeScriptInstance(options: Options, loader: any): TSInstance {
104
114
module : typescript . ModuleKind . CommonJS
105
115
} ;
106
116
117
+ // Load any available tsconfig.json file
107
118
var filesToLoad = [ ] ;
108
119
var configFilePath = findConfigFile ( compiler , path . dirname ( loader . resourcePath ) , options . configFileName ) ;
109
120
if ( configFilePath ) {
@@ -127,8 +138,8 @@ function ensureTypeScriptInstance(options: Options, loader: any): TSInstance {
127
138
128
139
var libFileName = 'lib.d.ts' ;
129
140
141
+ // Special handling for ES6 targets
130
142
if ( compilerOptions . target == typescript . ScriptTarget . ES6 ) {
131
- // Special handling for ES6 targets
132
143
compilerOptions . module = typescript . ModuleKind . None ;
133
144
libFileName = 'lib.es6.d.ts' ;
134
145
}
@@ -137,6 +148,7 @@ function ensureTypeScriptInstance(options: Options, loader: any): TSInstance {
137
148
filesToLoad . push ( path . join ( path . dirname ( require . resolve ( 'typescript' ) ) , libFileName ) ) ;
138
149
}
139
150
151
+ // Load initial files (core lib files, any files specified in tsconfig.json)
140
152
filesToLoad . forEach ( filePath => {
141
153
filePath = path . normalize ( filePath ) ;
142
154
files [ filePath ] = {
@@ -145,13 +157,16 @@ function ensureTypeScriptInstance(options: Options, loader: any): TSInstance {
145
157
}
146
158
} ) ;
147
159
160
+ // Create the TypeScript language service
148
161
var servicesHost = {
149
162
getScriptFileNames : ( ) => Object . keys ( files ) ,
150
163
getScriptVersion : fileName => {
151
164
fileName = path . normalize ( fileName ) ;
152
165
return files [ fileName ] && files [ fileName ] . version . toString ( ) ;
153
166
} ,
154
167
getScriptSnapshot : fileName => {
168
+ // This is called any time TypeScript needs a file's text
169
+ // We either load from memory or from disk
155
170
fileName = path . normalize ( fileName ) ;
156
171
var file = files [ fileName ] ;
157
172
@@ -243,17 +258,20 @@ function loader(contents) {
243
258
file = instance . files [ filePath ] ,
244
259
langService = instance . languageService ;
245
260
261
+ // Update TypeScript with the new file contents
246
262
if ( ! file ) {
247
263
file = instance . files [ filePath ] = < TSFile > { version : 0 } ;
248
264
}
249
265
250
266
file . text = contents ;
251
267
file . version ++ ;
252
268
269
+ // Make this file dependent on *all* definition files in the program
253
270
this . clearDependencies ( ) ;
254
271
this . addDependency ( filePath ) ;
255
272
Object . keys ( instance . files ) . filter ( filePath => ! ! filePath . match ( / \. d \. t s $ / ) ) . forEach ( this . addDependency . bind ( this ) ) ;
256
273
274
+ // Emit Javascript
257
275
var output = langService . getEmitOutput ( filePath ) ;
258
276
handleErrors (
259
277
langService . getSyntacticDiagnostics ( filePath ) . concat ( langService . getSemanticDiagnostics ( filePath ) ) ,
@@ -283,6 +301,9 @@ function loader(contents) {
283
301
contents = output . outputFiles [ 0 ] . text ;
284
302
}
285
303
304
+ // Make sure webpack is aware that even though the emitted JavaScript may be the same as
305
+ // a previously cached version the TypeScript may be different and therefore should be
306
+ // treated as new
286
307
this . _module . meta [ 'tsLoaderFileVersion' ] = file . version ;
287
308
288
309
callback ( null , contents , sourceMap )
0 commit comments