diff --git a/lib/AsyncDependenciesBlock.js b/lib/AsyncDependenciesBlock.js index e251a7d6e..656b1daef 100644 --- a/lib/AsyncDependenciesBlock.js +++ b/lib/AsyncDependenciesBlock.js @@ -14,7 +14,7 @@ const DependenciesBlock = require("./DependenciesBlock"); /** @typedef {import("./util/createHash").Hash} Hash */ /** @typedef {TODO} GroupOptions */ -module.exports = class AsyncDependenciesBlock extends DependenciesBlock { +class AsyncDependenciesBlock extends DependenciesBlock { /** * @param {GroupOptions} groupOptions options for the group * @param {Module} module the Module object @@ -36,6 +36,8 @@ module.exports = class AsyncDependenciesBlock extends DependenciesBlock { this.request = request; /** @type {DependenciesBlock} */ this.parent = undefined; + /** @type {[number, number]} */ + this.range = undefined; } /** @@ -96,4 +98,6 @@ module.exports = class AsyncDependenciesBlock extends DependenciesBlock { sortItems(sortChunks) { super.sortItems(); } -}; +} + +module.exports = AsyncDependenciesBlock; diff --git a/lib/Chunk.js b/lib/Chunk.js index efe5429b2..f55c6f8d7 100644 --- a/lib/Chunk.js +++ b/lib/Chunk.js @@ -109,9 +109,9 @@ class Chunk { * @param {string=} name of chunk being created, is optional (for subclasses) */ constructor(name) { - /** @type {number | null} */ + /** @type {number | string | null} */ this.id = null; - /** @type {number[] | null} */ + /** @type {(number|string)[] | null} */ this.ids = null; /** @type {number} */ this.debugId = debugId++; @@ -227,7 +227,7 @@ class Chunk { } /** - * @returns {SortableSet} return the modules SortableSet for this chunk + * @returns {SortableSet} return the modules SortableSet for this chunk */ get modulesIterable() { return this._modules; diff --git a/lib/ContextModule.js b/lib/ContextModule.js index 78b7adb0b..fbb1ea3d0 100644 --- a/lib/ContextModule.js +++ b/lib/ContextModule.js @@ -14,6 +14,7 @@ const contextify = require("./util/identifier").contextify; /** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./DependencyTemplates")} DependencyTemplates */ +/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */ /** @typedef {import("./Module").SourceContext} SourceContext */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ @@ -183,6 +184,10 @@ class ContextModule extends Module { return identifier; } + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ libIdent(options) { let identifier = contextify(options.context, this.context); if (this.options.mode) { diff --git a/lib/DelegatedModule.js b/lib/DelegatedModule.js index 613636ed0..af712e120 100644 --- a/lib/DelegatedModule.js +++ b/lib/DelegatedModule.js @@ -14,6 +14,7 @@ const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDepende /** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./DependencyTemplates")} DependencyTemplates */ +/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */ /** @typedef {import("./Module").SourceContext} SourceContext */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ @@ -36,6 +37,10 @@ class DelegatedModule extends Module { this.delegatedSourceDependency = undefined; } + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ libIdent(options) { return typeof this.originalRequest === "string" ? this.originalRequest diff --git a/lib/DelegatedModuleFactoryPlugin.js b/lib/DelegatedModuleFactoryPlugin.js index aee02fb98..898b02e12 100644 --- a/lib/DelegatedModuleFactoryPlugin.js +++ b/lib/DelegatedModuleFactoryPlugin.js @@ -74,8 +74,8 @@ class DelegatedModuleFactoryPlugin { normalModuleFactory.hooks.module.tap( "DelegatedModuleFactoryPlugin", module => { - if (module.libIdent) { - const request = module.libIdent(this.options); + const request = module.libIdent(this.options); + if (request) { if (request && request in this.options.content) { const resolved = this.options.content[request]; return new DelegatedModule( diff --git a/lib/ExternalModule.js b/lib/ExternalModule.js index d28eacb6d..3d76013be 100644 --- a/lib/ExternalModule.js +++ b/lib/ExternalModule.js @@ -13,6 +13,7 @@ const Template = require("./Template"); /** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./DependencyTemplates")} DependencyTemplates */ +/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */ /** @typedef {import("./Module").SourceContext} SourceContext */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ @@ -102,7 +103,7 @@ class ExternalModule extends Module { super("javascript/dynamic", null); // Info from Factory - /** @type {string} */ + /** @type {string | string[] | Record} */ this.request = request; /** @type {string} */ this.externalType = type; @@ -113,9 +114,10 @@ class ExternalModule extends Module { } /** - * @returns {string} the external module identifier + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion */ - libIdent() { + libIdent(options) { return this.userRequest; } diff --git a/lib/FlagDependencyUsagePlugin.js b/lib/FlagDependencyUsagePlugin.js index 3c4e4df7c..18e727f30 100644 --- a/lib/FlagDependencyUsagePlugin.js +++ b/lib/FlagDependencyUsagePlugin.js @@ -11,6 +11,12 @@ /** @typedef {false | true | string[]} UsedExports */ +/** + * @template T + * @param {T[]} a array (will be modified) + * @param {T[]} b array (will be added to a) + * @returns {T[]} a again + */ const addToSet = (a, b) => { for (const item of b) { if (!a.includes(item)) a.push(item); @@ -34,6 +40,12 @@ class FlagDependencyUsagePlugin { compilation.hooks.optimizeDependencies.tap( "FlagDependencyUsagePlugin", modules => { + /** + * + * @param {Module} module module to process + * @param {string[] | boolean} usedExports list of used exports + * @returns {void} + */ const processModule = (module, usedExports) => { module.used = true; if (module.usedExports === true) return; diff --git a/lib/FlagInitialModulesAsUsedPlugin.js b/lib/FlagInitialModulesAsUsedPlugin.js index 69d1026ff..3c7b89778 100644 --- a/lib/FlagInitialModulesAsUsedPlugin.js +++ b/lib/FlagInitialModulesAsUsedPlugin.js @@ -5,11 +5,17 @@ "use strict"; +/** @typedef {import("./Compiler")} Compiler */ + class FlagInitialModulesAsUsedPlugin { constructor(explanation) { this.explanation = explanation; } + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ apply(compiler) { compiler.hooks.compilation.tap( "FlagInitialModulesAsUsedPlugin", diff --git a/lib/HashedModuleIdsPlugin.js b/lib/HashedModuleIdsPlugin.js index c8a60bfcd..643092631 100644 --- a/lib/HashedModuleIdsPlugin.js +++ b/lib/HashedModuleIdsPlugin.js @@ -33,17 +33,19 @@ class HashedModuleIdsPlugin { "HashedModuleIdsPlugin", modules => { for (const module of modules) { - if (module.id === null && module.libIdent) { + if (module.id === null) { const id = module.libIdent({ context: this.options.context || compiler.options.context }); - const hash = createHash(options.hashFunction); - hash.update(id); - const hashId = hash.digest(options.hashDigest); - let len = options.hashDigestLength; - while (usedIds.has(hashId.substr(0, len))) len++; - module.id = hashId.substr(0, len); - usedIds.add(module.id); + if (id) { + const hash = createHash(options.hashFunction); + hash.update(id); + const hashId = hash.digest(options.hashDigest); + let len = options.hashDigestLength; + while (usedIds.has(hashId.substr(0, len))) len++; + module.id = hashId.substr(0, len); + usedIds.add(module.id); + } } } } diff --git a/lib/HotModuleReplacementPlugin.js b/lib/HotModuleReplacementPlugin.js index 773b43eff..6a48cd09e 100644 --- a/lib/HotModuleReplacementPlugin.js +++ b/lib/HotModuleReplacementPlugin.js @@ -20,6 +20,9 @@ const ConstDependency = require("./dependencies/ConstDependency"); const ModuleHotAcceptDependency = require("./dependencies/ModuleHotAcceptDependency"); const ModuleHotDeclineDependency = require("./dependencies/ModuleHotDeclineDependency"); +/** @typedef {import("./Compiler")} Compiler */ +/** @typedef {import("./Module")} Module */ + const hotInitCode = Template.getFunctionContent( require("./HotModuleReplacement.runtime") ); @@ -51,6 +54,10 @@ module.exports = class HotModuleReplacementPlugin { this.requestTimeout = this.options.requestTimeout || 10000; } + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ apply(compiler) { const multiStep = this.multiStep; const fullBuildTimeout = this.fullBuildTimeout; @@ -259,10 +266,14 @@ module.exports = class HotModuleReplacementPlugin { !records.chunkModuleIds ) return; + /** @type {Set} */ + const updatedModules = new Set(); for (const module of compilation.modules) { const identifier = module.identifier(); - let hash = module.hash; - module.hotUpdate = records.moduleHashs[identifier] !== hash; + const hash = module.hash; + if (records.moduleHashs[identifier] !== hash) { + updatedModules.add(module); + } } const hotUpdateMainContent = { h: compilation.hash, @@ -276,7 +287,8 @@ module.exports = class HotModuleReplacementPlugin { if (currentChunk) { const newModules = currentChunk .getModules() - .filter(module => module.hotUpdate); + .filter(module => updatedModules.has(module)); + /** @type {Set} */ const allModules = new Set(); for (const module of currentChunk.modulesIterable) { allModules.add(module.id); diff --git a/lib/LibManifestPlugin.js b/lib/LibManifestPlugin.js index 5b9f654ce..22eec9c02 100644 --- a/lib/LibManifestPlugin.js +++ b/lib/LibManifestPlugin.js @@ -47,19 +47,17 @@ class LibManifestPlugin { ) { return; } - if (module.libIdent) { - const ident = module.libIdent({ - context: this.options.context || compiler.options.context - }); - if (ident) { - return { - ident, - data: { - id: module.id, - buildMeta: module.buildMeta - } - }; - } + const ident = module.libIdent({ + context: this.options.context || compiler.options.context + }); + if (ident) { + return { + ident, + data: { + id: module.id, + buildMeta: module.buildMeta + } + }; } }) .filter(Boolean) diff --git a/lib/Module.js b/lib/Module.js index e3bb20503..73c331ba0 100644 --- a/lib/Module.js +++ b/lib/Module.js @@ -28,6 +28,11 @@ const SortableSet = require("./util/SortableSet"); * @property {string=} type the type of source that should be generated */ +/** + * @typedef {Object} LibIdentOptions + * @property {string} context absolute context path to which lib ident is relative to + */ + const EMPTY_RESOLVE_OPTIONS = {}; let debugId = 1000; @@ -498,6 +503,14 @@ class Module extends DependenciesBlock { throw new Error("Module.size: Must be overriden"); } + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ + libIdent(options) { + return null; + } + /** * @returns {string | null} absolute path which should be used for condition matching (usually the resource path) */ diff --git a/lib/NamedModulesPlugin.js b/lib/NamedModulesPlugin.js index 417676829..e566e1898 100644 --- a/lib/NamedModulesPlugin.js +++ b/lib/NamedModulesPlugin.js @@ -26,8 +26,11 @@ class NamedModulesPlugin { const context = this.options.context || compiler.options.context; for (const module of modules) { - if (module.id === null && module.libIdent) { - module.id = module.libIdent({ context }); + if (module.id === null) { + const id = module.libIdent({ context }); + if (id) { + module.id = id; + } } if (module.id !== null) { diff --git a/lib/NormalModule.js b/lib/NormalModule.js index fbf87e722..27db3695e 100644 --- a/lib/NormalModule.js +++ b/lib/NormalModule.js @@ -26,6 +26,7 @@ const contextify = require("./util/identifier").contextify; /** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./DependencyTemplates")} DependencyTemplates */ +/** @typedef {import("./Module").LibIdentOptions} LibIdentOptions */ /** @typedef {import("./Module").SourceContext} SourceContext */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ @@ -121,6 +122,10 @@ class NormalModule extends Module { return requestShortener.shorten(this.userRequest); } + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ libIdent(options) { return contextify(options.context, this.userRequest); } diff --git a/lib/UmdMainTemplatePlugin.js b/lib/UmdMainTemplatePlugin.js index 7d0e91d2f..e1e82c653 100644 --- a/lib/UmdMainTemplatePlugin.js +++ b/lib/UmdMainTemplatePlugin.js @@ -6,8 +6,11 @@ "use strict"; const { ConcatSource, OriginalSource } = require("webpack-sources"); +const ExternalModule = require("./ExternalModule"); const Template = require("./Template"); +/** @typedef {import("webpack-sources").Source} Source */ +/** @typedef {import("./Chunk")} Chunk */ /** @typedef {import("./Compilation")} Compilation */ /** @@ -85,14 +88,21 @@ class UmdMainTemplatePlugin { apply(compilation) { const { mainTemplate, chunkTemplate, runtimeTemplate } = compilation; + /** + * @param {Source} source source + * @param {Chunk} chunk chunk + * @param {string} hash Hash + * @returns {Source} new source + */ const onRenderWithEntry = (source, chunk, hash) => { - let externals = chunk + /** @type {ExternalModule[]} */ + let externals = /** @type {ExternalModule[]} */ (chunk .getModules() .filter( m => - m.external && + m instanceof ExternalModule && (m.externalType === "umd" || m.externalType === "umd2") - ); + )); const optionalExternals = []; let requiredExternals = []; if (this.optionalAmdExternalAsGlobal) { diff --git a/lib/dependencies/RequireEnsureDependenciesBlock.js b/lib/dependencies/RequireEnsureDependenciesBlock.js index 86cc8ee94..d62dd787a 100644 --- a/lib/dependencies/RequireEnsureDependenciesBlock.js +++ b/lib/dependencies/RequireEnsureDependenciesBlock.js @@ -20,12 +20,17 @@ module.exports = class RequireEnsureDependenciesBlock extends AsyncDependenciesB ) { super(chunkName, module, loc, null); this.expr = expr; + /** @type {[number, number] | undefined} */ const successBodyRange = successExpression && successExpression.body && successExpression.body.range; if (successBodyRange) { - this.range = [successBodyRange[0] + 1, successBodyRange[1] - 1]; + const range = /** @type {[number, number]} */ ([ + successBodyRange[0] + 1, + successBodyRange[1] - 1 + ]); + this.range = range; } this.chunkNameRange = chunkNameRange; const dep = new RequireEnsureDependency(this); diff --git a/lib/node/NodeChunkTemplatePlugin.js b/lib/node/NodeChunkTemplatePlugin.js index 292182a97..f18203bf1 100644 --- a/lib/node/NodeChunkTemplatePlugin.js +++ b/lib/node/NodeChunkTemplatePlugin.js @@ -7,7 +7,13 @@ const { ConcatSource } = require("webpack-sources"); +/** @typedef {import("../ChunkTemplate")} ChunkTemplate */ + class NodeChunkTemplatePlugin { + /** + * @param {ChunkTemplate} chunkTemplate the chunk template + * @returns {void} + */ apply(chunkTemplate) { chunkTemplate.hooks.render.tap( "NodeChunkTemplatePlugin", diff --git a/lib/optimize/ConcatenatedModule.js b/lib/optimize/ConcatenatedModule.js index 4f9047c15..e28b77afc 100644 --- a/lib/optimize/ConcatenatedModule.js +++ b/lib/optimize/ConcatenatedModule.js @@ -27,6 +27,7 @@ const createHash = require("../util/createHash"); /** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */ /** @typedef {import("../DependencyTemplates")} DependencyTemplates */ /** @typedef {import("../InitFragment")} InitFragment */ +/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */ /** @typedef {import("../Module").SourceContext} SourceContext */ /** @typedef {import("../RequestShortener")} RequestShortener */ /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ @@ -410,6 +411,10 @@ class ConcatenatedModule extends Module { ); } + /** + * @param {LibIdentOptions} options options + * @returns {string | null} an identifier for library inclusion + */ libIdent(options) { return this.rootModule.libIdent(options); } diff --git a/lib/optimize/OccurrenceModuleOrderPlugin.js b/lib/optimize/OccurrenceModuleOrderPlugin.js index fb6344c5f..a8125c47e 100644 --- a/lib/optimize/OccurrenceModuleOrderPlugin.js +++ b/lib/optimize/OccurrenceModuleOrderPlugin.js @@ -8,12 +8,19 @@ const validateOptions = require("schema-utils"); const schema = require("../../schemas/plugins/optimize/OccurrenceOrderModuleIdsPlugin.json"); +/** @typedef {import("../Compiler")} Compiler */ +/** @typedef {import("../ModuleReason")} ModuleReason */ + class OccurrenceOrderModuleIdsPlugin { constructor(options = {}) { validateOptions(schema, options, "Occurrence Order Module Ids Plugin"); this.options = options; } + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ apply(compiler) { const prioritiseInitial = this.options.prioritiseInitial; compiler.hooks.compilation.tap( @@ -38,12 +45,23 @@ class OccurrenceOrderModuleIdsPlugin { entryCountMap.set(m, entry); } + /** + * @param {number} sum sum of occurs + * @param {ModuleReason} r module reason + * @returns {number} count of occurs + */ const countOccursInEntry = (sum, r) => { if (!r.module) { return sum; } return sum + initialChunkChunkMap.get(r.module); }; + + /** + * @param {number} sum sum of occurs + * @param {ModuleReason} r module reason + * @returns {number} count of occurs + */ const countOccurs = (sum, r) => { if (!r.module) { return sum; diff --git a/lib/optimize/SideEffectsFlagPlugin.js b/lib/optimize/SideEffectsFlagPlugin.js index 68bc63656..fe88e2ba0 100644 --- a/lib/optimize/SideEffectsFlagPlugin.js +++ b/lib/optimize/SideEffectsFlagPlugin.js @@ -9,6 +9,7 @@ const mm = require("micromatch"); const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); +/** @typedef {import("../Compiler")} Compiler */ /** @typedef {import("../Dependency")} Dependency */ /** @typedef {import("../Module")} Module */ @@ -19,6 +20,10 @@ const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportS */ class SideEffectsFlagPlugin { + /** + * @param {Compiler} compiler webpack compiler + * @returns {void} + */ apply(compiler) { compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", nmf => { nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => {