@taro-hmr-compile/plugin-webpack 0.0.1-alpha.7 → 0.0.1-alpha.8

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.
@@ -0,0 +1,149 @@
1
+ import {type Compilation,} from "webpack";
2
+ import generator from '@babel/generator'
3
+ import {
4
+ parseHotUpdateAssets,
5
+ ParseHotUpdateAssetsOptions,
6
+ parseChunkAsset, mergeUpdatePatches, generatePatchAssetSource,
7
+ } from "./utils";
8
+ import {createHash} from "crypto";
9
+ import {ModuleFactory, UpdatePatchSource} from "./types";
10
+ import {DEFAULT_HMR_PATCH_HISTORY_LIMIT} from "../constants";
11
+
12
+ interface ModuleHash {
13
+ moduleId: string;
14
+ factoryHash: string;
15
+ }
16
+
17
+ interface ProcessChunkModulesOptions {
18
+ source: string
19
+ compilation: Compilation,
20
+ isBootstrapChunk: boolean
21
+ }
22
+
23
+ export interface HmrPatchProcessorOptions {
24
+ patchHistoryLimit?: number
25
+ }
26
+
27
+ interface ProcessUpdateOptions extends ParseHotUpdateAssetsOptions {
28
+ fromHash: string
29
+ toHash: string
30
+ }
31
+
32
+ type BootstrapFactories = Map<string, ModuleFactory>
33
+
34
+ type ModuleHashesByFullHash = Map<string, Map<string, ModuleHash>>
35
+
36
+ export class HmrPatchProcessor {
37
+ private readonly bootstrapFactories: BootstrapFactories = new Map()
38
+
39
+ private readonly bootstrapFactoriesByCompilation = new WeakMap<Compilation, BootstrapFactories>()
40
+
41
+ private readonly moduleHashesByFullHash: ModuleHashesByFullHash = new Map()
42
+
43
+ private recentUpdatePatches: UpdatePatchSource[] = []
44
+
45
+ private readonly opts: Partial<HmrPatchProcessorOptions>
46
+
47
+ constructor(opts: Partial<HmrPatchProcessorOptions>) {
48
+ this.opts = opts
49
+ }
50
+
51
+ private getChangedModuleIdsByFullHash(fromHash: string, toHash: string): Set<string> | undefined {
52
+ const fromModuleHashes = this.moduleHashesByFullHash.get(fromHash)
53
+
54
+ const toModuleHashes = this.moduleHashesByFullHash.get(toHash)
55
+
56
+ // 任一编译缺少 Hash 基线时不做过滤,避免误丢有效的 hot-update 模块。
57
+ if (!fromModuleHashes || !toModuleHashes) return
58
+
59
+ // 同时检查前后两次编译的模块,确保新增、修改和删除都能被识别。
60
+ const moduleIds = new Set(fromModuleHashes.keys())
61
+ toModuleHashes.forEach((_, moduleId) => moduleIds.add(moduleId))
62
+
63
+ const changedModuleIds = new Set<string>()
64
+ moduleIds.forEach(moduleId => {
65
+ const fromFactoryHash = fromModuleHashes.get(moduleId)?.factoryHash
66
+ const toFactoryHash = toModuleHashes.get(moduleId)?.factoryHash
67
+ if (fromFactoryHash !== toFactoryHash) changedModuleIds.add(moduleId)
68
+ })
69
+
70
+ return changedModuleIds
71
+ }
72
+
73
+ processUpdate(opt: ProcessUpdateOptions) {
74
+ const {fromHash, toHash} = opt
75
+
76
+ const tempPatchInfo = parseHotUpdateAssets(opt)
77
+
78
+ const changedModuleIds = this.getChangedModuleIdsByFullHash(fromHash, toHash)
79
+
80
+ const moduleFactories = (() => {
81
+ if (!changedModuleIds) return Array.from(tempPatchInfo.moduleFactories.values())
82
+ return Array.from(tempPatchInfo.moduleFactories.values()).filter(item => changedModuleIds.has(item.moduleId))
83
+ })()
84
+
85
+ const removedModules = (() => {
86
+ if (!changedModuleIds) return Array.from(tempPatchInfo.removedModules.values())
87
+ return Array.from(tempPatchInfo.removedModules.values()).filter(item => changedModuleIds.has(item))
88
+ })()
89
+
90
+ this.recentUpdatePatches.push({type: 'update', moduleFactories, fromHash, toHash, removedModules})
91
+
92
+ const patchHistoryLimit = Math.max(1, this.opts.patchHistoryLimit ?? DEFAULT_HMR_PATCH_HISTORY_LIMIT)
93
+
94
+ if (this.recentUpdatePatches.length <= patchHistoryLimit) return
95
+
96
+ const [oldestUpdatePatch, secondOldestUpdatePatch, ...rest] = this.recentUpdatePatches
97
+
98
+ const mergedUpdatePatch = mergeUpdatePatches(oldestUpdatePatch, secondOldestUpdatePatch)
99
+
100
+ this.recentUpdatePatches = [mergedUpdatePatch, ...rest]
101
+
102
+ this.moduleHashesByFullHash.delete(oldestUpdatePatch.toHash)
103
+ }
104
+
105
+ processChunkModules(opt: ProcessChunkModulesOptions) {
106
+ const {hash: fullHash} = opt.compilation
107
+ const modules = parseChunkAsset(opt.source)
108
+ modules.forEach(moduleFactory => {
109
+ const {moduleId, factory} = moduleFactory
110
+
111
+ if (opt.isBootstrapChunk) {
112
+ const compilationFactories = this.bootstrapFactoriesByCompilation.get(opt.compilation) ?? new Map()
113
+ compilationFactories.set(moduleId, {moduleId, factory})
114
+ this.bootstrapFactoriesByCompilation.set(opt.compilation, compilationFactories)
115
+ }
116
+
117
+ if (!fullHash) return
118
+
119
+ const moduleHashes = (() => {
120
+ const hasCurFullHashModuleHashMap = this.moduleHashesByFullHash.has(fullHash)
121
+ if (!hasCurFullHashModuleHashMap) this.moduleHashesByFullHash.set(fullHash, new Map())
122
+ return this.moduleHashesByFullHash.get(fullHash)!
123
+ })()
124
+
125
+ const {code: source} = generator(factory, {compact: true, comments: false, minified: true,})
126
+ const factoryHash = createHash('sha256').update(source).digest('hex')
127
+ moduleHashes.set(moduleId, {moduleId, factoryHash})
128
+ })
129
+ }
130
+
131
+ commitBootstrapFactories(compilation: Compilation) {
132
+ this.bootstrapFactories.clear()
133
+ this.bootstrapFactoriesByCompilation.get(compilation)?.forEach(moduleFactory => {
134
+ this.bootstrapFactories.set(moduleFactory.moduleId, moduleFactory)
135
+ })
136
+ this.bootstrapFactoriesByCompilation.delete(compilation)
137
+ }
138
+
139
+ generate() {
140
+ const {bootstrapFactories, recentUpdatePatches} = this
141
+ return generatePatchAssetSource({bootstrapFactories, recentUpdatePatches})
142
+ }
143
+
144
+ reset() {
145
+ this.bootstrapFactories.clear()
146
+ this.moduleHashesByFullHash.clear()
147
+ this.recentUpdatePatches = []
148
+ }
149
+ }
@@ -0,0 +1,19 @@
1
+ import type {Expression} from "@babel/types";
2
+
3
+ export interface ModuleFactory {
4
+ factory: Expression,
5
+ moduleId: string
6
+ }
7
+
8
+ export interface HotUpdateManifest {
9
+ m?: Array<string | number>
10
+ }
11
+
12
+ export interface UpdatePatchSource {
13
+ type: 'update'
14
+ fromHash: string
15
+ toHash: string
16
+ moduleFactories: ModuleFactory[]
17
+ removedModules: string[]
18
+ }
19
+
@@ -0,0 +1,174 @@
1
+ import * as t from "@babel/types";
2
+ import {parse} from "@babel/parser";
3
+ import traverse from "@babel/traverse";
4
+ import template from "@babel/template";
5
+ import generator from "@babel/generator";
6
+ import {Asset} from "webpack";
7
+ import {HotUpdateManifest, ModuleFactory} from "./types";
8
+ import type {ObjectExpression} from "@babel/types";
9
+ import {UpdatePatchSource} from "./types";
10
+
11
+
12
+ /**
13
+ * 解析模块 Factory
14
+ * @param expression
15
+ */
16
+ const parseModuleFactories = (expression: ObjectExpression) => {
17
+
18
+ const moduleFactories = new Map<string, ModuleFactory>()
19
+
20
+ if (!t.isObjectExpression(expression)) return moduleFactories.values()
21
+
22
+ expression.properties.forEach(property => {
23
+ if (!t.isObjectProperty(property) || !t.isExpression(property.value)) throw new Error('[taro-hmr-compile] HMR 模块对象包含无法识别的属性')
24
+
25
+ const {key, value: factory} = property
26
+
27
+ const moduleId = (() => {
28
+ if (t.isStringLiteral(key) || t.isNumericLiteral(key)) return String(key.value)
29
+ if (t.isIdentifier(key) && !property.computed) return key.name
30
+ throw new Error('[taro-hmr-compile] Chunk 模块对象包含无法识别的模块 ID')
31
+ })()
32
+
33
+ moduleFactories.set(moduleId, {factory, moduleId})
34
+ })
35
+
36
+ return moduleFactories.values()
37
+ }
38
+
39
+
40
+ export interface ParseHotUpdateAssetsOptions {
41
+ manifests: Readonly<Asset>[]
42
+ scripts: Readonly<Asset>[]
43
+ }
44
+
45
+ /**
46
+ * 解析热更新产物
47
+ * @param opt
48
+ */
49
+ export const parseHotUpdateAssets = (opt: ParseHotUpdateAssetsOptions) => {
50
+ const {manifests, scripts} = opt
51
+
52
+ const moduleFactories = new Map<string, ModuleFactory>()
53
+
54
+ scripts.forEach(asset => {
55
+
56
+ const ast = parse(asset.source.source().toString(), {sourceType: 'script'})
57
+
58
+ traverse(ast, {
59
+ CallExpression(nodePath) {
60
+ const {callee} = nodePath.node
61
+
62
+ if (!t.isMemberExpression(callee) || !t.isIdentifier(callee.object, {name: 'wx'})) return
63
+
64
+ if (!t.isStringLiteral(callee.property) || !callee.property.value.startsWith('webpackHotUpdate')) return
65
+
66
+ const [_, modules] = nodePath.node.arguments
67
+
68
+ if (!t.isObjectExpression(modules)) return
69
+
70
+ parseModuleFactories(modules).forEach(module => moduleFactories.set(module.moduleId, module))
71
+ },
72
+ })
73
+ })
74
+
75
+ const removedModules = new Set<string>()
76
+
77
+ manifests.forEach((module) => {
78
+
79
+ const manifest = JSON.parse(module.source.source().toString()) as HotUpdateManifest
80
+
81
+ const {m: tempRemoveModules = []} = manifest
82
+
83
+ tempRemoveModules.forEach(removedModule => removedModules.add(String(removedModule)))
84
+ }, [])
85
+
86
+ return {moduleFactories, removedModules}
87
+ }
88
+
89
+ /**
90
+ * 解析 chunk 产物
91
+ * @param source
92
+ */
93
+ export const parseChunkAsset = (source: string): Map<string, ModuleFactory> => {
94
+ const ast = parse(`(${source})`, {sourceType: 'script'})
95
+
96
+ const [statement] = ast.program.body
97
+
98
+ if (!t.isExpressionStatement(statement) || !t.isObjectExpression(statement.expression)) throw new Error('[taro-hmr-compile] Chunk 模块段不是对象表达式')
99
+
100
+ const moduleFactories = new Map<string, ModuleFactory>()
101
+
102
+ parseModuleFactories(statement.expression).forEach(module => moduleFactories.set(module.moduleId, module))
103
+
104
+ return moduleFactories
105
+ }
106
+
107
+ export const mergeUpdatePatches = (basePatch: UpdatePatchSource, nextPatch: UpdatePatchSource,): UpdatePatchSource => {
108
+ if (basePatch.toHash !== nextPatch.fromHash) throw new Error(`[taro-hmr-compile] 无法合并不连续的 HMR patch:${basePatch.toHash} !== ${nextPatch.fromHash}`)
109
+
110
+ const moduleFactories = new Map(basePatch.moduleFactories.map(moduleFactory => [moduleFactory.moduleId, moduleFactory]))
111
+
112
+ const removedModules = new Set(basePatch.removedModules)
113
+
114
+ nextPatch.moduleFactories.forEach(moduleFactory => {
115
+ const {moduleId} = moduleFactory
116
+ moduleFactories.set(moduleId, moduleFactory)
117
+ removedModules.delete(moduleId)
118
+ })
119
+
120
+ nextPatch.removedModules.forEach(moduleId => {
121
+ moduleFactories.delete(moduleId)
122
+ removedModules.add(moduleId)
123
+ })
124
+
125
+ return {
126
+ type: 'update',
127
+ fromHash: basePatch.fromHash,
128
+ toHash: nextPatch.toHash,
129
+ moduleFactories: [...moduleFactories.values()],
130
+ removedModules: [...removedModules],
131
+ }
132
+ }
133
+
134
+ export interface generatePatchAssetSourceOpts {
135
+ bootstrapFactories: Map<string, ModuleFactory>
136
+ recentUpdatePatches: UpdatePatchSource[]
137
+ }
138
+
139
+ export const generatePatchAssetSource = (opt: generatePatchAssetSourceOpts): string => {
140
+ const {bootstrapFactories, recentUpdatePatches} = opt
141
+ const buildBootstrapPatch = template.expression(`({
142
+ type: 'bootstrap',
143
+ modules: MODULES
144
+ })`)
145
+ const buildUpdatePatch = template.expression(`({
146
+ type: 'update',
147
+ fromHash: "FROM_HASH",
148
+ toHash: "TO_HASH",
149
+ modules: MODULES,
150
+ removedModules: REMOVED_MODULES
151
+ })`)
152
+ const buildPatchAsset = template.program('module.exports = PATCHES;')
153
+ const bootstrapModules = Array.from(bootstrapFactories.values()).map((moduleFactory) => {
154
+ const {moduleId, factory} = moduleFactory
155
+ return t.objectProperty(t.stringLiteral(moduleId), factory)
156
+ })
157
+ const patchNodes = [
158
+ buildBootstrapPatch({MODULES: t.objectExpression(bootstrapModules)}),
159
+ ...recentUpdatePatches.map(patch => {
160
+ const updateModules = patch.moduleFactories.map((moduleFactory) => {
161
+ const {moduleId, factory} = moduleFactory
162
+ return t.objectProperty(t.stringLiteral(moduleId), factory)
163
+ })
164
+ return buildUpdatePatch({
165
+ FROM_HASH: patch.fromHash,
166
+ TO_HASH: patch.toHash,
167
+ MODULES: t.objectExpression(updateModules),
168
+ REMOVED_MODULES: t.arrayExpression(patch.removedModules.map(moduleId => t.stringLiteral(moduleId))),
169
+ })
170
+ }),
171
+ ]
172
+
173
+ return generator(buildPatchAsset({PATCHES: t.arrayExpression(patchNodes)})).code
174
+ }
@@ -1,30 +0,0 @@
1
- import type { Expression } from '@babel/types';
2
- export interface BootstrapPatchSource {
3
- type: 'bootstrap';
4
- moduleFactories: Map<string, Expression>;
5
- }
6
- export interface UpdatePatchSource {
7
- type: 'update';
8
- fromHash: string;
9
- toHash: string;
10
- moduleFactories: Map<string, Expression>;
11
- removedModules: string[];
12
- }
13
- export type PatchSource = BootstrapPatchSource | UpdatePatchSource;
14
- /** 仅维护 bootstrap/update Patch 状态、连续性和压缩,不依赖 Webpack 编译对象。 */
15
- export declare class HmrPatchManager {
16
- private bootstrapPatch?;
17
- private compactedUpdatePatch?;
18
- private readonly recentUpdatePatches;
19
- private readonly limit;
20
- constructor(limit: number);
21
- clear(): void;
22
- setBootstrap(moduleFactories: Map<string, Expression>): void;
23
- /** 追加 update;发现 hash 不连续时丢弃旧 update 链,并在追加后执行容量压缩。 */
24
- appendUpdate(patch: UpdatePatchSource): void;
25
- /** 按客户端消费顺序返回 bootstrap、压缩 update 与近期 update。 */
26
- getPatches(): PatchSource[];
27
- private clearUpdateHistory;
28
- /** 将超出上限的旧 update 逐步合并到首个 update;bootstrap 永不参与 merge。 */
29
- private compactUpdateHistory;
30
- }
@@ -1,75 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HmrPatchManager = void 0;
4
- /** 合并两个连续 update,并按后一份 update 的最终模块状态解决修改和删除冲突。 */
5
- const mergeUpdatePatches = (basePatch, nextPatch) => {
6
- if (basePatch.toHash !== nextPatch.fromHash) {
7
- throw new Error(`[taro-hmr-compile] 无法合并不连续的 HMR patch:${basePatch.toHash} !== ${nextPatch.fromHash}`);
8
- }
9
- const moduleFactories = new Map(basePatch.moduleFactories);
10
- const removedModules = new Set(basePatch.removedModules);
11
- nextPatch.moduleFactories.forEach((factory, moduleId) => {
12
- moduleFactories.set(moduleId, factory);
13
- removedModules.delete(moduleId);
14
- });
15
- nextPatch.removedModules.forEach(moduleId => {
16
- moduleFactories.delete(moduleId);
17
- removedModules.add(moduleId);
18
- });
19
- return {
20
- type: 'update',
21
- fromHash: basePatch.fromHash,
22
- toHash: nextPatch.toHash,
23
- moduleFactories,
24
- removedModules: Array.from(removedModules),
25
- };
26
- };
27
- /** 仅维护 bootstrap/update Patch 状态、连续性和压缩,不依赖 Webpack 编译对象。 */
28
- class HmrPatchManager {
29
- constructor(limit) {
30
- this.recentUpdatePatches = [];
31
- this.limit = Math.max(1, limit);
32
- }
33
- clear() {
34
- this.bootstrapPatch = undefined;
35
- this.clearUpdateHistory();
36
- }
37
- setBootstrap(moduleFactories) {
38
- this.bootstrapPatch = moduleFactories.size > 0
39
- ? { type: 'bootstrap', moduleFactories: new Map(moduleFactories) }
40
- : undefined;
41
- }
42
- /** 追加 update;发现 hash 不连续时丢弃旧 update 链,并在追加后执行容量压缩。 */
43
- appendUpdate(patch) {
44
- var _a;
45
- const latestPatch = (_a = this.recentUpdatePatches[this.recentUpdatePatches.length - 1]) !== null && _a !== void 0 ? _a : this.compactedUpdatePatch;
46
- if (latestPatch && latestPatch.toHash !== patch.fromHash)
47
- this.clearUpdateHistory();
48
- this.recentUpdatePatches.push(patch);
49
- this.compactUpdateHistory();
50
- }
51
- /** 按客户端消费顺序返回 bootstrap、压缩 update 与近期 update。 */
52
- getPatches() {
53
- const updatePatches = this.compactedUpdatePatch
54
- ? [this.compactedUpdatePatch, ...this.recentUpdatePatches]
55
- : this.recentUpdatePatches;
56
- return this.bootstrapPatch
57
- ? [this.bootstrapPatch, ...updatePatches]
58
- : updatePatches;
59
- }
60
- clearUpdateHistory() {
61
- this.compactedUpdatePatch = undefined;
62
- this.recentUpdatePatches.length = 0;
63
- }
64
- /** 将超出上限的旧 update 逐步合并到首个 update;bootstrap 永不参与 merge。 */
65
- compactUpdateHistory() {
66
- while (this.recentUpdatePatches.length > this.limit) {
67
- const oldestUpdatePatch = this.recentUpdatePatches.shift();
68
- this.compactedUpdatePatch = this.compactedUpdatePatch
69
- ? mergeUpdatePatches(this.compactedUpdatePatch, oldestUpdatePatch)
70
- : oldestUpdatePatch;
71
- }
72
- }
73
- }
74
- exports.HmrPatchManager = HmrPatchManager;
75
- //# sourceMappingURL=hmr-patch-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hmr-patch-manager.js","sourceRoot":"","sources":["../../src/patch/hmr-patch-manager.ts"],"names":[],"mappings":"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"}
@@ -1,102 +0,0 @@
1
- import type {Expression} from '@babel/types'
2
-
3
- export interface BootstrapPatchSource {
4
- type: 'bootstrap'
5
- moduleFactories: Map<string, Expression>
6
- }
7
-
8
- export interface UpdatePatchSource {
9
- type: 'update'
10
- fromHash: string
11
- toHash: string
12
- moduleFactories: Map<string, Expression>
13
- removedModules: string[]
14
- }
15
-
16
- export type PatchSource = BootstrapPatchSource | UpdatePatchSource
17
-
18
- /** 合并两个连续 update,并按后一份 update 的最终模块状态解决修改和删除冲突。 */
19
- const mergeUpdatePatches = (basePatch: UpdatePatchSource, nextPatch: UpdatePatchSource): UpdatePatchSource => {
20
- if (basePatch.toHash !== nextPatch.fromHash) {
21
- throw new Error(`[taro-hmr-compile] 无法合并不连续的 HMR patch:${basePatch.toHash} !== ${nextPatch.fromHash}`)
22
- }
23
-
24
- const moduleFactories = new Map(basePatch.moduleFactories)
25
- const removedModules = new Set(basePatch.removedModules)
26
-
27
- nextPatch.moduleFactories.forEach((factory, moduleId) => {
28
- moduleFactories.set(moduleId, factory)
29
- removedModules.delete(moduleId)
30
- })
31
- nextPatch.removedModules.forEach(moduleId => {
32
- moduleFactories.delete(moduleId)
33
- removedModules.add(moduleId)
34
- })
35
-
36
- return {
37
- type: 'update',
38
- fromHash: basePatch.fromHash,
39
- toHash: nextPatch.toHash,
40
- moduleFactories,
41
- removedModules: Array.from(removedModules),
42
- }
43
- }
44
-
45
- /** 仅维护 bootstrap/update Patch 状态、连续性和压缩,不依赖 Webpack 编译对象。 */
46
- export class HmrPatchManager {
47
- private bootstrapPatch?: BootstrapPatchSource
48
-
49
- private compactedUpdatePatch?: UpdatePatchSource
50
-
51
- private readonly recentUpdatePatches: UpdatePatchSource[] = []
52
-
53
- private readonly limit: number
54
-
55
- constructor(limit: number) {
56
- this.limit = Math.max(1, limit)
57
- }
58
-
59
- clear() {
60
- this.bootstrapPatch = undefined
61
- this.clearUpdateHistory()
62
- }
63
-
64
- setBootstrap(moduleFactories: Map<string, Expression>) {
65
- this.bootstrapPatch = moduleFactories.size > 0
66
- ? {type: 'bootstrap', moduleFactories: new Map(moduleFactories)}
67
- : undefined
68
- }
69
-
70
- /** 追加 update;发现 hash 不连续时丢弃旧 update 链,并在追加后执行容量压缩。 */
71
- appendUpdate(patch: UpdatePatchSource) {
72
- const latestPatch = this.recentUpdatePatches[this.recentUpdatePatches.length - 1] ?? this.compactedUpdatePatch
73
- if (latestPatch && latestPatch.toHash !== patch.fromHash) this.clearUpdateHistory()
74
- this.recentUpdatePatches.push(patch)
75
- this.compactUpdateHistory()
76
- }
77
-
78
- /** 按客户端消费顺序返回 bootstrap、压缩 update 与近期 update。 */
79
- getPatches(): PatchSource[] {
80
- const updatePatches = this.compactedUpdatePatch
81
- ? [this.compactedUpdatePatch, ...this.recentUpdatePatches]
82
- : this.recentUpdatePatches
83
- return this.bootstrapPatch
84
- ? [this.bootstrapPatch, ...updatePatches]
85
- : updatePatches
86
- }
87
-
88
- private clearUpdateHistory() {
89
- this.compactedUpdatePatch = undefined
90
- this.recentUpdatePatches.length = 0
91
- }
92
-
93
- /** 将超出上限的旧 update 逐步合并到首个 update;bootstrap 永不参与 merge。 */
94
- private compactUpdateHistory() {
95
- while (this.recentUpdatePatches.length > this.limit) {
96
- const oldestUpdatePatch = this.recentUpdatePatches.shift()!
97
- this.compactedUpdatePatch = this.compactedUpdatePatch
98
- ? mergeUpdatePatches(this.compactedUpdatePatch, oldestUpdatePatch)
99
- : oldestUpdatePatch
100
- }
101
- }
102
- }