metro 0.83.3 → 0.83.5

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 (229) hide show
  1. package/package.json +28 -24
  2. package/src/Assets.d.ts +83 -0
  3. package/src/Assets.js +42 -29
  4. package/src/Assets.js.flow +26 -15
  5. package/src/Bundler/util.d.ts +27 -0
  6. package/src/Bundler/util.js +25 -21
  7. package/src/Bundler/util.js.flow +2 -2
  8. package/src/Bundler.d.ts +14 -15
  9. package/src/Bundler.js.flow +1 -1
  10. package/src/DeltaBundler/DeltaCalculator.d.ts +71 -0
  11. package/src/DeltaBundler/DeltaCalculator.js +4 -4
  12. package/src/DeltaBundler/DeltaCalculator.js.flow +8 -8
  13. package/src/DeltaBundler/Graph.d.ts +135 -8
  14. package/src/DeltaBundler/Graph.js +16 -16
  15. package/src/DeltaBundler/Graph.js.flow +30 -30
  16. package/src/DeltaBundler/Serializers/baseJSBundle.d.ts +20 -0
  17. package/src/DeltaBundler/Serializers/baseJSBundle.js.flow +1 -1
  18. package/src/DeltaBundler/Serializers/getAllFiles.d.ts +22 -0
  19. package/src/DeltaBundler/Serializers/getAllFiles.js.flow +2 -2
  20. package/src/DeltaBundler/Serializers/getAssets.d.ts +25 -0
  21. package/src/DeltaBundler/Serializers/getAssets.js.flow +2 -2
  22. package/src/DeltaBundler/Serializers/getExplodedSourceMap.js.flow +2 -2
  23. package/src/DeltaBundler/Serializers/getRamBundleInfo.d.ts +36 -6
  24. package/src/DeltaBundler/Serializers/getRamBundleInfo.js.flow +8 -8
  25. package/src/DeltaBundler/Serializers/helpers/getInlineSourceMappingURL.d.ts +12 -0
  26. package/src/DeltaBundler/Serializers/helpers/getSourceMapInfo.d.ts +33 -0
  27. package/src/DeltaBundler/Serializers/helpers/getTransitiveDependencies.d.ts +17 -0
  28. package/src/DeltaBundler/Serializers/helpers/js.d.ts +30 -0
  29. package/src/DeltaBundler/Serializers/helpers/js.js +25 -21
  30. package/src/DeltaBundler/Serializers/helpers/js.js.flow +6 -6
  31. package/src/DeltaBundler/Serializers/helpers/processModules.d.ts +25 -0
  32. package/src/DeltaBundler/Serializers/helpers/processModules.js.flow +3 -3
  33. package/src/DeltaBundler/Serializers/hmrJSBundle.d.ts +30 -0
  34. package/src/DeltaBundler/Serializers/hmrJSBundle.js +25 -21
  35. package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +5 -5
  36. package/src/DeltaBundler/Serializers/sourceMapGenerator.d.ts +29 -0
  37. package/src/DeltaBundler/Serializers/sourceMapGenerator.js.flow +6 -6
  38. package/src/DeltaBundler/Serializers/sourceMapObject.d.ts +23 -0
  39. package/src/DeltaBundler/Serializers/sourceMapObject.js.flow +2 -2
  40. package/src/DeltaBundler/Serializers/sourceMapString.d.ts +22 -0
  41. package/src/DeltaBundler/Serializers/sourceMapString.js.flow +2 -2
  42. package/src/DeltaBundler/Transformer.d.ts +38 -0
  43. package/src/DeltaBundler/Transformer.js.flow +3 -3
  44. package/src/DeltaBundler/Worker.d.ts +19 -27
  45. package/src/DeltaBundler/Worker.flow.js.flow +1 -1
  46. package/src/DeltaBundler/WorkerFarm.d.ts +70 -0
  47. package/src/DeltaBundler/WorkerFarm.js +1 -1
  48. package/src/DeltaBundler/WorkerFarm.js.flow +26 -13
  49. package/src/DeltaBundler/buildSubgraph.d.ts +30 -0
  50. package/src/DeltaBundler/buildSubgraph.js +4 -4
  51. package/src/DeltaBundler/buildSubgraph.js.flow +8 -8
  52. package/src/DeltaBundler/getTransformCacheKey.d.ts +18 -0
  53. package/src/DeltaBundler/mergeDeltas.d.ts +17 -0
  54. package/src/DeltaBundler/types.d.ts +97 -100
  55. package/src/DeltaBundler/types.js.flow +36 -34
  56. package/src/DeltaBundler.d.ts +14 -12
  57. package/src/DeltaBundler.js.flow +2 -2
  58. package/src/HmrServer.d.ts +79 -0
  59. package/src/HmrServer.js +34 -29
  60. package/src/HmrServer.js.flow +17 -12
  61. package/src/IncrementalBundler/GraphNotFoundError.d.ts +17 -0
  62. package/src/IncrementalBundler/ResourceNotFoundError.d.ts +15 -0
  63. package/src/IncrementalBundler/RevisionNotFoundError.d.ts +17 -0
  64. package/src/IncrementalBundler.d.ts +43 -45
  65. package/src/IncrementalBundler.js +29 -21
  66. package/src/IncrementalBundler.js.flow +13 -9
  67. package/src/ModuleGraph/worker/JsFileWrapping.d.ts +29 -0
  68. package/src/ModuleGraph/worker/JsFileWrapping.js +25 -21
  69. package/src/ModuleGraph/worker/JsFileWrapping.js.flow +10 -5
  70. package/src/ModuleGraph/worker/collectDependencies.d.ts +118 -14
  71. package/src/ModuleGraph/worker/collectDependencies.js +25 -21
  72. package/src/ModuleGraph/worker/collectDependencies.js.flow +27 -21
  73. package/src/ModuleGraph/worker/generateImportNames.d.ts +19 -0
  74. package/src/ModuleGraph/worker/generateImportNames.js.flow +4 -2
  75. package/src/ModuleGraph/worker/importLocationsPlugin.d.ts +26 -0
  76. package/src/ModuleGraph/worker/importLocationsPlugin.js.flow +7 -3
  77. package/src/Server/MultipartResponse.d.ts +5 -6
  78. package/src/Server/MultipartResponse.js.flow +1 -1
  79. package/src/Server/symbolicate.js.flow +4 -4
  80. package/src/Server.d.ts +220 -67
  81. package/src/Server.js +149 -45
  82. package/src/Server.js.flow +167 -57
  83. package/src/cli/parseKeyValueParamArray.d.ts +14 -0
  84. package/src/cli/parseKeyValueParamArray.js.flow +1 -1
  85. package/src/cli-utils.d.ts +19 -0
  86. package/src/cli-utils.js.flow +2 -2
  87. package/src/commands/build.d.ts +16 -0
  88. package/src/commands/build.js.flow +11 -10
  89. package/src/commands/dependencies.d.ts +16 -0
  90. package/src/commands/dependencies.js.flow +8 -4
  91. package/src/commands/serve.d.ts +16 -0
  92. package/src/commands/serve.js +2 -0
  93. package/src/commands/serve.js.flow +14 -9
  94. package/src/index.d.ts +97 -110
  95. package/src/index.flow.js +53 -35
  96. package/src/index.flow.js.flow +49 -29
  97. package/src/integration_tests/basic_bundle/AssetRegistry.js.flow +1 -1
  98. package/src/integration_tests/basic_bundle/ErrorBundle.js.flow +1 -1
  99. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-import.js.flow +1 -1
  100. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import-with-escapes.js.flow +1 -1
  101. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import.js.flow +1 -1
  102. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require-with-embedded-comment.js.flow +1 -1
  103. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require.js.flow +1 -1
  104. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-specifier-with-escapes.js.flow +1 -1
  105. package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-import.js.flow +1 -1
  106. package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-require.js.flow +1 -1
  107. package/src/integration_tests/basic_bundle/import-export/index.js +25 -21
  108. package/src/integration_tests/basic_bundle/import-export/index.js.flow +3 -3
  109. package/src/integration_tests/basic_bundle/import-export/utils.js.flow +2 -2
  110. package/src/integration_tests/basic_bundle/loadBundleAsyncForTest.js.flow +1 -1
  111. package/src/integration_tests/basic_bundle/optional-dependencies/index.js.flow +1 -1
  112. package/src/integration_tests/basic_bundle/require-context/conflict.js.flow +1 -1
  113. package/src/integration_tests/basic_bundle/require-context/empty.js.flow +1 -1
  114. package/src/integration_tests/basic_bundle/require-context/matching.js.flow +1 -1
  115. package/src/integration_tests/basic_bundle/require-context/mode-eager.js.flow +1 -1
  116. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js.flow +1 -1
  117. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js.flow +1 -1
  118. package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +2 -2
  119. package/src/integration_tests/basic_bundle/require-context/utils.js.flow +1 -1
  120. package/src/integration_tests/basic_bundle/require-resolveWeak/import-and-resolveWeak.js.flow +1 -1
  121. package/src/integration_tests/basic_bundle/require-resolveWeak/multiple.js.flow +1 -1
  122. package/src/integration_tests/basic_bundle/require-resolveWeak/never-required.js.flow +1 -1
  123. package/src/integration_tests/basic_bundle/require-resolveWeak/require-and-resolveWeak.js.flow +1 -1
  124. package/src/integration_tests/execBundle.js.flow +1 -1
  125. package/src/lib/BatchProcessor.d.ts +54 -0
  126. package/src/lib/BatchProcessor.js +5 -2
  127. package/src/lib/BatchProcessor.js.flow +10 -7
  128. package/src/lib/CountingSet.d.ts +10 -10
  129. package/src/lib/CountingSet.js.flow +4 -4
  130. package/src/lib/JsonReporter.d.ts +37 -0
  131. package/src/lib/JsonReporter.js +5 -3
  132. package/src/lib/JsonReporter.js.flow +19 -17
  133. package/src/lib/RamBundleParser.d.ts +29 -0
  134. package/src/lib/RamBundleParser.js.flow +1 -1
  135. package/src/lib/TerminalReporter.d.ts +97 -6
  136. package/src/lib/TerminalReporter.js +37 -34
  137. package/src/lib/TerminalReporter.js.flow +21 -30
  138. package/src/lib/bundleProgressUtils.d.ts +26 -0
  139. package/src/lib/bundleProgressUtils.js +19 -0
  140. package/src/lib/bundleProgressUtils.js.flow +35 -0
  141. package/src/lib/bundleToString.d.ts +19 -0
  142. package/src/lib/contextModule.d.ts +20 -9
  143. package/src/lib/contextModule.js.flow +1 -1
  144. package/src/lib/contextModuleTemplates.d.ts +25 -0
  145. package/src/lib/contextModuleTemplates.js +25 -21
  146. package/src/lib/countLines.d.ts +12 -0
  147. package/src/lib/countLines.js +4 -3
  148. package/src/lib/countLines.js.flow +3 -4
  149. package/src/lib/createWebsocketServer.d.ts +43 -0
  150. package/src/lib/createWebsocketServer.js +9 -2
  151. package/src/lib/createWebsocketServer.js.flow +16 -9
  152. package/src/lib/debounceAsyncQueue.d.ts +15 -0
  153. package/src/lib/debounceAsyncQueue.js.flow +1 -1
  154. package/src/lib/formatBundlingError.d.ts +23 -0
  155. package/src/lib/formatBundlingError.js.flow +1 -1
  156. package/src/lib/getAppendScripts.d.ts +31 -0
  157. package/src/lib/getAppendScripts.js.flow +4 -4
  158. package/src/lib/getGraphId.d.ts +15 -1
  159. package/src/lib/getGraphId.js.flow +1 -1
  160. package/src/lib/getPreludeCode.d.ts +18 -0
  161. package/src/lib/getPreludeCode.js +4 -0
  162. package/src/lib/getPreludeCode.js.flow +10 -3
  163. package/src/lib/getPrependedScripts.d.ts +24 -0
  164. package/src/lib/getPrependedScripts.js +36 -22
  165. package/src/lib/getPrependedScripts.js.flow +10 -3
  166. package/src/lib/isResolvedDependency.d.ts +15 -0
  167. package/src/lib/logToConsole.d.ts +19 -0
  168. package/src/lib/logToConsole.js.flow +2 -2
  169. package/src/lib/parseBundleOptionsFromBundleRequestUrl.d.ts +17 -0
  170. package/src/lib/parseBundleOptionsFromBundleRequestUrl.js +25 -21
  171. package/src/lib/parseCustomResolverOptions.d.ts +16 -0
  172. package/src/lib/parseCustomResolverOptions.js.flow +2 -2
  173. package/src/lib/parseCustomTransformOptions.d.ts +16 -0
  174. package/src/lib/parseCustomTransformOptions.js.flow +1 -1
  175. package/src/lib/parseJsonBody.d.ts +27 -0
  176. package/src/lib/parseJsonBody.js.flow +11 -1
  177. package/src/lib/pathUtils.d.ts +14 -0
  178. package/src/lib/pathUtils.js +25 -21
  179. package/src/lib/pathUtils.js.flow +1 -1
  180. package/src/lib/relativizeSourceMap.d.ts +17 -0
  181. package/src/lib/reporting.d.ts +65 -81
  182. package/src/lib/reporting.js.flow +4 -4
  183. package/src/lib/splitBundleOptions.d.ts +16 -0
  184. package/src/lib/transformHelpers.d.ts +35 -0
  185. package/src/lib/transformHelpers.js +11 -9
  186. package/src/lib/transformHelpers.js.flow +17 -15
  187. package/src/node-haste/DependencyGraph/ModuleResolution.d.ts +126 -0
  188. package/src/node-haste/DependencyGraph/ModuleResolution.js +48 -42
  189. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +35 -32
  190. package/src/node-haste/DependencyGraph/createFileMap.d.ts +29 -0
  191. package/src/node-haste/DependencyGraph/createFileMap.js +56 -38
  192. package/src/node-haste/DependencyGraph/createFileMap.js.flow +44 -18
  193. package/src/node-haste/DependencyGraph.d.ts +57 -33
  194. package/src/node-haste/DependencyGraph.js +40 -31
  195. package/src/node-haste/DependencyGraph.js.flow +35 -37
  196. package/src/node-haste/Package.d.ts +21 -0
  197. package/src/node-haste/PackageCache.d.ts +34 -0
  198. package/src/node-haste/lib/AssetPaths.d.ts +29 -0
  199. package/src/node-haste/lib/AssetPaths.js +2 -2
  200. package/src/node-haste/lib/AssetPaths.js.flow +4 -4
  201. package/src/node-haste/lib/parsePlatformFilePath.d.ts +25 -0
  202. package/src/node-haste/lib/parsePlatformFilePath.js +6 -6
  203. package/src/node-haste/lib/parsePlatformFilePath.js.flow +4 -4
  204. package/src/shared/output/RamBundle/as-assets.d.ts +25 -0
  205. package/src/shared/output/RamBundle/as-assets.js.flow +6 -6
  206. package/src/shared/output/RamBundle/as-indexed-file.d.ts +38 -0
  207. package/src/shared/output/RamBundle/as-indexed-file.js.flow +5 -5
  208. package/src/shared/output/RamBundle/buildSourcemapWithMetadata.d.ts +23 -0
  209. package/src/shared/output/RamBundle/buildSourcemapWithMetadata.js.flow +5 -5
  210. package/src/shared/output/RamBundle/magic-number.d.ts +14 -0
  211. package/src/shared/output/RamBundle/util.d.ts +41 -0
  212. package/src/shared/output/RamBundle/util.js.flow +5 -5
  213. package/src/shared/output/RamBundle/write-sourcemap.d.ts +16 -0
  214. package/src/shared/output/RamBundle/write-sourcemap.js.flow +1 -1
  215. package/src/shared/output/RamBundle.d.ts +26 -0
  216. package/src/shared/output/RamBundle.js.flow +1 -1
  217. package/src/shared/output/bundle.d.ts +9 -17
  218. package/src/shared/output/bundle.flow.js.flow +3 -3
  219. package/src/shared/output/meta.d.ts +15 -0
  220. package/src/shared/output/meta.js +2 -2
  221. package/src/shared/output/meta.js.flow +1 -1
  222. package/src/shared/output/unbundle.d.ts +11 -0
  223. package/src/shared/output/writeFile.d.ts +16 -0
  224. package/src/shared/output/writeFile.js +8 -3
  225. package/src/shared/output/writeFile.js.flow +8 -2
  226. package/src/shared/types.d.ts +81 -66
  227. package/src/shared/types.js.flow +20 -5
  228. package/src/Asset.d.ts +0 -25
  229. package/src/ModuleGraph/test-helpers.js +0 -75
@@ -22,6 +22,7 @@ import type {
22
22
  } from './DeltaBundler/types';
23
23
  import type {RevisionId} from './IncrementalBundler';
24
24
  import type {GraphId} from './lib/getGraphId';
25
+ import type {JsonData} from './lib/parseJsonBody';
25
26
  import type {Reporter} from './lib/reporting';
26
27
  import type {StackFrameInput, StackFrameOutput} from './Server/symbolicate';
27
28
  import type {
@@ -51,6 +52,7 @@ import getRamBundleInfo from './DeltaBundler/Serializers/getRamBundleInfo';
51
52
  import {sourceMapStringNonBlocking} from './DeltaBundler/Serializers/sourceMapString';
52
53
  import IncrementalBundler from './IncrementalBundler';
53
54
  import ResourceNotFoundError from './IncrementalBundler/ResourceNotFoundError';
55
+ import {calculateBundleProgressRatio} from './lib/bundleProgressUtils';
54
56
  import bundleToString from './lib/bundleToString';
55
57
  import formatBundlingError from './lib/formatBundlingError';
56
58
  import getGraphId from './lib/getGraphId';
@@ -65,7 +67,6 @@ import symbolicate from './Server/symbolicate';
65
67
  import {SourcePathsMode} from './shared/types';
66
68
  import {codeFrameColumns} from '@babel/code-frame';
67
69
  import * as fs from 'graceful-fs';
68
- import invariant from 'invariant';
69
70
  import * as jscSafeUrl from 'jsc-safe-url';
70
71
  import {Logger} from 'metro-core';
71
72
  import mime from 'mime-types';
@@ -98,6 +99,7 @@ export type BundleMetadata = {
98
99
  };
99
100
 
100
101
  type ProcessStartContext = {
102
+ ...SplitBundleOptions,
101
103
  +buildNumber: number,
102
104
  +bundleOptions: BundleOptions,
103
105
  +graphId: GraphId,
@@ -107,7 +109,6 @@ type ProcessStartContext = {
107
109
  +revisionId?: ?RevisionId,
108
110
  +bundlePerfLogger: RootPerfLogger,
109
111
  +requestStartTimestamp: number,
110
- ...SplitBundleOptions,
111
112
  };
112
113
 
113
114
  type ProcessDeleteContext = {
@@ -121,7 +122,7 @@ type ProcessEndContext<T> = {
121
122
  +result: T,
122
123
  };
123
124
 
124
- export type ServerOptions = $ReadOnly<{
125
+ export type ServerOptions = Readonly<{
125
126
  hasReducedPerformance?: boolean,
126
127
  onBundleBuilt?: (bundlePath: string) => void,
127
128
  watch?: boolean,
@@ -130,6 +131,13 @@ export type ServerOptions = $ReadOnly<{
130
131
  const DELTA_ID_HEADER = 'X-Metro-Delta-ID';
131
132
  const FILES_CHANGED_COUNT_HEADER = 'X-Metro-Files-Changed-Count';
132
133
 
134
+ type FetchTiming = {
135
+ graphId: GraphId,
136
+ startTime: number,
137
+ endTime: number | null,
138
+ isPrefetch: boolean,
139
+ };
140
+
133
141
  export default class Server {
134
142
  _bundler: IncrementalBundler;
135
143
  _config: ConfigT;
@@ -140,10 +148,12 @@ export default class Server {
140
148
  _platforms: Set<string>;
141
149
  _reporter: Reporter;
142
150
  _serverOptions: ServerOptions | void;
143
- _allowedSuffixesForSourceRequests: $ReadOnlyArray<string>;
144
- _sourceRequestRoutingMap: $ReadOnlyArray<
151
+ _allowedSuffixesForSourceRequests: ReadonlyArray<string>;
152
+ _sourceRequestRoutingMap: ReadonlyArray<
145
153
  [pathnamePrefix: string, normalizedRootDir: string],
146
154
  >;
155
+ _fetchTimings: Array<FetchTiming>;
156
+ _activeFetchCount: number;
147
157
 
148
158
  constructor(config: ConfigT, options?: ServerOptions) {
149
159
  this._config = config;
@@ -176,6 +186,8 @@ export default class Server {
176
186
  ]),
177
187
  ];
178
188
  this._isEnded = false;
189
+ this._fetchTimings = [];
190
+ this._activeFetchCount = 0;
179
191
 
180
192
  // TODO(T34760917): These two properties should eventually be instantiated
181
193
  // elsewhere and passed as parameters, since they are also needed by
@@ -208,9 +220,9 @@ export default class Server {
208
220
  splitOptions,
209
221
  prepend,
210
222
  graph,
211
- }: $ReadOnly<{
223
+ }: Readonly<{
212
224
  splitOptions: SplitBundleOptions,
213
- prepend: $ReadOnlyArray<Module<>>,
225
+ prepend: ReadonlyArray<Module<>>,
214
226
  graph: ReadOnlyGraph<>,
215
227
  }>): Promise<{code: string, map: string}> {
216
228
  const {
@@ -299,7 +311,7 @@ export default class Server {
299
311
  ): Promise<{
300
312
  code: string,
301
313
  map: string,
302
- assets?: $ReadOnlyArray<AssetData>,
314
+ assets?: ReadonlyArray<AssetData>,
303
315
  ...
304
316
  }> {
305
317
  const splitOptions = splitBundleOptions(bundleOptions);
@@ -403,7 +415,7 @@ export default class Server {
403
415
  });
404
416
  }
405
417
 
406
- async getAssets(options: BundleOptions): Promise<$ReadOnlyArray<AssetData>> {
418
+ async getAssets(options: BundleOptions): Promise<ReadonlyArray<AssetData>> {
407
419
  const {entryFile, onProgress, resolverOptions, transformOptions} =
408
420
  splitBundleOptions(options);
409
421
 
@@ -423,7 +435,7 @@ export default class Server {
423
435
  async _getAssetsFromDependencies(
424
436
  dependencies: ReadOnlyDependencies<>,
425
437
  platform: ?string,
426
- ): Promise<$ReadOnlyArray<AssetData>> {
438
+ ): Promise<ReadonlyArray<AssetData>> {
427
439
  return await getAssets(dependencies, {
428
440
  processModuleFilter: this._config.serializer.processModuleFilter,
429
441
  assetPlugins: this._config.transformer.assetPlugins,
@@ -549,12 +561,14 @@ export default class Server {
549
561
  );
550
562
 
551
563
  try {
564
+ const depGraph = await this._bundler.getBundler().getDependencyGraph();
552
565
  const data = await getAsset(
553
566
  assetPath,
554
567
  this._config.projectRoot,
555
568
  this._config.watchFolders,
556
569
  urlObj.searchParams.get('platform'),
557
570
  this._config.resolver.assetExts,
571
+ filePath => depGraph.doesFileExist(filePath),
558
572
  );
559
573
  // Tell clients to cache this for 1 year.
560
574
  // This is safe as the asset url contains a hash of the asset.
@@ -615,6 +629,13 @@ export default class Server {
615
629
  debug('Rewritten to: %s', req.url);
616
630
  }
617
631
  const reqHost = req.headers['x-forwarded-host'] || req.headers['host'];
632
+ debug('Request host is: %s', req.headers['host']);
633
+ if (req.headers['x-forwarded-host']) {
634
+ debug(
635
+ 'Request x-forwarded-host is: %s',
636
+ req.headers['x-forwarded-host'],
637
+ );
638
+ }
618
639
  if (!reqHost) {
619
640
  throw new Error('No host header was found.');
620
641
  }
@@ -759,7 +780,7 @@ export default class Server {
759
780
  req: IncomingMessage,
760
781
  res: ServerResponse,
761
782
  bundleOptions: BundleOptions,
762
- buildContext: $ReadOnly<{
783
+ buildContext: Readonly<{
763
784
  buildNumber: number,
764
785
  bundlePerfLogger: RootPerfLogger,
765
786
  }>,
@@ -769,7 +790,7 @@ export default class Server {
769
790
  req: IncomingMessage,
770
791
  res: ServerResponse,
771
792
  bundleOptions: BundleOptions,
772
- buildContext: $ReadOnly<{
793
+ buildContext: Readonly<{
773
794
  buildNumber: number,
774
795
  bundlePerfLogger: RootPerfLogger,
775
796
  }>,
@@ -837,25 +858,23 @@ export default class Server {
837
858
  const mres = MultipartResponse.wrapIfSupported(req, res);
838
859
 
839
860
  let onProgress = null;
840
- let lastProgress = -1;
861
+ let lastRatio = -1;
841
862
  if (this._config.reporter) {
842
863
  onProgress = (transformedFileCount: number, totalFileCount: number) => {
843
- const currentProgress = parseInt(
844
- (transformedFileCount / totalFileCount) * 100,
845
- 10,
864
+ const newRatio = calculateBundleProgressRatio(
865
+ transformedFileCount,
866
+ totalFileCount,
867
+ lastRatio,
846
868
  );
847
869
 
848
- // We want to throttle the updates so that we only show meaningful
849
- // UI updates slow enough for the client to actually handle them. For
850
- // that, we check the percentage, and only send percentages that are
851
- // actually different and that have increased from the last one we sent.
852
- if (currentProgress > lastProgress || totalFileCount < 10) {
870
+ if (newRatio > lastRatio) {
853
871
  if (mres instanceof MultipartResponse) {
854
872
  mres.writeChunk(
855
873
  {'Content-Type': 'application/json'},
856
874
  JSON.stringify({
857
875
  done: transformedFileCount,
858
876
  total: totalFileCount,
877
+ percent: Math.floor(newRatio * 100),
859
878
  }),
860
879
  );
861
880
  }
@@ -871,7 +890,7 @@ export default class Server {
871
890
  res.socket.uncork();
872
891
  }
873
892
 
874
- lastProgress = currentProgress;
893
+ lastRatio = newRatio;
875
894
  }
876
895
 
877
896
  this._reporter.update({
@@ -917,8 +936,18 @@ export default class Server {
917
936
  createActionStartEntry(createStartEntry(startContext)),
918
937
  );
919
938
 
939
+ const fetchTiming: FetchTiming = {
940
+ graphId,
941
+ startTime: requestStartTimestamp,
942
+ endTime: null,
943
+ isPrefetch: req.method === 'HEAD',
944
+ };
945
+
920
946
  let result;
921
947
  try {
948
+ this._fetchTimings.push(fetchTiming);
949
+ this._activeFetchCount++;
950
+
922
951
  result = await build(startContext);
923
952
  } catch (error) {
924
953
  const formattedError = formatBundlingError(error);
@@ -951,6 +980,33 @@ export default class Server {
951
980
  buildContext.bundlePerfLogger.end('FAIL');
952
981
 
953
982
  return;
983
+ } finally {
984
+ fetchTiming.endTime = performance.timeOrigin + performance.now();
985
+
986
+ if (!fetchTiming.isPrefetch) {
987
+ buildContext.bundlePerfLogger.annotate({
988
+ bool: {
989
+ had_competing_prefetch: this._fetchTimings
990
+ // fetching the same bundle as a prefetch don't compete, since they resolve a shared promise for the same graph id
991
+ .filter(t => t.isPrefetch && t.graphId !== graphId)
992
+ .some(prefetch => {
993
+ const prefetchEndTime =
994
+ prefetch.endTime ?? Number.MAX_SAFE_INTEGER;
995
+ const fetchEndTime =
996
+ fetchTiming.endTime ?? Number.MAX_SAFE_INTEGER;
997
+ return (
998
+ prefetch.startTime < fetchEndTime &&
999
+ prefetchEndTime > fetchTiming.startTime
1000
+ );
1001
+ }),
1002
+ },
1003
+ });
1004
+ }
1005
+
1006
+ this._activeFetchCount--;
1007
+ if (this._activeFetchCount === 0) {
1008
+ this._fetchTimings = [];
1009
+ }
954
1010
  }
955
1011
 
956
1012
  const endContext: ProcessEndContext<T> = {
@@ -980,7 +1036,7 @@ export default class Server {
980
1036
  req: IncomingMessage,
981
1037
  res: ServerResponse,
982
1038
  bundleOptions: BundleOptions,
983
- buildContext: $ReadOnly<{
1039
+ buildContext: Readonly<{
984
1040
  buildNumber: number,
985
1041
  bundlePerfLogger: RootPerfLogger,
986
1042
  }>,
@@ -990,6 +1046,7 @@ export default class Server {
990
1046
  return {
991
1047
  action_name: 'Requesting bundle',
992
1048
  bundle_url: context.req.url,
1049
+ bundle_original_url: context.req.originalUrl ?? 'unknown',
993
1050
  entry_point: context.entryFile,
994
1051
  bundler: 'delta',
995
1052
  build_id: getBuildID(context.buildNumber),
@@ -1174,7 +1231,7 @@ export default class Server {
1174
1231
 
1175
1232
  // This function ensures that modules in source maps are sorted in the same
1176
1233
  // order as in a plain JS bundle.
1177
- _getSortedModules(graph: ReadOnlyGraph<>): $ReadOnlyArray<Module<>> {
1234
+ _getSortedModules(graph: ReadOnlyGraph<>): ReadonlyArray<Module<>> {
1178
1235
  const modules = [...graph.dependencies.values()];
1179
1236
  // Assign IDs to modules in a consistent order
1180
1237
  for (const module of modules) {
@@ -1191,7 +1248,7 @@ export default class Server {
1191
1248
  req: IncomingMessage,
1192
1249
  res: ServerResponse,
1193
1250
  bundleOptions: BundleOptions,
1194
- buildContext: $ReadOnly<{
1251
+ buildContext: Readonly<{
1195
1252
  buildNumber: number,
1196
1253
  bundlePerfLogger: RootPerfLogger,
1197
1254
  }>,
@@ -1263,7 +1320,7 @@ export default class Server {
1263
1320
  req: IncomingMessage,
1264
1321
  res: ServerResponse,
1265
1322
  bundleOptions: BundleOptions,
1266
- buildContext: $ReadOnly<{
1323
+ buildContext: Readonly<{
1267
1324
  buildNumber: number,
1268
1325
  bundlePerfLogger: RootPerfLogger,
1269
1326
  }>,
@@ -1277,7 +1334,7 @@ export default class Server {
1277
1334
  bundler: 'delta',
1278
1335
  };
1279
1336
  },
1280
- createEndEntry(context: ProcessEndContext<$ReadOnlyArray<AssetData>>) {
1337
+ createEndEntry(context: ProcessEndContext<ReadonlyArray<AssetData>>) {
1281
1338
  return {
1282
1339
  bundler: 'delta',
1283
1340
  };
@@ -1309,10 +1366,12 @@ export default class Server {
1309
1366
  },
1310
1367
  });
1311
1368
 
1312
- async _symbolicate(req: IncomingMessage, res: ServerResponse) {
1369
+ async _symbolicate(req: IncomingMessage, res: ServerResponse): Promise<void> {
1370
+ const depGraph = await this._bundler.getBundler().getDependencyGraph();
1371
+
1313
1372
  const getCodeFrame = (
1314
1373
  urls: Set<string>,
1315
- symbolicatedStack: $ReadOnlyArray<StackFrameOutput>,
1374
+ symbolicatedStack: ReadonlyArray<StackFrameOutput>,
1316
1375
  ) => {
1317
1376
  const allFramesCollapsed = symbolicatedStack.every(
1318
1377
  ({collapse}) => collapse,
@@ -1332,6 +1391,13 @@ export default class Server {
1332
1391
  }
1333
1392
 
1334
1393
  const fileAbsolute = path.resolve(this._config.projectRoot, file ?? '');
1394
+ if (!depGraph.doesFileExist(fileAbsolute)) {
1395
+ debug(
1396
+ 'Skipping code frame for file not in dependency graph.',
1397
+ fileAbsolute,
1398
+ );
1399
+ continue;
1400
+ }
1335
1401
  try {
1336
1402
  return {
1337
1403
  content: codeFrameColumns(
@@ -1361,6 +1427,7 @@ export default class Server {
1361
1427
  return null;
1362
1428
  };
1363
1429
 
1430
+ let inputValidated = false;
1364
1431
  try {
1365
1432
  const symbolicatingLogEntry = log(
1366
1433
  createActionStartEntry('Symbolicating'),
@@ -1373,35 +1440,78 @@ export default class Server {
1373
1440
  // < 0.80 and Expo SDK < 53
1374
1441
  // $FlowFixMe[prop-missing] - rawBody assigned by legacy CLI integrations
1375
1442
  const body = await req.rawBody;
1376
- parsedBody = JSON.parse(body);
1443
+ parsedBody = JSON.parse(body) as JsonData;
1377
1444
  } else {
1378
- parsedBody = (await parseJsonBody(req)) as {
1379
- stack: $ReadOnlyArray<StackFrameInput>,
1380
- extraData: {[string]: mixed},
1381
- };
1445
+ parsedBody = await parseJsonBody(req, {strict: false});
1382
1446
  }
1383
1447
 
1384
- const rewriteAndNormalizeStackFrame = <T>(
1385
- frame: T,
1386
- lineNumber: number,
1387
- ): T => {
1388
- invariant(
1389
- frame != null && typeof frame === 'object',
1390
- 'Bad stack frame at line %d, expected object, received: %s',
1391
- lineNumber,
1392
- typeof frame,
1448
+ let validatedBody: {
1449
+ stack: ReadonlyArray<JsonData>,
1450
+ extraData?: JsonData,
1451
+ };
1452
+
1453
+ if (
1454
+ parsedBody != null &&
1455
+ typeof parsedBody === 'object' &&
1456
+ !Array.isArray(parsedBody) &&
1457
+ Array.isArray(parsedBody['stack'])
1458
+ ) {
1459
+ const maybeStack: Array<JsonData> = parsedBody['stack'];
1460
+ const extraData = parsedBody['extraData'];
1461
+ validatedBody = {
1462
+ stack: maybeStack,
1463
+ extraData,
1464
+ };
1465
+ } else {
1466
+ throw new Error(
1467
+ `Bad symbolication input, expected object with stack array, got: ${JSON.stringify(parsedBody)}`,
1393
1468
  );
1394
- const frameFile = frame.file;
1395
- if (typeof frameFile === 'string' && frameFile.includes('://')) {
1396
- return {
1397
- ...frame,
1398
- file: this._rewriteAndNormalizeUrl(frameFile),
1399
- };
1469
+ }
1470
+
1471
+ const validateAndNormalizeStackFrame = (
1472
+ frame: JsonData,
1473
+ ): StackFrameInput => {
1474
+ if (
1475
+ frame == null ||
1476
+ typeof frame !== 'object' ||
1477
+ Array.isArray(frame)
1478
+ ) {
1479
+ throw new Error('Expected frame to be a JSON object');
1480
+ }
1481
+ if (frame.file != null && typeof frame.file !== 'string') {
1482
+ throw new Error('Expected file to be string or nullish');
1483
+ }
1484
+ let frameFile = frame.file;
1485
+ if (frameFile != null && frameFile.includes('://')) {
1486
+ frameFile = this._rewriteAndNormalizeUrl(frameFile);
1487
+ }
1488
+ if (frame.methodName != null && typeof frame.methodName !== 'string') {
1489
+ throw new Error('Expected methodName to be string or nullish');
1490
+ }
1491
+ if (frame.lineNumber != null && typeof frame.lineNumber !== 'number') {
1492
+ throw new Error('Expected lineNumber to be number or nullish');
1400
1493
  }
1401
- return frame;
1494
+ if (frame.column != null && typeof frame.column !== 'number') {
1495
+ throw new Error('Expected column to be number or nullish');
1496
+ }
1497
+ return {
1498
+ ...frame,
1499
+ file: frameFile,
1500
+ lineNumber: frame.lineNumber,
1501
+ column: frame.column,
1502
+ methodName: frame.methodName,
1503
+ };
1402
1504
  };
1403
1505
 
1404
- const stack = parsedBody.stack.map(rewriteAndNormalizeStackFrame);
1506
+ const stack = validatedBody.stack.map((frame, lineNumber) => {
1507
+ try {
1508
+ return validateAndNormalizeStackFrame(frame);
1509
+ } catch (e) {
1510
+ throw new Error(`Bad frame at line ${lineNumber}: ${e.message}`);
1511
+ }
1512
+ });
1513
+
1514
+ inputValidated = true;
1405
1515
  // In case of multiple bundles / HMR, some stack frames can have different URLs from others
1406
1516
  const urls = new Set<string>();
1407
1517
 
@@ -1433,7 +1543,7 @@ export default class Server {
1433
1543
  stack,
1434
1544
  zip(urls.values(), sourceMaps),
1435
1545
  this._config,
1436
- parsedBody.extraData ?? {},
1546
+ validatedBody.extraData ?? {},
1437
1547
  );
1438
1548
 
1439
1549
  debug('Symbolication done');
@@ -1448,7 +1558,7 @@ export default class Server {
1448
1558
  });
1449
1559
  } catch (error) {
1450
1560
  debug('Symbolication failed', error.stack || error);
1451
- res.statusCode = 500;
1561
+ res.statusCode = inputValidated ? 500 : 400;
1452
1562
  res.end(JSON.stringify({error: error.message}));
1453
1563
  }
1454
1564
  }
@@ -1518,7 +1628,7 @@ export default class Server {
1518
1628
  relativeTo,
1519
1629
  resolverOptions,
1520
1630
  transformOptions,
1521
- }: $ReadOnly<{
1631
+ }: Readonly<{
1522
1632
  relativeTo: 'project' | 'server',
1523
1633
  resolverOptions: ResolverInputOptions,
1524
1634
  transformOptions: TransformInputOptions,
@@ -1543,15 +1653,15 @@ export default class Server {
1543
1653
  return this._nextBundleBuildNumber++;
1544
1654
  }
1545
1655
 
1546
- getPlatforms(): $ReadOnlyArray<string> {
1656
+ getPlatforms(): ReadonlyArray<string> {
1547
1657
  return this._config.resolver.platforms;
1548
1658
  }
1549
1659
 
1550
- getWatchFolders(): $ReadOnlyArray<string> {
1660
+ getWatchFolders(): ReadonlyArray<string> {
1551
1661
  return this._config.watchFolders;
1552
1662
  }
1553
1663
 
1554
- static DEFAULT_GRAPH_OPTIONS: $ReadOnly<{
1664
+ static DEFAULT_GRAPH_OPTIONS: Readonly<{
1555
1665
  customResolverOptions: CustomResolverOptions,
1556
1666
  customTransformOptions: CustomTransformOptions,
1557
1667
  dev: boolean,
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall react_native
9
+ */
10
+
11
+ declare function coerceKeyValueArray(keyValueArray: ReadonlyArray<string>): {
12
+ [key: string]: string;
13
+ };
14
+ export default coerceKeyValueArray;
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  export default function coerceKeyValueArray(
13
- keyValueArray: $ReadOnlyArray<string>,
13
+ keyValueArray: ReadonlyArray<string>,
14
14
  ): {
15
15
  [key: string]: string,
16
16
  __proto__: null,
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall react_native
9
+ */
10
+
11
+ export declare const watchFile: (
12
+ filename: string,
13
+ callback: () => unknown,
14
+ ) => Promise<void>;
15
+ export declare type watchFile = typeof watchFile;
16
+ export declare const makeAsyncCommand: <T>(
17
+ command: (argv: T) => Promise<void>,
18
+ ) => (argv: T) => void;
19
+ export declare type makeAsyncCommand = typeof makeAsyncCommand;
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @flow
7
+ * @flow strict
8
8
  * @format
9
9
  * @oncall react_native
10
10
  */
@@ -13,7 +13,7 @@ import fs from 'fs';
13
13
 
14
14
  export const watchFile = async function (
15
15
  filename: string,
16
- callback: () => any,
16
+ callback: () => unknown,
17
17
  ): Promise<void> {
18
18
  fs.watchFile(filename, () => {
19
19
  callback();
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall react_native
9
+ */
10
+
11
+ import type {CommandModule} from 'yargs';
12
+
13
+ declare const $$EXPORT_DEFAULT_DECLARATION$$: () => CommandModule;
14
+ declare type $$EXPORT_DEFAULT_DECLARATION$$ =
15
+ typeof $$EXPORT_DEFAULT_DECLARATION$$;
16
+ export default $$EXPORT_DEFAULT_DECLARATION$$;
@@ -4,7 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
- * @flow
7
+ * @flow strict-local
8
8
  * @format
9
9
  * @oncall react_native
10
10
  */
@@ -12,7 +12,7 @@
12
12
  import type {RunBuildOptions} from '../index';
13
13
  import type {CustomTransformOptions} from 'metro-babel-transformer';
14
14
  import type {CustomResolverOptions} from 'metro-resolver';
15
- import type {ModuleObject} from 'yargs';
15
+ import type {CommandModule} from 'yargs';
16
16
  import typeof Yargs from 'yargs';
17
17
 
18
18
  import {makeAsyncCommand} from '../cli-utils';
@@ -24,7 +24,9 @@ import {Terminal} from 'metro-core';
24
24
  const term = new Terminal(process.stdout);
25
25
  const updateReporter = new TerminalReporter(term);
26
26
 
27
- type Args = $ReadOnly<{
27
+ type Args = Readonly<{
28
+ _: unknown,
29
+ $0: unknown,
28
30
  config?: string,
29
31
  dev?: boolean,
30
32
  entry: string,
@@ -34,18 +36,16 @@ type Args = $ReadOnly<{
34
36
  out: string,
35
37
  outputType?: string,
36
38
  platform?: string,
37
- projectRoots?: $ReadOnlyArray<string>,
39
+ projectRoots?: ReadonlyArray<string>,
38
40
  resetCache?: boolean,
39
41
  sourceMap?: boolean,
40
42
  sourceMapUrl?: string,
41
43
  transformOption: CustomTransformOptions,
42
44
  resolverOption: CustomResolverOptions,
45
+ ...
43
46
  }>;
44
47
 
45
- export default (): {
46
- ...ModuleObject,
47
- handler: Function,
48
- } => ({
48
+ export default (): CommandModule => ({
49
49
  command: 'build <entry>',
50
50
  desc: 'Generates a JavaScript bundle containing the specified entrypoint and its descendants',
51
51
 
@@ -76,7 +76,7 @@ export default (): {
76
76
  type: 'string',
77
77
  array: true,
78
78
  alias: 'transformer-option',
79
- coerce: (parseKeyValueParamArray: $FlowFixMe),
79
+ coerce: parseKeyValueParamArray as $FlowFixMe,
80
80
  describe:
81
81
  'Custom transform options of the form key=value. URL-encoded. May be specified multiple times.',
82
82
  });
@@ -84,7 +84,7 @@ export default (): {
84
84
  yargs.option('resolver-option', {
85
85
  type: 'string',
86
86
  array: true,
87
- coerce: (parseKeyValueParamArray: $FlowFixMe),
87
+ coerce: parseKeyValueParamArray as $FlowFixMe,
88
88
  describe:
89
89
  'Custom resolver options of the form key=value. URL-encoded. May be specified multiple times.',
90
90
  });
@@ -94,6 +94,7 @@ export default (): {
94
94
  },
95
95
 
96
96
  handler: makeAsyncCommand(async (argv: Args) => {
97
+ // $FlowFixMe[incompatible-type] argv has extra props.
97
98
  const config = await loadConfig(argv);
98
99
  const options: RunBuildOptions = {
99
100
  entry: argv.entry,
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall react_native
9
+ */
10
+
11
+ import type {CommandModule} from 'yargs';
12
+
13
+ declare const $$EXPORT_DEFAULT_DECLARATION$$: () => CommandModule;
14
+ declare type $$EXPORT_DEFAULT_DECLARATION$$ =
15
+ typeof $$EXPORT_DEFAULT_DECLARATION$$;
16
+ export default $$EXPORT_DEFAULT_DECLARATION$$;