-
-
Notifications
You must be signed in to change notification settings - Fork 431
/
Copy pathwatch-run.ts
121 lines (111 loc) · 3.8 KB
/
watch-run.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import * as path from 'path';
import type * as webpack from 'webpack';
import * as constants from './constants';
import type { FilePathKey, LoaderOptions, TSInstance } from './interfaces';
import { updateFileWithText } from './servicesHost';
import { fsReadFile } from './utils';
/**
* Make function which will manually update changed files
*/
export function makeWatchRun(
instance: TSInstance,
loader: webpack.LoaderContext<LoaderOptions>
) {
// Called Before starting compilation after watch
const lastTimes = new Map<FilePathKey, number>();
const startTime = 0;
// Save the loader index.
const loaderIndex = loader.loaderIndex;
return (compiler: webpack.Compiler, callback: (err?: Error) => void) => {
instance.servicesHost?.clearCache?.();
instance.watchHost?.clearCache?.();
instance.moduleResolutionCache?.clear();
instance.typeReferenceResolutionCache?.clear();
const promises = [];
if (instance.loaderOptions.transpileOnly) {
instance.reportTranspileErrors = true;
} else {
const times = compiler.fileTimestamps;
if (times) {
for (const [filePath, date] of times) {
const key = instance.filePathKeyMapper(filePath);
const lastTime = lastTimes.get(key) || startTime;
if (
!date ||
date === 'ignore' ||
(date.timestamp || date.safeTime) <= lastTime
) {
continue;
}
lastTimes.set(key, date.timestamp || date.safeTime);
promises.push(updateFile(instance, key, filePath, loader, loaderIndex));
}
// On watch update add all known dts files expect the ones in node_modules
// (skip @types/* and modules with typings)
for (const [key, { fileName }] of instance.files.entries()) {
if (
fileName.match(constants.dtsDtsxOrDtsDtsxMapRegex) !== null &&
fileName.match(constants.nodeModules) === null
) {
promises.push(
updateFile(instance, key, fileName, loader, loaderIndex)
);
}
}
}
}
// Update all the watched files from solution builder
if (instance.solutionBuilderHost) {
for (const {
fileName,
} of instance.solutionBuilderHost.watchedFiles.values()) {
instance.solutionBuilderHost!.updateSolutionBuilderInputFile(fileName);
}
instance.solutionBuilderHost.clearCache();
}
Promise.all(promises)
.then(() => callback())
.catch(err => callback(err));
};
}
function updateFile(
instance: TSInstance,
key: FilePathKey,
filePath: string,
loader: webpack.LoaderContext<LoaderOptions>,
loaderIndex: number
) {
return new Promise<void>((resolve, reject) => {
// When other loaders are specified after ts-loader
// (e.g. `{ test: /\.ts$/, use: ['ts-loader', 'other-loader'] }`),
// manually apply them to TypeScript files.
// Otherwise, files not 'preprocessed' by them may cause complication errors (#1111).
if (
loaderIndex + 1 < loader.loaders.length &&
instance.rootFileNames.has(path.normalize(filePath))
) {
let request = `!!${path.resolve(__dirname, 'stringify-loader.js')}!`;
for (let i = loaderIndex + 1; i < loader.loaders.length; ++i) {
request += loader.loaders[i].request + '!';
}
request += filePath;
loader.loadModule(request, (err, source) => {
if (err) {
reject(err);
} else {
const text = JSON.parse(source);
updateFileWithText(instance, key, filePath, () => text);
resolve();
}
});
} else {
updateFileWithText(
instance,
key,
filePath,
nFilePath => fsReadFile(nFilePath) || ''
);
resolve();
}
});
}