Visitar URL original
perf(SourceMapDevToolPlugin): emit .map asset as Buffer to reduce V8 … · webpack/webpack@fb43cbd · GitHub
Skip to content

Commit fb43cbd

Browse files
perf(SourceMapDevToolPlugin): emit .map asset as Buffer to reduce V8 heap
The emitted `.map` asset stays in `compilation.assets` until the build finishes. Wrapping its JSON in a `RawSource(Buffer)` keeps the bytes in external memory (1 byte/char) rather than on the V8 heap, where the same content would otherwise sit as a V8 string for the rest of the build. On a 1000-module × 50-chunk synthetic build, peak V8 heap drops from 1422 MB to 1041 MB (-27%) with no change in wall-clock time. Also drops the unused `task.asset` field. Refs #20961
1 parent 46f1d0f commit fb43cbd

2 files changed

Lines changed: 20 additions & 5 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"webpack": patch
3+
---
4+
5+
Reduce peak V8 heap usage of `SourceMapDevToolPlugin` on large builds by emitting the external `.map` asset as a `Buffer` instead of a V8 string. The emitted asset lives in `compilation.assets` for the rest of the build, so storing its bytes as off-heap external memory keeps the JSON content out of the V8 heap and avoids holding the same content twice when V8 internally widens it. See issue #20961.

‎lib/SourceMapDevToolPlugin.js‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ const { makePathsAbsolute } = require("./util/identifier");
3636
/**
3737
* Defines the source map task type used by this module.
3838
* @typedef {object} SourceMapTask
39-
* @property {Source} asset
4039
* @property {AssetInfo} assetInfo
4140
* @property {(string | Module)[]} modules
4241
* @property {string} source
@@ -116,7 +115,6 @@ const getTaskForFile = (
116115

117116
return {
118117
file,
119-
asset,
120118
source,
121119
assetInfo,
122120
sourceMap,
@@ -523,12 +521,20 @@ class SourceMapDevToolPlugin {
523521
: debugIdComment;
524522
}
525523

526-
const sourceMapString = JSON.stringify(sourceMap);
527524
if (sourceMapFilename) {
525+
// External `.map` file: hold the serialized map as a
526+
// `Buffer` instead of a V8 string. `RawSource` accepts a
527+
// buffer directly, and the emitted asset stays in
528+
// `compilation.assets` until the build finishes — so using
529+
// a buffer keeps the in-memory footprint at 1 byte/char.
530+
const sourceMapBuffer = Buffer.from(
531+
JSON.stringify(sourceMap),
532+
"utf8"
533+
);
528534
const filename = file;
529535
const sourceMapContentHash = usesContentHash
530536
? createHash(compilation.outputOptions.hashFunction)
531-
.update(sourceMapString)
537+
.update(sourceMapBuffer)
532538
.digest("hex")
533539
: undefined;
534540

@@ -574,7 +580,7 @@ class SourceMapDevToolPlugin {
574580
assetsInfo[file] = assetInfo;
575581
compilation.updateAsset(file, asset, assetInfo);
576582
// Add source map file to compilation assets and chunk files
577-
const sourceMapAsset = new RawSource(sourceMapString);
583+
const sourceMapAsset = new RawSource(sourceMapBuffer);
578584
const sourceMapAssetInfo = {
579585
...sourceMapInfo,
580586
development: true
@@ -600,6 +606,10 @@ class SourceMapDevToolPlugin {
600606
`${PLUGIN_NAME}: append can't be a function when no filename is provided`
601607
);
602608
}
609+
// Inline data-URL form needs the map both as a string
610+
// (for `[map]` substitution) and as a buffer (for the
611+
// base64 data URL), so build them once here.
612+
const sourceMapString = JSON.stringify(sourceMap);
603613
/**
604614
* Add source map as data url to asset
605615
*/

0 commit comments

Comments
 (0)