metro 0.70.3 → 0.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/package.json +20 -20
  2. package/src/Assets.js.flow +4 -4
  3. package/src/Bundler/util.js +1 -1
  4. package/src/Bundler/util.js.flow +2 -2
  5. package/src/Bundler.js +17 -10
  6. package/src/Bundler.js.flow +19 -14
  7. package/src/DeltaBundler/DeltaCalculator.js +13 -17
  8. package/src/DeltaBundler/DeltaCalculator.js.flow +15 -20
  9. package/src/DeltaBundler/Serializers/getAllFiles.js.flow +2 -2
  10. package/src/DeltaBundler/Serializers/getAssets.js.flow +2 -2
  11. package/src/DeltaBundler/Serializers/getExplodedSourceMap.js.flow +4 -4
  12. package/src/DeltaBundler/Serializers/getRamBundleInfo.js.flow +6 -6
  13. package/src/DeltaBundler/Serializers/helpers/getSourceMapInfo.js.flow +4 -4
  14. package/src/DeltaBundler/Serializers/helpers/processBytecodeModules.js.flow +2 -2
  15. package/src/DeltaBundler/Serializers/helpers/processModules.js.flow +2 -2
  16. package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +2 -2
  17. package/src/DeltaBundler/Serializers/sourceMapGenerator.js.flow +6 -6
  18. package/src/DeltaBundler/Serializers/sourceMapObject.js.flow +4 -4
  19. package/src/DeltaBundler/Serializers/sourceMapString.js.flow +2 -2
  20. package/src/DeltaBundler/Worker.js.flow +4 -4
  21. package/src/DeltaBundler/WorkerFarm.js.flow +4 -4
  22. package/src/DeltaBundler/getTransformCacheKey.js.flow +2 -2
  23. package/src/DeltaBundler/{traverseDependencies.js → graphOperations.js} +43 -32
  24. package/src/DeltaBundler/{traverseDependencies.js.flow → graphOperations.js.flow} +52 -37
  25. package/src/DeltaBundler/types.flow.js.flow +36 -30
  26. package/src/DeltaBundler.js +14 -6
  27. package/src/DeltaBundler.js.flow +14 -10
  28. package/src/HmrServer.js.flow +6 -6
  29. package/src/IncrementalBundler.js +1 -1
  30. package/src/IncrementalBundler.js.flow +8 -8
  31. package/src/ModuleGraph/node-haste/ModuleCache.js +1 -1
  32. package/src/ModuleGraph/node-haste/ModuleCache.js.flow +1 -1
  33. package/src/ModuleGraph/node-haste/node-haste.flow.js.flow +2 -2
  34. package/src/ModuleGraph/node-haste/node-haste.js +4 -4
  35. package/src/ModuleGraph/node-haste/node-haste.js.flow +13 -7
  36. package/src/ModuleGraph/output/indexed-ram-bundle.js.flow +2 -2
  37. package/src/ModuleGraph/output/plain-bundle.js.flow +2 -2
  38. package/src/ModuleGraph/output/reverse-dependency-map-references.js.flow +8 -8
  39. package/src/ModuleGraph/output/util.js.flow +2 -2
  40. package/src/ModuleGraph/types.flow.js.flow +37 -37
  41. package/src/ModuleGraph/worker/collectDependencies.js.flow +2 -2
  42. package/src/Server/symbolicate.js.flow +1 -1
  43. package/src/Server.js.flow +18 -18
  44. package/src/commands/build.js.flow +2 -2
  45. package/src/commands/serve.js.flow +2 -2
  46. package/src/index.js +32 -18
  47. package/src/index.js.flow +42 -32
  48. package/src/lib/bundleToBytecode.js.flow +2 -2
  49. package/src/lib/bundleToString.js.flow +2 -2
  50. package/src/lib/getPreludeCode.js.flow +2 -2
  51. package/src/lib/transformHelpers.js.flow +2 -2
  52. package/src/node-haste/DependencyGraph/ModuleResolution.js +2 -1
  53. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +5 -12
  54. package/src/node-haste/DependencyGraph/createHasteMap.js +9 -7
  55. package/src/node-haste/DependencyGraph/createHasteMap.js.flow +6 -9
  56. package/src/node-haste/DependencyGraph.js +31 -27
  57. package/src/node-haste/DependencyGraph.js.flow +43 -37
  58. package/src/node-haste/ModuleCache.js.flow +1 -1
  59. package/src/node-haste/lib/AssetPaths.js.flow +2 -2
  60. package/src/node-haste/lib/parsePlatformFilePath.js.flow +2 -2
  61. package/src/shared/output/RamBundle/as-indexed-file.js.flow +1 -1
  62. package/src/shared/output/RamBundle/buildSourcemapWithMetadata.js.flow +2 -2
  63. package/src/shared/types.flow.js.flow +14 -14
  64. package/src/DeltaBundler/computeDelta.js +0 -42
  65. package/src/DeltaBundler/computeDelta.js.flow +0 -47
  66. package/src/node-haste/DependencyGraph/types.js +0 -10
  67. package/src/node-haste/DependencyGraph/types.js.flow +0 -88
package/src/index.js CHANGED
@@ -37,6 +37,8 @@ const { getDefaultConfig, loadConfig, mergeConfig } = require("metro-config");
37
37
 
38
38
  const { InspectorProxy } = require("metro-inspector-proxy");
39
39
 
40
+ const net = require("net");
41
+
40
42
  const { parse } = require("url");
41
43
 
42
44
  const ws = require("ws");
@@ -150,6 +152,8 @@ exports.runServer = async (
150
152
  websocketEndpoints = {},
151
153
  }
152
154
  ) => {
155
+ await earlyPortCheck(host, config.server.port);
156
+
153
157
  if (secure != null || secureCert != null || secureKey != null) {
154
158
  // eslint-disable-next-line no-console
155
159
  console.warn(
@@ -183,13 +187,11 @@ exports.runServer = async (
183
187
  let options = secureServerOptions;
184
188
 
185
189
  if (typeof secureKey === "string" && typeof secureCert === "string") {
186
- options = Object.assign(
187
- {
188
- key: fs.readFileSync(secureKey),
189
- cert: fs.readFileSync(secureCert),
190
- },
191
- secureServerOptions
192
- );
190
+ options = {
191
+ key: fs.readFileSync(secureKey),
192
+ cert: fs.readFileSync(secureCert),
193
+ ...secureServerOptions,
194
+ };
193
195
  }
194
196
 
195
197
  httpServer = https.createServer(options, serverApp);
@@ -197,14 +199,15 @@ exports.runServer = async (
197
199
  httpServer = http.createServer(serverApp);
198
200
  }
199
201
 
200
- httpServer.on("error", (error) => {
201
- if (onError) {
202
- onError(error);
203
- }
204
-
205
- end();
206
- });
207
202
  return new Promise((resolve, reject) => {
203
+ httpServer.on("error", (error) => {
204
+ if (onError) {
205
+ onError(error);
206
+ }
207
+
208
+ reject(error);
209
+ end();
210
+ });
208
211
  httpServer.listen(config.server.port, host, () => {
209
212
  if (onReady) {
210
213
  onReady(httpServer);
@@ -253,10 +256,6 @@ exports.runServer = async (
253
256
  // timeout of 120 seconds to respond to a request.
254
257
 
255
258
  httpServer.timeout = 0;
256
- httpServer.on("error", (error) => {
257
- end();
258
- reject(error);
259
- });
260
259
  httpServer.on("close", () => {
261
260
  end();
262
261
  });
@@ -376,3 +375,18 @@ exports.attachMetroCli = function (
376
375
 
377
376
  return yargs;
378
377
  };
378
+
379
+ async function earlyPortCheck(host, port) {
380
+ const server = net.createServer((c) => c.end());
381
+
382
+ try {
383
+ await new Promise((resolve, reject) => {
384
+ server.on("error", (err) => {
385
+ reject(err);
386
+ });
387
+ server.listen(port, host, undefined, () => resolve());
388
+ });
389
+ } finally {
390
+ await new Promise((resolve) => server.close(() => resolve()));
391
+ }
392
+ }
package/src/index.js.flow CHANGED
@@ -37,25 +37,26 @@ const http = require('http');
37
37
  const https = require('https');
38
38
  const {getDefaultConfig, loadConfig, mergeConfig} = require('metro-config');
39
39
  const {InspectorProxy} = require('metro-inspector-proxy');
40
+ const net = require('net');
40
41
  const {parse} = require('url');
41
42
  const ws = require('ws');
42
43
 
43
- type MetroMiddleWare = {|
44
+ type MetroMiddleWare = {
44
45
  attachHmrServer: (httpServer: HttpServer | HttpsServer) => void,
45
46
  end: () => void,
46
47
  metroServer: MetroServer,
47
48
  middleware: Middleware,
48
- |};
49
+ };
49
50
 
50
51
  export type RunMetroOptions = {
51
52
  ...ServerOptions,
52
53
  waitForBundler?: boolean,
53
54
  };
54
55
 
55
- export type RunServerOptions = {|
56
+ export type RunServerOptions = {
56
57
  hasReducedPerformance?: boolean,
57
58
  host?: string,
58
- onError?: (Error & {|code?: string|}) => void,
59
+ onError?: (Error & {code?: string}) => void,
59
60
  onReady?: (server: HttpServer | HttpsServer) => void,
60
61
  runInspectorProxy?: boolean,
61
62
  secureServerOptions?: Object,
@@ -66,9 +67,9 @@ export type RunServerOptions = {|
66
67
  websocketEndpoints?: {
67
68
  [path: string]: typeof ws.Server,
68
69
  },
69
- |};
70
+ };
70
71
 
71
- type BuildGraphOptions = {|
72
+ type BuildGraphOptions = {
72
73
  entries: $ReadOnlyArray<string>,
73
74
  customTransformOptions?: CustomTransformOptions,
74
75
  dev?: boolean,
@@ -76,9 +77,9 @@ type BuildGraphOptions = {|
76
77
  onProgress?: (transformedFileCount: number, totalFileCount: number) => void,
77
78
  platform?: string,
78
79
  type?: 'module' | 'script',
79
- |};
80
+ };
80
81
 
81
- export type RunBuildOptions = {|
82
+ export type RunBuildOptions = {
82
83
  entry: string,
83
84
  dev?: boolean,
84
85
  out?: string,
@@ -109,10 +110,10 @@ export type RunBuildOptions = {|
109
110
  platform?: string,
110
111
  sourceMap?: boolean,
111
112
  sourceMapUrl?: string,
112
- |};
113
+ };
113
114
 
114
- type BuildCommandOptions = {||} | null;
115
- type ServeCommandOptions = {||} | null;
115
+ type BuildCommandOptions = {} | null;
116
+ type ServeCommandOptions = {} | null;
116
117
 
117
118
  async function getConfig(config: InputConfigT): Promise<ConfigT> {
118
119
  const defaultConfig = await getDefaultConfig(config.projectRoot);
@@ -171,7 +172,7 @@ const createConnectMiddleware = async function (
171
172
  ): Promise<MetroMiddleWare> {
172
173
  const metroServer = await runMetro(config, options);
173
174
 
174
- let enhancedMiddleware = metroServer.processRequest;
175
+ let enhancedMiddleware: Middleware = metroServer.processRequest;
175
176
 
176
177
  // Enhance the resulting middleware using the config options
177
178
  if (config.server.enhanceMiddleware) {
@@ -225,6 +226,8 @@ exports.runServer = async (
225
226
  websocketEndpoints = {},
226
227
  }: RunServerOptions,
227
228
  ): Promise<HttpServer | HttpsServer> => {
229
+ await earlyPortCheck(host, config.server.port);
230
+
228
231
  if (secure != null || secureCert != null || secureKey != null) {
229
232
  // eslint-disable-next-line no-console
230
233
  console.warn(
@@ -256,31 +259,29 @@ exports.runServer = async (
256
259
  if (secure || secureServerOptions != null) {
257
260
  let options = secureServerOptions;
258
261
  if (typeof secureKey === 'string' && typeof secureCert === 'string') {
259
- options = Object.assign(
260
- {
261
- key: fs.readFileSync(secureKey),
262
- cert: fs.readFileSync(secureCert),
263
- },
264
- secureServerOptions,
265
- );
262
+ options = {
263
+ key: fs.readFileSync(secureKey),
264
+ cert: fs.readFileSync(secureCert),
265
+ ...secureServerOptions,
266
+ };
266
267
  }
267
268
  httpServer = https.createServer(options, serverApp);
268
269
  } else {
269
270
  httpServer = http.createServer(serverApp);
270
271
  }
271
-
272
- httpServer.on('error', error => {
273
- if (onError) {
274
- onError(error);
275
- }
276
- end();
277
- });
278
-
279
272
  return new Promise(
280
273
  (
281
274
  resolve: (result: HttpServer | HttpsServer) => void,
282
275
  reject: mixed => mixed,
283
276
  ) => {
277
+ httpServer.on('error', error => {
278
+ if (onError) {
279
+ onError(error);
280
+ }
281
+ reject(error);
282
+ end();
283
+ });
284
+
284
285
  httpServer.listen(config.server.port, host, () => {
285
286
  if (onReady) {
286
287
  onReady(httpServer);
@@ -331,11 +332,6 @@ exports.runServer = async (
331
332
  // timeout of 120 seconds to respond to a request.
332
333
  httpServer.timeout = 0;
333
334
 
334
- httpServer.on('error', error => {
335
- end();
336
- reject(error);
337
- });
338
-
339
335
  httpServer.on('close', () => {
340
336
  end();
341
337
  });
@@ -468,3 +464,17 @@ exports.attachMetroCli = function (
468
464
  }
469
465
  return yargs;
470
466
  };
467
+
468
+ async function earlyPortCheck(host: void | string, port: number) {
469
+ const server = net.createServer(c => c.end());
470
+ try {
471
+ await new Promise((resolve, reject) => {
472
+ server.on('error', err => {
473
+ reject(err);
474
+ });
475
+ server.listen(port, host, undefined, () => resolve());
476
+ });
477
+ } finally {
478
+ await new Promise(resolve => server.close(() => resolve()));
479
+ }
480
+ }
@@ -49,10 +49,10 @@ function addModuleHeader(buffer: Buffer): [Buffer, Buffer] {
49
49
  * ...
50
50
  *
51
51
  */
52
- function bundleToBytecode(bundle: BytecodeBundle): {|
52
+ function bundleToBytecode(bundle: BytecodeBundle): {
53
53
  +bytecode: Buffer,
54
54
  +metadata: BundleMetadata,
55
- |} {
55
+ } {
56
56
  const buffers = [];
57
57
 
58
58
  if (bundle.pre.length) {
@@ -18,10 +18,10 @@ import type {
18
18
  /**
19
19
  * Serializes a bundle into a plain JS bundle.
20
20
  */
21
- function bundleToString(bundle: Bundle): {|
21
+ function bundleToString(bundle: Bundle): {
22
22
  +code: string,
23
23
  +metadata: BundleMetadata,
24
- |} {
24
+ } {
25
25
  let code = bundle.pre.length > 0 ? bundle.pre + '\n' : '';
26
26
  const modules = [];
27
27
 
@@ -14,11 +14,11 @@ function getPreludeCode({
14
14
  extraVars,
15
15
  isDev,
16
16
  globalPrefix,
17
- }: {|
17
+ }: {
18
18
  +extraVars?: {[string]: mixed, ...},
19
19
  +isDev: boolean,
20
20
  +globalPrefix: string,
21
- |}): string {
21
+ }): string {
22
22
  const vars = [
23
23
  '__BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now()',
24
24
  `__DEV__=${String(isDev)}`,
@@ -21,10 +21,10 @@ const path = require('path');
21
21
 
22
22
  type InlineRequiresRaw = {+blockList: {[string]: true, ...}, ...} | boolean;
23
23
 
24
- type TransformOptionsWithRawInlines = {|
24
+ type TransformOptionsWithRawInlines = {
25
25
  ...TransformOptions,
26
26
  +inlineRequires: InlineRequiresRaw,
27
- |};
27
+ };
28
28
 
29
29
  const baseIgnoredInlineRequires = ['React', 'react', 'react-native'];
30
30
 
@@ -149,7 +149,8 @@ class ModuleResolver {
149
149
  }
150
150
 
151
151
  if (error instanceof Resolver.FailedToResolveNameError) {
152
- const { dirPaths, extraPaths } = error;
152
+ const dirPaths = error.dirPaths;
153
+ const extraPaths = error.extraPaths;
153
154
  const displayDirPaths = dirPaths
154
155
  .filter((dirPath) => this._options.dirExists(dirPath))
155
156
  .map((dirPath) => path.relative(this._options.projectRoot, dirPath))
@@ -10,7 +10,7 @@
10
10
 
11
11
  'use strict';
12
12
 
13
- import type {ModuleMap} from './types';
13
+ import type {ModuleMap} from 'metro-file-map';
14
14
  import type {
15
15
  CustomResolver,
16
16
  DoesFileExist,
@@ -53,7 +53,7 @@ export type ModuleishCache<TModule, TPackage> = interface {
53
53
  getPackageOf(modulePath: string): ?TPackage,
54
54
  };
55
55
 
56
- type Options<TModule, TPackage> = {|
56
+ type Options<TModule, TPackage> = {
57
57
  +dirExists: DirExistsFn,
58
58
  +disableHierarchicalLookup: boolean,
59
59
  +doesFileExist: DoesFileExist,
@@ -69,7 +69,7 @@ type Options<TModule, TPackage> = {|
69
69
  +resolveAsset: ResolveAsset,
70
70
  +resolveRequest: ?CustomResolver,
71
71
  +sourceExts: $ReadOnlyArray<string>,
72
- |};
72
+ };
73
73
 
74
74
  class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
75
75
  _options: Options<TModule, TPackage>;
@@ -204,15 +204,8 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
204
204
  );
205
205
  }
206
206
  if (error instanceof Resolver.FailedToResolveNameError) {
207
- const {
208
- dirPaths,
209
- extraPaths,
210
- }: {
211
- // $flowfixme these types are defined explicitly in FailedToResolveNameError but Flow refuses to recognize them here
212
- dirPaths: $ReadOnlyArray<string>,
213
- extraPaths: $ReadOnlyArray<string>,
214
- ...
215
- } = error;
207
+ const dirPaths = error.dirPaths;
208
+ const extraPaths = error.extraPaths;
216
209
  const displayDirPaths = dirPaths
217
210
  .filter((dirPath: string) => this._options.dirExists(dirPath))
218
211
  .map(dirPath => path.relative(this._options.projectRoot, dirPath))
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- var _jestHasteMap = _interopRequireDefault(require("jest-haste-map"));
3
+ var _metroFileMap = _interopRequireDefault(require("metro-file-map"));
4
4
 
5
5
  function _interopRequireDefault(obj) {
6
6
  return obj && obj.__esModule ? obj : { default: obj };
@@ -15,7 +15,6 @@ function _interopRequireDefault(obj) {
15
15
  *
16
16
  * @format
17
17
  */
18
- // $FlowFixMe: Types for `jest-haste-map`
19
18
  const ci = require("ci-info");
20
19
 
21
20
  const path = require("path");
@@ -46,7 +45,7 @@ function getIgnorePattern(config) {
46
45
  }
47
46
 
48
47
  function createHasteMap(config, options) {
49
- var _options$name, _options$throwOnModul;
48
+ var _config$fileMapCacheD, _options$name, _options$throwOnModul;
50
49
 
51
50
  const dependencyExtractor =
52
51
  (options === null || options === void 0
@@ -55,8 +54,12 @@ function createHasteMap(config, options) {
55
54
  ? null
56
55
  : config.resolver.dependencyExtractor;
57
56
  const computeDependencies = dependencyExtractor != null;
58
- const hasteConfig = {
59
- cacheDirectory: config.hasteMapCacheDirectory,
57
+ return _metroFileMap.default.create({
58
+ cacheDirectory:
59
+ (_config$fileMapCacheD = config.fileMapCacheDirectory) !== null &&
60
+ _config$fileMapCacheD !== void 0
61
+ ? _config$fileMapCacheD
62
+ : config.hasteMapCacheDirectory,
60
63
  computeDependencies,
61
64
  computeSha1: true,
62
65
  dependencyExtractor: config.resolver.dependencyExtractor,
@@ -92,8 +95,7 @@ function createHasteMap(config, options) {
92
95
  (options === null || options === void 0 ? void 0 : options.watch) == null
93
96
  ? !ci.isCI
94
97
  : options.watch,
95
- };
96
- return _jestHasteMap.default.create(hasteConfig);
98
+ });
97
99
  }
98
100
 
99
101
  module.exports = createHasteMap;
@@ -8,11 +8,9 @@
8
8
  * @format
9
9
  */
10
10
 
11
- import type {HasteConfig, HasteMap} from './types';
12
11
  import type {ConfigT} from 'metro-config/src/configTypes.flow';
13
12
 
14
- // $FlowFixMe: Types for `jest-haste-map`
15
- import JestHasteMap from 'jest-haste-map';
13
+ import MetroFileMap from 'metro-file-map';
16
14
 
17
15
  const ci = require('ci-info');
18
16
  const path = require('path');
@@ -52,15 +50,16 @@ function createHasteMap(
52
50
  throwOnModuleCollision?: boolean,
53
51
  name?: string,
54
52
  }>,
55
- ): HasteMap {
53
+ ): MetroFileMap {
56
54
  const dependencyExtractor =
57
55
  options?.extractDependencies === false
58
56
  ? null
59
57
  : config.resolver.dependencyExtractor;
60
58
  const computeDependencies = dependencyExtractor != null;
61
59
 
62
- const hasteConfig: HasteConfig = {
63
- cacheDirectory: config.hasteMapCacheDirectory,
60
+ return MetroFileMap.create({
61
+ cacheDirectory:
62
+ config.fileMapCacheDirectory ?? config.hasteMapCacheDirectory,
64
63
  computeDependencies,
65
64
  computeSha1: true,
66
65
  dependencyExtractor: config.resolver.dependencyExtractor,
@@ -80,9 +79,7 @@ function createHasteMap(
80
79
  throwOnModuleCollision: options?.throwOnModuleCollision ?? true,
81
80
  useWatchman: config.resolver.useWatchman,
82
81
  watch: options?.watch == null ? !ci.isCI : options.watch,
83
- };
84
-
85
- return JestHasteMap.create(hasteConfig);
82
+ });
86
83
  }
87
84
 
88
85
  module.exports = createHasteMap;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- var _jestHasteMap = require("jest-haste-map");
3
+ var _metroFileMap = require("metro-file-map");
4
4
 
5
5
  /**
6
6
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -35,7 +35,7 @@ const nullthrows = require("nullthrows");
35
35
 
36
36
  const path = require("path");
37
37
 
38
- const { DuplicateHasteCandidatesError } = _jestHasteMap.ModuleMap;
38
+ const { DuplicateHasteCandidatesError } = _metroFileMap.ModuleMap;
39
39
 
40
40
  function getOrCreate(map, field) {
41
41
  let subMap = map.get(field);
@@ -49,25 +49,12 @@ function getOrCreate(map, field) {
49
49
  }
50
50
 
51
51
  class DependencyGraph extends EventEmitter {
52
- constructor({ config, haste, initialHasteFS, initialModuleMap }) {
52
+ constructor(config, options) {
53
53
  super();
54
54
  this._config = config;
55
- this._haste = haste;
56
- this._hasteFS = initialHasteFS;
57
- this._moduleMap = initialModuleMap;
58
55
  this._assetExtensions = new Set(
59
56
  config.resolver.assetExts.map((asset) => "." + asset)
60
- ); // $FlowFixMe[method-unbinding] added when improving typing for this parameters
61
-
62
- this._haste.on("change", this._onHasteChange.bind(this));
63
-
64
- this._resolutionCache = new Map();
65
- this._moduleCache = this._createModuleCache();
66
-
67
- this._createModuleResolver();
68
- }
69
-
70
- static async load(config, options) {
57
+ );
71
58
  const { hasReducedPerformance, watch } =
72
59
  options !== null && options !== void 0 ? options : {};
73
60
  const initializingMetroLogEntry = log(
@@ -83,17 +70,34 @@ class DependencyGraph extends EventEmitter {
83
70
  // Bump this up to silence the max listeners EventEmitter warning.
84
71
 
85
72
  haste.setMaxListeners(1000);
86
- const { hasteFS, moduleMap } = await haste.build();
87
- log(createActionEndEntry(initializingMetroLogEntry));
88
- config.reporter.update({
89
- type: "dep_graph_loaded",
90
- });
91
- return new DependencyGraph({
92
- haste,
93
- initialHasteFS: hasteFS,
94
- initialModuleMap: moduleMap,
95
- config,
73
+ this._haste = haste;
74
+ this._readyPromise = haste.build().then(({ hasteFS, moduleMap }) => {
75
+ log(createActionEndEntry(initializingMetroLogEntry));
76
+ config.reporter.update({
77
+ type: "dep_graph_loaded",
78
+ });
79
+ this._hasteFS = hasteFS;
80
+ this._moduleMap = moduleMap; // $FlowFixMe[method-unbinding] added when improving typing for this parameters
81
+
82
+ this._haste.on("change", this._onHasteChange.bind(this));
83
+
84
+ this._resolutionCache = new Map();
85
+ this._moduleCache = this._createModuleCache();
86
+
87
+ this._createModuleResolver();
96
88
  });
89
+ } // Waits for the dependency graph to become ready after initialisation.
90
+ // Don't read anything from the graph until this resolves.
91
+
92
+ async ready() {
93
+ await this._readyPromise;
94
+ } // Creates the dependency graph and waits for it to become ready.
95
+ // @deprecated Use the constructor + ready() directly.
96
+
97
+ static async load(config, options) {
98
+ const self = new DependencyGraph(config, options);
99
+ await self.ready();
100
+ return self;
97
101
  }
98
102
 
99
103
  _getClosestPackage(filePath) {
@@ -8,11 +8,11 @@
8
8
  * @format
9
9
  */
10
10
 
11
- import type {HasteFS, HasteMap, ModuleMap} from './DependencyGraph/types';
12
11
  import type Package from './Package';
13
12
  import type {ConfigT} from 'metro-config/src/configTypes.flow';
13
+ import type MetroFileMap, {HasteFS} from 'metro-file-map';
14
14
 
15
- import {ModuleMap as JestHasteModuleMap} from 'jest-haste-map';
15
+ import {ModuleMap as MetroFileMapModuleMap} from 'metro-file-map';
16
16
 
17
17
  const createHasteMap = require('./DependencyGraph/createHasteMap');
18
18
  const {ModuleResolver} = require('./DependencyGraph/ModuleResolution');
@@ -29,7 +29,7 @@ const {InvalidPackageError} = require('metro-resolver');
29
29
  const nullthrows = require('nullthrows');
30
30
  const path = require('path');
31
31
 
32
- const {DuplicateHasteCandidatesError} = JestHasteModuleMap;
32
+ const {DuplicateHasteCandidatesError} = MetroFileMapModuleMap;
33
33
 
34
34
  function getOrCreate<T>(
35
35
  map: Map<string, Map<string, T>>,
@@ -46,43 +46,28 @@ function getOrCreate<T>(
46
46
  class DependencyGraph extends EventEmitter {
47
47
  _assetExtensions: Set<string>;
48
48
  _config: ConfigT;
49
- _haste: HasteMap;
49
+ _haste: MetroFileMap;
50
50
  _hasteFS: HasteFS;
51
51
  _moduleCache: ModuleCache;
52
- _moduleMap: ModuleMap;
52
+ _moduleMap: MetroFileMapModuleMap;
53
53
  _moduleResolver: ModuleResolver<Module, Package>;
54
54
  _resolutionCache: Map<string, Map<string, Map<string, string>>>;
55
+ _readyPromise: Promise<void>;
55
56
 
56
- constructor({
57
- config,
58
- haste,
59
- initialHasteFS,
60
- initialModuleMap,
61
- }: {|
62
- +config: ConfigT,
63
- +haste: HasteMap,
64
- +initialHasteFS: HasteFS,
65
- +initialModuleMap: ModuleMap,
66
- |}) {
57
+ constructor(
58
+ config: ConfigT,
59
+ options?: {
60
+ +hasReducedPerformance?: boolean,
61
+ +watch?: boolean,
62
+ },
63
+ ) {
67
64
  super();
65
+
68
66
  this._config = config;
69
- this._haste = haste;
70
- this._hasteFS = initialHasteFS;
71
- this._moduleMap = initialModuleMap;
72
67
  this._assetExtensions = new Set(
73
68
  config.resolver.assetExts.map(asset => '.' + asset),
74
69
  );
75
- // $FlowFixMe[method-unbinding] added when improving typing for this parameters
76
- this._haste.on('change', this._onHasteChange.bind(this));
77
- this._resolutionCache = new Map();
78
- this._moduleCache = this._createModuleCache();
79
- this._createModuleResolver();
80
- }
81
70
 
82
- static async load(
83
- config: ConfigT,
84
- options?: {|+hasReducedPerformance?: boolean, +watch?: boolean|},
85
- ): Promise<DependencyGraph> {
86
71
  const {hasReducedPerformance, watch} = options ?? {};
87
72
  const initializingMetroLogEntry = log(
88
73
  createActionStartEntry('Initializing Metro'),
@@ -98,19 +83,40 @@ class DependencyGraph extends EventEmitter {
98
83
  // Bump this up to silence the max listeners EventEmitter warning.
99
84
  haste.setMaxListeners(1000);
100
85
 
101
- const {hasteFS, moduleMap} = await haste.build();
86
+ this._haste = haste;
87
+
88
+ this._readyPromise = haste.build().then(({hasteFS, moduleMap}) => {
89
+ log(createActionEndEntry(initializingMetroLogEntry));
90
+ config.reporter.update({type: 'dep_graph_loaded'});
102
91
 
103
- log(createActionEndEntry(initializingMetroLogEntry));
104
- config.reporter.update({type: 'dep_graph_loaded'});
92
+ this._hasteFS = hasteFS;
93
+ this._moduleMap = moduleMap;
105
94
 
106
- return new DependencyGraph({
107
- haste,
108
- initialHasteFS: hasteFS,
109
- initialModuleMap: moduleMap,
110
- config,
95
+ // $FlowFixMe[method-unbinding] added when improving typing for this parameters
96
+ this._haste.on('change', this._onHasteChange.bind(this));
97
+ this._resolutionCache = new Map();
98
+ this._moduleCache = this._createModuleCache();
99
+ this._createModuleResolver();
111
100
  });
112
101
  }
113
102
 
103
+ // Waits for the dependency graph to become ready after initialisation.
104
+ // Don't read anything from the graph until this resolves.
105
+ async ready(): Promise<void> {
106
+ await this._readyPromise;
107
+ }
108
+
109
+ // Creates the dependency graph and waits for it to become ready.
110
+ // @deprecated Use the constructor + ready() directly.
111
+ static async load(
112
+ config: ConfigT,
113
+ options?: {+hasReducedPerformance?: boolean, +watch?: boolean},
114
+ ): Promise<DependencyGraph> {
115
+ const self = new DependencyGraph(config, options);
116
+ await self.ready();
117
+ return self;
118
+ }
119
+
114
120
  _getClosestPackage(filePath: string): ?string {
115
121
  const parsedPath = path.parse(filePath);
116
122
  const root = parsedPath.root;
@@ -69,7 +69,7 @@ class ModuleCache {
69
69
  }
70
70
 
71
71
  getPackageOf(modulePath: string): ?Package {
72
- let packagePath = this._packagePathByModulePath[modulePath];
72
+ let packagePath: ?string = this._packagePathByModulePath[modulePath];
73
73
  if (packagePath && this._packageCache[packagePath]) {
74
74
  return this._packageCache[packagePath];
75
75
  }