metro 0.83.3 → 0.84.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.
- package/package.json +28 -25
- package/src/Assets.js +42 -29
- package/src/Assets.js.flow +26 -15
- package/src/Bundler/util.js +25 -21
- package/src/Bundler/util.js.flow +2 -2
- package/src/Bundler.js.flow +1 -1
- package/src/DeltaBundler/DeltaCalculator.js +4 -4
- package/src/DeltaBundler/DeltaCalculator.js.flow +8 -8
- package/src/DeltaBundler/Graph.js +16 -16
- package/src/DeltaBundler/Graph.js.flow +30 -30
- package/src/DeltaBundler/Serializers/baseJSBundle.js.flow +1 -1
- package/src/DeltaBundler/Serializers/getAllFiles.js.flow +2 -2
- package/src/DeltaBundler/Serializers/getAssets.js.flow +2 -2
- package/src/DeltaBundler/Serializers/getExplodedSourceMap.js.flow +2 -2
- package/src/DeltaBundler/Serializers/getRamBundleInfo.js.flow +8 -8
- package/src/DeltaBundler/Serializers/helpers/js.js +25 -21
- package/src/DeltaBundler/Serializers/helpers/js.js.flow +6 -6
- package/src/DeltaBundler/Serializers/helpers/processModules.js.flow +3 -3
- package/src/DeltaBundler/Serializers/hmrJSBundle.js +25 -21
- package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +5 -5
- package/src/DeltaBundler/Serializers/sourceMapGenerator.js.flow +6 -6
- package/src/DeltaBundler/Serializers/sourceMapObject.js.flow +2 -2
- package/src/DeltaBundler/Serializers/sourceMapString.js.flow +2 -2
- package/src/DeltaBundler/Transformer.js.flow +3 -3
- package/src/DeltaBundler/Worker.flow.js.flow +1 -1
- package/src/DeltaBundler/WorkerFarm.js +1 -1
- package/src/DeltaBundler/WorkerFarm.js.flow +26 -13
- package/src/DeltaBundler/buildSubgraph.js +4 -4
- package/src/DeltaBundler/buildSubgraph.js.flow +8 -8
- package/src/DeltaBundler/types.js.flow +36 -34
- package/src/DeltaBundler.js.flow +2 -2
- package/src/HmrServer.js +34 -29
- package/src/HmrServer.js.flow +17 -12
- package/src/IncrementalBundler.js +29 -21
- package/src/IncrementalBundler.js.flow +13 -9
- package/src/ModuleGraph/worker/JsFileWrapping.js +25 -21
- package/src/ModuleGraph/worker/JsFileWrapping.js.flow +10 -5
- package/src/ModuleGraph/worker/collectDependencies.js +25 -21
- package/src/ModuleGraph/worker/collectDependencies.js.flow +27 -21
- package/src/ModuleGraph/worker/generateImportNames.js.flow +4 -2
- package/src/ModuleGraph/worker/importLocationsPlugin.js.flow +7 -3
- package/src/Server/MultipartResponse.js.flow +1 -1
- package/src/Server/symbolicate.js.flow +4 -4
- package/src/Server.js +139 -39
- package/src/Server.js.flow +158 -47
- package/src/cli/parseKeyValueParamArray.js.flow +1 -1
- package/src/cli-utils.js.flow +2 -2
- package/src/commands/build.js.flow +11 -10
- package/src/commands/dependencies.js.flow +8 -4
- package/src/commands/serve.js +2 -0
- package/src/commands/serve.js.flow +14 -9
- package/src/index.flow.js +30 -26
- package/src/index.flow.js.flow +25 -20
- package/src/integration_tests/basic_bundle/AssetRegistry.js.flow +1 -1
- package/src/integration_tests/basic_bundle/ErrorBundle.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-import.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import-with-escapes.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require-with-embedded-comment.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-specifier-with-escapes.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-import.js.flow +1 -1
- package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-require.js.flow +1 -1
- package/src/integration_tests/basic_bundle/import-export/index.js +25 -21
- package/src/integration_tests/basic_bundle/import-export/index.js.flow +3 -3
- package/src/integration_tests/basic_bundle/import-export/utils.js.flow +2 -2
- package/src/integration_tests/basic_bundle/loadBundleAsyncForTest.js.flow +1 -1
- package/src/integration_tests/basic_bundle/optional-dependencies/index.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-context/conflict.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-context/empty.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-context/matching.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-context/mode-eager.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-context/mode-lazy.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +2 -2
- package/src/integration_tests/basic_bundle/require-context/utils.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-resolveWeak/import-and-resolveWeak.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-resolveWeak/multiple.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-resolveWeak/never-required.js.flow +1 -1
- package/src/integration_tests/basic_bundle/require-resolveWeak/require-and-resolveWeak.js.flow +1 -1
- package/src/integration_tests/execBundle.js.flow +1 -1
- package/src/lib/BatchProcessor.js +5 -2
- package/src/lib/BatchProcessor.js.flow +10 -7
- package/src/lib/CountingSet.js.flow +4 -4
- package/src/lib/JsonReporter.js +5 -3
- package/src/lib/JsonReporter.js.flow +19 -17
- package/src/lib/RamBundleParser.js.flow +1 -1
- package/src/lib/TerminalReporter.js +31 -27
- package/src/lib/TerminalReporter.js.flow +15 -15
- package/src/lib/contextModule.js.flow +1 -1
- package/src/lib/contextModuleTemplates.js +25 -21
- package/src/lib/countLines.js +4 -3
- package/src/lib/countLines.js.flow +3 -4
- package/src/lib/createWebsocketServer.js +9 -2
- package/src/lib/createWebsocketServer.js.flow +16 -9
- package/src/lib/debounceAsyncQueue.js.flow +1 -1
- package/src/lib/formatBundlingError.js.flow +1 -1
- package/src/lib/getAppendScripts.js.flow +4 -4
- package/src/lib/getGraphId.js.flow +1 -1
- package/src/lib/getPreludeCode.js +4 -0
- package/src/lib/getPreludeCode.js.flow +10 -3
- package/src/lib/getPrependedScripts.js +36 -22
- package/src/lib/getPrependedScripts.js.flow +10 -3
- package/src/lib/logToConsole.js.flow +2 -2
- package/src/lib/parseBundleOptionsFromBundleRequestUrl.js +25 -21
- package/src/lib/parseCustomResolverOptions.js.flow +2 -2
- package/src/lib/parseCustomTransformOptions.js.flow +1 -1
- package/src/lib/parseJsonBody.js.flow +11 -1
- package/src/lib/pathUtils.js +25 -21
- package/src/lib/pathUtils.js.flow +1 -1
- package/src/lib/reporting.js.flow +4 -4
- package/src/lib/transformHelpers.js +11 -9
- package/src/lib/transformHelpers.js.flow +17 -15
- package/src/node-haste/DependencyGraph/ModuleResolution.js +48 -42
- package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +35 -32
- package/src/node-haste/DependencyGraph/createFileMap.js +56 -38
- package/src/node-haste/DependencyGraph/createFileMap.js.flow +44 -18
- package/src/node-haste/DependencyGraph.js +40 -31
- package/src/node-haste/DependencyGraph.js.flow +35 -37
- package/src/node-haste/lib/AssetPaths.js +2 -2
- package/src/node-haste/lib/AssetPaths.js.flow +4 -4
- package/src/node-haste/lib/parsePlatformFilePath.js +6 -6
- package/src/node-haste/lib/parsePlatformFilePath.js.flow +4 -4
- package/src/shared/output/RamBundle/as-assets.js.flow +6 -6
- package/src/shared/output/RamBundle/as-indexed-file.js.flow +5 -5
- package/src/shared/output/RamBundle/buildSourcemapWithMetadata.js.flow +5 -5
- package/src/shared/output/RamBundle/util.js.flow +5 -5
- package/src/shared/output/RamBundle/write-sourcemap.js.flow +1 -1
- package/src/shared/output/RamBundle.js.flow +1 -1
- package/src/shared/output/bundle.flow.js.flow +3 -3
- package/src/shared/output/meta.js +2 -2
- package/src/shared/output/meta.js.flow +1 -1
- package/src/shared/output/writeFile.js +8 -3
- package/src/shared/output/writeFile.js.flow +8 -2
- package/src/shared/types.js.flow +20 -5
- package/src/Asset.d.ts +0 -25
- package/src/Bundler.d.ts +0 -39
- package/src/DeltaBundler/Graph.d.ts +0 -40
- package/src/DeltaBundler/Serializers/getExplodedSourceMap.d.ts +0 -26
- package/src/DeltaBundler/Serializers/getRamBundleInfo.d.ts +0 -18
- package/src/DeltaBundler/Worker.d.ts +0 -45
- package/src/DeltaBundler/types.d.ts +0 -166
- package/src/DeltaBundler.d.ts +0 -58
- package/src/IncrementalBundler.d.ts +0 -98
- package/src/ModuleGraph/test-helpers.js +0 -75
- package/src/ModuleGraph/worker/collectDependencies.d.ts +0 -27
- package/src/Server/MultipartResponse.d.ts +0 -31
- package/src/Server/symbolicate.d.ts +0 -31
- package/src/Server.d.ts +0 -118
- package/src/index.d.ts +0 -193
- package/src/lib/CountingSet.d.ts +0 -48
- package/src/lib/TerminalReporter.d.ts +0 -27
- package/src/lib/contextModule.d.ts +0 -22
- package/src/lib/getGraphId.d.ts +0 -11
- package/src/lib/reporting.d.ts +0 -144
- package/src/node-haste/DependencyGraph.d.ts +0 -62
- package/src/shared/output/bundle.d.ts +0 -35
- package/src/shared/types.d.ts +0 -130
package/src/Server.js.flow
CHANGED
|
@@ -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 {
|
|
@@ -65,7 +66,6 @@ import symbolicate from './Server/symbolicate';
|
|
|
65
66
|
import {SourcePathsMode} from './shared/types';
|
|
66
67
|
import {codeFrameColumns} from '@babel/code-frame';
|
|
67
68
|
import * as fs from 'graceful-fs';
|
|
68
|
-
import invariant from 'invariant';
|
|
69
69
|
import * as jscSafeUrl from 'jsc-safe-url';
|
|
70
70
|
import {Logger} from 'metro-core';
|
|
71
71
|
import mime from 'mime-types';
|
|
@@ -98,6 +98,7 @@ export type BundleMetadata = {
|
|
|
98
98
|
};
|
|
99
99
|
|
|
100
100
|
type ProcessStartContext = {
|
|
101
|
+
...SplitBundleOptions,
|
|
101
102
|
+buildNumber: number,
|
|
102
103
|
+bundleOptions: BundleOptions,
|
|
103
104
|
+graphId: GraphId,
|
|
@@ -107,7 +108,6 @@ type ProcessStartContext = {
|
|
|
107
108
|
+revisionId?: ?RevisionId,
|
|
108
109
|
+bundlePerfLogger: RootPerfLogger,
|
|
109
110
|
+requestStartTimestamp: number,
|
|
110
|
-
...SplitBundleOptions,
|
|
111
111
|
};
|
|
112
112
|
|
|
113
113
|
type ProcessDeleteContext = {
|
|
@@ -121,7 +121,7 @@ type ProcessEndContext<T> = {
|
|
|
121
121
|
+result: T,
|
|
122
122
|
};
|
|
123
123
|
|
|
124
|
-
export type ServerOptions =
|
|
124
|
+
export type ServerOptions = Readonly<{
|
|
125
125
|
hasReducedPerformance?: boolean,
|
|
126
126
|
onBundleBuilt?: (bundlePath: string) => void,
|
|
127
127
|
watch?: boolean,
|
|
@@ -130,6 +130,13 @@ export type ServerOptions = $ReadOnly<{
|
|
|
130
130
|
const DELTA_ID_HEADER = 'X-Metro-Delta-ID';
|
|
131
131
|
const FILES_CHANGED_COUNT_HEADER = 'X-Metro-Files-Changed-Count';
|
|
132
132
|
|
|
133
|
+
type FetchTiming = {
|
|
134
|
+
graphId: GraphId,
|
|
135
|
+
startTime: number,
|
|
136
|
+
endTime: number | null,
|
|
137
|
+
isPrefetch: boolean,
|
|
138
|
+
};
|
|
139
|
+
|
|
133
140
|
export default class Server {
|
|
134
141
|
_bundler: IncrementalBundler;
|
|
135
142
|
_config: ConfigT;
|
|
@@ -140,10 +147,12 @@ export default class Server {
|
|
|
140
147
|
_platforms: Set<string>;
|
|
141
148
|
_reporter: Reporter;
|
|
142
149
|
_serverOptions: ServerOptions | void;
|
|
143
|
-
_allowedSuffixesForSourceRequests:
|
|
144
|
-
_sourceRequestRoutingMap:
|
|
150
|
+
_allowedSuffixesForSourceRequests: ReadonlyArray<string>;
|
|
151
|
+
_sourceRequestRoutingMap: ReadonlyArray<
|
|
145
152
|
[pathnamePrefix: string, normalizedRootDir: string],
|
|
146
153
|
>;
|
|
154
|
+
_fetchTimings: Array<FetchTiming>;
|
|
155
|
+
_activeFetchCount: number;
|
|
147
156
|
|
|
148
157
|
constructor(config: ConfigT, options?: ServerOptions) {
|
|
149
158
|
this._config = config;
|
|
@@ -176,6 +185,8 @@ export default class Server {
|
|
|
176
185
|
]),
|
|
177
186
|
];
|
|
178
187
|
this._isEnded = false;
|
|
188
|
+
this._fetchTimings = [];
|
|
189
|
+
this._activeFetchCount = 0;
|
|
179
190
|
|
|
180
191
|
// TODO(T34760917): These two properties should eventually be instantiated
|
|
181
192
|
// elsewhere and passed as parameters, since they are also needed by
|
|
@@ -208,9 +219,9 @@ export default class Server {
|
|
|
208
219
|
splitOptions,
|
|
209
220
|
prepend,
|
|
210
221
|
graph,
|
|
211
|
-
}:
|
|
222
|
+
}: Readonly<{
|
|
212
223
|
splitOptions: SplitBundleOptions,
|
|
213
|
-
prepend:
|
|
224
|
+
prepend: ReadonlyArray<Module<>>,
|
|
214
225
|
graph: ReadOnlyGraph<>,
|
|
215
226
|
}>): Promise<{code: string, map: string}> {
|
|
216
227
|
const {
|
|
@@ -299,7 +310,7 @@ export default class Server {
|
|
|
299
310
|
): Promise<{
|
|
300
311
|
code: string,
|
|
301
312
|
map: string,
|
|
302
|
-
assets?:
|
|
313
|
+
assets?: ReadonlyArray<AssetData>,
|
|
303
314
|
...
|
|
304
315
|
}> {
|
|
305
316
|
const splitOptions = splitBundleOptions(bundleOptions);
|
|
@@ -403,7 +414,7 @@ export default class Server {
|
|
|
403
414
|
});
|
|
404
415
|
}
|
|
405
416
|
|
|
406
|
-
async getAssets(options: BundleOptions): Promise
|
|
417
|
+
async getAssets(options: BundleOptions): Promise<ReadonlyArray<AssetData>> {
|
|
407
418
|
const {entryFile, onProgress, resolverOptions, transformOptions} =
|
|
408
419
|
splitBundleOptions(options);
|
|
409
420
|
|
|
@@ -423,7 +434,7 @@ export default class Server {
|
|
|
423
434
|
async _getAssetsFromDependencies(
|
|
424
435
|
dependencies: ReadOnlyDependencies<>,
|
|
425
436
|
platform: ?string,
|
|
426
|
-
): Promise
|
|
437
|
+
): Promise<ReadonlyArray<AssetData>> {
|
|
427
438
|
return await getAssets(dependencies, {
|
|
428
439
|
processModuleFilter: this._config.serializer.processModuleFilter,
|
|
429
440
|
assetPlugins: this._config.transformer.assetPlugins,
|
|
@@ -549,12 +560,14 @@ export default class Server {
|
|
|
549
560
|
);
|
|
550
561
|
|
|
551
562
|
try {
|
|
563
|
+
const depGraph = await this._bundler.getBundler().getDependencyGraph();
|
|
552
564
|
const data = await getAsset(
|
|
553
565
|
assetPath,
|
|
554
566
|
this._config.projectRoot,
|
|
555
567
|
this._config.watchFolders,
|
|
556
568
|
urlObj.searchParams.get('platform'),
|
|
557
569
|
this._config.resolver.assetExts,
|
|
570
|
+
filePath => depGraph.doesFileExist(filePath),
|
|
558
571
|
);
|
|
559
572
|
// Tell clients to cache this for 1 year.
|
|
560
573
|
// This is safe as the asset url contains a hash of the asset.
|
|
@@ -615,6 +628,13 @@ export default class Server {
|
|
|
615
628
|
debug('Rewritten to: %s', req.url);
|
|
616
629
|
}
|
|
617
630
|
const reqHost = req.headers['x-forwarded-host'] || req.headers['host'];
|
|
631
|
+
debug('Request host is: %s', req.headers['host']);
|
|
632
|
+
if (req.headers['x-forwarded-host']) {
|
|
633
|
+
debug(
|
|
634
|
+
'Request x-forwarded-host is: %s',
|
|
635
|
+
req.headers['x-forwarded-host'],
|
|
636
|
+
);
|
|
637
|
+
}
|
|
618
638
|
if (!reqHost) {
|
|
619
639
|
throw new Error('No host header was found.');
|
|
620
640
|
}
|
|
@@ -759,7 +779,7 @@ export default class Server {
|
|
|
759
779
|
req: IncomingMessage,
|
|
760
780
|
res: ServerResponse,
|
|
761
781
|
bundleOptions: BundleOptions,
|
|
762
|
-
buildContext:
|
|
782
|
+
buildContext: Readonly<{
|
|
763
783
|
buildNumber: number,
|
|
764
784
|
bundlePerfLogger: RootPerfLogger,
|
|
765
785
|
}>,
|
|
@@ -769,7 +789,7 @@ export default class Server {
|
|
|
769
789
|
req: IncomingMessage,
|
|
770
790
|
res: ServerResponse,
|
|
771
791
|
bundleOptions: BundleOptions,
|
|
772
|
-
buildContext:
|
|
792
|
+
buildContext: Readonly<{
|
|
773
793
|
buildNumber: number,
|
|
774
794
|
bundlePerfLogger: RootPerfLogger,
|
|
775
795
|
}>,
|
|
@@ -917,8 +937,18 @@ export default class Server {
|
|
|
917
937
|
createActionStartEntry(createStartEntry(startContext)),
|
|
918
938
|
);
|
|
919
939
|
|
|
940
|
+
const fetchTiming: FetchTiming = {
|
|
941
|
+
graphId,
|
|
942
|
+
startTime: requestStartTimestamp,
|
|
943
|
+
endTime: null,
|
|
944
|
+
isPrefetch: req.method === 'HEAD',
|
|
945
|
+
};
|
|
946
|
+
|
|
920
947
|
let result;
|
|
921
948
|
try {
|
|
949
|
+
this._fetchTimings.push(fetchTiming);
|
|
950
|
+
this._activeFetchCount++;
|
|
951
|
+
|
|
922
952
|
result = await build(startContext);
|
|
923
953
|
} catch (error) {
|
|
924
954
|
const formattedError = formatBundlingError(error);
|
|
@@ -951,6 +981,33 @@ export default class Server {
|
|
|
951
981
|
buildContext.bundlePerfLogger.end('FAIL');
|
|
952
982
|
|
|
953
983
|
return;
|
|
984
|
+
} finally {
|
|
985
|
+
fetchTiming.endTime = performance.timeOrigin + performance.now();
|
|
986
|
+
|
|
987
|
+
if (!fetchTiming.isPrefetch) {
|
|
988
|
+
buildContext.bundlePerfLogger.annotate({
|
|
989
|
+
bool: {
|
|
990
|
+
had_competing_prefetch: this._fetchTimings
|
|
991
|
+
// fetching the same bundle as a prefetch don't compete, since they resolve a shared promise for the same graph id
|
|
992
|
+
.filter(t => t.isPrefetch && t.graphId !== graphId)
|
|
993
|
+
.some(prefetch => {
|
|
994
|
+
const prefetchEndTime =
|
|
995
|
+
prefetch.endTime ?? Number.MAX_SAFE_INTEGER;
|
|
996
|
+
const fetchEndTime =
|
|
997
|
+
fetchTiming.endTime ?? Number.MAX_SAFE_INTEGER;
|
|
998
|
+
return (
|
|
999
|
+
prefetch.startTime < fetchEndTime &&
|
|
1000
|
+
prefetchEndTime > fetchTiming.startTime
|
|
1001
|
+
);
|
|
1002
|
+
}),
|
|
1003
|
+
},
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
this._activeFetchCount--;
|
|
1008
|
+
if (this._activeFetchCount === 0) {
|
|
1009
|
+
this._fetchTimings = [];
|
|
1010
|
+
}
|
|
954
1011
|
}
|
|
955
1012
|
|
|
956
1013
|
const endContext: ProcessEndContext<T> = {
|
|
@@ -980,7 +1037,7 @@ export default class Server {
|
|
|
980
1037
|
req: IncomingMessage,
|
|
981
1038
|
res: ServerResponse,
|
|
982
1039
|
bundleOptions: BundleOptions,
|
|
983
|
-
buildContext:
|
|
1040
|
+
buildContext: Readonly<{
|
|
984
1041
|
buildNumber: number,
|
|
985
1042
|
bundlePerfLogger: RootPerfLogger,
|
|
986
1043
|
}>,
|
|
@@ -990,6 +1047,7 @@ export default class Server {
|
|
|
990
1047
|
return {
|
|
991
1048
|
action_name: 'Requesting bundle',
|
|
992
1049
|
bundle_url: context.req.url,
|
|
1050
|
+
bundle_original_url: context.req.originalUrl ?? 'unknown',
|
|
993
1051
|
entry_point: context.entryFile,
|
|
994
1052
|
bundler: 'delta',
|
|
995
1053
|
build_id: getBuildID(context.buildNumber),
|
|
@@ -1174,7 +1232,7 @@ export default class Server {
|
|
|
1174
1232
|
|
|
1175
1233
|
// This function ensures that modules in source maps are sorted in the same
|
|
1176
1234
|
// order as in a plain JS bundle.
|
|
1177
|
-
_getSortedModules(graph: ReadOnlyGraph<>):
|
|
1235
|
+
_getSortedModules(graph: ReadOnlyGraph<>): ReadonlyArray<Module<>> {
|
|
1178
1236
|
const modules = [...graph.dependencies.values()];
|
|
1179
1237
|
// Assign IDs to modules in a consistent order
|
|
1180
1238
|
for (const module of modules) {
|
|
@@ -1191,7 +1249,7 @@ export default class Server {
|
|
|
1191
1249
|
req: IncomingMessage,
|
|
1192
1250
|
res: ServerResponse,
|
|
1193
1251
|
bundleOptions: BundleOptions,
|
|
1194
|
-
buildContext:
|
|
1252
|
+
buildContext: Readonly<{
|
|
1195
1253
|
buildNumber: number,
|
|
1196
1254
|
bundlePerfLogger: RootPerfLogger,
|
|
1197
1255
|
}>,
|
|
@@ -1263,7 +1321,7 @@ export default class Server {
|
|
|
1263
1321
|
req: IncomingMessage,
|
|
1264
1322
|
res: ServerResponse,
|
|
1265
1323
|
bundleOptions: BundleOptions,
|
|
1266
|
-
buildContext:
|
|
1324
|
+
buildContext: Readonly<{
|
|
1267
1325
|
buildNumber: number,
|
|
1268
1326
|
bundlePerfLogger: RootPerfLogger,
|
|
1269
1327
|
}>,
|
|
@@ -1277,7 +1335,7 @@ export default class Server {
|
|
|
1277
1335
|
bundler: 'delta',
|
|
1278
1336
|
};
|
|
1279
1337
|
},
|
|
1280
|
-
createEndEntry(context: ProcessEndContext
|
|
1338
|
+
createEndEntry(context: ProcessEndContext<ReadonlyArray<AssetData>>) {
|
|
1281
1339
|
return {
|
|
1282
1340
|
bundler: 'delta',
|
|
1283
1341
|
};
|
|
@@ -1309,10 +1367,12 @@ export default class Server {
|
|
|
1309
1367
|
},
|
|
1310
1368
|
});
|
|
1311
1369
|
|
|
1312
|
-
async _symbolicate(req: IncomingMessage, res: ServerResponse) {
|
|
1370
|
+
async _symbolicate(req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
1371
|
+
const depGraph = await this._bundler.getBundler().getDependencyGraph();
|
|
1372
|
+
|
|
1313
1373
|
const getCodeFrame = (
|
|
1314
1374
|
urls: Set<string>,
|
|
1315
|
-
symbolicatedStack:
|
|
1375
|
+
symbolicatedStack: ReadonlyArray<StackFrameOutput>,
|
|
1316
1376
|
) => {
|
|
1317
1377
|
const allFramesCollapsed = symbolicatedStack.every(
|
|
1318
1378
|
({collapse}) => collapse,
|
|
@@ -1332,6 +1392,13 @@ export default class Server {
|
|
|
1332
1392
|
}
|
|
1333
1393
|
|
|
1334
1394
|
const fileAbsolute = path.resolve(this._config.projectRoot, file ?? '');
|
|
1395
|
+
if (!depGraph.doesFileExist(fileAbsolute)) {
|
|
1396
|
+
debug(
|
|
1397
|
+
'Skipping code frame for file not in dependency graph.',
|
|
1398
|
+
fileAbsolute,
|
|
1399
|
+
);
|
|
1400
|
+
continue;
|
|
1401
|
+
}
|
|
1335
1402
|
try {
|
|
1336
1403
|
return {
|
|
1337
1404
|
content: codeFrameColumns(
|
|
@@ -1361,6 +1428,7 @@ export default class Server {
|
|
|
1361
1428
|
return null;
|
|
1362
1429
|
};
|
|
1363
1430
|
|
|
1431
|
+
let inputValidated = false;
|
|
1364
1432
|
try {
|
|
1365
1433
|
const symbolicatingLogEntry = log(
|
|
1366
1434
|
createActionStartEntry('Symbolicating'),
|
|
@@ -1373,35 +1441,78 @@ export default class Server {
|
|
|
1373
1441
|
// < 0.80 and Expo SDK < 53
|
|
1374
1442
|
// $FlowFixMe[prop-missing] - rawBody assigned by legacy CLI integrations
|
|
1375
1443
|
const body = await req.rawBody;
|
|
1376
|
-
parsedBody = JSON.parse(body);
|
|
1444
|
+
parsedBody = JSON.parse(body) as JsonData;
|
|
1377
1445
|
} else {
|
|
1378
|
-
parsedBody =
|
|
1379
|
-
stack: $ReadOnlyArray<StackFrameInput>,
|
|
1380
|
-
extraData: {[string]: mixed},
|
|
1381
|
-
};
|
|
1446
|
+
parsedBody = await parseJsonBody(req, {strict: false});
|
|
1382
1447
|
}
|
|
1383
1448
|
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1449
|
+
let validatedBody: {
|
|
1450
|
+
stack: ReadonlyArray<JsonData>,
|
|
1451
|
+
extraData?: JsonData,
|
|
1452
|
+
};
|
|
1453
|
+
|
|
1454
|
+
if (
|
|
1455
|
+
parsedBody != null &&
|
|
1456
|
+
typeof parsedBody === 'object' &&
|
|
1457
|
+
!Array.isArray(parsedBody) &&
|
|
1458
|
+
Array.isArray(parsedBody['stack'])
|
|
1459
|
+
) {
|
|
1460
|
+
const maybeStack: Array<JsonData> = parsedBody['stack'];
|
|
1461
|
+
const extraData = parsedBody['extraData'];
|
|
1462
|
+
validatedBody = {
|
|
1463
|
+
stack: maybeStack,
|
|
1464
|
+
extraData,
|
|
1465
|
+
};
|
|
1466
|
+
} else {
|
|
1467
|
+
throw new Error(
|
|
1468
|
+
`Bad symbolication input, expected object with stack array, got: ${JSON.stringify(parsedBody)}`,
|
|
1393
1469
|
);
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
const validateAndNormalizeStackFrame = (
|
|
1473
|
+
frame: JsonData,
|
|
1474
|
+
): StackFrameInput => {
|
|
1475
|
+
if (
|
|
1476
|
+
frame == null ||
|
|
1477
|
+
typeof frame !== 'object' ||
|
|
1478
|
+
Array.isArray(frame)
|
|
1479
|
+
) {
|
|
1480
|
+
throw new Error('Expected frame to be a JSON object');
|
|
1481
|
+
}
|
|
1482
|
+
if (frame.file != null && typeof frame.file !== 'string') {
|
|
1483
|
+
throw new Error('Expected file to be string or nullish');
|
|
1484
|
+
}
|
|
1485
|
+
let frameFile = frame.file;
|
|
1486
|
+
if (frameFile != null && frameFile.includes('://')) {
|
|
1487
|
+
frameFile = this._rewriteAndNormalizeUrl(frameFile);
|
|
1488
|
+
}
|
|
1489
|
+
if (frame.methodName != null && typeof frame.methodName !== 'string') {
|
|
1490
|
+
throw new Error('Expected methodName to be string or nullish');
|
|
1491
|
+
}
|
|
1492
|
+
if (frame.lineNumber != null && typeof frame.lineNumber !== 'number') {
|
|
1493
|
+
throw new Error('Expected lineNumber to be number or nullish');
|
|
1494
|
+
}
|
|
1495
|
+
if (frame.column != null && typeof frame.column !== 'number') {
|
|
1496
|
+
throw new Error('Expected column to be number or nullish');
|
|
1400
1497
|
}
|
|
1401
|
-
return
|
|
1498
|
+
return {
|
|
1499
|
+
...frame,
|
|
1500
|
+
file: frameFile,
|
|
1501
|
+
lineNumber: frame.lineNumber,
|
|
1502
|
+
column: frame.column,
|
|
1503
|
+
methodName: frame.methodName,
|
|
1504
|
+
};
|
|
1402
1505
|
};
|
|
1403
1506
|
|
|
1404
|
-
const stack =
|
|
1507
|
+
const stack = validatedBody.stack.map((frame, lineNumber) => {
|
|
1508
|
+
try {
|
|
1509
|
+
return validateAndNormalizeStackFrame(frame);
|
|
1510
|
+
} catch (e) {
|
|
1511
|
+
throw new Error(`Bad frame at line ${lineNumber}: ${e.message}`);
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
inputValidated = true;
|
|
1405
1516
|
// In case of multiple bundles / HMR, some stack frames can have different URLs from others
|
|
1406
1517
|
const urls = new Set<string>();
|
|
1407
1518
|
|
|
@@ -1433,7 +1544,7 @@ export default class Server {
|
|
|
1433
1544
|
stack,
|
|
1434
1545
|
zip(urls.values(), sourceMaps),
|
|
1435
1546
|
this._config,
|
|
1436
|
-
|
|
1547
|
+
validatedBody.extraData ?? {},
|
|
1437
1548
|
);
|
|
1438
1549
|
|
|
1439
1550
|
debug('Symbolication done');
|
|
@@ -1448,7 +1559,7 @@ export default class Server {
|
|
|
1448
1559
|
});
|
|
1449
1560
|
} catch (error) {
|
|
1450
1561
|
debug('Symbolication failed', error.stack || error);
|
|
1451
|
-
res.statusCode = 500;
|
|
1562
|
+
res.statusCode = inputValidated ? 500 : 400;
|
|
1452
1563
|
res.end(JSON.stringify({error: error.message}));
|
|
1453
1564
|
}
|
|
1454
1565
|
}
|
|
@@ -1518,7 +1629,7 @@ export default class Server {
|
|
|
1518
1629
|
relativeTo,
|
|
1519
1630
|
resolverOptions,
|
|
1520
1631
|
transformOptions,
|
|
1521
|
-
}:
|
|
1632
|
+
}: Readonly<{
|
|
1522
1633
|
relativeTo: 'project' | 'server',
|
|
1523
1634
|
resolverOptions: ResolverInputOptions,
|
|
1524
1635
|
transformOptions: TransformInputOptions,
|
|
@@ -1543,15 +1654,15 @@ export default class Server {
|
|
|
1543
1654
|
return this._nextBundleBuildNumber++;
|
|
1544
1655
|
}
|
|
1545
1656
|
|
|
1546
|
-
getPlatforms():
|
|
1657
|
+
getPlatforms(): ReadonlyArray<string> {
|
|
1547
1658
|
return this._config.resolver.platforms;
|
|
1548
1659
|
}
|
|
1549
1660
|
|
|
1550
|
-
getWatchFolders():
|
|
1661
|
+
getWatchFolders(): ReadonlyArray<string> {
|
|
1551
1662
|
return this._config.watchFolders;
|
|
1552
1663
|
}
|
|
1553
1664
|
|
|
1554
|
-
static DEFAULT_GRAPH_OPTIONS:
|
|
1665
|
+
static DEFAULT_GRAPH_OPTIONS: Readonly<{
|
|
1555
1666
|
customResolverOptions: CustomResolverOptions,
|
|
1556
1667
|
customTransformOptions: CustomTransformOptions,
|
|
1557
1668
|
dev: boolean,
|
package/src/cli-utils.js.flow
CHANGED
|
@@ -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: () =>
|
|
16
|
+
callback: () => unknown,
|
|
17
17
|
): Promise<void> {
|
|
18
18
|
fs.watchFile(filename, () => {
|
|
19
19
|
callback();
|
|
@@ -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 {
|
|
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 =
|
|
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?:
|
|
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:
|
|
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:
|
|
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,
|
|
@@ -4,13 +4,13 @@
|
|
|
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
|
*/
|
|
11
11
|
|
|
12
12
|
import type {ConfigT} from 'metro-config';
|
|
13
|
-
import type {
|
|
13
|
+
import type {CommandModule} from 'yargs';
|
|
14
14
|
import typeof Yargs from 'yargs';
|
|
15
15
|
|
|
16
16
|
import {makeAsyncCommand} from '../cli-utils';
|
|
@@ -20,7 +20,9 @@ import {loadConfig} from 'metro-config';
|
|
|
20
20
|
import path from 'path';
|
|
21
21
|
import {promisify} from 'util';
|
|
22
22
|
|
|
23
|
-
type Args =
|
|
23
|
+
type Args = Readonly<{
|
|
24
|
+
_: unknown,
|
|
25
|
+
$0: unknown,
|
|
24
26
|
entryFile: string,
|
|
25
27
|
output?: string,
|
|
26
28
|
platform?: string,
|
|
@@ -28,6 +30,7 @@ type Args = $ReadOnly<{
|
|
|
28
30
|
maxWorkers?: number,
|
|
29
31
|
dev: boolean,
|
|
30
32
|
verbose: boolean,
|
|
33
|
+
...
|
|
31
34
|
}>;
|
|
32
35
|
|
|
33
36
|
async function dependencies(args: Args, config: ConfigT) {
|
|
@@ -82,7 +85,7 @@ async function dependencies(args: Args, config: ConfigT) {
|
|
|
82
85
|
: Promise.resolve();
|
|
83
86
|
}
|
|
84
87
|
|
|
85
|
-
export default ():
|
|
88
|
+
export default (): CommandModule => ({
|
|
86
89
|
command: 'get-dependencies [entryFile]',
|
|
87
90
|
desc: 'List all dependencies that will be bundled for a given entry point',
|
|
88
91
|
builder: (yargs: Yargs) => {
|
|
@@ -123,6 +126,7 @@ export default (): {...ModuleObject, handler: Function} => ({
|
|
|
123
126
|
});
|
|
124
127
|
},
|
|
125
128
|
handler: makeAsyncCommand(async (argv: Args) => {
|
|
129
|
+
// $FlowFixMe[incompatible-type] argv has extra props.
|
|
126
130
|
const config = await loadConfig(argv);
|
|
127
131
|
await dependencies(argv, config);
|
|
128
132
|
}),
|
package/src/commands/serve.js
CHANGED
|
@@ -4,36 +4,37 @@
|
|
|
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
|
*/
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type {ServerOptions as HttpsServerOptions} from 'https';
|
|
13
|
+
import type {CommandModule} from 'yargs';
|
|
13
14
|
import typeof Yargs from 'yargs';
|
|
14
15
|
|
|
15
16
|
import {makeAsyncCommand, watchFile} from '../cli-utils';
|
|
16
17
|
import {loadConfig, resolveConfig} from 'metro-config';
|
|
17
18
|
import {promisify} from 'util';
|
|
18
19
|
|
|
19
|
-
type Args =
|
|
20
|
-
|
|
20
|
+
type Args = Readonly<{
|
|
21
|
+
_: unknown,
|
|
22
|
+
$0: unknown,
|
|
23
|
+
projectRoots?: ReadonlyArray<string>,
|
|
21
24
|
host: string,
|
|
22
25
|
port: number,
|
|
23
26
|
maxWorkers?: number,
|
|
24
27
|
secure?: boolean,
|
|
25
28
|
secureKey?: string,
|
|
26
29
|
secureCert?: string,
|
|
27
|
-
secureServerOptions?:
|
|
30
|
+
secureServerOptions?: HttpsServerOptions,
|
|
28
31
|
hmrEnabled?: boolean,
|
|
29
32
|
config?: string,
|
|
30
33
|
resetCache?: boolean,
|
|
34
|
+
...
|
|
31
35
|
}>;
|
|
32
36
|
|
|
33
|
-
export default (): {
|
|
34
|
-
...ModuleObject,
|
|
35
|
-
handler: Function,
|
|
36
|
-
} => ({
|
|
37
|
+
export default (): CommandModule => ({
|
|
37
38
|
command: 'serve',
|
|
38
39
|
aliases: ['start'],
|
|
39
40
|
desc: 'Starts Metro on the given port, building bundles on the fly',
|
|
@@ -91,6 +92,7 @@ export default (): {
|
|
|
91
92
|
await promisify(server.close).call(server);
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
// $FlowFixMe[incompatible-type] argv has extra props.
|
|
94
96
|
const config = await loadConfig(argv);
|
|
95
97
|
|
|
96
98
|
// Inline require() to avoid circular dependency with ../index
|
|
@@ -98,6 +100,8 @@ export default (): {
|
|
|
98
100
|
const MetroApi = require('../index');
|
|
99
101
|
|
|
100
102
|
const {
|
|
103
|
+
_,
|
|
104
|
+
$0: _0,
|
|
101
105
|
config: _config,
|
|
102
106
|
hmrEnabled: _hmrEnabled,
|
|
103
107
|
maxWorkers: _maxWorkers,
|
|
@@ -108,6 +112,7 @@ export default (): {
|
|
|
108
112
|
} = argv;
|
|
109
113
|
({httpServer: server} = await MetroApi.runServer(
|
|
110
114
|
config,
|
|
115
|
+
// $FlowFixMe[incompatible-exact] argv has extra props.
|
|
111
116
|
runServerOptions,
|
|
112
117
|
));
|
|
113
118
|
|