UNPKG

webpack

Version:

Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.

436 lines (375 loc) 10.4 kB
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const util = require("util"); const DependenciesBlock = require("./DependenciesBlock"); const ModuleReason = require("./ModuleReason"); const SortableSet = require("./util/SortableSet"); const Template = require("./Template"); /** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./WebpackError")} WebpackError */ /** @typedef {import("./util/createHash").Hash} Hash */ const EMPTY_RESOLVE_OPTIONS = {}; let debugId = 1000; const sortById = (a, b) => { return a.id - b.id; }; const sortByDebugId = (a, b) => { return a.debugId - b.debugId; }; /** @typedef {(requestShortener: RequestShortener) => string} OptimizationBailoutFunction */ class Module extends DependenciesBlock { constructor(type, context = null) { super(); /** @type {string} */ this.type = type; /** @type {string} */ this.context = context; // Unique Id /** @type {number} */ this.debugId = debugId++; // Hash /** @type {string} */ this.hash = undefined; /** @type {string} */ this.renderedHash = undefined; // Info from Factory /** @type {TODO} */ this.resolveOptions = EMPTY_RESOLVE_OPTIONS; /** @type {object} */ this.factoryMeta = {}; // Info from Build /** @type {WebpackError[]} */ this.warnings = []; /** @type {WebpackError[]} */ this.errors = []; /** @type {object} */ this.buildMeta = undefined; /** @type {object} */ this.buildInfo = undefined; // Graph (per Compilation) /** @type {ModuleReason[]} */ this.reasons = []; /** @type {SortableSet<Chunk>} */ this._chunks = new SortableSet(undefined, sortById); // Info from Compilation (per Compilation) /** @type {number|string} */ this.id = null; /** @type {number} */ this.index = null; /** @type {number} */ this.index2 = null; /** @type {number} */ this.depth = null; /** @type {Module} */ this.issuer = null; /** @type {undefined | object} */ this.profile = undefined; /** @type {boolean} */ this.prefetched = false; /** @type {boolean} */ this.built = false; // Info from Optimization (per Compilation) /** @type {null | boolean} */ this.used = null; /** @type {false | true | string[]} */ this.usedExports = null; /** @type {(string | OptimizationBailoutFunction)[]} */ this.optimizationBailout = []; // delayed operations /** @type {undefined | {oldChunk: Chunk, newChunks: Chunk[]}[] } */ this._rewriteChunkInReasons = undefined; /** @type {boolean} */ this.useSourceMap = false; // info from build this._source = null; } get exportsArgument() { return (this.buildInfo && this.buildInfo.exportsArgument) || "exports"; } get moduleArgument() { return (this.buildInfo && this.buildInfo.moduleArgument) || "module"; } disconnect() { this.hash = undefined; this.renderedHash = undefined; this.reasons.length = 0; this._rewriteChunkInReasons = undefined; this._chunks.clear(); this.id = null; this.index = null; this.index2 = null; this.depth = null; this.issuer = null; this.profile = undefined; this.prefetched = false; this.built = false; this.used = null; this.usedExports = null; this.optimizationBailout.length = 0; super.disconnect(); } unseal() { this.id = null; this.index = null; this.index2 = null; this.depth = null; this._chunks.clear(); super.unseal(); } setChunks(chunks) { this._chunks = new SortableSet(chunks, sortById); } addChunk(chunk) { if (this._chunks.has(chunk)) return false; this._chunks.add(chunk); return true; } removeChunk(chunk) { if (this._chunks.delete(chunk)) { chunk.removeModule(this); return true; } return false; } isInChunk(chunk) { return this._chunks.has(chunk); } isEntryModule() { for (const chunk of this._chunks) { if (chunk.entryModule === this) return true; } return false; } get optional() { return ( this.reasons.length > 0 && this.reasons.every(r => r.dependency && r.dependency.optional) ); } /** * @returns {Chunk[]} all chunks which contain the module */ getChunks() { return Array.from(this._chunks); } getNumberOfChunks() { return this._chunks.size; } get chunksIterable() { return this._chunks; } hasEqualsChunks(otherModule) { if (this._chunks.size !== otherModule._chunks.size) return false; this._chunks.sortWith(sortByDebugId); otherModule._chunks.sortWith(sortByDebugId); const a = this._chunks[Symbol.iterator](); const b = otherModule._chunks[Symbol.iterator](); // eslint-disable-next-line no-constant-condition while (true) { const aItem = a.next(); const bItem = b.next(); if (aItem.done) return true; if (aItem.value !== bItem.value) return false; } } addReason(module, dependency, explanation) { this.reasons.push(new ModuleReason(module, dependency, explanation)); } removeReason(module, dependency) { for (let i = 0; i < this.reasons.length; i++) { let r = this.reasons[i]; if (r.module === module && r.dependency === dependency) { this.reasons.splice(i, 1); return true; } } return false; } hasReasonForChunk(chunk) { if (this._rewriteChunkInReasons) { for (const operation of this._rewriteChunkInReasons) { this._doRewriteChunkInReasons(operation.oldChunk, operation.newChunks); } this._rewriteChunkInReasons = undefined; } for (let i = 0; i < this.reasons.length; i++) { if (this.reasons[i].hasChunk(chunk)) return true; } return false; } hasReasons() { return this.reasons.length > 0; } rewriteChunkInReasons(oldChunk, newChunks) { // This is expensive. Delay operation until we really need the data if (this._rewriteChunkInReasons === undefined) { this._rewriteChunkInReasons = []; } this._rewriteChunkInReasons.push({ oldChunk, newChunks }); } _doRewriteChunkInReasons(oldChunk, newChunks) { for (let i = 0; i < this.reasons.length; i++) { this.reasons[i].rewriteChunks(oldChunk, newChunks); } } /** * @param {string=} exportName the name of the export * @returns {boolean|string} false if the export isn't used, true if no exportName is provided and the module is used, or the name to access it if the export is used */ isUsed(exportName) { if (!exportName) return this.used !== false; if (this.used === null || this.usedExports === null) return exportName; if (!this.used) return false; if (!this.usedExports) return false; if (this.usedExports === true) return exportName; let idx = this.usedExports.indexOf(exportName); if (idx < 0) return false; // Mangle export name if possible if (this.isProvided(exportName)) { if (this.buildMeta.exportsType === "namespace") { return Template.numberToIdentifer(idx); } if ( this.buildMeta.exportsType === "named" && !this.usedExports.includes("default") ) { return Template.numberToIdentifer(idx); } } return exportName; } isProvided(exportName) { if (!Array.isArray(this.buildMeta.providedExports)) return null; return this.buildMeta.providedExports.includes(exportName); } toString() { return `Module[${this.id || this.debugId}]`; } needRebuild(fileTimestamps, contextTimestamps) { return true; } /** * @param {Hash} hash the hash used to track dependencies * @returns {void} */ updateHash(hash) { hash.update(`${this.id}`); hash.update(JSON.stringify(this.usedExports)); super.updateHash(hash); } sortItems(sortChunks) { super.sortItems(); if (sortChunks) this._chunks.sort(); this.reasons.sort((a, b) => { if (a.module === b.module) return 0; if (!a.module) return -1; if (!b.module) return 1; return sortById(a.module, b.module); }); if (Array.isArray(this.usedExports)) { this.usedExports.sort(); } } unbuild() { this.dependencies.length = 0; this.blocks.length = 0; this.variables.length = 0; this.buildMeta = undefined; this.buildInfo = undefined; this.disconnect(); } get arguments() { throw new Error("Module.arguments was removed, there is no replacement."); } set arguments(value) { throw new Error("Module.arguments was removed, there is no replacement."); } } // TODO remove in webpack 5 Object.defineProperty(Module.prototype, "forEachChunk", { configurable: false, value: util.deprecate( /** * @deprecated * @param {function(any, any, Set<any>): void} fn callback function * @returns {void} * @this {Module} */ function(fn) { this._chunks.forEach(fn); }, "Module.forEachChunk: Use for(const chunk of module.chunksIterable) instead" ) }); // TODO remove in webpack 5 Object.defineProperty(Module.prototype, "mapChunks", { configurable: false, value: util.deprecate( /** * @deprecated * @param {function(any, any): void} fn Mapper function * @returns {Array<TODO>} Array of chunks mapped * @this {Module} */ function(fn) { return Array.from(this._chunks, fn); }, "Module.mapChunks: Use Array.from(module.chunksIterable, fn) instead" ) }); // TODO remove in webpack 5 Object.defineProperty(Module.prototype, "entry", { configurable: false, get() { throw new Error("Module.entry was removed. Use Chunk.entryModule"); }, set() { throw new Error("Module.entry was removed. Use Chunk.entryModule"); } }); // TODO remove in webpack 5 Object.defineProperty(Module.prototype, "meta", { configurable: false, get: util.deprecate( /** * @deprecated * @returns {void} * @this {Module} */ function() { return this.buildMeta; }, "Module.meta was renamed to Module.buildMeta" ), set: util.deprecate( /** * @deprecated * @param {TODO} value Value * @returns {void} * @this {Module} */ function(value) { this.buildMeta = value; }, "Module.meta was renamed to Module.buildMeta" ) }); /** @type {function(): string} */ Module.prototype.identifier = null; /** @type {function(RequestShortener): string} */ Module.prototype.readableIdentifier = null; Module.prototype.build = null; Module.prototype.source = null; Module.prototype.size = null; Module.prototype.nameForCondition = null; /** @type {null | function(Chunk): boolean} */ Module.prototype.chunkCondition = null; Module.prototype.updateCacheModule = null; module.exports = Module;