Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a Set to store modules in a chunk #4764

Merged
merged 1 commit into from May 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 1 addition & 11 deletions lib/AsyncDependenciesBlock.js
Expand Up @@ -37,17 +37,7 @@ module.exports = class AsyncDependenciesBlock extends DependenciesBlock {
sortItems() {
super.sortItems();
if(this.chunks) {
this.chunks.sort((a, b) => {
let i = 0;
while(true) { // eslint-disable-line no-constant-condition
if(!a.modules[i] && !b.modules[i]) return 0;
if(!a.modules[i]) return -1;
if(!b.modules[i]) return 1;
if(a.modules[i].id > b.modules[i].id) return 1;
if(a.modules[i].id < b.modules[i].id) return -1;
i++;
}
});
this.chunks.sort((a, b) => a.compareTo(b));
}
}
};
111 changes: 94 additions & 17 deletions lib/Chunk.js
Expand Up @@ -4,6 +4,7 @@
*/
"use strict";

const util = require("util");
const compareLocations = require("./compareLocations");
let debugId = 1000;

Expand All @@ -20,7 +21,8 @@ class Chunk {
this.ids = null;
this.debugId = debugId++;
this.name = name;
this.modules = [];
this._modules = new Set();
this._modulesIsSorted = true;
this.entrypoints = [];
this.chunks = [];
this.parents = [];
Expand Down Expand Up @@ -88,17 +90,20 @@ class Chunk {
}

addModule(module) {
return this.addToCollection(this.modules, module);
if(!this._modules.has(module)) {
this._modules.add(module);
this._modulesIsSorted = false;
return true;
}
return false;
}

addBlock(block) {
return this.addToCollection(this.blocks, block);
}

removeModule(module) {
const idx = this.modules.indexOf(module);
if(idx >= 0) {
this.modules.splice(idx, 1);
if(this._modules.delete(module)) {
module.removeChunk(this);
return true;
}
Expand Down Expand Up @@ -133,9 +138,72 @@ class Chunk {
});
}

setModules(modules) {
this._modules = new Set(modules);
this._modulesIsSorted = false;
}

getNumberOfModules() {
return this._modules.size;
}

get modulesIterable() {
return this._modules;
}

forEachModule(fn) {
this._modules.forEach(fn);
}

mapModules(fn) {
const modules = this._modules;
const array = new Array(modules.size);
let idx = 0;
for(let module of modules) {
array[idx++] = fn(module, idx, modules);
}
return array;
}

_ensureModulesSorted() {
if(this._modulesIsSorted) return;
this._modules = new Set(Array.from(this._modules).sort((a, b) => {
if(a.identifier() > b.identifier()) return 1;
if(a.identifier() < b.identifier()) return -1;
return 0;
}));
this._modulesIsSorted = true;
}

compareTo(otherChunk) {
this._ensureModulesSorted();
otherChunk._ensureModulesSorted();
if(this._modules.size > otherChunk._modules.size) return -1;
if(this._modules.size < otherChunk._modules.size) return 1;
const a = this._modules[Symbol.iterator]();
const b = otherChunk._modules[Symbol.iterator]();
while(true) { // eslint-disable-line
const aItem = a.next();
const bItem = b.next();
if(aItem.done) return 0;
const aModuleIdentifier = aItem.value.identifier();
const bModuleIdentifier = bItem.value.identifier();
if(aModuleIdentifier > bModuleIdentifier) return -1;
if(aModuleIdentifier < bModuleIdentifier) return 1;
}
}

containsModule(module) {
return this._modules.has(module);
}

getModules() {
return Array.from(this._modules);
}

remove(reason) {
// cleanup modules
this.modules.slice().forEach(module => {
Array.from(this._modules).forEach(module => {
module.removeChunk(this);
});

Expand Down Expand Up @@ -219,9 +287,9 @@ class Chunk {
return false;
}

const otherChunkModules = otherChunk.modules.slice();
const otherChunkModules = Array.from(otherChunk._modules);
otherChunkModules.forEach(module => otherChunk.moveModule(module, this));
otherChunk.modules.length = 0;
otherChunk._modules.clear();

otherChunk.parents.forEach(parentChunk => parentChunk.replaceChunk(otherChunk, this));
otherChunk.parents.length = 0;
Expand Down Expand Up @@ -276,14 +344,14 @@ class Chunk {
}

isEmpty() {
return this.modules.length === 0;
return this._modules.size === 0;
}

updateHash(hash) {
hash.update(`${this.id} `);
hash.update(this.ids ? this.ids.join(",") : "");
hash.update(`${this.name || ""} `);
this.modules.forEach(m => m.updateHash(hash));
this._modules.forEach(m => m.updateHash(hash));
}

canBeIntegrated(otherChunk) {
Expand All @@ -307,8 +375,8 @@ class Chunk {

modulesSize() {
let count = 0;
for(let i = 0; i < this.modules.length; i++) {
count += this.modules[i].size();
for(let module of this._modules) {
count += module.size();
}
return count;
}
Expand All @@ -325,9 +393,8 @@ class Chunk {

let integratedModulesSize = this.modulesSize();
// only count modules that do not exist in this chunk!
for(let i = 0; i < otherChunk.modules.length; i++) {
const otherModule = otherChunk.modules[i];
if(this.modules.indexOf(otherModule) === -1) {
for(let otherModule of otherChunk._modules) {
if(!this._modules.has(otherModule)) {
integratedModulesSize += otherModule.size();
}
}
Expand Down Expand Up @@ -356,7 +423,7 @@ class Chunk {
}

sortItems() {
this.modules.sort(byId);
this._modules = new Set(Array.from(this._modules).sort(byId));
this.origins.sort((a, b) => {
const aIdent = a.module.identifier();
const bIdent = b.module.identifier();
Expand All @@ -373,7 +440,7 @@ class Chunk {
}

toString() {
return `Chunk[${this.modules.join()}]`;
return `Chunk[${Array.from(this._modules).join()}]`;
}

checkConstraints() {
Expand All @@ -393,4 +460,14 @@ class Chunk {
}
}

Object.defineProperty(Chunk.prototype, "modules", {
configurable: false,
get: util.deprecate(function() {
return Array.from(this._modules);
}, "Chunk.modules is deprecated. Use Chunk.getNumberOfModules/mapModules/forEachModule/containsModule instead."),
set: util.deprecate(function(value) {
this.setModules(value);
}, "Chunk.modules is deprecated. Use Chunk.addModule/removeModule instead.")
});

module.exports = Chunk;
2 changes: 1 addition & 1 deletion lib/FlagInitialModulesAsUsedPlugin.js
Expand Up @@ -12,7 +12,7 @@ class FlagInitialModulesAsUsedPlugin {
if(!chunk.isInitial()) {
return;
}
chunk.modules.forEach((module) => {
chunk.forEachModule((module) => {
module.usedExports = true;
});
});
Expand Down
6 changes: 3 additions & 3 deletions lib/HotModuleReplacementPlugin.js
Expand Up @@ -54,7 +54,7 @@ HotModuleReplacementPlugin.prototype.apply = function(compiler) {
});
records.chunkModuleIds = {};
this.chunks.forEach(function(chunk) {
records.chunkModuleIds[chunk.id] = chunk.modules.map(function(m) {
records.chunkModuleIds[chunk.id] = chunk.mapModules(function(m) {
return m.id;
});
});
Expand Down Expand Up @@ -112,11 +112,11 @@ HotModuleReplacementPlugin.prototype.apply = function(compiler) {
chunkId = isNaN(+chunkId) ? chunkId : +chunkId;
var currentChunk = this.chunks.find(chunk => chunk.id === chunkId);
if(currentChunk) {
var newModules = currentChunk.modules.filter(function(module) {
var newModules = currentChunk.mapModules(m => m).filter(function(module) {
return module.hotUpdate;
});
var allModules = {};
currentChunk.modules.forEach(function(module) {
currentChunk.forEachModule(function(module) {
allModules[module.id] = true;
});
var removedModules = records.chunkModuleIds[chunkId].filter(function(id) {
Expand Down
11 changes: 6 additions & 5 deletions lib/HotUpdateChunkTemplate.js
Expand Up @@ -5,18 +5,19 @@
"use strict";

const Template = require("./Template");
const Chunk = require("./Chunk");

module.exports = class HotUpdateChunkTemplate extends Template {
constructor(outputOptions) {
super(outputOptions);
}

render(id, modules, removedModules, hash, moduleTemplate, dependencyTemplates) {
const modulesSource = this.renderChunkModules({
id: id,
modules: modules,
removedModules: removedModules
}, moduleTemplate, dependencyTemplates);
const hotUpdateChunk = new Chunk();
hotUpdateChunk.id = id;
hotUpdateChunk.setModules(modules);
hotUpdateChunk.removedModules = removedModules;
const modulesSource = this.renderChunkModules(hotUpdateChunk, moduleTemplate, dependencyTemplates);
const core = this.applyPluginsWaterfall("modules", modulesSource, modules, removedModules, moduleTemplate, dependencyTemplates);
const source = this.applyPluginsWaterfall("render", core, modules, removedModules, hash, id, moduleTemplate, dependencyTemplates);
return source;
Expand Down
15 changes: 10 additions & 5 deletions lib/LibManifestPlugin.js
Expand Up @@ -30,19 +30,24 @@ class LibManifestPlugin {
const manifest = {
name,
type: this.options.type,
content: chunk.modules.reduce((obj, module) => {
content: chunk.mapModules(module => {
if(module.libIdent) {
const ident = module.libIdent({
context: this.options.context || compiler.options.context
});
if(ident) {
obj[ident] = {
id: module.id,
meta: module.meta,
exports: Array.isArray(module.providedExports) ? module.providedExports : undefined
return {
ident,
data: {
id: module.id,
meta: module.meta,
exports: Array.isArray(module.providedExports) ? module.providedExports : undefined
}
};
}
}
}).filter(Boolean).reduce((obj, item) => {
obj[item.ident] = item.data;
return obj;
}, {})
};
Expand Down
8 changes: 4 additions & 4 deletions lib/Stats.js
Expand Up @@ -328,19 +328,19 @@ class Stats {
entry: chunk.hasRuntime(),
recorded: chunk.recorded,
extraAsync: !!chunk.extraAsync,
size: chunk.modules.reduce((size, module) => size + module.size(), 0),
size: chunk.mapModules(m => m.size()).reduce((size, moduleSize) => size + moduleSize, 0),
names: chunk.name ? [chunk.name] : [],
files: chunk.files.slice(),
hash: chunk.renderedHash,
parents: chunk.parents.map(c => c.id)
};
if(showChunkModules) {
obj.modules = chunk.modules
.slice()
obj.modules = chunk
.mapModules(m => m)
.sort(sortByField("depth"))
.filter(createModuleFilter())
.map(fnModule);
obj.filteredModules = chunk.modules.length - obj.modules.length;
obj.filteredModules = chunk.getNumberOfModules() - obj.modules.length;
obj.modules.sort(sortByField(sortModules));
}
if(showChunkOrigins) {
Expand Down
6 changes: 3 additions & 3 deletions lib/Template.js
Expand Up @@ -99,12 +99,12 @@ module.exports = class Template extends Tapable {
renderChunkModules(chunk, moduleTemplate, dependencyTemplates, prefix) {
if(!prefix) prefix = "";
var source = new ConcatSource();
if(chunk.modules.length === 0) {
if(chunk.getNumberOfModules() === 0) {
source.add("[]");
return source;
}
var removedModules = chunk.removedModules;
var allModules = chunk.modules.map(function(module) {
var allModules = chunk.mapModules(function(module) {
return {
id: module.id,
source: moduleTemplate.render(module, dependencyTemplates, chunk)
Expand All @@ -118,7 +118,7 @@ module.exports = class Template extends Tapable {
});
});
}
var bounds = this.getModulesArrayBounds(chunk.modules);
var bounds = this.getModulesArrayBounds(allModules);

if(bounds) {
// Render a spare array
Expand Down
2 changes: 1 addition & 1 deletion lib/UmdMainTemplatePlugin.js
Expand Up @@ -32,7 +32,7 @@ class UmdMainTemplatePlugin {
apply(compilation) {
const mainTemplate = compilation.mainTemplate;
compilation.templatesPlugin("render-with-entry", function(source, chunk, hash) {
let externals = chunk.modules.filter(m => m.external);
let externals = chunk.mapModules(m => m).filter(m => m.external);
const optionalExternals = [];
let requiredExternals = [];
if(this.optionalAmdExternalAsGlobal) {
Expand Down