webpack 4.28.4 → 4.29.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.
- package/declarations/WebpackOptions.d.ts +4 -0
- package/lib/Compilation.js +2 -0
- package/lib/Compiler.js +132 -13
- package/lib/Parser.js +11 -7
- package/lib/Stats.js +4 -1
- package/package.json +3 -3
- package/schemas/WebpackOptions.json +4 -0
@@ -1051,6 +1051,10 @@ export interface OutputOptions {
|
|
1051
1051
|
* Specifies the name of each output file on disk. You must **not** specify an absolute path here! The `output.path` option determines the location on disk the files are written to, filename is used solely for naming the individual files.
|
1052
1052
|
*/
|
1053
1053
|
filename?: string | Function;
|
1054
|
+
/**
|
1055
|
+
* Use the future version of asset emitting logic, which is allows freeing memory of assets after emitting. It could break plugins which assume that assets are still readable after emitting. Will be the new default in the next major version.
|
1056
|
+
*/
|
1057
|
+
futureEmitAssets?: boolean;
|
1054
1058
|
/**
|
1055
1059
|
* An expression which is used to address the global object/scope in runtime code
|
1056
1060
|
*/
|
package/lib/Compilation.js
CHANGED
@@ -491,6 +491,8 @@ class Compilation extends Tapable {
|
|
491
491
|
this._buildingModules = new Map();
|
492
492
|
/** @private @type {Map<Module, Callback[]>} */
|
493
493
|
this._rebuildingModules = new Map();
|
494
|
+
/** @type {Set<string>} */
|
495
|
+
this.emittedAssets = new Set();
|
494
496
|
}
|
495
497
|
|
496
498
|
getStats() {
|
package/lib/Compiler.js
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
const parseJson = require("json-parse-better-errors");
|
8
8
|
const asyncLib = require("neo-async");
|
9
9
|
const path = require("path");
|
10
|
+
const { Source } = require("webpack-sources");
|
10
11
|
const util = require("util");
|
11
12
|
const {
|
12
13
|
Tapable,
|
@@ -188,6 +189,11 @@ class Compiler extends Tapable {
|
|
188
189
|
|
189
190
|
/** @type {boolean} */
|
190
191
|
this.watchMode = false;
|
192
|
+
|
193
|
+
/** @private @type {WeakMap<Source, { sizeOnlySource: SizeOnlySource, writtenTo: Map<string, number> }>} */
|
194
|
+
this._assetEmittingSourceCache = new WeakMap();
|
195
|
+
/** @private @type {Map<string, number>} */
|
196
|
+
this._assetEmittingWrittenFiles = new Map();
|
191
197
|
}
|
192
198
|
|
193
199
|
watch(watchOptions, handler) {
|
@@ -312,8 +318,9 @@ class Compiler extends Tapable {
|
|
312
318
|
const emitFiles = err => {
|
313
319
|
if (err) return callback(err);
|
314
320
|
|
315
|
-
asyncLib.
|
321
|
+
asyncLib.forEachLimit(
|
316
322
|
compilation.assets,
|
323
|
+
15,
|
317
324
|
(source, file, callback) => {
|
318
325
|
let targetFile = file;
|
319
326
|
const queryStringIdx = targetFile.indexOf("?");
|
@@ -327,19 +334,86 @@ class Compiler extends Tapable {
|
|
327
334
|
outputPath,
|
328
335
|
targetFile
|
329
336
|
);
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
337
|
+
// TODO webpack 5 remove futureEmitAssets option and make it on by default
|
338
|
+
if (this.options.output.futureEmitAssets) {
|
339
|
+
// check if the target file has already been written by this Compiler
|
340
|
+
const targetFileGeneration = this._assetEmittingWrittenFiles.get(
|
341
|
+
targetPath
|
342
|
+
);
|
343
|
+
|
344
|
+
// create an cache entry for this Source if not already existing
|
345
|
+
let cacheEntry = this._assetEmittingSourceCache.get(source);
|
346
|
+
if (cacheEntry === undefined) {
|
347
|
+
cacheEntry = {
|
348
|
+
sizeOnlySource: undefined,
|
349
|
+
writtenTo: new Map()
|
350
|
+
};
|
351
|
+
this._assetEmittingSourceCache.set(source, cacheEntry);
|
352
|
+
}
|
353
|
+
|
354
|
+
// if the target file has already been written
|
355
|
+
if (targetFileGeneration !== undefined) {
|
356
|
+
// check if the Source has been written to this target file
|
357
|
+
const writtenGeneration = cacheEntry.writtenTo.get(targetPath);
|
358
|
+
if (writtenGeneration === targetFileGeneration) {
|
359
|
+
// if yes, we skip writing the file
|
360
|
+
// as it's already there
|
361
|
+
// (we assume one doesn't remove files while the Compiler is running)
|
362
|
+
return callback();
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
// get the binary (Buffer) content from the Source
|
367
|
+
/** @type {Buffer} */
|
368
|
+
let content;
|
369
|
+
if (typeof source.buffer === "function") {
|
370
|
+
content = source.buffer();
|
371
|
+
} else {
|
372
|
+
const bufferOrString = source.source();
|
373
|
+
if (Buffer.isBuffer(bufferOrString)) {
|
374
|
+
content = bufferOrString;
|
375
|
+
} else {
|
376
|
+
content = Buffer.from(bufferOrString, "utf8");
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
// Create a replacement resource which only allows to ask for size
|
381
|
+
// This allows to GC all memory allocated by the Source
|
382
|
+
// (expect when the Source is stored in any other cache)
|
383
|
+
cacheEntry.sizeOnlySource = new SizeOnlySource(content.length);
|
384
|
+
compilation.assets[file] = cacheEntry.sizeOnlySource;
|
385
|
+
|
386
|
+
// Write the file to output file system
|
387
|
+
this.outputFileSystem.writeFile(targetPath, content, err => {
|
388
|
+
if (err) return callback(err);
|
389
|
+
|
390
|
+
// information marker that the asset has been emitted
|
391
|
+
compilation.emittedAssets.add(file);
|
392
|
+
|
393
|
+
// cache the information that the Source has been written to that location
|
394
|
+
const newGeneration =
|
395
|
+
targetFileGeneration === undefined
|
396
|
+
? 1
|
397
|
+
: targetFileGeneration + 1;
|
398
|
+
cacheEntry.writtenTo.set(targetPath, newGeneration);
|
399
|
+
this._assetEmittingWrittenFiles.set(targetPath, newGeneration);
|
400
|
+
callback();
|
401
|
+
});
|
402
|
+
} else {
|
403
|
+
if (source.existsAt === targetPath) {
|
404
|
+
source.emitted = false;
|
405
|
+
return callback();
|
406
|
+
}
|
407
|
+
let content = source.source();
|
408
|
+
|
409
|
+
if (!Buffer.isBuffer(content)) {
|
410
|
+
content = Buffer.from(content, "utf8");
|
411
|
+
}
|
412
|
+
|
413
|
+
source.existsAt = targetPath;
|
414
|
+
source.emitted = true;
|
415
|
+
this.outputFileSystem.writeFile(targetPath, content, callback);
|
338
416
|
}
|
339
|
-
|
340
|
-
source.existsAt = targetPath;
|
341
|
-
source.emitted = true;
|
342
|
-
this.outputFileSystem.writeFile(targetPath, content, callback);
|
343
417
|
};
|
344
418
|
|
345
419
|
if (targetFile.match(/\/|\\/)) {
|
@@ -562,3 +636,48 @@ class Compiler extends Tapable {
|
|
562
636
|
}
|
563
637
|
|
564
638
|
module.exports = Compiler;
|
639
|
+
|
640
|
+
class SizeOnlySource extends Source {
|
641
|
+
constructor(size) {
|
642
|
+
super();
|
643
|
+
this._size = size;
|
644
|
+
}
|
645
|
+
|
646
|
+
_error() {
|
647
|
+
return new Error(
|
648
|
+
"Content and Map of this Source is no longer available (only size() is supported)"
|
649
|
+
);
|
650
|
+
}
|
651
|
+
|
652
|
+
size() {
|
653
|
+
return this._size;
|
654
|
+
}
|
655
|
+
|
656
|
+
/**
|
657
|
+
* @param {any} options options
|
658
|
+
* @returns {string} the source
|
659
|
+
*/
|
660
|
+
source(options) {
|
661
|
+
throw this._error();
|
662
|
+
}
|
663
|
+
|
664
|
+
node() {
|
665
|
+
throw this._error();
|
666
|
+
}
|
667
|
+
|
668
|
+
listMap() {
|
669
|
+
throw this._error();
|
670
|
+
}
|
671
|
+
|
672
|
+
map() {
|
673
|
+
throw this._error();
|
674
|
+
}
|
675
|
+
|
676
|
+
listNode() {
|
677
|
+
throw this._error();
|
678
|
+
}
|
679
|
+
|
680
|
+
updateHash() {
|
681
|
+
throw this._error();
|
682
|
+
}
|
683
|
+
}
|
package/lib/Parser.js
CHANGED
@@ -6,7 +6,8 @@
|
|
6
6
|
|
7
7
|
// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
|
8
8
|
|
9
|
-
const acorn = require("acorn
|
9
|
+
const acorn = require("acorn");
|
10
|
+
const acornDynamicImport = require("acorn-dynamic-import").default;
|
10
11
|
const { Tapable, SyncBailHook, HookMap } = require("tapable");
|
11
12
|
const util = require("util");
|
12
13
|
const vm = require("vm");
|
@@ -14,6 +15,8 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
|
14
15
|
const StackedSetMap = require("./util/StackedSetMap");
|
15
16
|
const TrackingSet = require("./util/TrackingSet");
|
16
17
|
|
18
|
+
const acornParser = acorn.Parser.extend(acornDynamicImport);
|
19
|
+
|
17
20
|
const joinRanges = (startRange, endRange) => {
|
18
21
|
if (!endRange) return startRange;
|
19
22
|
if (!startRange) return endRange;
|
@@ -25,10 +28,7 @@ const defaultParserOptions = {
|
|
25
28
|
locations: true,
|
26
29
|
ecmaVersion: 2019,
|
27
30
|
sourceType: "module",
|
28
|
-
onComment: null
|
29
|
-
plugins: {
|
30
|
-
dynamicImport: true
|
31
|
-
}
|
31
|
+
onComment: null
|
32
32
|
};
|
33
33
|
|
34
34
|
// regexp to match at lease one "magic comment"
|
@@ -2133,9 +2133,13 @@ class Parser extends Tapable {
|
|
2133
2133
|
sourceType: this.sourceType,
|
2134
2134
|
locations: false
|
2135
2135
|
});
|
2136
|
+
// TODO(https://github.com/acornjs/acorn/issues/741)
|
2137
|
+
// @ts-ignore
|
2136
2138
|
if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") {
|
2137
2139
|
throw new Error("evaluate: Source is not a expression");
|
2138
2140
|
}
|
2141
|
+
// TODO(https://github.com/acornjs/acorn/issues/741)
|
2142
|
+
// @ts-ignore
|
2139
2143
|
return this.evaluateExpression(ast.body[0].expression);
|
2140
2144
|
}
|
2141
2145
|
|
@@ -2226,7 +2230,7 @@ class Parser extends Tapable {
|
|
2226
2230
|
let error;
|
2227
2231
|
let threw = false;
|
2228
2232
|
try {
|
2229
|
-
ast =
|
2233
|
+
ast = acornParser.parse(code, parserOptions);
|
2230
2234
|
} catch (e) {
|
2231
2235
|
error = e;
|
2232
2236
|
threw = true;
|
@@ -2238,7 +2242,7 @@ class Parser extends Tapable {
|
|
2238
2242
|
parserOptions.onComment.length = 0;
|
2239
2243
|
}
|
2240
2244
|
try {
|
2241
|
-
ast =
|
2245
|
+
ast = acornParser.parse(code, parserOptions);
|
2242
2246
|
threw = false;
|
2243
2247
|
} catch (e) {
|
2244
2248
|
threw = true;
|
package/lib/Stats.js
CHANGED
@@ -400,7 +400,10 @@ class Stats {
|
|
400
400
|
size: compilation.assets[asset].size(),
|
401
401
|
chunks: [],
|
402
402
|
chunkNames: [],
|
403
|
-
|
403
|
+
// TODO webpack 5: remove .emitted
|
404
|
+
emitted:
|
405
|
+
compilation.assets[asset].emitted ||
|
406
|
+
compilation.emittedAssets.has(asset)
|
404
407
|
};
|
405
408
|
|
406
409
|
if (showPerformance) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "webpack",
|
3
|
-
"version": "4.
|
3
|
+
"version": "4.29.0",
|
4
4
|
"author": "Tobias Koppers @sokra",
|
5
5
|
"description": "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.",
|
6
6
|
"license": "MIT",
|
@@ -9,8 +9,8 @@
|
|
9
9
|
"@webassemblyjs/helper-module-context": "1.7.11",
|
10
10
|
"@webassemblyjs/wasm-edit": "1.7.11",
|
11
11
|
"@webassemblyjs/wasm-parser": "1.7.11",
|
12
|
-
"acorn": "^
|
13
|
-
"acorn-dynamic-import": "^
|
12
|
+
"acorn": "^6.0.5",
|
13
|
+
"acorn-dynamic-import": "^4.0.0",
|
14
14
|
"ajv": "^6.1.0",
|
15
15
|
"ajv-keywords": "^3.1.0",
|
16
16
|
"chrome-trace-event": "^1.0.0",
|
@@ -867,6 +867,10 @@
|
|
867
867
|
}
|
868
868
|
]
|
869
869
|
},
|
870
|
+
"futureEmitAssets": {
|
871
|
+
"description": "Use the future version of asset emitting logic, which is allows freeing memory of assets after emitting. It could break plugins which assume that assets are still readable after emitting. Will be the new default in the next major version.",
|
872
|
+
"type": "boolean"
|
873
|
+
},
|
870
874
|
"globalObject": {
|
871
875
|
"description": "An expression which is used to address the global object/scope in runtime code",
|
872
876
|
"type": "string",
|