webpack 4.35.3 → 4.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -148,9 +148,8 @@ class JavascriptModulesPlugin {
148
148
  hash.update(m.hash);
149
149
  }
150
150
  }
151
- chunk.contentHash.javascript = hash
152
- .digest(hashDigest)
153
- .substr(0, hashDigestLength);
151
+ const digest = /** @type {string} */ (hash.digest(hashDigest));
152
+ chunk.contentHash.javascript = digest.substr(0, hashDigestLength);
154
153
  });
155
154
  }
156
155
  );
@@ -44,7 +44,8 @@ const getBefore = (str, token) => {
44
44
  const getHash = str => {
45
45
  const hash = createHash("md4");
46
46
  hash.update(str);
47
- return hash.digest("hex").substr(0, 4);
47
+ const digest = /** @type {string} */ (hash.digest("hex"));
48
+ return digest.substr(0, 4);
48
49
  };
49
50
 
50
51
  const asRegExp = test => {
@@ -10,7 +10,8 @@ const RequestShortener = require("./RequestShortener");
10
10
  const getHash = str => {
11
11
  const hash = createHash("md4");
12
12
  hash.update(str);
13
- return hash.digest("hex").substr(0, 4);
13
+ const digest = /** @type {string} */ (hash.digest("hex"));
14
+ return digest.substr(0, 4);
14
15
  };
15
16
 
16
17
  class NamedModulesPlugin {
@@ -147,16 +147,20 @@ class NormalModule extends Module {
147
147
 
148
148
  createLoaderContext(resolver, options, compilation, fs) {
149
149
  const requestShortener = compilation.runtimeTemplate.requestShortener;
150
+ const getCurrentLoaderName = () => {
151
+ const currentLoader = this.getCurrentLoader(loaderContext);
152
+ if (!currentLoader) return "(not in loader scope)";
153
+ return requestShortener.shorten(currentLoader.loader);
154
+ };
150
155
  const loaderContext = {
151
156
  version: 2,
152
157
  emitWarning: warning => {
153
158
  if (!(warning instanceof Error)) {
154
159
  warning = new NonErrorEmittedError(warning);
155
160
  }
156
- const currentLoader = this.getCurrentLoader(loaderContext);
157
161
  this.warnings.push(
158
162
  new ModuleWarning(this, warning, {
159
- from: requestShortener.shorten(currentLoader.loader)
163
+ from: getCurrentLoaderName()
160
164
  })
161
165
  );
162
166
  },
@@ -164,13 +168,20 @@ class NormalModule extends Module {
164
168
  if (!(error instanceof Error)) {
165
169
  error = new NonErrorEmittedError(error);
166
170
  }
167
- const currentLoader = this.getCurrentLoader(loaderContext);
168
171
  this.errors.push(
169
172
  new ModuleError(this, error, {
170
- from: requestShortener.shorten(currentLoader.loader)
173
+ from: getCurrentLoaderName()
171
174
  })
172
175
  );
173
176
  },
177
+ getLogger: name => {
178
+ const currentLoader = this.getCurrentLoader(loaderContext);
179
+ return compilation.getLogger(() =>
180
+ [currentLoader && currentLoader.loader, name, this.identifier()]
181
+ .filter(Boolean)
182
+ .join("|")
183
+ );
184
+ },
174
185
  // TODO remove in webpack 5
175
186
  exec: (code, filename) => {
176
187
  // @ts-ignore Argument of type 'this' is not assignable to parameter of type 'Module'.
@@ -405,7 +416,7 @@ class NormalModule extends Module {
405
416
  }
406
417
  hash.update("meta");
407
418
  hash.update(JSON.stringify(this.buildMeta));
408
- this._buildHash = hash.digest("hex");
419
+ this._buildHash = /** @type {string} */ (hash.digest("hex"));
409
420
  }
410
421
 
411
422
  build(options, compilation, resolver, fs, callback) {
@@ -17,7 +17,7 @@ const {
17
17
  const NormalModule = require("./NormalModule");
18
18
  const RawModule = require("./RawModule");
19
19
  const RuleSet = require("./RuleSet");
20
- const cachedMerge = require("./util/cachedMerge");
20
+ const { cachedCleverMerge } = require("./util/cleverMerge");
21
21
 
22
22
  const EMPTY_RESOLVE_OPTIONS = {};
23
23
 
@@ -304,7 +304,7 @@ class NormalModuleFactory extends Tapable {
304
304
  typeof settings[r.type] === "object" &&
305
305
  settings[r.type] !== null
306
306
  ) {
307
- settings[r.type] = cachedMerge(settings[r.type], r.value);
307
+ settings[r.type] = cachedCleverMerge(settings[r.type], r.value);
308
308
  } else {
309
309
  settings[r.type] = r.value;
310
310
  }
@@ -6,8 +6,8 @@
6
6
 
7
7
  /**
8
8
  * Gets the value at path of object
9
- * @param {object} obj - object to query
10
- * @param {string} path - query path
9
+ * @param {object} obj object to query
10
+ * @param {string} path query path
11
11
  * @returns {any} - if {@param path} requests element from array, then `undefined` will be returned
12
12
  */
13
13
  const getProperty = (obj, path) => {
@@ -21,9 +21,9 @@ const getProperty = (obj, path) => {
21
21
 
22
22
  /**
23
23
  * Sets the value at path of object. Stops execution, if {@param path} requests element from array to be set
24
- * @param {object} obj - object to query
25
- * @param {string} path - query path
26
- * @param {any} value - value to be set
24
+ * @param {object} obj object to query
25
+ * @param {string} path query path
26
+ * @param {any} value value to be set
27
27
  * @returns {void}
28
28
  */
29
29
  const setProperty = (obj, path, value) => {
@@ -65,7 +65,7 @@ class OptionsDefaulter {
65
65
 
66
66
  /**
67
67
  * Enhancing {@param options} with default values
68
- * @param {object} options - provided options
68
+ * @param {object} options provided options
69
69
  * @returns {object} - enhanced options
70
70
  * @throws {Error} - will throw error, if configuration value is other then `undefined` or {@link ConfigType}
71
71
  */
@@ -122,9 +122,9 @@ class OptionsDefaulter {
122
122
 
123
123
  /**
124
124
  * Builds up default values
125
- * @param {string} name - option path
126
- * @param {ConfigType | any} config - if {@param def} is provided, then only {@link ConfigType} is allowed
127
- * @param {MakeConfigHandler | CallConfigHandler | AppendConfigValues} [def] - defaults
125
+ * @param {string} name option path
126
+ * @param {ConfigType | any} config if {@param def} is provided, then only {@link ConfigType} is allowed
127
+ * @param {MakeConfigHandler | CallConfigHandler | AppendConfigValues} [def] defaults
128
128
  * @returns {void}
129
129
  */
130
130
  set(name, config, def) {
@@ -263,7 +263,6 @@ class ProgressPlugin {
263
263
  recordModules: "record modules",
264
264
  recordChunks: "record chunks",
265
265
  beforeHash: "hashing",
266
- contentHash: "content hashing",
267
266
  afterHash: "after hashing",
268
267
  recordHash: "record hash",
269
268
  beforeModuleAssets: "module assets processing",
@@ -6,9 +6,12 @@
6
6
 
7
7
  const { Tapable, HookMap, SyncHook, SyncWaterfallHook } = require("tapable");
8
8
  const Factory = require("enhanced-resolve").ResolverFactory;
9
+ const { cachedCleverMerge } = require("./util/cleverMerge");
9
10
 
10
11
  /** @typedef {import("enhanced-resolve").Resolver} Resolver */
11
12
 
13
+ const EMTPY_RESOLVE_OPTIONS = {};
14
+
12
15
  module.exports = class ResolverFactory extends Tapable {
13
16
  constructor() {
14
17
  super();
@@ -22,30 +25,24 @@ module.exports = class ResolverFactory extends Tapable {
22
25
  let match;
23
26
  match = /^resolve-options (.+)$/.exec(options.name);
24
27
  if (match) {
25
- this.hooks.resolveOptions.tap(
26
- match[1],
27
- options.fn.name || "unnamed compat plugin",
28
- options.fn
29
- );
28
+ this.hooks.resolveOptions
29
+ .for(match[1])
30
+ .tap(options.fn.name || "unnamed compat plugin", options.fn);
30
31
  return true;
31
32
  }
32
33
  match = /^resolver (.+)$/.exec(options.name);
33
34
  if (match) {
34
- this.hooks.resolver.tap(
35
- match[1],
36
- options.fn.name || "unnamed compat plugin",
37
- options.fn
38
- );
35
+ this.hooks.resolver
36
+ .for(match[1])
37
+ .tap(options.fn.name || "unnamed compat plugin", options.fn);
39
38
  return true;
40
39
  }
41
40
  });
42
- this.cache1 = new WeakMap();
43
41
  this.cache2 = new Map();
44
42
  }
45
43
 
46
44
  get(type, resolveOptions) {
47
- const cachedResolver = this.cache1.get(resolveOptions);
48
- if (cachedResolver) return cachedResolver();
45
+ resolveOptions = resolveOptions || EMTPY_RESOLVE_OPTIONS;
49
46
  const ident = `${type}|${JSON.stringify(resolveOptions)}`;
50
47
  const resolver = this.cache2.get(ident);
51
48
  if (resolver) return resolver;
@@ -66,7 +63,7 @@ module.exports = class ResolverFactory extends Tapable {
66
63
  resolver.withOptions = options => {
67
64
  const cacheEntry = childCache.get(options);
68
65
  if (cacheEntry !== undefined) return cacheEntry;
69
- const mergedOptions = Object.assign({}, originalResolveOptions, options);
66
+ const mergedOptions = cachedCleverMerge(originalResolveOptions, options);
70
67
  const resolver = this.get(type, mergedOptions);
71
68
  childCache.set(options, resolver);
72
69
  return resolver;
@@ -14,25 +14,52 @@ const validateOptions = require("schema-utils");
14
14
  const schema = require("../schemas/plugins/SourceMapDevToolPlugin.json");
15
15
 
16
16
  /** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */
17
+ /** @typedef {import("./Chunk")} Chunk */
18
+ /** @typedef {import("webpack-sources").Source} Source */
19
+ /** @typedef {import("source-map").RawSourceMap} SourceMap */
20
+ /** @typedef {import("./Module")} Module */
21
+ /** @typedef {import("./Compilation")} Compilation */
22
+ /** @typedef {import("./Compiler")} Compiler */
23
+ /** @typedef {import("./Compilation")} SourceMapDefinition */
17
24
 
25
+ /**
26
+ * @typedef {object} SourceMapTask
27
+ * @property {Source} asset
28
+ * @property {Array<string | Module>} [modules]
29
+ * @property {string} source
30
+ * @property {string} file
31
+ * @property {SourceMap} sourceMap
32
+ * @property {Chunk} chunk
33
+ */
34
+
35
+ /**
36
+ * @param {string} name file path
37
+ * @returns {string} file name
38
+ */
18
39
  const basename = name => {
19
40
  if (!name.includes("/")) return name;
20
41
  return name.substr(name.lastIndexOf("/") + 1);
21
42
  };
22
43
 
44
+ /**
45
+ * @type {WeakMap<Source, {file: string, assets: {[k: string]: ConcatSource | RawSource}}>}
46
+ */
23
47
  const assetsCache = new WeakMap();
24
48
 
25
- const getTaskForFile = (file, chunk, options, compilation) => {
26
- const asset = compilation.assets[file];
27
- const cache = assetsCache.get(asset);
28
- if (cache && cache.file === file) {
29
- for (const cachedFile in cache.assets) {
30
- compilation.assets[cachedFile] = cache.assets[cachedFile];
31
- if (cachedFile !== file) chunk.files.push(cachedFile);
32
- }
33
- return;
34
- }
49
+ /**
50
+ * Creating {@link SourceMapTask} for given file
51
+ * @param {string} file current compiled file
52
+ * @param {Source} asset the asset
53
+ * @param {Chunk} chunk related chunk
54
+ * @param {SourceMapDevToolPluginOptions} options source map options
55
+ * @param {Compilation} compilation compilation instance
56
+ * @returns {SourceMapTask | undefined} created task instance or `undefined`
57
+ */
58
+ const getTaskForFile = (file, asset, chunk, options, compilation) => {
35
59
  let source, sourceMap;
60
+ /**
61
+ * Check if asset can build source map
62
+ */
36
63
  if (asset.sourceAndMap) {
37
64
  const sourceAndMap = asset.sourceAndMap(options);
38
65
  sourceMap = sourceAndMap.map;
@@ -55,7 +82,8 @@ const getTaskForFile = (file, chunk, options, compilation) => {
55
82
 
56
83
  class SourceMapDevToolPlugin {
57
84
  /**
58
- * @param {SourceMapDevToolPluginOptions=} options options object
85
+ * @param {SourceMapDevToolPluginOptions} [options] options object
86
+ * @throws {Error} throws error, if got more than 1 arguments
59
87
  */
60
88
  constructor(options) {
61
89
  if (arguments.length > 1) {
@@ -68,21 +96,31 @@ class SourceMapDevToolPlugin {
68
96
 
69
97
  validateOptions(schema, options, "SourceMap DevTool Plugin");
70
98
 
99
+ /** @type {string | false} */
71
100
  this.sourceMapFilename = options.filename;
72
101
  /** @type {string | false} */
73
102
  this.sourceMappingURLComment =
74
103
  options.append === false
75
104
  ? false
76
105
  : options.append || "\n//# sourceMappingURL=[url]";
106
+ /** @type {string | Function} */
77
107
  this.moduleFilenameTemplate =
78
108
  options.moduleFilenameTemplate || "webpack://[namespace]/[resourcePath]";
109
+ /** @type {string | Function} */
79
110
  this.fallbackModuleFilenameTemplate =
80
111
  options.fallbackModuleFilenameTemplate ||
81
112
  "webpack://[namespace]/[resourcePath]?[hash]";
113
+ /** @type {string} */
82
114
  this.namespace = options.namespace || "";
115
+ /** @type {SourceMapDevToolPluginOptions} */
83
116
  this.options = options;
84
117
  }
85
118
 
119
+ /**
120
+ * Apply compiler
121
+ * @param {Compiler} compiler compiler instance
122
+ * @returns {void}
123
+ */
86
124
  apply(compiler) {
87
125
  const sourceMapFilename = this.sourceMapFilename;
88
126
  const sourceMappingURLComment = this.sourceMappingURLComment;
@@ -102,12 +140,21 @@ class SourceMapDevToolPlugin {
102
140
  new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
103
141
 
104
142
  compilation.hooks.afterOptimizeChunkAssets.tap(
105
- {
106
- name: "SourceMapDevToolPlugin",
107
- context: true
108
- },
143
+ /** @type {TODO} */
144
+ ({ name: "SourceMapDevToolPlugin", context: true }),
145
+ /**
146
+ * @param {object} context hook context
147
+ * @param {Array<Chunk>} chunks resulted chunks
148
+ * @throws {Error} throws error, if `sourceMapFilename === false && sourceMappingURLComment === false`
149
+ * @returns {void}
150
+ */
109
151
  (context, chunks) => {
152
+ /** @type {Map<string | Module, string>} */
110
153
  const moduleToSourceNameMapping = new Map();
154
+ /**
155
+ * @type {Function}
156
+ * @returns {void}
157
+ */
111
158
  const reportProgress =
112
159
  context && context.reportProgress
113
160
  ? context.reportProgress
@@ -128,12 +175,35 @@ class SourceMapDevToolPlugin {
128
175
  reportProgress(0.0);
129
176
  const tasks = [];
130
177
  files.forEach(({ file, chunk }, idx) => {
178
+ const asset = compilation.assets[file];
179
+ const cache = assetsCache.get(asset);
180
+ /**
181
+ * If presented in cache, reassigns assets. Cache assets already have source maps.
182
+ */
183
+ if (cache && cache.file === file) {
184
+ for (const cachedFile in cache.assets) {
185
+ compilation.assets[cachedFile] = cache.assets[cachedFile];
186
+ /**
187
+ * Add file to chunk, if not presented there
188
+ */
189
+ if (cachedFile !== file) chunk.files.push(cachedFile);
190
+ }
191
+ return;
192
+ }
193
+
131
194
  reportProgress(
132
195
  (0.5 * idx) / files.length,
133
196
  file,
134
197
  "generate SourceMap"
135
198
  );
136
- const task = getTaskForFile(file, chunk, options, compilation);
199
+ /** @type {SourceMapTask | undefined} */
200
+ const task = getTaskForFile(
201
+ file,
202
+ asset,
203
+ chunk,
204
+ options,
205
+ compilation
206
+ );
137
207
 
138
208
  if (task) {
139
209
  const modules = task.sourceMap.sources.map(source => {
@@ -165,10 +235,15 @@ class SourceMapDevToolPlugin {
165
235
  });
166
236
 
167
237
  reportProgress(0.5, "resolve sources");
238
+ /** @type {Set<string>} */
168
239
  const usedNamesSet = new Set(moduleToSourceNameMapping.values());
240
+ /** @type {Set<string>} */
169
241
  const conflictDetectionSet = new Set();
170
242
 
171
- // all modules in defined order (longest identifier first)
243
+ /**
244
+ * all modules in defined order (longest identifier first)
245
+ * @type {Array<string | Module>}
246
+ */
172
247
  const allModules = Array.from(moduleToSourceNameMapping.keys()).sort(
173
248
  (a, b) => {
174
249
  const ai = typeof a === "string" ? a : a.identifier();
@@ -254,7 +329,7 @@ class SourceMapDevToolPlugin {
254
329
  query = filename.substr(idx);
255
330
  filename = filename.substr(0, idx);
256
331
  }
257
- let sourceMapFile = compilation.getPath(sourceMapFilename, {
332
+ const pathParams = {
258
333
  chunk,
259
334
  filename: options.fileContext
260
335
  ? path.relative(options.fileContext, filename)
@@ -264,21 +339,31 @@ class SourceMapDevToolPlugin {
264
339
  contentHash: createHash("md4")
265
340
  .update(sourceMapString)
266
341
  .digest("hex")
267
- });
342
+ };
343
+ let sourceMapFile = compilation.getPath(
344
+ sourceMapFilename,
345
+ pathParams
346
+ );
268
347
  const sourceMapUrl = options.publicPath
269
348
  ? options.publicPath + sourceMapFile.replace(/\\/g, "/")
270
349
  : path
271
350
  .relative(path.dirname(file), sourceMapFile)
272
351
  .replace(/\\/g, "/");
352
+ /**
353
+ * Add source map url to compilation asset, if {@link currentSourceMappingURLComment} presented
354
+ */
273
355
  if (currentSourceMappingURLComment !== false) {
274
356
  assets[file] = compilation.assets[file] = new ConcatSource(
275
357
  new RawSource(source),
276
- currentSourceMappingURLComment.replace(
277
- /\[url\]/g,
278
- sourceMapUrl
358
+ compilation.getPath(
359
+ currentSourceMappingURLComment,
360
+ Object.assign({ url: sourceMapUrl }, pathParams)
279
361
  )
280
362
  );
281
363
  }
364
+ /**
365
+ * Add source map file to compilation assets and chunk files
366
+ */
282
367
  assets[sourceMapFile] = compilation.assets[
283
368
  sourceMapFile
284
369
  ] = new RawSource(sourceMapString);
@@ -289,6 +374,9 @@ class SourceMapDevToolPlugin {
289
374
  "SourceMapDevToolPlugin: append can't be false when no filename is provided"
290
375
  );
291
376
  }
377
+ /**
378
+ * Add source map as data url to asset
379
+ */
292
380
  assets[file] = compilation.assets[file] = new ConcatSource(
293
381
  new RawSource(source),
294
382
  currentSourceMappingURLComment