webpack 5.27.2 → 5.31.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.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

@@ -121,13 +121,16 @@ const getNormalizedWebpackOptions = config => {
121
121
  if (cache === false) return false;
122
122
  if (cache === true) {
123
123
  return {
124
- type: "memory"
124
+ type: "memory",
125
+ maxGenerations: undefined
125
126
  };
126
127
  }
127
128
  switch (cache.type) {
128
129
  case "filesystem":
129
130
  return {
130
131
  type: "filesystem",
132
+ maxMemoryGenerations: cache.maxMemoryGenerations,
133
+ maxAge: cache.maxAge,
131
134
  buildDependencies: cloneObject(cache.buildDependencies),
132
135
  cacheDirectory: cache.cacheDirectory,
133
136
  cacheLocation: cache.cacheLocation,
@@ -141,7 +144,8 @@ const getNormalizedWebpackOptions = config => {
141
144
  case undefined:
142
145
  case "memory":
143
146
  return {
144
- type: "memory"
147
+ type: "memory",
148
+ maxGenerations: cache.maxGenerations
145
149
  };
146
150
  default:
147
151
  // @ts-expect-error Property 'type' does not exist on type 'never'. ts(2339)
@@ -39,6 +39,7 @@ class HarmonyExportExpressionDependency extends NullDependency {
39
39
  getExports(moduleGraph) {
40
40
  return {
41
41
  exports: ["default"],
42
+ priority: 1,
42
43
  terminalBinding: true,
43
44
  dependencies: undefined
44
45
  };
@@ -543,6 +543,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
543
543
  export: item.ids,
544
544
  hidden: item.hidden
545
545
  })),
546
+ priority: 1,
546
547
  dependencies: [from.module]
547
548
  };
548
549
  }
@@ -557,6 +558,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
557
558
  export: ["default"]
558
559
  }
559
560
  ],
561
+ priority: 1,
560
562
  dependencies: [from.module]
561
563
  };
562
564
  }
@@ -584,6 +586,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
584
586
  ]
585
587
  }
586
588
  ],
589
+ priority: 1,
587
590
  dependencies: [from.module]
588
591
  };
589
592
  }
@@ -597,6 +600,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
597
600
  export: null
598
601
  }
599
602
  ],
603
+ priority: 1,
600
604
  dependencies: [from.module]
601
605
  };
602
606
  }
@@ -610,6 +614,7 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
610
614
  export: ["default"]
611
615
  }
612
616
  ],
617
+ priority: 1,
613
618
  dependencies: [from.module]
614
619
  };
615
620
  }
@@ -35,6 +35,7 @@ class HarmonyExportSpecifierDependency extends NullDependency {
35
35
  getExports(moduleGraph) {
36
36
  return {
37
37
  exports: [this.name],
38
+ priority: 1,
38
39
  terminalBinding: true,
39
40
  dependencies: undefined
40
41
  };
@@ -101,6 +101,7 @@ module.exports = function () {
101
101
  }
102
102
 
103
103
  function createModuleHotObject(moduleId, me) {
104
+ var _main = currentChildModule !== moduleId;
104
105
  var hot = {
105
106
  // private stuff
106
107
  _acceptedDependencies: {},
@@ -110,10 +111,10 @@ module.exports = function () {
110
111
  _selfDeclined: false,
111
112
  _selfInvalidated: false,
112
113
  _disposeHandlers: [],
113
- _main: currentChildModule !== moduleId,
114
+ _main: _main,
114
115
  _requireSelf: function () {
115
116
  currentParents = me.parents.slice();
116
- currentChildModule = moduleId;
117
+ currentChildModule = _main ? undefined : moduleId;
117
118
  __webpack_require__(moduleId);
118
119
  },
119
120
 
@@ -207,7 +207,7 @@ module.exports = function () {
207
207
  var module = $moduleCache$[outdatedModuleId];
208
208
  if (
209
209
  module &&
210
- module.hot._selfAccepted &&
210
+ (module.hot._selfAccepted || module.hot._main) &&
211
211
  // removed self-accepted modules should not be required
212
212
  appliedUpdate[outdatedModuleId] !== warnUnexpectedRequire &&
213
213
  // when called invalidate self-accepting is not possible
package/lib/index.js CHANGED
@@ -28,7 +28,20 @@ const memoize = require("./util/memoize");
28
28
  /** @typedef {import("./MultiStats")} MultiStats */
29
29
  /** @typedef {import("./Parser").ParserState} ParserState */
30
30
  /** @typedef {import("./Watching")} Watching */
31
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsAsset} StatsAsset */
32
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsChunk} StatsChunk */
33
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsChunkGroup} StatsChunkGroup */
34
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsChunkOrigin} StatsChunkOrigin */
31
35
  /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsCompilation} StatsCompilation */
36
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsError} StatsError */
37
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsLogging} StatsLogging */
38
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsLoggingEntry} StatsLoggingEntry */
39
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModule} StatsModule */
40
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleIssuer} StatsModuleIssuer */
41
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleReason} StatsModuleReason */
42
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleTraceDependency} StatsModuleTraceDependency */
43
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleTraceItem} StatsModuleTraceItem */
44
+ /** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsProfile} StatsProfile */
32
45
 
33
46
  /**
34
47
  * @template {Function} T
@@ -101,6 +114,9 @@ module.exports = mergeExports(fn, {
101
114
  get AutomaticPrefetchPlugin() {
102
115
  return require("./AutomaticPrefetchPlugin");
103
116
  },
117
+ get AsyncDependenciesBlock() {
118
+ return require("./AsyncDependenciesBlock");
119
+ },
104
120
  get BannerPlugin() {
105
121
  return require("./BannerPlugin");
106
122
  },
@@ -305,6 +321,18 @@ module.exports = mergeExports(fn, {
305
321
  }
306
322
  },
307
323
 
324
+ dependencies: {
325
+ get ModuleDependency() {
326
+ return require("./dependencies/ModuleDependency");
327
+ },
328
+ get ConstDependency() {
329
+ return require("./dependencies/ConstDependency");
330
+ },
331
+ get NullDependency() {
332
+ return require("./dependencies/NullDependency");
333
+ }
334
+ },
335
+
308
336
  ids: {
309
337
  get ChunkModuleIdRangePlugin() {
310
338
  return require("./ids/ChunkModuleIdRangePlugin");
@@ -942,6 +942,10 @@ class JavascriptParser extends Parser {
942
942
  .setRange(expr.range);
943
943
  }
944
944
  });
945
+ this.hooks.finish.tap("JavascriptParser", () => {
946
+ // Cleanup for GC
947
+ cachedExpression = cachedInfo = undefined;
948
+ });
945
949
  };
946
950
  tapEvaluateWithVariableInfo("Identifier", expr => {
947
951
  const info = this.getVariableInfo(
@@ -13,11 +13,29 @@ const { LogType } = require("./Logger");
13
13
 
14
14
  /** @typedef {function(string): boolean} FilterFunction */
15
15
 
16
+ /**
17
+ * @typedef {Object} LoggerConsole
18
+ * @property {function(): void} clear
19
+ * @property {function(): void} trace
20
+ * @property {(...args: any[]) => void} info
21
+ * @property {(...args: any[]) => void} log
22
+ * @property {(...args: any[]) => void} warn
23
+ * @property {(...args: any[]) => void} error
24
+ * @property {(...args: any[]) => void=} debug
25
+ * @property {(...args: any[]) => void=} group
26
+ * @property {(...args: any[]) => void=} groupCollapsed
27
+ * @property {(...args: any[]) => void=} groupEnd
28
+ * @property {(...args: any[]) => void=} status
29
+ * @property {(...args: any[]) => void=} profile
30
+ * @property {(...args: any[]) => void=} profileEnd
31
+ * @property {(...args: any[]) => void=} logTime
32
+ */
33
+
16
34
  /**
17
35
  * @typedef {Object} LoggerOptions
18
36
  * @property {false|true|"none"|"error"|"warn"|"info"|"log"|"verbose"} level loglevel
19
37
  * @property {FilterTypes|boolean} debug filter for debug logging
20
- * @property {Console & { status?: Function, logTime?: Function }} console the console to log to
38
+ * @property {LoggerConsole} console the console to log to
21
39
  */
22
40
 
23
41
  /**
@@ -11,11 +11,16 @@ const createConsoleLogger = require("../logging/createConsoleLogger");
11
11
  const NodeWatchFileSystem = require("./NodeWatchFileSystem");
12
12
  const nodeConsole = require("./nodeConsole");
13
13
 
14
+ /** @typedef {import("../../declarations/WebpackOptions").InfrastructureLogging} InfrastructureLogging */
14
15
  /** @typedef {import("../Compiler")} Compiler */
15
16
 
16
17
  class NodeEnvironmentPlugin {
18
+ /**
19
+ * @param {Object} options options
20
+ * @param {InfrastructureLogging} options.infrastructureLogging infrastructure logging options
21
+ */
17
22
  constructor(options) {
18
- this.options = options || {};
23
+ this.options = options;
19
24
  }
20
25
 
21
26
  /**
@@ -24,16 +29,18 @@ class NodeEnvironmentPlugin {
24
29
  * @returns {void}
25
30
  */
26
31
  apply(compiler) {
27
- compiler.infrastructureLogger = createConsoleLogger(
28
- Object.assign(
29
- {
30
- level: "info",
31
- debug: false,
32
- console: nodeConsole
33
- },
34
- this.options.infrastructureLogging
35
- )
36
- );
32
+ const { infrastructureLogging } = this.options;
33
+ compiler.infrastructureLogger = createConsoleLogger({
34
+ level: infrastructureLogging.level || "info",
35
+ debug: infrastructureLogging.debug || false,
36
+ console:
37
+ infrastructureLogging.console ||
38
+ nodeConsole({
39
+ colors: infrastructureLogging.colors,
40
+ appendOnly: infrastructureLogging.appendOnly,
41
+ stream: infrastructureLogging.stream
42
+ })
43
+ });
37
44
  compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000);
38
45
  const inputFileSystem = compiler.inputFileSystem;
39
46
  compiler.outputFileSystem = fs;
@@ -8,127 +8,136 @@
8
8
  const util = require("util");
9
9
  const truncateArgs = require("../logging/truncateArgs");
10
10
 
11
- const tty = process.stderr.isTTY && process.env.TERM !== "dumb";
11
+ module.exports = ({ colors, appendOnly, stream }) => {
12
+ let currentStatusMessage = undefined;
13
+ let hasStatusMessage = false;
14
+ let currentIndent = "";
15
+ let currentCollapsed = 0;
12
16
 
13
- let currentStatusMessage = undefined;
14
- let hasStatusMessage = false;
15
- let currentIndent = "";
16
- let currentCollapsed = 0;
17
-
18
- const indent = (str, prefix, colorPrefix, colorSuffix) => {
19
- if (str === "") return str;
20
- prefix = currentIndent + prefix;
21
- if (tty) {
22
- return (
23
- prefix +
24
- colorPrefix +
25
- str.replace(/\n/g, colorSuffix + "\n" + prefix + colorPrefix) +
26
- colorSuffix
27
- );
28
- } else {
29
- return prefix + str.replace(/\n/g, "\n" + prefix);
30
- }
31
- };
17
+ const indent = (str, prefix, colorPrefix, colorSuffix) => {
18
+ if (str === "") return str;
19
+ prefix = currentIndent + prefix;
20
+ if (colors) {
21
+ return (
22
+ prefix +
23
+ colorPrefix +
24
+ str.replace(/\n/g, colorSuffix + "\n" + prefix + colorPrefix) +
25
+ colorSuffix
26
+ );
27
+ } else {
28
+ return prefix + str.replace(/\n/g, "\n" + prefix);
29
+ }
30
+ };
32
31
 
33
- const clearStatusMessage = () => {
34
- if (hasStatusMessage) {
35
- process.stderr.write("\x1b[2K\r");
36
- hasStatusMessage = false;
37
- }
38
- };
32
+ const clearStatusMessage = () => {
33
+ if (hasStatusMessage) {
34
+ stream.write("\x1b[2K\r");
35
+ hasStatusMessage = false;
36
+ }
37
+ };
39
38
 
40
- const writeStatusMessage = () => {
41
- if (!currentStatusMessage) return;
42
- const l = process.stderr.columns;
43
- const args = l
44
- ? truncateArgs(currentStatusMessage, l - 1)
45
- : currentStatusMessage;
46
- const str = args.join(" ");
47
- const coloredStr = `\u001b[1m${str}\u001b[39m\u001b[22m`;
48
- process.stderr.write(`\x1b[2K\r${coloredStr}`);
49
- hasStatusMessage = true;
50
- };
39
+ const writeStatusMessage = () => {
40
+ if (!currentStatusMessage) return;
41
+ const l = stream.columns;
42
+ const args = l
43
+ ? truncateArgs(currentStatusMessage, l - 1)
44
+ : currentStatusMessage;
45
+ const str = args.join(" ");
46
+ const coloredStr = `\u001b[1m${str}\u001b[39m\u001b[22m`;
47
+ stream.write(`\x1b[2K\r${coloredStr}`);
48
+ hasStatusMessage = true;
49
+ };
51
50
 
52
- const writeColored = (prefix, colorPrefix, colorSuffix) => {
53
- return (...args) => {
54
- if (currentCollapsed > 0) return;
55
- clearStatusMessage();
56
- const str = indent(util.format(...args), prefix, colorPrefix, colorSuffix);
57
- process.stderr.write(str + "\n");
58
- writeStatusMessage();
51
+ const writeColored = (prefix, colorPrefix, colorSuffix) => {
52
+ return (...args) => {
53
+ if (currentCollapsed > 0) return;
54
+ clearStatusMessage();
55
+ const str = indent(
56
+ util.format(...args),
57
+ prefix,
58
+ colorPrefix,
59
+ colorSuffix
60
+ );
61
+ stream.write(str + "\n");
62
+ writeStatusMessage();
63
+ };
59
64
  };
60
- };
61
65
 
62
- const writeGroupMessage = writeColored(
63
- "<-> ",
64
- "\u001b[1m\u001b[36m",
65
- "\u001b[39m\u001b[22m"
66
- );
66
+ const writeGroupMessage = writeColored(
67
+ "<-> ",
68
+ "\u001b[1m\u001b[36m",
69
+ "\u001b[39m\u001b[22m"
70
+ );
67
71
 
68
- const writeGroupCollapsedMessage = writeColored(
69
- "<+> ",
70
- "\u001b[1m\u001b[36m",
71
- "\u001b[39m\u001b[22m"
72
- );
72
+ const writeGroupCollapsedMessage = writeColored(
73
+ "<+> ",
74
+ "\u001b[1m\u001b[36m",
75
+ "\u001b[39m\u001b[22m"
76
+ );
73
77
 
74
- module.exports = {
75
- log: writeColored(" ", "\u001b[1m", "\u001b[22m"),
76
- debug: writeColored(" ", "", ""),
77
- trace: writeColored(" ", "", ""),
78
- info: writeColored("<i> ", "\u001b[1m\u001b[32m", "\u001b[39m\u001b[22m"),
79
- warn: writeColored("<w> ", "\u001b[1m\u001b[33m", "\u001b[39m\u001b[22m"),
80
- error: writeColored("<e> ", "\u001b[1m\u001b[31m", "\u001b[39m\u001b[22m"),
81
- logTime: writeColored("<t> ", "\u001b[1m\u001b[35m", "\u001b[39m\u001b[22m"),
82
- group: (...args) => {
83
- writeGroupMessage(...args);
84
- if (currentCollapsed > 0) {
78
+ return {
79
+ log: writeColored(" ", "\u001b[1m", "\u001b[22m"),
80
+ debug: writeColored(" ", "", ""),
81
+ trace: writeColored(" ", "", ""),
82
+ info: writeColored("<i> ", "\u001b[1m\u001b[32m", "\u001b[39m\u001b[22m"),
83
+ warn: writeColored("<w> ", "\u001b[1m\u001b[33m", "\u001b[39m\u001b[22m"),
84
+ error: writeColored("<e> ", "\u001b[1m\u001b[31m", "\u001b[39m\u001b[22m"),
85
+ logTime: writeColored(
86
+ "<t> ",
87
+ "\u001b[1m\u001b[35m",
88
+ "\u001b[39m\u001b[22m"
89
+ ),
90
+ group: (...args) => {
91
+ writeGroupMessage(...args);
92
+ if (currentCollapsed > 0) {
93
+ currentCollapsed++;
94
+ } else {
95
+ currentIndent += " ";
96
+ }
97
+ },
98
+ groupCollapsed: (...args) => {
99
+ writeGroupCollapsedMessage(...args);
85
100
  currentCollapsed++;
86
- } else {
87
- currentIndent += " ";
88
- }
89
- },
90
- groupCollapsed: (...args) => {
91
- writeGroupCollapsedMessage(...args);
92
- currentCollapsed++;
93
- },
94
- groupEnd: () => {
95
- if (currentCollapsed > 0) currentCollapsed--;
96
- else if (currentIndent.length >= 2)
97
- currentIndent = currentIndent.slice(0, currentIndent.length - 2);
98
- },
99
- // eslint-disable-next-line node/no-unsupported-features/node-builtins
100
- profile: console.profile && (name => console.profile(name)),
101
- // eslint-disable-next-line node/no-unsupported-features/node-builtins
102
- profileEnd: console.profileEnd && (name => console.profileEnd(name)),
103
- clear:
104
- tty &&
101
+ },
102
+ groupEnd: () => {
103
+ if (currentCollapsed > 0) currentCollapsed--;
104
+ else if (currentIndent.length >= 2)
105
+ currentIndent = currentIndent.slice(0, currentIndent.length - 2);
106
+ },
105
107
  // eslint-disable-next-line node/no-unsupported-features/node-builtins
106
- console.clear &&
107
- (() => {
108
- clearStatusMessage();
108
+ profile: console.profile && (name => console.profile(name)),
109
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
110
+ profileEnd: console.profileEnd && (name => console.profileEnd(name)),
111
+ clear:
112
+ !appendOnly &&
109
113
  // eslint-disable-next-line node/no-unsupported-features/node-builtins
110
- console.clear();
111
- writeStatusMessage();
112
- }),
113
- status: tty
114
- ? (name, ...args) => {
115
- args = args.filter(Boolean);
116
- if (name === undefined && args.length === 0) {
117
- clearStatusMessage();
118
- currentStatusMessage = undefined;
119
- } else if (
120
- typeof name === "string" &&
121
- name.startsWith("[webpack.Progress] ")
122
- ) {
123
- currentStatusMessage = [name.slice(19), ...args];
124
- writeStatusMessage();
125
- } else if (name === "[webpack.Progress]") {
126
- currentStatusMessage = [...args];
127
- writeStatusMessage();
128
- } else {
129
- currentStatusMessage = [name, ...args];
130
- writeStatusMessage();
131
- }
132
- }
133
- : writeColored("<s> ", "", "")
114
+ console.clear &&
115
+ (() => {
116
+ clearStatusMessage();
117
+ // eslint-disable-next-line node/no-unsupported-features/node-builtins
118
+ console.clear();
119
+ writeStatusMessage();
120
+ }),
121
+ status: appendOnly
122
+ ? writeColored("<s> ", "", "")
123
+ : (name, ...args) => {
124
+ args = args.filter(Boolean);
125
+ if (name === undefined && args.length === 0) {
126
+ clearStatusMessage();
127
+ currentStatusMessage = undefined;
128
+ } else if (
129
+ typeof name === "string" &&
130
+ name.startsWith("[webpack.Progress] ")
131
+ ) {
132
+ currentStatusMessage = [name.slice(19), ...args];
133
+ writeStatusMessage();
134
+ } else if (name === "[webpack.Progress]") {
135
+ currentStatusMessage = [...args];
136
+ writeStatusMessage();
137
+ } else {
138
+ currentStatusMessage = [name, ...args];
139
+ writeStatusMessage();
140
+ }
141
+ }
142
+ };
134
143
  };
@@ -253,13 +253,13 @@ class ObjectMiddleware extends SerializerMiddleware {
253
253
  */
254
254
  serialize(data, context) {
255
255
  /** @type {any[]} */
256
- const result = [CURRENT_VERSION];
256
+ let result = [CURRENT_VERSION];
257
257
  let currentPos = 0;
258
- const referenceable = new Map();
258
+ let referenceable = new Map();
259
259
  const addReferenceable = item => {
260
260
  referenceable.set(item, currentPos++);
261
261
  };
262
- const bufferDedupeMap = new Map();
262
+ let bufferDedupeMap = new Map();
263
263
  const dedupeBuffer = buf => {
264
264
  const len = buf.length;
265
265
  const entry = bufferDedupeMap.get(len);
@@ -322,7 +322,7 @@ class ObjectMiddleware extends SerializerMiddleware {
322
322
  }
323
323
  };
324
324
  let currentPosTypeLookup = 0;
325
- const objectTypeLookup = new Map();
325
+ let objectTypeLookup = new Map();
326
326
  const cycleStack = new Set();
327
327
  const stackToString = item => {
328
328
  const arr = Array.from(cycleStack);
@@ -370,7 +370,7 @@ class ObjectMiddleware extends SerializerMiddleware {
370
370
  .join(" -> ");
371
371
  };
372
372
  let hasDebugInfoAttached;
373
- const ctx = {
373
+ let ctx = {
374
374
  write(value, key) {
375
375
  try {
376
376
  process(value);
@@ -408,16 +408,13 @@ class ObjectMiddleware extends SerializerMiddleware {
408
408
  };
409
409
  this.extendContext(ctx);
410
410
  const process = item => {
411
- // check if we can emit a reference
412
- const ref = referenceable.get(item);
413
-
414
- if (ref !== undefined) {
415
- result.push(ESCAPE, ref - currentPos);
416
-
417
- return;
418
- }
419
-
420
411
  if (Buffer.isBuffer(item)) {
412
+ // check if we can emit a reference
413
+ const ref = referenceable.get(item);
414
+ if (ref !== undefined) {
415
+ result.push(ESCAPE, ref - currentPos);
416
+ return;
417
+ }
421
418
  const alreadyUsedBuffer = dedupeBuffer(item);
422
419
  if (alreadyUsedBuffer !== item) {
423
420
  const ref = referenceable.get(alreadyUsedBuffer);
@@ -431,7 +428,19 @@ class ObjectMiddleware extends SerializerMiddleware {
431
428
  addReferenceable(item);
432
429
 
433
430
  result.push(item);
434
- } else if (typeof item === "object" && item !== null) {
431
+ } else if (item === ESCAPE) {
432
+ result.push(ESCAPE, ESCAPE_ESCAPE_VALUE);
433
+ } else if (
434
+ typeof item === "object"
435
+ // We don't have to check for null as ESCAPE is null and this has been checked before
436
+ ) {
437
+ // check if we can emit a reference
438
+ const ref = referenceable.get(item);
439
+ if (ref !== undefined) {
440
+ result.push(ESCAPE, ref - currentPos);
441
+ return;
442
+ }
443
+
435
444
  if (cycleStack.has(item)) {
436
445
  throw new Error(`Circular references can't be serialized`);
437
446
  }
@@ -464,6 +473,12 @@ class ObjectMiddleware extends SerializerMiddleware {
464
473
  } else if (typeof item === "string") {
465
474
  if (item.length > 1) {
466
475
  // short strings are shorter when not emitting a reference (this saves 1 byte per empty string)
476
+ // check if we can emit a reference
477
+ const ref = referenceable.get(item);
478
+ if (ref !== undefined) {
479
+ result.push(ESCAPE, ref - currentPos);
480
+ return;
481
+ }
467
482
  addReferenceable(item);
468
483
  }
469
484
 
@@ -476,8 +491,6 @@ class ObjectMiddleware extends SerializerMiddleware {
476
491
  }
477
492
 
478
493
  result.push(item);
479
- } else if (item === ESCAPE) {
480
- result.push(ESCAPE, ESCAPE_ESCAPE_VALUE);
481
494
  } else if (typeof item === "function") {
482
495
  if (!SerializerMiddleware.isLazy(item))
483
496
  throw new Error("Unexpected function " + item);
@@ -511,13 +524,18 @@ class ObjectMiddleware extends SerializerMiddleware {
511
524
  for (const item of data) {
512
525
  process(item);
513
526
  }
527
+ return result;
514
528
  } catch (e) {
515
529
  if (e === NOT_SERIALIZABLE) return null;
516
530
 
517
531
  throw e;
532
+ } finally {
533
+ // Get rid of these references to avoid leaking memory
534
+ // This happens because the optimized code v8 generates
535
+ // is optimized for our "ctx.write" method so it will reference
536
+ // it from e. g. Dependency.prototype.serialize -(IC)-> ctx.write
537
+ data = result = referenceable = bufferDedupeMap = objectTypeLookup = ctx = undefined;
518
538
  }
519
-
520
- return result;
521
539
  }
522
540
 
523
541
  /**
@@ -545,8 +563,8 @@ class ObjectMiddleware extends SerializerMiddleware {
545
563
  };
546
564
  let currentPosTypeLookup = 0;
547
565
  let objectTypeLookup = [];
548
- const result = [];
549
- const ctx = {
566
+ let result = [];
567
+ let ctx = {
550
568
  read() {
551
569
  return decodeValue();
552
570
  },
@@ -673,16 +691,18 @@ class ObjectMiddleware extends SerializerMiddleware {
673
691
  }
674
692
  };
675
693
 
676
- while (currentDataPos < data.length) {
677
- result.push(decodeValue());
694
+ try {
695
+ while (currentDataPos < data.length) {
696
+ result.push(decodeValue());
697
+ }
698
+ return result;
699
+ } finally {
700
+ // Get rid of these references to avoid leaking memory
701
+ // This happens because the optimized code v8 generates
702
+ // is optimized for our "ctx.read" method so it will reference
703
+ // it from e. g. Dependency.prototype.deserialize -(IC)-> ctx.read
704
+ result = referenceable = data = objectTypeLookup = ctx = undefined;
678
705
  }
679
-
680
- // Help the GC, as functions above might be cached in inline caches
681
- referenceable = undefined;
682
- objectTypeLookup = undefined;
683
- data = undefined;
684
-
685
- return result;
686
706
  }
687
707
  }
688
708