Skip to content

Commit 6392f9a

Browse files
committed
perf: implement snapshot validation
1 parent 9d36380 commit 6392f9a

File tree

1 file changed

+53
-45
lines changed

1 file changed

+53
-45
lines changed

lib/cached-child-compiler.js

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class CachedChildCompilation {
5151
/**
5252
* @param {Compiler} compiler
5353
*/
54-
constructor (compiler) {
54+
constructor(compiler) {
5555
/**
5656
* @private
5757
* @type {Compiler}
@@ -71,7 +71,7 @@ class CachedChildCompilation {
7171
* apply is called by the webpack main compiler during the start phase
7272
* @param {string} entry
7373
*/
74-
addEntry (entry) {
74+
addEntry(entry) {
7575
const persistentChildCompilerSingletonPlugin = compilerMap.get(this.compiler);
7676
if (!persistentChildCompilerSingletonPlugin) {
7777
throw new Error(
@@ -81,7 +81,7 @@ class CachedChildCompilation {
8181
persistentChildCompilerSingletonPlugin.addEntry(entry);
8282
}
8383

84-
getCompilationResult () {
84+
getCompilationResult() {
8585
const persistentChildCompilerSingletonPlugin = compilerMap.get(this.compiler);
8686
if (!persistentChildCompilerSingletonPlugin) {
8787
throw new Error(
@@ -99,7 +99,7 @@ class CachedChildCompilation {
9999
| { mainCompilationHash: string, compiledEntry: ChildCompilationTemplateResult }
100100
}
101101
*/
102-
getCompilationEntryResult (entry) {
102+
getCompilationEntryResult(entry) {
103103
const latestResult = this.getCompilationResult();
104104
const compilationResult = latestResult.compilationResult;
105105
return 'error' in compilationResult ? {
@@ -115,27 +115,27 @@ class CachedChildCompilation {
115115
class PersistentChildCompilerSingletonPlugin {
116116
/**
117117
*
118-
* @param {{fileDependencies: string[], contextDependencies: string[], missingDependencies: string[]}} fileDependencies
118+
* @param {string[]} fileDependencies
119119
* @param {Compilation} mainCompilation
120-
* @param {number} startTime
121120
*/
122-
static createSnapshot (fileDependencies, mainCompilation, startTime) {
123-
return new Promise((resolve, reject) => {
124-
mainCompilation.fileSystemInfo.createSnapshot(
125-
startTime,
126-
fileDependencies.fileDependencies,
127-
fileDependencies.contextDependencies,
128-
fileDependencies.missingDependencies,
129-
// @ts-ignore
130-
null,
131-
(err, snapshot) => {
132-
if (err) {
133-
return reject(err);
134-
}
135-
resolve(snapshot);
136-
}
137-
);
138-
});
121+
static createSnapshot(fileDependencies, mainCompilation) {
122+
const timestamps = {};
123+
const fs = mainCompilation.inputFileSystem;
124+
125+
return Promise.all(
126+
fileDependencies.map(file => {
127+
return new Promise(resolve => {
128+
fs.stat(file, (err, stat) => {
129+
if (!err && stat) {
130+
timestamps[file] = stat.mtime.getTime();
131+
} else {
132+
timestamps[file] = null;
133+
}
134+
resolve();
135+
});
136+
});
137+
})
138+
).then(() => timestamps);
139139
}
140140

141141
/**
@@ -146,29 +146,37 @@ class PersistentChildCompilerSingletonPlugin {
146146
* @param {Compilation} mainCompilation
147147
* @returns {Promise<boolean | undefined>}
148148
*/
149-
static isSnapshotValid (snapshot, mainCompilation) {
150-
return new Promise((resolve, reject) => {
151-
mainCompilation.fileSystemInfo.checkSnapshotValid(
152-
snapshot,
153-
(err, isValid) => {
154-
if (err) {
155-
reject(err);
156-
}
157-
resolve(isValid);
158-
}
159-
);
160-
});
149+
static isSnapshotValid(snapshot, mainCompilation) {
150+
const fs = mainCompilation.inputFileSystem;
151+
152+
return Promise.all(
153+
Object.keys(snapshot).map(file => {
154+
return new Promise(resolve => {
155+
fs.stat(file, (err, stat) => {
156+
if (!err && stat && snapshot[file] !== null) {
157+
// File exists and check if the timestamp is the same
158+
resolve(stat.mtime.getTime() === snapshot[file]);
159+
} else if (err && snapshot[file] === null) {
160+
// File does not exist and was not existing before
161+
resolve(true);
162+
} else {
163+
resolve(false);
164+
}
165+
});
166+
});
167+
})
168+
).then(results => !results.includes(false));
161169
}
162170

163-
static watchFiles (mainCompilation, fileDependencies) {
171+
static watchFiles(mainCompilation, fileDependencies) {
164172
Object.keys(fileDependencies).forEach((depencyTypes) => {
165173
fileDependencies[depencyTypes].forEach(fileDependency => {
166174
mainCompilation[depencyTypes].add(fileDependency);
167175
});
168176
});
169177
}
170178

171-
constructor () {
179+
constructor() {
172180
/**
173181
* @private
174182
* @type {
@@ -214,7 +222,7 @@ class PersistentChildCompilerSingletonPlugin {
214222
* apply is called by the webpack main compiler during the start phase
215223
* @param {Compiler} compiler
216224
*/
217-
apply (compiler) {
225+
apply(compiler) {
218226
/** @type Promise<ChildCompilationResult> */
219227
let childCompilationResultPromise = Promise.resolve({
220228
dependencies: {
@@ -271,7 +279,7 @@ class PersistentChildCompilerSingletonPlugin {
271279
// this might possibly cause bugs if files were changed inbetween
272280
// compilation start and snapshot creation
273281
compiledEntriesPromise.then((childCompilationResult) => {
274-
return PersistentChildCompilerSingletonPlugin.createSnapshot(childCompilationResult.dependencies, mainCompilation, compilationStartTime);
282+
return PersistentChildCompilerSingletonPlugin.createSnapshot(childCompilationResult.dependencies.fileDependencies, mainCompilation);
275283
}).then((snapshot) => {
276284
previousFileSystemSnapshot = snapshot;
277285
});
@@ -334,7 +342,7 @@ class PersistentChildCompilerSingletonPlugin {
334342
* Add a new entry to the next compile run
335343
* @param {string} entry
336344
*/
337-
addEntry (entry) {
345+
addEntry(entry) {
338346
if (this.compilationState.isCompiling || this.compilationState.isVerifyingCache) {
339347
throw new Error(
340348
'The child compiler has already started to compile. ' +
@@ -347,7 +355,7 @@ class PersistentChildCompilerSingletonPlugin {
347355
}
348356
}
349357

350-
getLatestResult () {
358+
getLatestResult() {
351359
if (this.compilationState.isCompiling || this.compilationState.isVerifyingCache) {
352360
throw new Error(
353361
'The child compiler is not done compiling. ' +
@@ -368,7 +376,7 @@ class PersistentChildCompilerSingletonPlugin {
368376
* @param {Compilation} mainCompilation
369377
* @returns {Promise<boolean | undefined>}
370378
*/
371-
isCacheValid (snapshot, mainCompilation) {
379+
isCacheValid(snapshot, mainCompilation) {
372380
if (!this.compilationState.isVerifyingCache) {
373381
return Promise.reject(new Error('Cache validation can only be done right before the compilation starts'));
374382
}
@@ -396,11 +404,11 @@ class PersistentChildCompilerSingletonPlugin {
396404
* @param {string[]} entries
397405
* @returns {Promise<ChildCompilationResult>}
398406
*/
399-
compileEntries (mainCompilation, entries) {
407+
compileEntries(mainCompilation, entries) {
400408
const compiler = new HtmlWebpackChildCompiler(entries);
401409
return compiler.compileTemplates(mainCompilation).then((result) => {
402410
return {
403-
// The compiled sources to render the content
411+
// The compiled sources to render the content
404412
compiledEntries: result,
405413
// The file dependencies to find out if a
406414
// recompilation is required
@@ -426,7 +434,7 @@ class PersistentChildCompilerSingletonPlugin {
426434
* @param {Compilation} mainCompilation
427435
* @param {FileDependencies} files
428436
*/
429-
watchFiles (mainCompilation, files) {
437+
watchFiles(mainCompilation, files) {
430438
PersistentChildCompilerSingletonPlugin.watchFiles(mainCompilation, files);
431439
}
432440
}

0 commit comments

Comments
 (0)