metro 0.71.0 → 0.71.3
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/package.json +23 -22
- package/src/Bundler.js +0 -2
- package/src/Bundler.js.flow +1 -1
- package/src/DeltaBundler/DeltaCalculator.js +2 -0
- package/src/DeltaBundler/DeltaCalculator.js.flow +2 -0
- package/src/DeltaBundler/Worker.flow.js +78 -0
- package/src/DeltaBundler/Worker.flow.js.flow +121 -0
- package/src/DeltaBundler/Worker.js +8 -66
- package/src/DeltaBundler/Worker.js.flow +8 -107
- package/src/DeltaBundler/WorkerFarm.js.flow +2 -2
- package/src/DeltaBundler/__fixtures__/hasteImpl.js +4 -0
- package/src/DeltaBundler/graphOperations.js +382 -222
- package/src/DeltaBundler/graphOperations.js.flow +404 -232
- package/src/DeltaBundler/types.flow.js +6 -0
- package/src/DeltaBundler/types.flow.js.flow +7 -1
- package/src/DeltaBundler.js +0 -2
- package/src/DeltaBundler.js.flow +1 -1
- package/src/HmrServer.js +0 -2
- package/src/HmrServer.js.flow +1 -2
- package/src/ModuleGraph/node-haste/node-haste.flow.js +0 -1
- package/src/ModuleGraph/node-haste/node-haste.flow.js.flow +1 -2
- package/src/ModuleGraph/node-haste/node-haste.js.flow +7 -2
- package/src/ModuleGraph/output/util.js.flow +2 -2
- package/src/ModuleGraph/silent-console.js +5 -4
- package/src/ModuleGraph/silent-console.js.flow +8 -4
- package/src/ModuleGraph/worker/collectDependencies.js +215 -8
- package/src/ModuleGraph/worker/collectDependencies.js.flow +233 -13
- package/src/Server.js +2 -0
- package/src/Server.js.flow +9 -2
- package/src/cli.js +5 -0
- package/src/cli.js.flow +5 -0
- package/src/commands/build.js +4 -3
- package/src/commands/build.js.flow +3 -1
- package/src/commands/serve.js +3 -3
- package/src/commands/serve.js.flow +3 -1
- package/src/index.flow.js +392 -0
- package/src/index.flow.js.flow +480 -0
- package/src/index.js +8 -380
- package/src/index.js.flow +8 -466
- package/src/lib/CountingSet.js +116 -0
- package/src/lib/CountingSet.js.flow +126 -0
- package/src/lib/JsonReporter.js +0 -2
- package/src/lib/JsonReporter.js.flow +1 -1
- package/src/lib/getAppendScripts.js +10 -4
- package/src/lib/getAppendScripts.js.flow +6 -4
- package/src/lib/getPreludeCode.js +19 -1
- package/src/lib/getPreludeCode.js.flow +15 -0
- package/src/lib/getPrependedScripts.js +10 -2
- package/src/lib/getPrependedScripts.js.flow +11 -2
- package/src/lib/reporting.js +0 -2
- package/src/lib/reporting.js.flow +2 -1
- package/src/node-haste/DependencyGraph/ModuleResolution.js +15 -3
- package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +15 -0
- package/src/node-haste/DependencyGraph/createHasteMap.js +78 -19
- package/src/node-haste/DependencyGraph/createHasteMap.js.flow +14 -9
- package/src/node-haste/DependencyGraph.js +2 -2
- package/src/node-haste/DependencyGraph.js.flow +4 -2
|
@@ -7,16 +7,50 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @format
|
|
9
9
|
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Portions of this code are based on the Synchronous Cycle Collection
|
|
13
|
+
* algorithm described in:
|
|
14
|
+
*
|
|
15
|
+
* David F. Bacon and V. T. Rajan. 2001. Concurrent Cycle Collection in
|
|
16
|
+
* Reference Counted Systems. In Proceedings of the 15th European Conference on
|
|
17
|
+
* Object-Oriented Programming (ECOOP '01). Springer-Verlag, Berlin,
|
|
18
|
+
* Heidelberg, 207–235.
|
|
19
|
+
*
|
|
20
|
+
* Notable differences from the algorithm in the paper:
|
|
21
|
+
* 1. Our implementation uses the inverseDependencies set (which we already
|
|
22
|
+
* have to maintain) instead of a separate refcount variable. A module's
|
|
23
|
+
* reference count is equal to the size of its inverseDependencies set, plus
|
|
24
|
+
* 1 if it's an entry point of the graph.
|
|
25
|
+
* 2. We keep the "root buffer" (possibleCycleRoots) free of duplicates by
|
|
26
|
+
* making it a Set, instead of storing a "buffered" flag on each node.
|
|
27
|
+
* 3. On top of tracking edges between nodes, we also count references between
|
|
28
|
+
* nodes and entries in the importBundleNames set.
|
|
29
|
+
*/
|
|
10
30
|
"use strict";
|
|
11
31
|
|
|
12
|
-
|
|
32
|
+
var _CountingSet = _interopRequireDefault(require("../lib/CountingSet"));
|
|
33
|
+
|
|
34
|
+
function _interopRequireDefault(obj) {
|
|
35
|
+
return obj && obj.__esModule ? obj : { default: obj };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const invariant = require("invariant");
|
|
39
|
+
|
|
40
|
+
const nullthrows = require("nullthrows"); // TODO: Convert to a Flow enum
|
|
13
41
|
|
|
14
42
|
function createGraph(options) {
|
|
15
43
|
return {
|
|
16
44
|
...options,
|
|
17
45
|
dependencies: new Map(),
|
|
18
46
|
importBundleNames: new Set(),
|
|
19
|
-
privateState: {
|
|
47
|
+
privateState: {
|
|
48
|
+
gc: {
|
|
49
|
+
color: new Map(),
|
|
50
|
+
possibleCycleRoots: new Set(),
|
|
51
|
+
importBundleRefs: new Map(),
|
|
52
|
+
},
|
|
53
|
+
},
|
|
20
54
|
};
|
|
21
55
|
}
|
|
22
56
|
|
|
@@ -55,7 +89,7 @@ async function traverseDependencies(paths, graph, options) {
|
|
|
55
89
|
added: new Set(),
|
|
56
90
|
modified: new Set(),
|
|
57
91
|
deleted: new Set(),
|
|
58
|
-
|
|
92
|
+
earlyInverseDependencies: new Map(),
|
|
59
93
|
};
|
|
60
94
|
const internalOptions = getInternalOptions(options);
|
|
61
95
|
|
|
@@ -72,6 +106,7 @@ async function traverseDependencies(paths, graph, options) {
|
|
|
72
106
|
}
|
|
73
107
|
}
|
|
74
108
|
|
|
109
|
+
collectCycles(graph, delta);
|
|
75
110
|
const added = new Map();
|
|
76
111
|
|
|
77
112
|
for (const path of delta.added) {
|
|
@@ -99,9 +134,26 @@ async function initialTraverseDependencies(graph, options) {
|
|
|
99
134
|
added: new Set(),
|
|
100
135
|
modified: new Set(),
|
|
101
136
|
deleted: new Set(),
|
|
102
|
-
|
|
137
|
+
earlyInverseDependencies: new Map(),
|
|
103
138
|
};
|
|
104
139
|
const internalOptions = getInternalOptions(options);
|
|
140
|
+
invariant(
|
|
141
|
+
graph.dependencies.size === 0,
|
|
142
|
+
"initialTraverseDependencies called on nonempty graph"
|
|
143
|
+
);
|
|
144
|
+
invariant(
|
|
145
|
+
graph.importBundleNames.size === 0,
|
|
146
|
+
"initialTraverseDependencies called on nonempty graph"
|
|
147
|
+
);
|
|
148
|
+
graph.privateState.gc.color.clear();
|
|
149
|
+
graph.privateState.gc.possibleCycleRoots.clear();
|
|
150
|
+
graph.privateState.gc.importBundleRefs.clear();
|
|
151
|
+
|
|
152
|
+
for (const path of graph.entryPoints) {
|
|
153
|
+
// Each entry point implicitly has a refcount of 1, so mark them all black.
|
|
154
|
+
graph.privateState.gc.color.set(path, "black");
|
|
155
|
+
}
|
|
156
|
+
|
|
105
157
|
await Promise.all(
|
|
106
158
|
[...graph.entryPoints].map((path) =>
|
|
107
159
|
traverseDependenciesForSingleFile(path, graph, delta, internalOptions)
|
|
@@ -135,264 +187,182 @@ async function processModule(path, graph, delta, options) {
|
|
|
135
187
|
options
|
|
136
188
|
);
|
|
137
189
|
const previousModule = graph.dependencies.get(path) || {
|
|
138
|
-
inverseDependencies:
|
|
190
|
+
inverseDependencies:
|
|
191
|
+
delta.earlyInverseDependencies.get(path) || new _CountingSet.default(),
|
|
139
192
|
path,
|
|
140
193
|
};
|
|
141
194
|
const previousDependencies = previousModule.dependencies || new Map(); // Update the module information.
|
|
142
195
|
|
|
143
196
|
const module = {
|
|
144
197
|
...previousModule,
|
|
145
|
-
dependencies: new Map(),
|
|
198
|
+
dependencies: new Map(previousDependencies),
|
|
146
199
|
getSource: result.getSource,
|
|
147
200
|
output: result.output,
|
|
148
201
|
};
|
|
149
|
-
graph.dependencies.set(module.path, module);
|
|
202
|
+
graph.dependencies.set(module.path, module); // Diff dependencies (1/2): remove dependencies that have changed or been removed.
|
|
150
203
|
|
|
151
|
-
for (const [relativePath,
|
|
152
|
-
|
|
153
|
-
}
|
|
204
|
+
for (const [relativePath, prevDependency] of previousDependencies) {
|
|
205
|
+
const curDependency = currentDependencies.get(relativePath);
|
|
154
206
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
for (const [relativePath, dependency] of currentDependencies) {
|
|
171
|
-
if (!options.shallow) {
|
|
172
|
-
if (
|
|
173
|
-
options.experimentalImportBundleSupport &&
|
|
174
|
-
dependency.data.data.asyncType != null
|
|
175
|
-
) {
|
|
176
|
-
graph.importBundleNames.add(dependency.absolutePath);
|
|
177
|
-
} else if (
|
|
178
|
-
!previousDependencies.has(relativePath) ||
|
|
179
|
-
nullthrows(previousDependencies.get(relativePath)).absolutePath !==
|
|
180
|
-
dependency.absolutePath
|
|
181
|
-
) {
|
|
182
|
-
promises.push(
|
|
183
|
-
addDependency(module, dependency.absolutePath, graph, delta, options)
|
|
184
|
-
);
|
|
185
|
-
}
|
|
207
|
+
if (
|
|
208
|
+
!curDependency ||
|
|
209
|
+
curDependency.absolutePath !== prevDependency.absolutePath ||
|
|
210
|
+
(options.experimentalImportBundleSupport &&
|
|
211
|
+
curDependency.data.data.asyncType !==
|
|
212
|
+
prevDependency.data.data.asyncType)
|
|
213
|
+
) {
|
|
214
|
+
removeDependency(
|
|
215
|
+
module,
|
|
216
|
+
relativePath,
|
|
217
|
+
prevDependency,
|
|
218
|
+
graph,
|
|
219
|
+
delta,
|
|
220
|
+
options
|
|
221
|
+
);
|
|
186
222
|
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
await Promise.all(promises);
|
|
191
|
-
} catch (err) {
|
|
192
|
-
// If there is an error, restore the previous dependency list.
|
|
193
|
-
// This ensures we don't skip over them during the next traversal attempt.
|
|
194
|
-
// $FlowFixMe[cannot-write]
|
|
195
|
-
module.dependencies = previousDependencies;
|
|
196
|
-
throw err;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
return module;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async function addDependency(parentModule, path, graph, delta, options) {
|
|
203
|
-
// The new dependency was already in the graph, we don't need to do anything.
|
|
204
|
-
const existingModule = graph.dependencies.get(path);
|
|
205
|
-
|
|
206
|
-
if (existingModule) {
|
|
207
|
-
existingModule.inverseDependencies.add(parentModule.path);
|
|
208
|
-
return;
|
|
209
|
-
} // This module is being transformed at the moment in parallel, so we should
|
|
210
|
-
// only mark its parent as an inverse dependency.
|
|
211
|
-
|
|
212
|
-
const inverse = delta.inverseDependencies.get(path);
|
|
223
|
+
} // Diff dependencies (2/2): add dependencies that have changed or been added.
|
|
213
224
|
|
|
214
|
-
|
|
215
|
-
inverse.add(parentModule.path);
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (delta.deleted.has(path)) {
|
|
220
|
-
// Mark the addition by clearing a prior deletion.
|
|
221
|
-
delta.deleted.delete(path);
|
|
222
|
-
} else {
|
|
223
|
-
// Mark the addition in the added set.
|
|
224
|
-
delta.added.add(path);
|
|
225
|
-
delta.modified.delete(path);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
delta.inverseDependencies.set(path, new Set([parentModule.path]));
|
|
229
|
-
options.onDependencyAdd();
|
|
230
|
-
const module = await processModule(path, graph, delta, options);
|
|
231
|
-
graph.dependencies.set(module.path, module);
|
|
232
|
-
module.inverseDependencies.add(parentModule.path);
|
|
233
|
-
options.onDependencyAdded();
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Recursively look up `inverseDependencies` until it is empty,
|
|
237
|
-
* returning a set of paths for the last module that does not have
|
|
238
|
-
* `inverseDependencies`.
|
|
239
|
-
*/
|
|
240
|
-
|
|
241
|
-
function getAllTopLevelInverseDependencies(
|
|
242
|
-
inverseDependencies,
|
|
243
|
-
graph,
|
|
244
|
-
currModule,
|
|
245
|
-
visited
|
|
246
|
-
) {
|
|
247
|
-
if (visited.has(currModule)) {
|
|
248
|
-
return new Set();
|
|
249
|
-
}
|
|
225
|
+
const promises = [];
|
|
250
226
|
|
|
251
|
-
|
|
227
|
+
for (const [relativePath, curDependency] of currentDependencies) {
|
|
228
|
+
const prevDependency = previousDependencies.get(relativePath);
|
|
252
229
|
|
|
253
|
-
|
|
254
|
-
|
|
230
|
+
if (
|
|
231
|
+
!prevDependency ||
|
|
232
|
+
prevDependency.absolutePath !== curDependency.absolutePath ||
|
|
233
|
+
(options.experimentalImportBundleSupport &&
|
|
234
|
+
prevDependency.data.data.asyncType !==
|
|
235
|
+
curDependency.data.data.asyncType)
|
|
236
|
+
) {
|
|
237
|
+
promises.push(
|
|
238
|
+
addDependency(
|
|
239
|
+
module,
|
|
240
|
+
relativePath,
|
|
241
|
+
curDependency,
|
|
242
|
+
graph,
|
|
243
|
+
delta,
|
|
244
|
+
options
|
|
245
|
+
)
|
|
246
|
+
);
|
|
247
|
+
}
|
|
255
248
|
}
|
|
256
249
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
250
|
+
await Promise.all(promises); // Replace dependencies with the correctly-ordered version. As long as all
|
|
251
|
+
// the above promises have resolved, this will be the same map but without
|
|
252
|
+
// the added nondeterminism of promise resolution order. Because this
|
|
253
|
+
// assignment does not add or remove edges, it does NOT invalidate any of the
|
|
254
|
+
// garbage collection state.
|
|
255
|
+
// Catch obvious errors with a cheap assertion.
|
|
261
256
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
257
|
+
invariant(
|
|
258
|
+
module.dependencies.size === currentDependencies.size,
|
|
259
|
+
"Failed to add the correct dependencies"
|
|
260
|
+
); // $FlowFixMe[cannot-write]
|
|
265
261
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
graph,
|
|
269
|
-
inverseDep,
|
|
270
|
-
visited
|
|
271
|
-
).forEach((x) => {
|
|
272
|
-
acc.add(x);
|
|
273
|
-
});
|
|
274
|
-
return acc;
|
|
275
|
-
}, new Set());
|
|
262
|
+
module.dependencies = currentDependencies;
|
|
263
|
+
return module;
|
|
276
264
|
}
|
|
277
|
-
/**
|
|
278
|
-
* Given `inverseDependencies`, tracing back inverse dependencies to
|
|
279
|
-
* see if it only leads back to `parentModule`.
|
|
280
|
-
*/
|
|
281
265
|
|
|
282
|
-
function
|
|
283
|
-
inverseDependencies,
|
|
266
|
+
async function addDependency(
|
|
284
267
|
parentModule,
|
|
268
|
+
relativePath,
|
|
269
|
+
dependency,
|
|
285
270
|
graph,
|
|
286
|
-
|
|
287
|
-
|
|
271
|
+
delta,
|
|
272
|
+
options
|
|
288
273
|
) {
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
274
|
+
const path = dependency.absolutePath; // The module may already exist, in which case we just need to update some
|
|
275
|
+
// bookkeeping instead of adding a new node to the graph.
|
|
276
|
+
|
|
277
|
+
let module = graph.dependencies.get(path);
|
|
278
|
+
|
|
279
|
+
if (options.shallow) {
|
|
280
|
+
// Don't add a node for the module if the graph is shallow (single-module).
|
|
281
|
+
} else if (
|
|
282
|
+
options.experimentalImportBundleSupport &&
|
|
283
|
+
dependency.data.data.asyncType != null
|
|
284
|
+
) {
|
|
285
|
+
// Don't add a node for the module if we are traversing async dependencies
|
|
286
|
+
// lazily (and this is an async dependency). Instead, record it in
|
|
287
|
+
// importBundleNames.
|
|
288
|
+
incrementImportBundleReference(dependency, graph);
|
|
289
|
+
} else {
|
|
290
|
+
if (!module) {
|
|
291
|
+
// Add a new node to the graph.
|
|
292
|
+
const earlyInverseDependencies = delta.earlyInverseDependencies.get(path);
|
|
293
|
+
|
|
294
|
+
if (earlyInverseDependencies) {
|
|
295
|
+
// This module is being transformed at the moment in parallel, so we
|
|
296
|
+
// should only mark its parent as an inverse dependency.
|
|
297
|
+
earlyInverseDependencies.add(parentModule.path);
|
|
298
|
+
} else {
|
|
299
|
+
if (delta.deleted.has(path)) {
|
|
300
|
+
// Mark the addition by clearing a prior deletion.
|
|
301
|
+
delta.deleted.delete(path);
|
|
302
|
+
} else {
|
|
303
|
+
// Mark the addition in the added set.
|
|
304
|
+
delta.added.add(path);
|
|
305
|
+
delta.modified.delete(path);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
delta.earlyInverseDependencies.set(path, new _CountingSet.default());
|
|
309
|
+
options.onDependencyAdd();
|
|
310
|
+
module = await processModule(path, graph, delta, options);
|
|
311
|
+
options.onDependencyAdded();
|
|
312
|
+
graph.dependencies.set(module.path, module);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
305
315
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
*/
|
|
316
|
-
|
|
317
|
-
const canSafelyRemove =
|
|
318
|
-
!undeletedInverseDependencies.length ||
|
|
319
|
-
(undeletedInverseDependencies.length === 1 &&
|
|
320
|
-
undeletedInverseDependencies[0] === parentModule);
|
|
321
|
-
|
|
322
|
-
if (canSafelyRemove) {
|
|
323
|
-
visited.forEach((mod) => {
|
|
324
|
-
canBeRemovedSafely.add(mod);
|
|
325
|
-
});
|
|
326
|
-
}
|
|
316
|
+
if (module) {
|
|
317
|
+
// We either added a new node to the graph, or we're updating an existing one.
|
|
318
|
+
module.inverseDependencies.add(parentModule.path);
|
|
319
|
+
markModuleInUse(module, graph);
|
|
320
|
+
}
|
|
321
|
+
} // Always update the parent's dependency map.
|
|
322
|
+
// This means the parent's dependencies can get desynced from
|
|
323
|
+
// inverseDependencies and the other fields in the case of lazy edges.
|
|
324
|
+
// Not an optimal representation :(
|
|
327
325
|
|
|
328
|
-
|
|
326
|
+
parentModule.dependencies.set(relativePath, dependency);
|
|
329
327
|
}
|
|
330
328
|
|
|
331
329
|
function removeDependency(
|
|
332
330
|
parentModule,
|
|
333
|
-
|
|
331
|
+
relativePath,
|
|
332
|
+
dependency,
|
|
334
333
|
graph,
|
|
335
|
-
delta,
|
|
336
|
-
|
|
337
|
-
// inverse dependency traversals.
|
|
338
|
-
canBeRemovedSafely = new Set()
|
|
334
|
+
delta,
|
|
335
|
+
options
|
|
339
336
|
) {
|
|
337
|
+
parentModule.dependencies.delete(relativePath);
|
|
338
|
+
const { absolutePath } = dependency;
|
|
339
|
+
|
|
340
|
+
if (
|
|
341
|
+
options.experimentalImportBundleSupport &&
|
|
342
|
+
dependency.data.data.asyncType != null
|
|
343
|
+
) {
|
|
344
|
+
decrementImportBundleReference(dependency, graph);
|
|
345
|
+
}
|
|
346
|
+
|
|
340
347
|
const module = graph.dependencies.get(absolutePath);
|
|
341
348
|
|
|
342
349
|
if (!module) {
|
|
343
350
|
return;
|
|
344
351
|
}
|
|
345
352
|
|
|
346
|
-
module.inverseDependencies.delete(parentModule.path);
|
|
347
|
-
// there is no circular dependency. Thus, we check if it can be safely removed
|
|
348
|
-
// by tracing back the inverseDependencies.
|
|
349
|
-
|
|
350
|
-
if (!canBeRemovedSafely.has(module.path)) {
|
|
351
|
-
if (
|
|
352
|
-
module.inverseDependencies.size &&
|
|
353
|
-
!canSafelyRemoveFromParentModule(
|
|
354
|
-
module.inverseDependencies,
|
|
355
|
-
module.path,
|
|
356
|
-
graph,
|
|
357
|
-
canBeRemovedSafely,
|
|
358
|
-
delta
|
|
359
|
-
)
|
|
360
|
-
) {
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
353
|
+
module.inverseDependencies.delete(parentModule.path);
|
|
364
354
|
|
|
365
|
-
if (
|
|
366
|
-
|
|
367
|
-
|
|
355
|
+
if (
|
|
356
|
+
module.inverseDependencies.size > 0 ||
|
|
357
|
+
graph.entryPoints.has(absolutePath)
|
|
358
|
+
) {
|
|
359
|
+
// The reference count has decreased, but not to zero.
|
|
360
|
+
// NOTE: Each entry point implicitly has a refcount of 1.
|
|
361
|
+
markAsPossibleCycleRoot(module, graph);
|
|
368
362
|
} else {
|
|
369
|
-
//
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
} // This module is not used anywhere else! We can clear it from the bundle.
|
|
373
|
-
// Clean up all the state associated with this module in order to correctly
|
|
374
|
-
// re-add it if we encounter it again.
|
|
375
|
-
|
|
376
|
-
graph.dependencies.delete(module.path);
|
|
377
|
-
delta.inverseDependencies.delete(module.path); // Now we need to iterate through the module dependencies in order to
|
|
378
|
-
// clean up everything (we cannot read the module because it may have
|
|
379
|
-
// been deleted).
|
|
380
|
-
|
|
381
|
-
Array.from(module.dependencies.values())
|
|
382
|
-
.filter(
|
|
383
|
-
(dependency) =>
|
|
384
|
-
graph.dependencies.has(dependency.absolutePath) &&
|
|
385
|
-
dependency.absolutePath !== parentModule.path
|
|
386
|
-
)
|
|
387
|
-
.forEach((dependency) =>
|
|
388
|
-
removeDependency(
|
|
389
|
-
module,
|
|
390
|
-
dependency.absolutePath,
|
|
391
|
-
graph,
|
|
392
|
-
delta,
|
|
393
|
-
canBeRemovedSafely
|
|
394
|
-
)
|
|
395
|
-
);
|
|
363
|
+
// The reference count has decreased to zero.
|
|
364
|
+
releaseModule(module, graph, delta, options);
|
|
365
|
+
}
|
|
396
366
|
}
|
|
397
367
|
|
|
398
368
|
function resolveDependencies(parentPath, dependencies, options) {
|
|
@@ -472,6 +442,196 @@ function reorderDependencies(graph, module, orderedDependencies, options) {
|
|
|
472
442
|
reorderDependencies(graph, childModule, orderedDependencies, options);
|
|
473
443
|
});
|
|
474
444
|
}
|
|
445
|
+
/** Garbage collection functions */
|
|
446
|
+
// Add an entry to importBundleNames (or increase the reference count of an existing one)
|
|
447
|
+
|
|
448
|
+
function incrementImportBundleReference(dependency, graph) {
|
|
449
|
+
var _graph$privateState$g;
|
|
450
|
+
|
|
451
|
+
const { absolutePath } = dependency;
|
|
452
|
+
graph.privateState.gc.importBundleRefs.set(
|
|
453
|
+
absolutePath,
|
|
454
|
+
((_graph$privateState$g =
|
|
455
|
+
graph.privateState.gc.importBundleRefs.get(absolutePath)) !== null &&
|
|
456
|
+
_graph$privateState$g !== void 0
|
|
457
|
+
? _graph$privateState$g
|
|
458
|
+
: 0) + 1
|
|
459
|
+
);
|
|
460
|
+
graph.importBundleNames.add(absolutePath);
|
|
461
|
+
} // Decrease the reference count of an entry in importBundleNames (and delete it if necessary)
|
|
462
|
+
|
|
463
|
+
function decrementImportBundleReference(dependency, graph) {
|
|
464
|
+
const { absolutePath } = dependency;
|
|
465
|
+
const prevRefCount = nullthrows(
|
|
466
|
+
graph.privateState.gc.importBundleRefs.get(absolutePath)
|
|
467
|
+
);
|
|
468
|
+
invariant(
|
|
469
|
+
prevRefCount > 0,
|
|
470
|
+
"experimentalImportBundleSupport: import bundle refcount not valid"
|
|
471
|
+
);
|
|
472
|
+
graph.privateState.gc.importBundleRefs.set(absolutePath, prevRefCount - 1);
|
|
473
|
+
|
|
474
|
+
if (prevRefCount === 1) {
|
|
475
|
+
graph.privateState.gc.importBundleRefs.delete(absolutePath);
|
|
476
|
+
graph.importBundleNames.delete(absolutePath);
|
|
477
|
+
}
|
|
478
|
+
} // Mark a module as in use (ref count >= 1)
|
|
479
|
+
|
|
480
|
+
function markModuleInUse(module, graph) {
|
|
481
|
+
graph.privateState.gc.color.set(module.path, "black");
|
|
482
|
+
} // Delete an unreachable module from the graph immediately, unless it's queued
|
|
483
|
+
// for later deletion as a potential cycle root. Delete the module's outbound
|
|
484
|
+
// edges.
|
|
485
|
+
// Called when the reference count of a module has reached 0.
|
|
486
|
+
|
|
487
|
+
function releaseModule(module, graph, delta, options) {
|
|
488
|
+
for (const [relativePath, dependency] of module.dependencies) {
|
|
489
|
+
removeDependency(module, relativePath, dependency, graph, delta, options);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
graph.privateState.gc.color.set(module.path, "black");
|
|
493
|
+
|
|
494
|
+
if (!graph.privateState.gc.possibleCycleRoots.has(module.path)) {
|
|
495
|
+
freeModule(module, graph, delta);
|
|
496
|
+
}
|
|
497
|
+
} // Delete an unreachable module from the graph.
|
|
498
|
+
|
|
499
|
+
function freeModule(module, graph, delta) {
|
|
500
|
+
if (delta.added.has(module.path)) {
|
|
501
|
+
// Mark the deletion by clearing a prior addition.
|
|
502
|
+
delta.added.delete(module.path);
|
|
503
|
+
} else {
|
|
504
|
+
// Mark the deletion in the deleted set.
|
|
505
|
+
delta.deleted.add(module.path);
|
|
506
|
+
delta.modified.delete(module.path);
|
|
507
|
+
} // This module is not used anywhere else! We can clear it from the bundle.
|
|
508
|
+
// Clean up all the state associated with this module in order to correctly
|
|
509
|
+
// re-add it if we encounter it again.
|
|
510
|
+
|
|
511
|
+
graph.dependencies.delete(module.path);
|
|
512
|
+
delta.earlyInverseDependencies.delete(module.path);
|
|
513
|
+
graph.privateState.gc.possibleCycleRoots.delete(module.path);
|
|
514
|
+
graph.privateState.gc.color.delete(module.path);
|
|
515
|
+
} // Mark a module as a possible cycle root
|
|
516
|
+
|
|
517
|
+
function markAsPossibleCycleRoot(module, graph) {
|
|
518
|
+
if (nullthrows(graph.privateState.gc.color.get(module.path)) !== "purple") {
|
|
519
|
+
graph.privateState.gc.color.set(module.path, "purple");
|
|
520
|
+
graph.privateState.gc.possibleCycleRoots.add(module.path);
|
|
521
|
+
}
|
|
522
|
+
} // Collect any unreachable cycles in the graph.
|
|
523
|
+
|
|
524
|
+
function collectCycles(graph, delta) {
|
|
525
|
+
// Mark recursively from roots (trial deletion)
|
|
526
|
+
for (const path of graph.privateState.gc.possibleCycleRoots) {
|
|
527
|
+
const module = nullthrows(graph.dependencies.get(path));
|
|
528
|
+
const color = nullthrows(graph.privateState.gc.color.get(path));
|
|
529
|
+
|
|
530
|
+
if (color === "purple") {
|
|
531
|
+
markGray(module, graph);
|
|
532
|
+
} else {
|
|
533
|
+
graph.privateState.gc.possibleCycleRoots.delete(path);
|
|
534
|
+
|
|
535
|
+
if (
|
|
536
|
+
color === "black" &&
|
|
537
|
+
module.inverseDependencies.size === 0 &&
|
|
538
|
+
!graph.entryPoints.has(path)
|
|
539
|
+
) {
|
|
540
|
+
freeModule(module, graph, delta);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
} // Scan recursively from roots (undo unsuccessful trial deletions)
|
|
544
|
+
|
|
545
|
+
for (const path of graph.privateState.gc.possibleCycleRoots) {
|
|
546
|
+
const module = nullthrows(graph.dependencies.get(path));
|
|
547
|
+
scan(module, graph);
|
|
548
|
+
} // Collect recursively from roots (free unreachable cycles)
|
|
549
|
+
|
|
550
|
+
for (const path of graph.privateState.gc.possibleCycleRoots) {
|
|
551
|
+
graph.privateState.gc.possibleCycleRoots.delete(path);
|
|
552
|
+
const module = nullthrows(graph.dependencies.get(path));
|
|
553
|
+
collectWhite(module, graph, delta);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function markGray(module, graph) {
|
|
558
|
+
const color = nullthrows(graph.privateState.gc.color.get(module.path));
|
|
559
|
+
|
|
560
|
+
if (color !== "gray") {
|
|
561
|
+
graph.privateState.gc.color.set(module.path, "gray");
|
|
562
|
+
|
|
563
|
+
for (const dependency of module.dependencies.values()) {
|
|
564
|
+
const childModule = nullthrows(
|
|
565
|
+
graph.dependencies.get(dependency.absolutePath)
|
|
566
|
+
); // The inverse dependency will be restored during the scan phase if this module remains live.
|
|
567
|
+
|
|
568
|
+
childModule.inverseDependencies.delete(module.path);
|
|
569
|
+
markGray(childModule, graph);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function scan(module, graph) {
|
|
575
|
+
const color = nullthrows(graph.privateState.gc.color.get(module.path));
|
|
576
|
+
|
|
577
|
+
if (color === "gray") {
|
|
578
|
+
if (
|
|
579
|
+
module.inverseDependencies.size > 0 ||
|
|
580
|
+
graph.entryPoints.has(module.path)
|
|
581
|
+
) {
|
|
582
|
+
scanBlack(module, graph);
|
|
583
|
+
} else {
|
|
584
|
+
graph.privateState.gc.color.set(module.path, "white");
|
|
585
|
+
|
|
586
|
+
for (const dependency of module.dependencies.values()) {
|
|
587
|
+
const childModule = nullthrows(
|
|
588
|
+
graph.dependencies.get(dependency.absolutePath)
|
|
589
|
+
);
|
|
590
|
+
scan(childModule, graph);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function scanBlack(module, graph) {
|
|
597
|
+
graph.privateState.gc.color.set(module.path, "black");
|
|
598
|
+
|
|
599
|
+
for (const dependency of module.dependencies.values()) {
|
|
600
|
+
const childModule = nullthrows(
|
|
601
|
+
graph.dependencies.get(dependency.absolutePath)
|
|
602
|
+
); // The inverse dependency must have been deleted during the mark phase.
|
|
603
|
+
|
|
604
|
+
childModule.inverseDependencies.add(module.path);
|
|
605
|
+
const childColor = nullthrows(
|
|
606
|
+
graph.privateState.gc.color.get(childModule.path)
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
if (childColor !== "black") {
|
|
610
|
+
scanBlack(childModule, graph);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function collectWhite(module, graph, delta) {
|
|
616
|
+
const color = nullthrows(graph.privateState.gc.color.get(module.path));
|
|
617
|
+
|
|
618
|
+
if (
|
|
619
|
+
color === "white" &&
|
|
620
|
+
!graph.privateState.gc.possibleCycleRoots.has(module.path)
|
|
621
|
+
) {
|
|
622
|
+
graph.privateState.gc.color.set(module.path, "black");
|
|
623
|
+
|
|
624
|
+
for (const dependency of module.dependencies.values()) {
|
|
625
|
+
const childModule = nullthrows(
|
|
626
|
+
graph.dependencies.get(dependency.absolutePath)
|
|
627
|
+
);
|
|
628
|
+
collectWhite(childModule, graph, delta);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
freeModule(module, graph, delta);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
/** End of garbage collection functions */
|
|
475
635
|
|
|
476
636
|
module.exports = {
|
|
477
637
|
createGraph,
|