metro 0.80.2 → 0.80.4
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 +17 -17
- package/src/DeltaBundler/DeltaCalculator.js +0 -8
- package/src/DeltaBundler/DeltaCalculator.js.flow +0 -9
- package/src/DeltaBundler/Graph.js +290 -275
- package/src/DeltaBundler/Graph.js.flow +314 -278
- package/src/DeltaBundler/buildSubgraph.js +138 -0
- package/src/DeltaBundler/buildSubgraph.js.flow +161 -0
- package/src/DeltaBundler/types.flow.js.flow +29 -18
- package/src/ModuleGraph/worker/collectDependencies.js.flow +1 -1
- package/src/index.flow.js +1 -0
- package/src/index.flow.js.flow +1 -1
- package/src/lib/splitBundleOptions.js +1 -0
- package/src/lib/splitBundleOptions.js.flow +1 -0
- package/src/node-haste/DependencyGraph/ModuleResolution.js +4 -1
- package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +2 -1
- package/src/node-haste/DependencyGraph.js +3 -14
- package/src/node-haste/DependencyGraph.js.flow +3 -14
- package/src/shared/types.flow.js.flow +1 -0
|
@@ -6,47 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Graph = void 0;
|
|
7
7
|
var _contextModule = require("../lib/contextModule");
|
|
8
8
|
var _CountingSet = _interopRequireDefault(require("../lib/CountingSet"));
|
|
9
|
-
var
|
|
10
|
-
function _getRequireWildcardCache(nodeInterop) {
|
|
11
|
-
if (typeof WeakMap !== "function") return null;
|
|
12
|
-
var cacheBabelInterop = new WeakMap();
|
|
13
|
-
var cacheNodeInterop = new WeakMap();
|
|
14
|
-
return (_getRequireWildcardCache = function (nodeInterop) {
|
|
15
|
-
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
16
|
-
})(nodeInterop);
|
|
17
|
-
}
|
|
18
|
-
function _interopRequireWildcard(obj, nodeInterop) {
|
|
19
|
-
if (!nodeInterop && obj && obj.__esModule) {
|
|
20
|
-
return obj;
|
|
21
|
-
}
|
|
22
|
-
if (obj === null || (typeof obj !== "object" && typeof obj !== "function")) {
|
|
23
|
-
return { default: obj };
|
|
24
|
-
}
|
|
25
|
-
var cache = _getRequireWildcardCache(nodeInterop);
|
|
26
|
-
if (cache && cache.has(obj)) {
|
|
27
|
-
return cache.get(obj);
|
|
28
|
-
}
|
|
29
|
-
var newObj = {};
|
|
30
|
-
var hasPropertyDescriptor =
|
|
31
|
-
Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
32
|
-
for (var key in obj) {
|
|
33
|
-
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
34
|
-
var desc = hasPropertyDescriptor
|
|
35
|
-
? Object.getOwnPropertyDescriptor(obj, key)
|
|
36
|
-
: null;
|
|
37
|
-
if (desc && (desc.get || desc.set)) {
|
|
38
|
-
Object.defineProperty(newObj, key, desc);
|
|
39
|
-
} else {
|
|
40
|
-
newObj[key] = obj[key];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
newObj.default = obj;
|
|
45
|
-
if (cache) {
|
|
46
|
-
cache.set(obj, newObj);
|
|
47
|
-
}
|
|
48
|
-
return newObj;
|
|
49
|
-
}
|
|
9
|
+
var _buildSubgraph = require("./buildSubgraph");
|
|
50
10
|
function _interopRequireDefault(obj) {
|
|
51
11
|
return obj && obj.__esModule ? obj : { default: obj };
|
|
52
12
|
}
|
|
@@ -98,6 +58,10 @@ function getInternalOptions({ transform, resolve, onProgress, lazy, shallow }) {
|
|
|
98
58
|
shallow,
|
|
99
59
|
};
|
|
100
60
|
}
|
|
61
|
+
function isWeakOrLazy(dependency, options) {
|
|
62
|
+
const asyncType = dependency.data.data.asyncType;
|
|
63
|
+
return asyncType === "weak" || (asyncType != null && options.lazy);
|
|
64
|
+
}
|
|
101
65
|
class Graph {
|
|
102
66
|
dependencies = new Map();
|
|
103
67
|
#importBundleNodes = new Map();
|
|
@@ -127,82 +91,118 @@ class Graph {
|
|
|
127
91
|
* since the last traversal.
|
|
128
92
|
*/
|
|
129
93
|
async traverseDependencies(paths, options) {
|
|
130
|
-
const delta = {
|
|
131
|
-
added: new Set(),
|
|
132
|
-
modified: new Set(),
|
|
133
|
-
deleted: new Set(),
|
|
134
|
-
earlyInverseDependencies: new Map(),
|
|
135
|
-
};
|
|
136
94
|
const internalOptions = getInternalOptions(options);
|
|
95
|
+
const modifiedPathsInBaseGraph = new Set(
|
|
96
|
+
paths.filter((path) => this.dependencies.has(path))
|
|
97
|
+
);
|
|
98
|
+
const allModifiedPaths = new Set(paths);
|
|
99
|
+
const delta = await this._buildDelta(
|
|
100
|
+
modifiedPathsInBaseGraph,
|
|
101
|
+
internalOptions,
|
|
102
|
+
// Traverse new or modified paths
|
|
103
|
+
(absolutePath) =>
|
|
104
|
+
!this.dependencies.has(absolutePath) ||
|
|
105
|
+
allModifiedPaths.has(absolutePath)
|
|
106
|
+
);
|
|
137
107
|
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
// that
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
108
|
+
// If we have errors we might need to roll back any changes - take
|
|
109
|
+
// snapshots of all modified modules at the base state. We'll also snapshot
|
|
110
|
+
// unmodified modules that become unreachable as they are released, so that
|
|
111
|
+
// we have everything we need to restore the graph to base.
|
|
112
|
+
if (delta.errors.size > 0) {
|
|
113
|
+
for (const modified of modifiedPathsInBaseGraph) {
|
|
114
|
+
delta.baseModuleData.set(
|
|
115
|
+
modified,
|
|
116
|
+
this._moduleSnapshot(nullthrows(this.dependencies.get(modified)))
|
|
117
|
+
);
|
|
147
118
|
}
|
|
148
119
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
//
|
|
156
|
-
if
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
delta,
|
|
160
|
-
internalOptions
|
|
161
|
-
);
|
|
120
|
+
|
|
121
|
+
// Commit changes in a subtractive pass and then an additive pass - this
|
|
122
|
+
// ensures that any errors encountered on the additive pass would also be
|
|
123
|
+
// encountered on a fresh build (implying legitimate errors in the graph,
|
|
124
|
+
// rather than an error in a module that's no longer reachable).
|
|
125
|
+
for (const modified of modifiedPathsInBaseGraph) {
|
|
126
|
+
// Skip this module if it has errors. Hopefully it will be removed -
|
|
127
|
+
// if not, we'll throw during the additive pass.
|
|
128
|
+
if (delta.errors.has(modified)) {
|
|
129
|
+
continue;
|
|
162
130
|
}
|
|
131
|
+
const module = this.dependencies.get(modified);
|
|
132
|
+
// The module may have already been released from the graph - we'll readd
|
|
133
|
+
// it if necessary later.
|
|
134
|
+
if (module == null) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
// Process the transform result and dependency removals. This should
|
|
138
|
+
// never encounter an error.
|
|
139
|
+
this._recursivelyCommitModule(modified, delta, internalOptions, {
|
|
140
|
+
onlyRemove: true,
|
|
141
|
+
});
|
|
163
142
|
}
|
|
143
|
+
|
|
144
|
+
// Ensure we have released any unreachable modules before the additive
|
|
145
|
+
// pass.
|
|
164
146
|
this._collectCycles(delta, internalOptions);
|
|
147
|
+
|
|
148
|
+
// Additive pass - any errors we encounter here should be thrown after
|
|
149
|
+
// rolling back the commit.
|
|
150
|
+
try {
|
|
151
|
+
for (const modified of modifiedPathsInBaseGraph) {
|
|
152
|
+
const module = this.dependencies.get(modified);
|
|
153
|
+
// The module may have already been released from the graph (it may yet
|
|
154
|
+
// be readded via another dependency).
|
|
155
|
+
if (module == null) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
this._recursivelyCommitModule(modified, delta, internalOptions);
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
// Roll back to base before re-throwing.
|
|
162
|
+
const rollbackDelta = {
|
|
163
|
+
added: delta.added,
|
|
164
|
+
deleted: delta.deleted,
|
|
165
|
+
touched: new Set(),
|
|
166
|
+
updatedModuleData: delta.baseModuleData,
|
|
167
|
+
baseModuleData: new Map(),
|
|
168
|
+
errors: new Map(),
|
|
169
|
+
};
|
|
170
|
+
for (const modified of modifiedPathsInBaseGraph) {
|
|
171
|
+
const module = this.dependencies.get(modified);
|
|
172
|
+
// The module may have already been released from the graph (it may yet
|
|
173
|
+
// be readded via another dependency).
|
|
174
|
+
if (module == null) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
// Set the module and descendants back to base state.
|
|
178
|
+
this._recursivelyCommitModule(modified, rollbackDelta, internalOptions);
|
|
179
|
+
}
|
|
180
|
+
// Collect cycles again after rolling back. There's no need if we're
|
|
181
|
+
// not rolling back, because we have not removed any edges.
|
|
182
|
+
this._collectCycles(delta, internalOptions);
|
|
183
|
+
|
|
184
|
+
// Cheap check to validate the rollback.
|
|
185
|
+
invariant(
|
|
186
|
+
rollbackDelta.added.size === 0 && rollbackDelta.deleted.size === 0,
|
|
187
|
+
"attempted to roll back a graph commit but there were still changes"
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// Re-throw the transform or resolution error originally seen by
|
|
191
|
+
// `buildSubgraph`.
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
165
194
|
const added = new Map();
|
|
166
195
|
for (const path of delta.added) {
|
|
167
196
|
added.set(path, nullthrows(this.dependencies.get(path)));
|
|
168
197
|
}
|
|
169
198
|
const modified = new Map();
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
!delta.added.has(path),
|
|
178
|
-
"delta.added has %s, but this path was already in the graph.",
|
|
179
|
-
path
|
|
180
|
-
);
|
|
181
|
-
if (delta.modified.has(path)) {
|
|
182
|
-
// It's expected that a module may be both modified and subsequently
|
|
183
|
-
// deleted - we'll only return it as deleted.
|
|
184
|
-
if (!delta.deleted.has(path)) {
|
|
185
|
-
// If a module existed before and has not been deleted, it must be
|
|
186
|
-
// in the dependencies map.
|
|
187
|
-
const newModule = nullthrows(this.dependencies.get(path));
|
|
188
|
-
if (
|
|
189
|
-
// Module.dependencies is mutable, so it's not obviously the case
|
|
190
|
-
// that referential equality implies no modification. However, we
|
|
191
|
-
// only mutate dependencies in two cases:
|
|
192
|
-
// 1. Within _processModule. In that case, we always mutate a new
|
|
193
|
-
// module and set a new reference in this.dependencies.
|
|
194
|
-
// 2. During _releaseModule, when recursively removing
|
|
195
|
-
// dependencies. In that case, we immediately discard the module
|
|
196
|
-
// object.
|
|
197
|
-
// TODO: Refactor for more explicit immutability
|
|
198
|
-
newModule !== originalModule ||
|
|
199
|
-
transfromOutputMayDiffer(newModule, originalModule) ||
|
|
200
|
-
// $FlowFixMe[incompatible-call]
|
|
201
|
-
!allDependenciesEqual(newModule, originalModule)
|
|
202
|
-
) {
|
|
203
|
-
modified.set(path, newModule);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
199
|
+
for (const path of modifiedPathsInBaseGraph) {
|
|
200
|
+
if (
|
|
201
|
+
delta.touched.has(path) &&
|
|
202
|
+
!delta.deleted.has(path) &&
|
|
203
|
+
!delta.added.has(path)
|
|
204
|
+
) {
|
|
205
|
+
modified.set(path, nullthrows(this.dependencies.get(path)));
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
return {
|
|
@@ -212,12 +212,6 @@ class Graph {
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
async initialTraverseDependencies(options) {
|
|
215
|
-
const delta = {
|
|
216
|
-
added: new Set(),
|
|
217
|
-
modified: new Set(),
|
|
218
|
-
deleted: new Set(),
|
|
219
|
-
earlyInverseDependencies: new Map(),
|
|
220
|
-
};
|
|
221
215
|
const internalOptions = getInternalOptions(options);
|
|
222
216
|
invariant(
|
|
223
217
|
this.dependencies.size === 0,
|
|
@@ -230,11 +224,18 @@ class Graph {
|
|
|
230
224
|
// Each entry point implicitly has a refcount of 1, so mark them all black.
|
|
231
225
|
this.#gc.color.set(path, "black");
|
|
232
226
|
}
|
|
233
|
-
await
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
227
|
+
const delta = await this._buildDelta(this.entryPoints, internalOptions);
|
|
228
|
+
if (delta.errors.size > 0) {
|
|
229
|
+
// If we encountered any errors during traversal, throw one of them.
|
|
230
|
+
// Since errors are encountered in a non-deterministic order, even on
|
|
231
|
+
// fresh builds, it's valid to arbitrarily pick the first.
|
|
232
|
+
throw delta.errors.values().next().value;
|
|
233
|
+
}
|
|
234
|
+
for (const path of this.entryPoints) {
|
|
235
|
+
// We have already thrown on userland errors in the delta, so any error
|
|
236
|
+
// encountered here would be exceptional and fatal.
|
|
237
|
+
this._recursivelyCommitModule(path, delta, internalOptions);
|
|
238
|
+
}
|
|
238
239
|
this.reorderGraph({
|
|
239
240
|
shallow: options.shallow,
|
|
240
241
|
});
|
|
@@ -244,44 +245,80 @@ class Graph {
|
|
|
244
245
|
deleted: new Set(),
|
|
245
246
|
};
|
|
246
247
|
}
|
|
247
|
-
async
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
248
|
+
async _buildDelta(pathsToVisit, options, moduleFilter) {
|
|
249
|
+
const subGraph = await (0, _buildSubgraph.buildSubgraph)(
|
|
250
|
+
pathsToVisit,
|
|
251
|
+
this.#resolvedContexts,
|
|
252
|
+
{
|
|
253
|
+
resolve: options.resolve,
|
|
254
|
+
transform: async (absolutePath, requireContext) => {
|
|
255
|
+
options.onDependencyAdd();
|
|
256
|
+
const result = await options.transform(absolutePath, requireContext);
|
|
257
|
+
options.onDependencyAdded();
|
|
258
|
+
return result;
|
|
259
|
+
},
|
|
260
|
+
shouldTraverse: (dependency) => {
|
|
261
|
+
if (options.shallow || isWeakOrLazy(dependency, options)) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
return moduleFilter == null || moduleFilter(dependency.absolutePath);
|
|
265
|
+
},
|
|
266
|
+
}
|
|
265
267
|
);
|
|
268
|
+
return {
|
|
269
|
+
added: new Set(),
|
|
270
|
+
touched: new Set(),
|
|
271
|
+
deleted: new Set(),
|
|
272
|
+
updatedModuleData: subGraph.moduleData,
|
|
273
|
+
baseModuleData: new Map(),
|
|
274
|
+
errors: subGraph.errors,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
_recursivelyCommitModule(
|
|
278
|
+
path,
|
|
279
|
+
delta,
|
|
280
|
+
options,
|
|
281
|
+
commitOptions = {
|
|
282
|
+
onlyRemove: false,
|
|
283
|
+
}
|
|
284
|
+
) {
|
|
285
|
+
if (delta.errors.has(path)) {
|
|
286
|
+
throw delta.errors.get(path);
|
|
287
|
+
}
|
|
266
288
|
const previousModule = this.dependencies.get(path);
|
|
289
|
+
const currentModule = nullthrows(
|
|
290
|
+
delta.updatedModuleData.get(path) ?? delta.baseModuleData.get(path)
|
|
291
|
+
);
|
|
267
292
|
const previousDependencies = previousModule?.dependencies ?? new Map();
|
|
293
|
+
const {
|
|
294
|
+
dependencies: currentDependencies,
|
|
295
|
+
resolvedContexts,
|
|
296
|
+
...transformResult
|
|
297
|
+
} = currentModule;
|
|
268
298
|
const nextModule = {
|
|
269
299
|
...(previousModule ?? {
|
|
270
|
-
inverseDependencies:
|
|
271
|
-
delta.earlyInverseDependencies.get(path) ??
|
|
272
|
-
new _CountingSet.default(),
|
|
300
|
+
inverseDependencies: new _CountingSet.default(),
|
|
273
301
|
path,
|
|
274
302
|
}),
|
|
303
|
+
...transformResult,
|
|
275
304
|
dependencies: new Map(previousDependencies),
|
|
276
|
-
getSource: result.getSource,
|
|
277
|
-
output: result.output,
|
|
278
|
-
unstable_transformResultKey: result.unstable_transformResultKey,
|
|
279
305
|
};
|
|
280
306
|
|
|
281
307
|
// Update the module information.
|
|
282
308
|
this.dependencies.set(nextModule.path, nextModule);
|
|
309
|
+
if (previousModule == null) {
|
|
310
|
+
// If the module is not currently in the graph, it is either new or was
|
|
311
|
+
// released earlier in the commit.
|
|
312
|
+
if (delta.deleted.has(path)) {
|
|
313
|
+
// Mark the addition by clearing a prior deletion.
|
|
314
|
+
delta.deleted.delete(path);
|
|
315
|
+
} else {
|
|
316
|
+
// Mark the addition in the added set.
|
|
317
|
+
delta.added.add(path);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
283
320
|
|
|
284
|
-
// Diff dependencies (1/
|
|
321
|
+
// Diff dependencies (1/3): remove dependencies that have changed or been removed.
|
|
285
322
|
let dependenciesRemoved = false;
|
|
286
323
|
for (const [key, prevDependency] of previousDependencies) {
|
|
287
324
|
const curDependency = currentDependencies.get(key);
|
|
@@ -294,48 +331,77 @@ class Graph {
|
|
|
294
331
|
}
|
|
295
332
|
}
|
|
296
333
|
|
|
297
|
-
// Diff dependencies (2/
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
334
|
+
// Diff dependencies (2/3): add dependencies that have changed or been added.
|
|
335
|
+
let dependenciesAdded = false;
|
|
336
|
+
if (!commitOptions.onlyRemove) {
|
|
337
|
+
for (const [key, curDependency] of currentDependencies) {
|
|
338
|
+
const prevDependency = previousDependencies.get(key);
|
|
339
|
+
if (
|
|
340
|
+
!prevDependency ||
|
|
341
|
+
!dependenciesEqual(prevDependency, curDependency, options)
|
|
342
|
+
) {
|
|
343
|
+
dependenciesAdded = true;
|
|
344
|
+
this._addDependency(
|
|
345
|
+
nextModule,
|
|
346
|
+
key,
|
|
347
|
+
curDependency,
|
|
348
|
+
resolvedContexts.get(key),
|
|
349
|
+
delta,
|
|
350
|
+
options
|
|
351
|
+
);
|
|
352
|
+
}
|
|
308
353
|
}
|
|
309
354
|
}
|
|
355
|
+
|
|
356
|
+
// Diff dependencies (3/3): detect changes in the ordering of dependency
|
|
357
|
+
// keys, which must be committed even if no other changes were made.
|
|
358
|
+
const previousDependencyKeys = [...previousDependencies.keys()];
|
|
359
|
+
const dependencyKeysChangedOrReordered =
|
|
360
|
+
currentDependencies.size !== previousDependencies.size ||
|
|
361
|
+
[...currentDependencies.keys()].some(
|
|
362
|
+
(currentKey, index) => currentKey !== previousDependencyKeys[index]
|
|
363
|
+
);
|
|
310
364
|
if (
|
|
311
|
-
previousModule &&
|
|
312
|
-
!
|
|
365
|
+
previousModule != null &&
|
|
366
|
+
!transformOutputMayDiffer(previousModule, nextModule) &&
|
|
313
367
|
!dependenciesRemoved &&
|
|
314
|
-
|
|
368
|
+
!dependenciesAdded &&
|
|
369
|
+
!dependencyKeysChangedOrReordered
|
|
315
370
|
) {
|
|
316
371
|
// We have not operated on nextModule, so restore previousModule
|
|
317
|
-
// to aid diffing.
|
|
372
|
+
// to aid diffing. Don't add this path to delta.touched.
|
|
318
373
|
this.dependencies.set(previousModule.path, previousModule);
|
|
319
374
|
return previousModule;
|
|
320
375
|
}
|
|
321
|
-
delta.
|
|
322
|
-
await Promise.all(addDependencyPromises);
|
|
376
|
+
delta.touched.add(path);
|
|
323
377
|
|
|
324
|
-
// Replace dependencies with the correctly-ordered version
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
//
|
|
378
|
+
// Replace dependencies with the correctly-ordered version, matching the
|
|
379
|
+
// transform output. Because this assignment does not add or remove edges,
|
|
380
|
+
// it does NOT invalidate any of the garbage collection state.
|
|
381
|
+
|
|
382
|
+
// A subtractive pass only partially commits modules, so our dependencies
|
|
383
|
+
// are not generally complete yet. We'll address ordering in the next pass
|
|
384
|
+
// after processing additions.
|
|
385
|
+
if (commitOptions.onlyRemove) {
|
|
386
|
+
return nextModule;
|
|
387
|
+
}
|
|
329
388
|
|
|
330
389
|
// Catch obvious errors with a cheap assertion.
|
|
331
390
|
invariant(
|
|
332
391
|
nextModule.dependencies.size === currentDependencies.size,
|
|
333
392
|
"Failed to add the correct dependencies"
|
|
334
393
|
);
|
|
335
|
-
nextModule.dependencies = currentDependencies;
|
|
394
|
+
nextModule.dependencies = new Map(currentDependencies);
|
|
336
395
|
return nextModule;
|
|
337
396
|
}
|
|
338
|
-
|
|
397
|
+
_addDependency(
|
|
398
|
+
parentModule,
|
|
399
|
+
key,
|
|
400
|
+
dependency,
|
|
401
|
+
requireContext,
|
|
402
|
+
delta,
|
|
403
|
+
options
|
|
404
|
+
) {
|
|
339
405
|
const path = dependency.absolutePath;
|
|
340
406
|
|
|
341
407
|
// The module may already exist, in which case we just need to update some
|
|
@@ -352,36 +418,37 @@ class Graph {
|
|
|
352
418
|
this._incrementImportBundleReference(dependency, parentModule);
|
|
353
419
|
} else {
|
|
354
420
|
if (!module) {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
delta.added.add(path);
|
|
421
|
+
try {
|
|
422
|
+
module = this._recursivelyCommitModule(path, delta, options);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
// If we couldn't add this module but it was added to the graph
|
|
425
|
+
// before failing on a sub-dependency, it may be orphaned. Mark it as
|
|
426
|
+
// a possible garbage root.
|
|
427
|
+
const module = this.dependencies.get(path);
|
|
428
|
+
if (module) {
|
|
429
|
+
if (module.inverseDependencies.size > 0) {
|
|
430
|
+
this._markAsPossibleCycleRoot(module);
|
|
431
|
+
} else {
|
|
432
|
+
this._releaseModule(module, delta, options);
|
|
433
|
+
}
|
|
369
434
|
}
|
|
370
|
-
|
|
371
|
-
options.onDependencyAdd();
|
|
372
|
-
module = await this._processModule(path, delta, options);
|
|
373
|
-
options.onDependencyAdded();
|
|
374
|
-
this.dependencies.set(module.path, module);
|
|
435
|
+
throw error;
|
|
375
436
|
}
|
|
376
437
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
438
|
+
|
|
439
|
+
// We either added a new node to the graph, or we're updating an existing one.
|
|
440
|
+
module.inverseDependencies.add(parentModule.path);
|
|
441
|
+
this._markModuleInUse(module);
|
|
442
|
+
}
|
|
443
|
+
if (requireContext) {
|
|
444
|
+
this.#resolvedContexts.set(path, requireContext);
|
|
445
|
+
} else {
|
|
446
|
+
// This dependency may have existed previously as a require.context -
|
|
447
|
+
// clean it up.
|
|
448
|
+
this.#resolvedContexts.delete(path);
|
|
382
449
|
}
|
|
383
450
|
|
|
384
|
-
//
|
|
451
|
+
// Update the parent's dependency map unless we failed to add a dependency.
|
|
385
452
|
// This means the parent's dependencies can get desynced from
|
|
386
453
|
// inverseDependencies and the other fields in the case of lazy edges.
|
|
387
454
|
// Not an optimal representation :(
|
|
@@ -441,74 +508,6 @@ class Graph {
|
|
|
441
508
|
yield* this.dependencies.get(filePath)?.inverseDependencies ?? [];
|
|
442
509
|
yield* this.#importBundleNodes.get(filePath)?.inverseDependencies ?? [];
|
|
443
510
|
}
|
|
444
|
-
_resolveDependencies(parentPath, dependencies, options) {
|
|
445
|
-
const maybeResolvedDeps = new Map();
|
|
446
|
-
for (const dep of dependencies) {
|
|
447
|
-
let resolvedDep;
|
|
448
|
-
|
|
449
|
-
// `require.context`
|
|
450
|
-
const { contextParams } = dep.data;
|
|
451
|
-
if (contextParams) {
|
|
452
|
-
// Ensure the filepath has uniqueness applied to ensure multiple `require.context`
|
|
453
|
-
// statements can be used to target the same file with different properties.
|
|
454
|
-
const from = path.join(parentPath, "..", dep.name);
|
|
455
|
-
const absolutePath = (0, _contextModule.deriveAbsolutePathFromContext)(
|
|
456
|
-
from,
|
|
457
|
-
contextParams
|
|
458
|
-
);
|
|
459
|
-
const resolvedContext = {
|
|
460
|
-
from,
|
|
461
|
-
mode: contextParams.mode,
|
|
462
|
-
recursive: contextParams.recursive,
|
|
463
|
-
filter: new RegExp(
|
|
464
|
-
contextParams.filter.pattern,
|
|
465
|
-
contextParams.filter.flags
|
|
466
|
-
),
|
|
467
|
-
};
|
|
468
|
-
this.#resolvedContexts.set(absolutePath, resolvedContext);
|
|
469
|
-
resolvedDep = {
|
|
470
|
-
absolutePath,
|
|
471
|
-
data: dep,
|
|
472
|
-
};
|
|
473
|
-
} else {
|
|
474
|
-
try {
|
|
475
|
-
resolvedDep = {
|
|
476
|
-
absolutePath: options.resolve(parentPath, dep).filePath,
|
|
477
|
-
data: dep,
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
// This dependency may have existed previously as a require.context -
|
|
481
|
-
// clean it up.
|
|
482
|
-
this.#resolvedContexts.delete(resolvedDep.absolutePath);
|
|
483
|
-
} catch (error) {
|
|
484
|
-
// Ignore unavailable optional dependencies. They are guarded
|
|
485
|
-
// with a try-catch block and will be handled during runtime.
|
|
486
|
-
if (dep.data.isOptional !== true) {
|
|
487
|
-
throw error;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
const key = dep.data.key;
|
|
492
|
-
if (maybeResolvedDeps.has(key)) {
|
|
493
|
-
throw new Error(
|
|
494
|
-
`resolveDependencies: Found duplicate dependency key '${key}' in ${parentPath}`
|
|
495
|
-
);
|
|
496
|
-
}
|
|
497
|
-
maybeResolvedDeps.set(key, resolvedDep);
|
|
498
|
-
}
|
|
499
|
-
const resolvedDeps = new Map();
|
|
500
|
-
// Return just the dependencies we successfully resolved.
|
|
501
|
-
// FIXME: This has a bad bug affecting all dependencies *after* an unresolved
|
|
502
|
-
// optional dependency. We'll need to propagate the nulls all the way to the
|
|
503
|
-
// serializer and the require() runtime to keep the dependency map from being
|
|
504
|
-
// desynced from the contents of the module.
|
|
505
|
-
for (const [key, resolvedDep] of maybeResolvedDeps) {
|
|
506
|
-
if (resolvedDep) {
|
|
507
|
-
resolvedDeps.set(key, resolvedDep);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
return resolvedDeps;
|
|
511
|
-
}
|
|
512
511
|
|
|
513
512
|
/**
|
|
514
513
|
* Re-traverse the dependency graph in DFS order to reorder the modules and
|
|
@@ -588,18 +587,47 @@ class Graph {
|
|
|
588
587
|
// dependencies having a corresponding inverse dependency.
|
|
589
588
|
*_children(module, options) {
|
|
590
589
|
for (const dependency of module.dependencies.values()) {
|
|
591
|
-
|
|
592
|
-
if (asyncType === "weak" || (options.lazy && asyncType != null)) {
|
|
590
|
+
if (isWeakOrLazy(dependency, options)) {
|
|
593
591
|
continue;
|
|
594
592
|
}
|
|
595
593
|
yield nullthrows(this.dependencies.get(dependency.absolutePath));
|
|
596
594
|
}
|
|
597
595
|
}
|
|
596
|
+
_moduleSnapshot(module) {
|
|
597
|
+
const { dependencies, getSource, output, unstable_transformResultKey } =
|
|
598
|
+
module;
|
|
599
|
+
const resolvedContexts = new Map();
|
|
600
|
+
for (const [key, dependency] of dependencies) {
|
|
601
|
+
const resolvedContext = this.#resolvedContexts.get(
|
|
602
|
+
dependency.absolutePath
|
|
603
|
+
);
|
|
604
|
+
if (resolvedContext != null) {
|
|
605
|
+
resolvedContexts.set(key, resolvedContext);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
dependencies: new Map(dependencies),
|
|
610
|
+
resolvedContexts,
|
|
611
|
+
getSource,
|
|
612
|
+
output,
|
|
613
|
+
unstable_transformResultKey,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
598
616
|
|
|
599
617
|
// Delete an unreachable module (and its outbound edges) from the graph
|
|
600
618
|
// immediately.
|
|
601
619
|
// Called when the reference count of a module has reached 0.
|
|
602
620
|
_releaseModule(module, delta, options) {
|
|
621
|
+
if (
|
|
622
|
+
!delta.updatedModuleData.has(module.path) &&
|
|
623
|
+
!delta.baseModuleData.has(module.path)
|
|
624
|
+
) {
|
|
625
|
+
// Before releasing a module, take a snapshot of the data we might need
|
|
626
|
+
// to reintroduce it to the graph later in this commit. As it is not
|
|
627
|
+
// already present in updatedModuleData we can infer it has not been modified,
|
|
628
|
+
// so the transform output and dependencies we copy here are current.
|
|
629
|
+
delta.baseModuleData.set(module.path, this._moduleSnapshot(module));
|
|
630
|
+
}
|
|
603
631
|
for (const [key, dependency] of module.dependencies) {
|
|
604
632
|
this._removeDependency(module, key, dependency, delta, options);
|
|
605
633
|
}
|
|
@@ -621,7 +649,6 @@ class Graph {
|
|
|
621
649
|
// Clean up all the state associated with this module in order to correctly
|
|
622
650
|
// re-add it if we encounter it again.
|
|
623
651
|
this.dependencies.delete(module.path);
|
|
624
|
-
delta.earlyInverseDependencies.delete(module.path);
|
|
625
652
|
this.#gc.possibleCycleRoots.delete(module.path);
|
|
626
653
|
this.#gc.color.delete(module.path);
|
|
627
654
|
this.#resolvedContexts.delete(module.path);
|
|
@@ -629,7 +656,7 @@ class Graph {
|
|
|
629
656
|
|
|
630
657
|
// Mark a module as a possible cycle root
|
|
631
658
|
_markAsPossibleCycleRoot(module) {
|
|
632
|
-
if (
|
|
659
|
+
if (this.#gc.color.get(module.path) !== "purple") {
|
|
633
660
|
this.#gc.color.set(module.path, "purple");
|
|
634
661
|
this.#gc.possibleCycleRoots.add(module.path);
|
|
635
662
|
}
|
|
@@ -730,18 +757,6 @@ function dependenciesEqual(a, b, options) {
|
|
|
730
757
|
contextParamsEqual(a.data.data.contextParams, b.data.data.contextParams))
|
|
731
758
|
);
|
|
732
759
|
}
|
|
733
|
-
function allDependenciesEqual(a, b, options) {
|
|
734
|
-
if (a.dependencies.size !== b.dependencies.size) {
|
|
735
|
-
return false;
|
|
736
|
-
}
|
|
737
|
-
for (const [key, depA] of a.dependencies) {
|
|
738
|
-
const depB = b.dependencies.get(key);
|
|
739
|
-
if (!depB || !dependenciesEqual(depA, depB, options)) {
|
|
740
|
-
return false;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
return true;
|
|
744
|
-
}
|
|
745
760
|
function contextParamsEqual(a, b) {
|
|
746
761
|
return (
|
|
747
762
|
a === b ||
|
|
@@ -754,7 +769,7 @@ function contextParamsEqual(a, b) {
|
|
|
754
769
|
a.mode === b.mode)
|
|
755
770
|
);
|
|
756
771
|
}
|
|
757
|
-
function
|
|
772
|
+
function transformOutputMayDiffer(a, b) {
|
|
758
773
|
return (
|
|
759
774
|
a.unstable_transformResultKey == null ||
|
|
760
775
|
a.unstable_transformResultKey !== b.unstable_transformResultKey
|