Skip to content

Commit 5cdb8cb

Browse files
committed
cache chunks, cache assets
1 parent e43ec62 commit 5cdb8cb

13 files changed

+182
-87
lines changed

bin/config-optimist.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ module.exports = function(optimist) {
5353

5454
.boolean("optimize-minimize").describe("optimize-minimize")
5555

56+
.boolean("optimize-occurence-order").describe("optimize-occurence-order")
57+
5658
.string("provide").describe("provide")
5759

5860
.string("plugin").describe("plugin")

bin/convert-argv.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ module.exports = function(optimist, argv, convertOptions) {
1515
}
1616
if(argv.p) {
1717
argv["optimize-minimize"] = true;
18+
argv["optimize-occurence-order"] = true;
1819
}
1920

2021
function ifArg(name, fn, init) {
@@ -249,6 +250,11 @@ module.exports = function(optimist, argv, convertOptions) {
249250
options.optimize.minimize = true;
250251
});
251252

253+
ifBooleanArg("optimize-occurence-order", function() {
254+
ensureObject(options, "optimize");
255+
options.optimize.occurenceOrder = true;
256+
});
257+
252258
ifArg("provide", function(value) {
253259
ensureObject(options, "provide");
254260
var idx = value.indexOf("=");

lib/Chunk.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
*/
55
function Chunk(name) {
66
this.id = null;
7+
this.ids = null;
78
this.name = name;
89
this.modules = [];
910
this.chunks = [];
1011
this.parents = [];
1112
this.blocks = [];
13+
this.rendered = false;
1214
}
1315
module.exports = Chunk;
1416

@@ -127,7 +129,9 @@ Chunk.prototype.isEmpty = function() {
127129
};
128130

129131
Chunk.prototype.updateHash = function(hash) {
130-
hash.update(this.id + "");
132+
hash.update(this.id + " ");
133+
hash.update(this.ids ? this.ids.join(",") : "");
134+
hash.update(this.name + "");
131135
this.modules.forEach(function(m) {
132136
m.updateHash(hash);
133137
});

lib/ChunkTemplate.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ ChunkTemplate.prototype.render = function(chunk, moduleTemplate, dependencyTempl
2222
});
2323
source.add("\n\n");
2424
source.add(this.asString(this.renderFooter(chunk)));
25+
chunk.rendered = true;
2526
return source;
2627
};
2728

lib/Compilation.js

Lines changed: 54 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ Compilation.prototype = Object.create(Tapable.prototype);
4646
Compilation.prototype.addModule = function(module) {
4747
var identifier = module.identifier();
4848
if(this._modules[identifier]) return false;
49-
if(this.cache && this.cache[identifier]) {
50-
var cacheModule = this.cache[identifier];
51-
49+
if(this.cache && this.cache["m" + identifier]) {
50+
var cacheModule = this.cache["m" + identifier];
51+
5252
var rebuild = true;
5353
if(!cacheModule.error && cacheModule.cacheable && this.fileTimestamps && this.contextTimestamps) {
5454
rebuild = cacheModule.needRebuild(this.fileTimestamps, this.contextTimestamps);
@@ -65,10 +65,12 @@ Compilation.prototype.addModule = function(module) {
6565
this.warnings.push(err);
6666
}, this);
6767
return cacheModule;
68+
} else {
69+
module.lastId = cacheModule.id;
6870
}
6971
}
7072
this._modules[identifier] = module;
71-
if(this.cache) this.cache[identifier] = module;
73+
if(this.cache) this.cache["m" + identifier] = module;
7274
this.modules.push(module);
7375
return true;
7476
};
@@ -164,7 +166,7 @@ Compilation.prototype.processModuleDependencies = function(module, callback) {
164166
}
165167
if(err) return errorOrWarningAndCallback(new ModuleNotFoundError(module, err));
166168
if(!dependantModule) return callback();
167-
169+
168170
var newModule = this.addModule(dependantModule);
169171

170172
if(!newModule) {
@@ -180,15 +182,15 @@ Compilation.prototype.processModuleDependencies = function(module, callback) {
180182

181183
if(newModule instanceof Module) { // from cache
182184
dependantModule = newModule;
183-
185+
184186
dependencies.forEach(function(dep) {
185187
dep.module = dependantModule;
186188
dependantModule.addReason(module, dep);
187189
});
188190

189191
return this.processModuleDependencies(dependantModule, callback);
190192
}
191-
193+
192194
this.buildModule(dependantModule, function(err) {
193195
if(err) return errorOrWarningAndCallback(err);
194196

@@ -231,7 +233,7 @@ Compilation.prototype.addEntry = function process(context, entry, name, callback
231233
if(!result) {
232234
return callback(new Error("Entry module is already added"));
233235
}
234-
236+
235237
if(result instanceof Module) {
236238
module = result;
237239
}
@@ -248,7 +250,7 @@ Compilation.prototype.addEntry = function process(context, entry, name, callback
248250
entryReady.call(this);
249251
}.bind(this));
250252
}
251-
253+
252254
function entryReady() {
253255
this.processModuleDependencies(module, function(err) {
254256
if(err) return callback(err);
@@ -272,7 +274,9 @@ Compilation.prototype.seal = function seal(callback) {
272274
this.applyPlugins("after-optimize-modules", this.modules);
273275
this.applyPlugins("optimize-chunks", this.chunks);
274276
this.applyPlugins("after-optimize-chunks", this.chunks);
277+
this.applyPlugins("optimize-module-order", this.modules);
275278
this.applyModuleIds();
279+
this.applyPlugins("optimize-chunk-order", this.chunks);
276280
this.applyChunkIds();
277281
this.applyPlugins("optimize-module-ids", this.modules);
278282
this.applyPlugins("after-optimize-module-ids", this.modules);
@@ -337,77 +341,25 @@ Compilation.prototype.processDependenciesBlockForChunk = function processDepende
337341
};
338342

339343
Compilation.prototype.applyModuleIds = function applyModuleIds() {
340-
var i = 0;
341-
function entryChunks(m) {
342-
return m.chunks.filter(function(c) {
343-
return c.entry;
344-
}).length;
345-
}
346-
function occursInEntry(m) {
347-
return m.reasons.map(function(r) {
348-
if(!r.module) return 0;
349-
return entryChunks(r.module);
350-
}).reduce(function(a, b) { return a+b; }, 0) + entryChunks(m);
351-
}
352-
function occurs(m) {
353-
return m.reasons.map(function(r) {
354-
if(!r.module) return 0;
355-
return r.module.chunks.length;
356-
}).reduce(function(a, b) { return a+b; }, 0) + m.chunks.length;
357-
}
358-
this.modules.sort(function(a, b) {
359-
var aEntryOccurs = occursInEntry(a);
360-
var bEntryOccurs = occursInEntry(b);
361-
if(aEntryOccurs > bEntryOccurs) return -1;
362-
if(aEntryOccurs < bEntryOccurs) return 1;
363-
var aOccurs = occurs(a);
364-
var bOccurs = occurs(b);
365-
if(aOccurs > bOccurs) return -1;
366-
if(aOccurs < bOccurs) return 1;
367-
if(a.identifier() > b.identifier()) return 1;
368-
if(a.identifier() < b.identifier()) return -1;
369-
return 0;
370-
});
344+
var i = this.cache && this.cache["nextModuleId"] || 1;
345+
var usedIds = {0:true};
371346
this.modules.forEach(function(module) {
372-
if(module.id === null)
373-
module.id = ++i;
347+
if(module.id === null) {
348+
if(module.lastId > 0) {
349+
if(!usedIds[module.lastId]) {
350+
usedIds[module.lastId] = true;
351+
module.id = module.lastId;
352+
return;
353+
}
354+
}
355+
module.id = i++;
356+
}
374357
});
358+
if(this.cache) this.cache["nextModuleId"] = i;
375359
};
376360

377361
Compilation.prototype.applyChunkIds = function applyChunkIds() {
378362
var i = 0;
379-
function occursInEntry(c) {
380-
return c.parents.filter(function(p) {
381-
return p.entry;
382-
}).length;
383-
}
384-
function occurs(c) {
385-
return c.blocks.length;
386-
}
387-
this.chunks.forEach(function(c) {
388-
c.modules.sort(function(a, b) {
389-
if(a.identifier() > b.identifier()) return 1;
390-
if(a.identifier() < b.identifier()) return -1;
391-
return 0;
392-
});
393-
});
394-
this.chunks.sort(function(a, b) {
395-
var aEntryOccurs = occursInEntry(a);
396-
var bEntryOccurs = occursInEntry(b);
397-
if(aEntryOccurs > bEntryOccurs) return -1;
398-
if(aEntryOccurs < bEntryOccurs) return 1;
399-
var aOccurs = occurs(a);
400-
var bOccurs = occurs(b);
401-
if(aOccurs > bOccurs) return -1;
402-
if(aOccurs < bOccurs) return 1;
403-
if(a.modules.length > b.modules.length) return -1;
404-
if(a.modules.length < b.modules.length) return 1;
405-
for(var i = 0; i < a.modules.length; i++) {
406-
if(a.modules[i].identifier() > b.modules[i].identifier()) return -1;
407-
if(a.modules[i].identifier() < b.modules[i].identifier()) return 1;
408-
}
409-
return 0;
410-
});
411363
this.chunks.forEach(function(chunk) {
412364
if(chunk.id === null)
413365
chunk.id = ++i;
@@ -494,7 +446,17 @@ Compilation.prototype.createChunkAssets = function createChunkAssets() {
494446
var source;
495447
var file;
496448
if(chunk.entry) {
497-
source = this.mainTemplate.render(hash, chunk, this.moduleTemplate, this.dependencyTemplates);
449+
if(this.cache && this.cache["c" + chunk.id + chunk.name] && this.cache["c" + chunk.id + chunk.name].hash == hash) {
450+
source = this.cache["c" + chunk.id + chunk.name].source;
451+
} else {
452+
source = this.mainTemplate.render(hash, chunk, this.moduleTemplate, this.dependencyTemplates);
453+
if(this.cache) {
454+
this.cache["c" + chunk.id + chunk.name] = {
455+
hash: hash,
456+
source: source
457+
}
458+
}
459+
}
498460
this.assets[
499461
file = filename
500462
.replace(Template.REGEXP_HASH, hash)
@@ -504,7 +466,23 @@ Compilation.prototype.createChunkAssets = function createChunkAssets() {
504466
chunk.files.push(file);
505467
this.applyPlugins("chunk-asset", chunk, file);
506468
} else {
507-
source = this.chunkTemplate.render(chunk, this.moduleTemplate, this.dependencyTemplates);
469+
if(this.cache) {
470+
var chunkHash = new (require("crypto").Hash)("md5");
471+
chunk.updateHash(chunkHash);
472+
this.chunkTemplate.updateHash(chunkHash);
473+
chunkHash = chunkHash.digest("hex");
474+
}
475+
if(this.cache && this.cache["c" + chunk.id] && this.cache["c" + chunk.id].hash == chunkHash) {
476+
source = this.cache["c" + chunk.id].source;
477+
} else {
478+
source = this.chunkTemplate.render(chunk, this.moduleTemplate, this.dependencyTemplates);
479+
if(this.cache) {
480+
this.cache["c" + chunk.id] = {
481+
hash: chunkHash,
482+
source: source
483+
}
484+
}
485+
}
508486
this.assets[
509487
file = chunkFilename
510488
.replace(Template.REGEXP_HASH, hash)

lib/Compiler.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function Compiler() {
100100
this.outputFileSystem = null;
101101
this.inputFileSystem = null;
102102
this.separateExecutor = null;
103-
103+
104104
this.fileTimestamps = {};
105105
this.contextTimestamps = {};
106106

@@ -179,10 +179,18 @@ Compiler.prototype.emitAssets = function(compilation, callback) {
179179
} else writeOut.call(this);
180180
function writeOut(err) {
181181
if(err) return callback(err);
182-
var content = compilation.assets[file].source();
182+
var targetPath = this.outputFileSystem.join(this.outputPath, file);
183+
var source = compilation.assets[file];
184+
if(source.existsAt === targetPath) {
185+
source.emitted = false;
186+
return callback();
187+
}
188+
var content = source.source();
183189
if(!Buffer.isBuffer(content))
184190
content = new Buffer(content, "utf-8");
185-
this.outputFileSystem.writeFile(this.outputFileSystem.join(this.outputPath, file), content, callback);
191+
source.existsAt = targetPath;
192+
source.emitted = true;
193+
this.outputFileSystem.writeFile(targetPath, content, callback);
186194
};
187195

188196
}.bind(this), function(err) {

lib/MainTemplate.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ MainTemplate.prototype.render = function(hash, chunk, moduleTemplate, dependency
4242
source.add(moduleTemplate.render(module, dependencyTemplates));
4343
});
4444
source.add("\n/******/ })");
45+
chunk.rendered = true;
4546
return source;
4647
};
4748

lib/Module.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ function Module() {
1111
this.context = null;
1212
this.reasons = [];
1313
this.debugId = debugId++;
14+
this.lastId = -1;
1415
this.id = null;
1516
this.chunks = [];
1617
this.warnings = [];
@@ -26,6 +27,7 @@ Module.prototype.separable = function(callback) {
2627

2728
Module.prototype.disconnect = function() {
2829
this.reasons.length = 0;
30+
this.lastId = this.id;
2931
this.id = null;
3032
this.chunks.length = 0;
3133
DependenciesBlock.prototype.disconnect.call(this);

lib/Stats.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ Stats.prototype.toJson = function toJson(options, forToString) {
8787
name: asset,
8888
size: compilation.assets[asset].size(),
8989
chunks: [],
90-
chunkNames: []
90+
chunkNames: [],
91+
emitted: compilation.assets[asset].emitted
9192
};
9293
assetsByFile[asset] = obj;
9394
return obj;
@@ -142,6 +143,7 @@ Stats.prototype.toJson = function toJson(options, forToString) {
142143
obj.chunks = compilation.chunks.map(function(chunk) {
143144
var obj = {
144145
id: chunk.id,
146+
rendered: chunk.rendered,
145147
size: chunk.modules.reduce(function(size, module) { return size + module.size(); }, 0),
146148
names: chunk.name ? [chunk.name] : [],
147149
files: chunk.files.slice(),
@@ -277,16 +279,17 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
277279
newline();
278280
}
279281
if(obj.assets) {
280-
var t = [["Asset", "Size", "Chunks", "Chunk Names"]]
282+
var t = [["Asset", "Size", "Chunks", "", "Chunk Names"]]
281283
obj.assets.forEach(function(asset) {
282284
t.push([
283285
asset.name,
284286
asset.size,
285287
asset.chunks.join(", "),
288+
asset.emitted ? "[emitted]" : "",
286289
asset.chunkNames.join(", ")
287290
])
288291
});
289-
table(t, [green, normal, bold, normal], "rrrl");
292+
table(t, [green, normal, bold, green, normal], "rrrll");
290293
}
291294
if(obj.chunks) {
292295
obj.chunks.forEach(function(chunk) {
@@ -306,11 +309,13 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
306309
normal(" ");
307310
normal(chunk.size);
308311
chunk.parents.forEach(function(id) {
309-
normal(" ");
310-
normal("{");
312+
normal(" {");
311313
yellow(id);
312-
normal("} ");
314+
normal("}");
313315
});
316+
if(chunk.rendered) {
317+
green(" [rendered]");
318+
}
314319
newline();
315320
if(chunk.modules) {
316321
chunk.modules.forEach(function(module) {

0 commit comments

Comments
 (0)