metro 0.71.2 → 0.72.1

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.
Files changed (91) hide show
  1. package/package.json +21 -21
  2. package/src/Assets.js +3 -2
  3. package/src/Assets.js.flow +3 -2
  4. package/src/Bundler.js +11 -2
  5. package/src/Bundler.js.flow +7 -1
  6. package/src/DeltaBundler/DeltaCalculator.js +85 -21
  7. package/src/DeltaBundler/DeltaCalculator.js.flow +63 -8
  8. package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +1 -3
  9. package/src/DeltaBundler/Transformer.js +27 -4
  10. package/src/DeltaBundler/Transformer.js.flow +18 -2
  11. package/src/DeltaBundler/Worker.flow.js +45 -1
  12. package/src/DeltaBundler/Worker.flow.js.flow +42 -1
  13. package/src/DeltaBundler/WorkerFarm.js +3 -2
  14. package/src/DeltaBundler/WorkerFarm.js.flow +5 -3
  15. package/src/DeltaBundler/graphOperations.js +170 -63
  16. package/src/DeltaBundler/graphOperations.js.flow +144 -64
  17. package/src/DeltaBundler/types.flow.js.flow +11 -5
  18. package/src/HmrServer.js +2 -0
  19. package/src/HmrServer.js.flow +2 -0
  20. package/src/IncrementalBundler.js +6 -0
  21. package/src/IncrementalBundler.js.flow +6 -0
  22. package/src/ModuleGraph/node-haste/HasteFS.js.flow +1 -1
  23. package/src/ModuleGraph/node-haste/node-haste.js +14 -7
  24. package/src/ModuleGraph/node-haste/node-haste.js.flow +35 -10
  25. package/src/ModuleGraph/output/indexed-ram-bundle.js.flow +5 -13
  26. package/src/ModuleGraph/output/multiple-files-ram-bundle.js.flow +4 -14
  27. package/src/ModuleGraph/output/util.js +1 -0
  28. package/src/ModuleGraph/output/util.js.flow +4 -3
  29. package/src/ModuleGraph/silent-console.js +5 -4
  30. package/src/ModuleGraph/silent-console.js.flow +8 -4
  31. package/src/ModuleGraph/worker/collectDependencies.js +19 -30
  32. package/src/ModuleGraph/worker/collectDependencies.js.flow +28 -43
  33. package/src/Server.js +8 -0
  34. package/src/Server.js.flow +48 -12
  35. package/src/cli-utils.js.flow +1 -1
  36. package/src/commands/build.js +1 -2
  37. package/src/commands/build.js.flow +6 -9
  38. package/src/commands/dependencies.js +1 -1
  39. package/src/commands/serve.js +2 -1
  40. package/src/commands/serve.js.flow +7 -8
  41. package/src/index.flow.js +11 -8
  42. package/src/index.flow.js.flow +10 -7
  43. package/src/integration_tests/basic_bundle/require-context/conflict.js +25 -0
  44. package/src/integration_tests/basic_bundle/require-context/conflict.js.flow +27 -0
  45. package/src/integration_tests/basic_bundle/require-context/empty.js +29 -0
  46. package/src/integration_tests/basic_bundle/require-context/empty.js.flow +26 -0
  47. package/src/integration_tests/basic_bundle/require-context/matching.js +26 -0
  48. package/src/integration_tests/basic_bundle/require-context/matching.js.flow +27 -0
  49. package/src/integration_tests/basic_bundle/require-context/mode-eager.js +22 -0
  50. package/src/integration_tests/basic_bundle/require-context/mode-eager.js.flow +24 -0
  51. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js +22 -0
  52. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js.flow +24 -0
  53. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js +22 -0
  54. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js.flow +24 -0
  55. package/src/integration_tests/basic_bundle/require-context/mode-sync.js +20 -0
  56. package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +22 -0
  57. package/src/integration_tests/basic_bundle/require-context/subdir/a.js +12 -0
  58. package/src/integration_tests/basic_bundle/require-context/subdir/a.js.flow +11 -0
  59. package/src/integration_tests/basic_bundle/require-context/subdir/b.js +18 -0
  60. package/src/integration_tests/basic_bundle/require-context/subdir/b.js.flow +11 -0
  61. package/src/integration_tests/basic_bundle/require-context/subdir/c.js +12 -0
  62. package/src/integration_tests/basic_bundle/require-context/subdir/c.js.flow +11 -0
  63. package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js +12 -0
  64. package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js.flow +11 -0
  65. package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js +12 -0
  66. package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js.flow +11 -0
  67. package/src/integration_tests/basic_bundle/require-context/utils.js +29 -0
  68. package/src/integration_tests/basic_bundle/require-context/utils.js.flow +44 -0
  69. package/src/lib/CountingSet.js +1 -0
  70. package/src/lib/CountingSet.js.flow +1 -0
  71. package/src/lib/contextModule.js +80 -0
  72. package/src/lib/contextModule.js.flow +86 -0
  73. package/src/lib/contextModuleTemplates.js +186 -0
  74. package/src/lib/contextModuleTemplates.js.flow +148 -0
  75. package/src/lib/getGraphId.js +2 -1
  76. package/src/lib/getGraphId.js.flow +3 -0
  77. package/src/lib/getPrependedScripts.js +2 -0
  78. package/src/lib/getPrependedScripts.js.flow +2 -0
  79. package/src/lib/parseOptionsFromUrl.js.flow +7 -18
  80. package/src/lib/transformHelpers.js +41 -9
  81. package/src/lib/transformHelpers.js.flow +46 -9
  82. package/src/node-haste/DependencyGraph/ModuleResolution.js +1 -0
  83. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +3 -2
  84. package/src/node-haste/DependencyGraph/createHasteMap.js +7 -1
  85. package/src/node-haste/DependencyGraph/createHasteMap.js.flow +8 -2
  86. package/src/node-haste/DependencyGraph.js +7 -0
  87. package/src/node-haste/DependencyGraph.js.flow +17 -2
  88. package/src/shared/output/bundle.flow.js +67 -0
  89. package/src/shared/output/bundle.flow.js.flow +89 -0
  90. package/src/shared/output/bundle.js +8 -55
  91. package/src/shared/output/bundle.js.flow +8 -75
@@ -51,11 +51,53 @@ type Data = $ReadOnly<{
51
51
  transformFileEndLogEntry: LogEntry,
52
52
  }>;
53
53
 
54
+ /**
55
+ * When the `Buffer` is sent over the worker thread it gets serialized into a JSON object.
56
+ * This helper method will deserialize it if needed.
57
+ *
58
+ * @returns `Buffer` representation of the JSON object.
59
+ * @returns `null` if the given object is nullish or not a serialized `Buffer` object.
60
+ */
61
+ function asDeserializedBuffer(value: any): Buffer | null {
62
+ if (Buffer.isBuffer(value)) {
63
+ return value;
64
+ }
65
+ if (value && value.type === 'Buffer') {
66
+ return Buffer.from(value.data);
67
+ }
68
+ return null;
69
+ }
70
+
54
71
  async function transform(
55
72
  filename: string,
56
73
  transformOptions: JsTransformOptions,
57
74
  projectRoot: string,
58
75
  transformerConfig: TransformerConfig,
76
+ fileBuffer?: Buffer,
77
+ ): Promise<Data> {
78
+ let data;
79
+
80
+ const fileBufferObject = asDeserializedBuffer(fileBuffer);
81
+ if (fileBufferObject) {
82
+ data = fileBufferObject;
83
+ } else {
84
+ data = fs.readFileSync(path.resolve(projectRoot, filename));
85
+ }
86
+ return transformFile(
87
+ filename,
88
+ data,
89
+ transformOptions,
90
+ projectRoot,
91
+ transformerConfig,
92
+ );
93
+ }
94
+
95
+ async function transformFile(
96
+ filename: string,
97
+ data: Buffer,
98
+ transformOptions: JsTransformOptions,
99
+ projectRoot: string,
100
+ transformerConfig: TransformerConfig,
59
101
  ): Promise<Data> {
60
102
  // eslint-disable-next-line no-useless-call
61
103
  const Transformer = (require.call(
@@ -71,7 +113,6 @@ async function transform(
71
113
  start_timestamp: process.hrtime(),
72
114
  };
73
115
 
74
- const data = fs.readFileSync(path.resolve(projectRoot, filename));
75
116
  const sha1 = crypto.createHash('sha1').update(data).digest('hex');
76
117
 
77
118
  const result = await Transformer.transform(
@@ -50,13 +50,14 @@ class WorkerFarm {
50
50
  }
51
51
  }
52
52
 
53
- async transform(filename, options) {
53
+ async transform(filename, options, fileBuffer) {
54
54
  try {
55
55
  const data = await this._worker.transform(
56
56
  filename,
57
57
  options,
58
58
  this._config.projectRoot,
59
- this._transformerConfig
59
+ this._transformerConfig,
60
+ fileBuffer
60
61
  );
61
62
  Logger.log(data.transformFileStartLogEntry);
62
63
  Logger.log(data.transformFileEndLogEntry);
@@ -78,6 +78,7 @@ class WorkerFarm {
78
78
  async transform(
79
79
  filename: string,
80
80
  options: TransformOptions,
81
+ fileBuffer?: Buffer,
81
82
  ): Promise<TransformerResult> {
82
83
  try {
83
84
  const data = await this._worker.transform(
@@ -85,6 +86,7 @@ class WorkerFarm {
85
86
  options,
86
87
  this._config.projectRoot,
87
88
  this._transformerConfig,
89
+ fileBuffer,
88
90
  );
89
91
 
90
92
  Logger.log(data.transformFileStartLogEntry);
@@ -107,7 +109,7 @@ class WorkerFarm {
107
109
  workerPath: string,
108
110
  exposedMethods: $ReadOnlyArray<string>,
109
111
  numWorkers: number,
110
- ) {
112
+ ): any {
111
113
  const env = {
112
114
  ...process.env,
113
115
  // Force color to print syntax highlighted code frames.
@@ -136,7 +138,7 @@ class WorkerFarm {
136
138
  return null;
137
139
  }
138
140
 
139
- _formatGenericError(err, filename: string): TransformError {
141
+ _formatGenericError(err: any, filename: string): TransformError {
140
142
  const error = new TransformError(`${filename}: ${err.message}`);
141
143
 
142
144
  return Object.assign(error, {
@@ -145,7 +147,7 @@ class WorkerFarm {
145
147
  });
146
148
  }
147
149
 
148
- _formatBabelError(err, filename: string): TransformError {
150
+ _formatBabelError(err: any, filename: string): TransformError {
149
151
  const error = new TransformError(
150
152
  `${err.type || 'Error'}${
151
153
  err.message.includes(filename) ? '' : ' in ' + filename
@@ -31,6 +31,52 @@
31
31
 
32
32
  var _CountingSet = _interopRequireDefault(require("../lib/CountingSet"));
33
33
 
34
+ var _contextModule = require("../lib/contextModule");
35
+
36
+ var path = _interopRequireWildcard(require("path"));
37
+
38
+ function _getRequireWildcardCache(nodeInterop) {
39
+ if (typeof WeakMap !== "function") return null;
40
+ var cacheBabelInterop = new WeakMap();
41
+ var cacheNodeInterop = new WeakMap();
42
+ return (_getRequireWildcardCache = function (nodeInterop) {
43
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
44
+ })(nodeInterop);
45
+ }
46
+
47
+ function _interopRequireWildcard(obj, nodeInterop) {
48
+ if (!nodeInterop && obj && obj.__esModule) {
49
+ return obj;
50
+ }
51
+ if (obj === null || (typeof obj !== "object" && typeof obj !== "function")) {
52
+ return { default: obj };
53
+ }
54
+ var cache = _getRequireWildcardCache(nodeInterop);
55
+ if (cache && cache.has(obj)) {
56
+ return cache.get(obj);
57
+ }
58
+ var newObj = {};
59
+ var hasPropertyDescriptor =
60
+ Object.defineProperty && Object.getOwnPropertyDescriptor;
61
+ for (var key in obj) {
62
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
63
+ var desc = hasPropertyDescriptor
64
+ ? Object.getOwnPropertyDescriptor(obj, key)
65
+ : null;
66
+ if (desc && (desc.get || desc.set)) {
67
+ Object.defineProperty(newObj, key, desc);
68
+ } else {
69
+ newObj[key] = obj[key];
70
+ }
71
+ }
72
+ }
73
+ newObj.default = obj;
74
+ if (cache) {
75
+ cache.set(obj, newObj);
76
+ }
77
+ return newObj;
78
+ }
79
+
34
80
  function _interopRequireDefault(obj) {
35
81
  return obj && obj.__esModule ? obj : { default: obj };
36
82
  }
@@ -45,6 +91,7 @@ function createGraph(options) {
45
91
  dependencies: new Map(),
46
92
  importBundleNames: new Set(),
47
93
  privateState: {
94
+ resolvedContexts: new Map(),
48
95
  gc: {
49
96
  color: new Map(),
50
97
  possibleCycleRoots: new Set(),
@@ -78,7 +125,7 @@ function getInternalOptions({
78
125
  * dependency graph.
79
126
  * Instead of traversing the whole graph each time, it just calculates the
80
127
  * difference between runs by only traversing the added/removed dependencies.
81
- * To do so, it uses the passed passed graph dependencies and it mutates it.
128
+ * To do so, it uses the passed graph dependencies and it mutates it.
82
129
  * The paths parameter contains the absolute paths of the root files that the
83
130
  * method should traverse. Normally, these paths should be the modified files
84
131
  * since the last traversal.
@@ -176,12 +223,14 @@ async function traverseDependenciesForSingleFile(path, graph, delta, options) {
176
223
  }
177
224
 
178
225
  async function processModule(path, graph, delta, options) {
179
- // Transform the file via the given option.
226
+ const resolvedContext = graph.privateState.resolvedContexts.get(path); // Transform the file via the given option.
180
227
  // TODO: Unbind the transform method from options
181
- const result = await options.transform(path); // Get the absolute path of all sub-dependencies (some of them could have been
228
+
229
+ const result = await options.transform(path, resolvedContext); // Get the absolute path of all sub-dependencies (some of them could have been
182
230
  // moved but maintain the same relative path).
183
231
 
184
232
  const currentDependencies = resolveDependencies(
233
+ graph,
185
234
  path,
186
235
  result.dependencies,
187
236
  options
@@ -201,48 +250,28 @@ async function processModule(path, graph, delta, options) {
201
250
  };
202
251
  graph.dependencies.set(module.path, module); // Diff dependencies (1/2): remove dependencies that have changed or been removed.
203
252
 
204
- for (const [relativePath, prevDependency] of previousDependencies) {
205
- const curDependency = currentDependencies.get(relativePath);
253
+ for (const [key, prevDependency] of previousDependencies) {
254
+ const curDependency = currentDependencies.get(key);
206
255
 
207
256
  if (
208
257
  !curDependency ||
209
- curDependency.absolutePath !== prevDependency.absolutePath ||
210
- (options.experimentalImportBundleSupport &&
211
- curDependency.data.data.asyncType !==
212
- prevDependency.data.data.asyncType)
258
+ !dependenciesEqual(prevDependency, curDependency, options)
213
259
  ) {
214
- removeDependency(
215
- module,
216
- relativePath,
217
- prevDependency,
218
- graph,
219
- delta,
220
- options
221
- );
260
+ removeDependency(module, key, prevDependency, graph, delta, options);
222
261
  }
223
262
  } // Diff dependencies (2/2): add dependencies that have changed or been added.
224
263
 
225
264
  const promises = [];
226
265
 
227
- for (const [relativePath, curDependency] of currentDependencies) {
228
- const prevDependency = previousDependencies.get(relativePath);
266
+ for (const [key, curDependency] of currentDependencies) {
267
+ const prevDependency = previousDependencies.get(key);
229
268
 
230
269
  if (
231
270
  !prevDependency ||
232
- prevDependency.absolutePath !== curDependency.absolutePath ||
233
- (options.experimentalImportBundleSupport &&
234
- prevDependency.data.data.asyncType !==
235
- curDependency.data.data.asyncType)
271
+ !dependenciesEqual(prevDependency, curDependency, options)
236
272
  ) {
237
273
  promises.push(
238
- addDependency(
239
- module,
240
- relativePath,
241
- curDependency,
242
- graph,
243
- delta,
244
- options
245
- )
274
+ addDependency(module, key, curDependency, graph, delta, options)
246
275
  );
247
276
  }
248
277
  }
@@ -263,9 +292,32 @@ async function processModule(path, graph, delta, options) {
263
292
  return module;
264
293
  }
265
294
 
295
+ function dependenciesEqual(a, b, options) {
296
+ return (
297
+ a === b ||
298
+ (a.absolutePath === b.absolutePath &&
299
+ (!options.experimentalImportBundleSupport ||
300
+ a.data.data.asyncType === b.data.data.asyncType) &&
301
+ contextParamsEqual(a.data.data.contextParams, b.data.data.contextParams))
302
+ );
303
+ }
304
+
305
+ function contextParamsEqual(a, b) {
306
+ return (
307
+ a === b ||
308
+ (a == null && b == null) ||
309
+ (a != null &&
310
+ b != null &&
311
+ a.recursive === b.recursive &&
312
+ a.filter.pattern === b.filter.pattern &&
313
+ a.filter.flags === b.filter.flags &&
314
+ a.mode === b.mode)
315
+ );
316
+ }
317
+
266
318
  async function addDependency(
267
319
  parentModule,
268
- relativePath,
320
+ key,
269
321
  dependency,
270
322
  graph,
271
323
  delta,
@@ -323,18 +375,18 @@ async function addDependency(
323
375
  // inverseDependencies and the other fields in the case of lazy edges.
324
376
  // Not an optimal representation :(
325
377
 
326
- parentModule.dependencies.set(relativePath, dependency);
378
+ parentModule.dependencies.set(key, dependency);
327
379
  }
328
380
 
329
381
  function removeDependency(
330
382
  parentModule,
331
- relativePath,
383
+ key,
332
384
  dependency,
333
385
  graph,
334
386
  delta,
335
387
  options
336
388
  ) {
337
- parentModule.dependencies.delete(relativePath);
389
+ parentModule.dependencies.delete(key);
338
390
  const { absolutePath } = dependency;
339
391
 
340
392
  if (
@@ -364,40 +416,93 @@ function removeDependency(
364
416
  releaseModule(module, graph, delta, options);
365
417
  }
366
418
  }
419
+ /**
420
+ * Collect a list of context modules which include a given file.
421
+ */
422
+
423
+ function markModifiedContextModules(graph, filePath, modifiedPaths) {
424
+ for (const [absolutePath, context] of graph.privateState.resolvedContexts) {
425
+ if (
426
+ !modifiedPaths.has(absolutePath) &&
427
+ (0, _contextModule.fileMatchesContext)(filePath, context)
428
+ ) {
429
+ modifiedPaths.add(absolutePath);
430
+ }
431
+ }
432
+ }
433
+
434
+ function resolveDependencies(graph, parentPath, dependencies, options) {
435
+ const maybeResolvedDeps = new Map();
436
+
437
+ for (const dep of dependencies) {
438
+ let resolvedDep; // `require.context`
367
439
 
368
- function resolveDependencies(parentPath, dependencies, options) {
369
- const resolve = (parentPath, result) => {
370
- const relativePath = result.name;
371
-
372
- try {
373
- return [
374
- relativePath,
375
- {
376
- absolutePath: options.resolve(parentPath, relativePath),
377
- data: result,
378
- },
379
- ];
380
- } catch (error) {
381
- // Ignore unavailable optional dependencies. They are guarded
382
- // with a try-catch block and will be handled during runtime.
383
- if (result.data.isOptional !== true) {
384
- throw error;
440
+ const { contextParams } = dep.data;
441
+
442
+ if (contextParams) {
443
+ // Ensure the filepath has uniqueness applied to ensure multiple `require.context`
444
+ // statements can be used to target the same file with different properties.
445
+ const from = path.join(parentPath, "..", dep.name);
446
+ const absolutePath = (0, _contextModule.deriveAbsolutePathFromContext)(
447
+ from,
448
+ contextParams
449
+ );
450
+ const resolvedContext = {
451
+ from,
452
+ mode: contextParams.mode,
453
+ recursive: contextParams.recursive,
454
+ filter: new RegExp(
455
+ contextParams.filter.pattern,
456
+ contextParams.filter.flags
457
+ ),
458
+ };
459
+ graph.privateState.resolvedContexts.set(absolutePath, resolvedContext);
460
+ resolvedDep = {
461
+ absolutePath,
462
+ data: dep,
463
+ };
464
+ } else {
465
+ try {
466
+ resolvedDep = {
467
+ absolutePath: options.resolve(parentPath, dep.name),
468
+ data: dep,
469
+ }; // This dependency may have existed previously as a require.context -
470
+ // clean it up.
471
+
472
+ graph.privateState.resolvedContexts.delete(resolvedDep.absolutePath);
473
+ } catch (error) {
474
+ // Ignore unavailable optional dependencies. They are guarded
475
+ // with a try-catch block and will be handled during runtime.
476
+ if (dep.data.isOptional !== true) {
477
+ throw error;
478
+ }
385
479
  }
386
480
  }
387
481
 
388
- return undefined;
389
- };
482
+ const key = dep.data.key;
390
483
 
391
- const resolved = dependencies.reduce((list, result) => {
392
- const resolvedPath = resolve(parentPath, result);
484
+ if (maybeResolvedDeps.has(key)) {
485
+ throw new Error(
486
+ `resolveDependencies: Found duplicate dependency key '${key}' in ${parentPath}`
487
+ );
488
+ }
489
+
490
+ maybeResolvedDeps.set(key, resolvedDep);
491
+ }
393
492
 
394
- if (resolvedPath) {
395
- list.push(resolvedPath);
493
+ const resolvedDeps = new Map(); // Return just the dependencies we successfully resolved.
494
+ // FIXME: This has a bad bug affecting all dependencies *after* an unresolved
495
+ // optional dependency. We'll need to propagate the nulls all the way to the
496
+ // serializer and the require() runtime to keep the dependency map from being
497
+ // desynced from the contents of the module.
498
+
499
+ for (const [key, resolvedDep] of maybeResolvedDeps) {
500
+ if (resolvedDep) {
501
+ resolvedDeps.set(key, resolvedDep);
396
502
  }
503
+ }
397
504
 
398
- return list;
399
- }, []);
400
- return new Map(resolved);
505
+ return resolvedDeps;
401
506
  }
402
507
  /**
403
508
  * Re-traverse the dependency graph in DFS order to reorder the modules and
@@ -485,8 +590,8 @@ function markModuleInUse(module, graph) {
485
590
  // Called when the reference count of a module has reached 0.
486
591
 
487
592
  function releaseModule(module, graph, delta, options) {
488
- for (const [relativePath, dependency] of module.dependencies) {
489
- removeDependency(module, relativePath, dependency, graph, delta, options);
593
+ for (const [key, dependency] of module.dependencies) {
594
+ removeDependency(module, key, dependency, graph, delta, options);
490
595
  }
491
596
 
492
597
  graph.privateState.gc.color.set(module.path, "black");
@@ -512,6 +617,7 @@ function freeModule(module, graph, delta) {
512
617
  delta.earlyInverseDependencies.delete(module.path);
513
618
  graph.privateState.gc.possibleCycleRoots.delete(module.path);
514
619
  graph.privateState.gc.color.delete(module.path);
620
+ graph.privateState.resolvedContexts.delete(module.path);
515
621
  } // Mark a module as a possible cycle root
516
622
 
517
623
  function markAsPossibleCycleRoot(module, graph) {
@@ -638,4 +744,5 @@ module.exports = {
638
744
  initialTraverseDependencies,
639
745
  traverseDependencies,
640
746
  reorderGraph,
747
+ markModifiedContextModules,
641
748
  };