metro 0.70.3 → 0.70.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +20 -19
- package/src/DeltaBundler/Serializers/hmrJSBundle.js +3 -1
- package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +2 -1
- package/src/Server.js +45 -18
- package/src/Server.js.flow +41 -17
- package/src/lib/parseOptionsFromUrl.js +5 -3
- package/src/lib/parseOptionsFromUrl.js.flow +4 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metro",
|
|
3
|
-
"version": "0.70.
|
|
3
|
+
"version": "0.70.4",
|
|
4
4
|
"description": "🚇 The JavaScript bundler for React Native.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": "src/cli.js",
|
|
@@ -36,22 +36,23 @@
|
|
|
36
36
|
"invariant": "^2.2.4",
|
|
37
37
|
"jest-haste-map": "^27.3.1",
|
|
38
38
|
"jest-worker": "^27.2.0",
|
|
39
|
+
"jsc-safe-url": "^0.2.2",
|
|
39
40
|
"lodash.throttle": "^4.1.1",
|
|
40
|
-
"metro-babel-transformer": "0.70.
|
|
41
|
-
"metro-cache": "0.70.
|
|
42
|
-
"metro-cache-key": "0.70.
|
|
43
|
-
"metro-config": "0.70.
|
|
44
|
-
"metro-core": "0.70.
|
|
45
|
-
"metro-hermes-compiler": "0.70.
|
|
46
|
-
"metro-inspector-proxy": "0.70.
|
|
47
|
-
"metro-minify-uglify": "0.70.
|
|
48
|
-
"metro-react-native-babel-preset": "0.70.
|
|
49
|
-
"metro-resolver": "0.70.
|
|
50
|
-
"metro-runtime": "0.70.
|
|
51
|
-
"metro-source-map": "0.70.
|
|
52
|
-
"metro-symbolicate": "0.70.
|
|
53
|
-
"metro-transform-plugins": "0.70.
|
|
54
|
-
"metro-transform-worker": "0.70.
|
|
41
|
+
"metro-babel-transformer": "0.70.4",
|
|
42
|
+
"metro-cache": "0.70.4",
|
|
43
|
+
"metro-cache-key": "0.70.4",
|
|
44
|
+
"metro-config": "0.70.4",
|
|
45
|
+
"metro-core": "0.70.4",
|
|
46
|
+
"metro-hermes-compiler": "0.70.4",
|
|
47
|
+
"metro-inspector-proxy": "0.70.4",
|
|
48
|
+
"metro-minify-uglify": "0.70.4",
|
|
49
|
+
"metro-react-native-babel-preset": "0.70.4",
|
|
50
|
+
"metro-resolver": "0.70.4",
|
|
51
|
+
"metro-runtime": "0.70.4",
|
|
52
|
+
"metro-source-map": "0.70.4",
|
|
53
|
+
"metro-symbolicate": "0.70.4",
|
|
54
|
+
"metro-transform-plugins": "0.70.4",
|
|
55
|
+
"metro-transform-worker": "0.70.4",
|
|
55
56
|
"mime-types": "^2.1.27",
|
|
56
57
|
"node-fetch": "^2.2.0",
|
|
57
58
|
"nullthrows": "^1.1.1",
|
|
@@ -70,9 +71,9 @@
|
|
|
70
71
|
"babel-jest": "^26.6.3",
|
|
71
72
|
"dedent": "^0.7.0",
|
|
72
73
|
"jest-snapshot": "^26.5.2",
|
|
73
|
-
"metro-memory-fs": "0.70.
|
|
74
|
-
"metro-react-native-babel-preset": "0.70.
|
|
75
|
-
"metro-react-native-babel-transformer": "0.70.
|
|
74
|
+
"metro-memory-fs": "0.70.4",
|
|
75
|
+
"metro-react-native-babel-preset": "0.70.4",
|
|
76
|
+
"metro-react-native-babel-transformer": "0.70.4",
|
|
76
77
|
"stack-trace": "^0.0.10"
|
|
77
78
|
},
|
|
78
79
|
"license": "MIT"
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
const { isJsModule, wrapModule } = require("./helpers/js");
|
|
13
13
|
|
|
14
|
+
const jscSafeUrl = require("jsc-safe-url");
|
|
15
|
+
|
|
14
16
|
const { addParamsToDefineCall } = require("metro-transform-plugins");
|
|
15
17
|
|
|
16
18
|
const path = require("path");
|
|
@@ -37,7 +39,7 @@ function generateModules(sourceModules, graph, options) {
|
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
const sourceMappingURL = getURL("map");
|
|
40
|
-
const sourceURL = getURL("bundle");
|
|
42
|
+
const sourceURL = jscSafeUrl.toJscSafeUrl(getURL("bundle"));
|
|
41
43
|
const code =
|
|
42
44
|
prepareModule(module, graph, options) +
|
|
43
45
|
`\n//# sourceMappingURL=${sourceMappingURL}\n` +
|
|
@@ -15,6 +15,7 @@ import type {DeltaResult, Graph, Module} from '../types.flow';
|
|
|
15
15
|
import type {HmrModule} from 'metro-runtime/src/modules/types.flow';
|
|
16
16
|
|
|
17
17
|
const {isJsModule, wrapModule} = require('./helpers/js');
|
|
18
|
+
const jscSafeUrl = require('jsc-safe-url');
|
|
18
19
|
const {addParamsToDefineCall} = require('metro-transform-plugins');
|
|
19
20
|
const path = require('path');
|
|
20
21
|
const url = require('url');
|
|
@@ -52,7 +53,7 @@ function generateModules(
|
|
|
52
53
|
};
|
|
53
54
|
|
|
54
55
|
const sourceMappingURL = getURL('map');
|
|
55
|
-
const sourceURL = getURL('bundle');
|
|
56
|
+
const sourceURL = jscSafeUrl.toJscSafeUrl(getURL('bundle'));
|
|
56
57
|
const code =
|
|
57
58
|
prepareModule(module, graph, options) +
|
|
58
59
|
`\n//# sourceMappingURL=${sourceMappingURL}\n` +
|
package/src/Server.js
CHANGED
|
@@ -57,6 +57,10 @@ const debug = require("debug")("Metro:Server");
|
|
|
57
57
|
|
|
58
58
|
const fs = require("graceful-fs");
|
|
59
59
|
|
|
60
|
+
const invariant = require("invariant");
|
|
61
|
+
|
|
62
|
+
const jscSafeUrl = require("jsc-safe-url");
|
|
63
|
+
|
|
60
64
|
const {
|
|
61
65
|
Logger,
|
|
62
66
|
Logger: { createActionStartEntry, createActionEndEntry, log },
|
|
@@ -399,9 +403,15 @@ class Server {
|
|
|
399
403
|
);
|
|
400
404
|
}
|
|
401
405
|
|
|
406
|
+
_rewriteAndNormalizeUrl(requestUrl) {
|
|
407
|
+
return jscSafeUrl.toNormalUrl(
|
|
408
|
+
this._config.server.rewriteRequestUrl(jscSafeUrl.toNormalUrl(requestUrl))
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
402
412
|
async _processRequest(req, res, next) {
|
|
403
413
|
const originalUrl = req.url;
|
|
404
|
-
req.url = this.
|
|
414
|
+
req.url = this._rewriteAndNormalizeUrl(req.url);
|
|
405
415
|
const urlObj = url.parse(req.url, true);
|
|
406
416
|
const { host } = req.headers;
|
|
407
417
|
debug(
|
|
@@ -707,7 +717,7 @@ class Server {
|
|
|
707
717
|
};
|
|
708
718
|
},
|
|
709
719
|
|
|
710
|
-
finish({ req, mres, result }) {
|
|
720
|
+
finish({ req, mres, serializerOptions, result }) {
|
|
711
721
|
if (
|
|
712
722
|
// We avoid parsing the dates since the client should never send a more
|
|
713
723
|
// recent date than the one returned by the Delta Bundler (if that's the
|
|
@@ -724,6 +734,15 @@ class Server {
|
|
|
724
734
|
String(result.numModifiedFiles)
|
|
725
735
|
);
|
|
726
736
|
mres.setHeader(DELTA_ID_HEADER, String(result.nextRevId));
|
|
737
|
+
|
|
738
|
+
if (
|
|
739
|
+
(serializerOptions === null || serializerOptions === void 0
|
|
740
|
+
? void 0
|
|
741
|
+
: serializerOptions.sourceUrl) != null
|
|
742
|
+
) {
|
|
743
|
+
mres.setHeader("Content-Location", serializerOptions.sourceUrl);
|
|
744
|
+
}
|
|
745
|
+
|
|
727
746
|
mres.setHeader("Content-Type", "application/javascript; charset=UTF-8");
|
|
728
747
|
mres.setHeader("Last-Modified", result.lastModifiedDate.toUTCString());
|
|
729
748
|
mres.setHeader(
|
|
@@ -1011,19 +1030,29 @@ class Server {
|
|
|
1011
1030
|
/* $FlowFixMe: where is `rawBody` defined? Is it added by the `connect` framework? */
|
|
1012
1031
|
|
|
1013
1032
|
const body = await req.rawBody;
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1033
|
+
const parsedBody = JSON.parse(body);
|
|
1034
|
+
|
|
1035
|
+
const rewriteAndNormalizeStackFrame = (frame, lineNumber) => {
|
|
1036
|
+
invariant(
|
|
1037
|
+
frame != null && typeof frame === "object",
|
|
1038
|
+
"Bad stack frame at line %d, expected object, received: %s",
|
|
1039
|
+
lineNumber,
|
|
1040
|
+
typeof frame
|
|
1041
|
+
);
|
|
1042
|
+
const frameFile = frame.file;
|
|
1043
|
+
|
|
1044
|
+
if (typeof frameFile === "string" && frameFile.includes("://")) {
|
|
1045
|
+
return { ...frame, file: this._rewriteAndNormalizeUrl(frameFile) };
|
|
1020
1046
|
}
|
|
1021
1047
|
|
|
1022
1048
|
return frame;
|
|
1023
|
-
}
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
const stack = parsedBody.stack.map(rewriteAndNormalizeStackFrame); // In case of multiple bundles / HMR, some stack frames can have different URLs from others
|
|
1024
1052
|
|
|
1025
1053
|
const urls = new Set();
|
|
1026
1054
|
stack.forEach((frame) => {
|
|
1055
|
+
// These urls have been rewritten and normalized above.
|
|
1027
1056
|
const sourceUrl = frame.file; // Skip `/debuggerWorker.js` which does not need symbolication.
|
|
1028
1057
|
|
|
1029
1058
|
if (
|
|
@@ -1037,8 +1066,11 @@ class Server {
|
|
|
1037
1066
|
});
|
|
1038
1067
|
debug("Getting source maps for symbolication");
|
|
1039
1068
|
const sourceMaps = await Promise.all(
|
|
1040
|
-
|
|
1041
|
-
|
|
1069
|
+
Array.from(urls.values()).map((normalizedUrl) =>
|
|
1070
|
+
this._explodedSourceMapForBundleOptions(
|
|
1071
|
+
this._parseOptions(normalizedUrl)
|
|
1072
|
+
)
|
|
1073
|
+
)
|
|
1042
1074
|
);
|
|
1043
1075
|
debug("Performing fast symbolication");
|
|
1044
1076
|
const symbolicatedStack = await await symbolicate(
|
|
@@ -1067,19 +1099,14 @@ class Server {
|
|
|
1067
1099
|
}
|
|
1068
1100
|
}
|
|
1069
1101
|
|
|
1070
|
-
async
|
|
1071
|
-
const options = parseOptionsFromUrl(
|
|
1072
|
-
reqUrl,
|
|
1073
|
-
new Set(this._config.resolver.platforms),
|
|
1074
|
-
BYTECODE_VERSION
|
|
1075
|
-
);
|
|
1102
|
+
async _explodedSourceMapForBundleOptions(bundleOptions) {
|
|
1076
1103
|
const {
|
|
1077
1104
|
entryFile,
|
|
1078
1105
|
transformOptions,
|
|
1079
1106
|
serializerOptions,
|
|
1080
1107
|
graphOptions,
|
|
1081
1108
|
onProgress,
|
|
1082
|
-
} = splitBundleOptions(
|
|
1109
|
+
} = splitBundleOptions(bundleOptions);
|
|
1083
1110
|
/**
|
|
1084
1111
|
* `entryFile` is relative to projectRoot, we need to use resolution function
|
|
1085
1112
|
* to find the appropriate file with supported extensions.
|
package/src/Server.js.flow
CHANGED
|
@@ -60,6 +60,8 @@ const symbolicate = require('./Server/symbolicate');
|
|
|
60
60
|
const {codeFrameColumns} = require('@babel/code-frame');
|
|
61
61
|
const debug = require('debug')('Metro:Server');
|
|
62
62
|
const fs = require('graceful-fs');
|
|
63
|
+
const invariant = require('invariant');
|
|
64
|
+
const jscSafeUrl = require('jsc-safe-url');
|
|
63
65
|
const {
|
|
64
66
|
Logger,
|
|
65
67
|
Logger: {createActionStartEntry, createActionEndEntry, log},
|
|
@@ -444,14 +446,19 @@ class Server {
|
|
|
444
446
|
);
|
|
445
447
|
}
|
|
446
448
|
|
|
449
|
+
_rewriteAndNormalizeUrl(requestUrl: string): string {
|
|
450
|
+
return jscSafeUrl.toNormalUrl(
|
|
451
|
+
this._config.server.rewriteRequestUrl(jscSafeUrl.toNormalUrl(requestUrl)),
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
447
455
|
async _processRequest(
|
|
448
456
|
req: IncomingMessage,
|
|
449
457
|
res: ServerResponse,
|
|
450
458
|
next: (?Error) => mixed,
|
|
451
459
|
) {
|
|
452
460
|
const originalUrl = req.url;
|
|
453
|
-
req.url = this.
|
|
454
|
-
|
|
461
|
+
req.url = this._rewriteAndNormalizeUrl(req.url);
|
|
455
462
|
const urlObj = url.parse(req.url, true);
|
|
456
463
|
const {host} = req.headers;
|
|
457
464
|
debug(
|
|
@@ -774,7 +781,7 @@ class Server {
|
|
|
774
781
|
bundle: bundleCode,
|
|
775
782
|
};
|
|
776
783
|
},
|
|
777
|
-
finish({req, mres, result}) {
|
|
784
|
+
finish({req, mres, serializerOptions, result}) {
|
|
778
785
|
if (
|
|
779
786
|
// We avoid parsing the dates since the client should never send a more
|
|
780
787
|
// recent date than the one returned by the Delta Bundler (if that's the
|
|
@@ -791,6 +798,9 @@ class Server {
|
|
|
791
798
|
String(result.numModifiedFiles),
|
|
792
799
|
);
|
|
793
800
|
mres.setHeader(DELTA_ID_HEADER, String(result.nextRevId));
|
|
801
|
+
if (serializerOptions?.sourceUrl != null) {
|
|
802
|
+
mres.setHeader('Content-Location', serializerOptions.sourceUrl);
|
|
803
|
+
}
|
|
794
804
|
mres.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
|
|
795
805
|
mres.setHeader('Last-Modified', result.lastModifiedDate.toUTCString());
|
|
796
806
|
mres.setHeader(
|
|
@@ -1051,19 +1061,34 @@ class Server {
|
|
|
1051
1061
|
debug('Start symbolication');
|
|
1052
1062
|
/* $FlowFixMe: where is `rawBody` defined? Is it added by the `connect` framework? */
|
|
1053
1063
|
const body = await req.rawBody;
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1064
|
+
const parsedBody = JSON.parse(body);
|
|
1065
|
+
|
|
1066
|
+
const rewriteAndNormalizeStackFrame = <T>(
|
|
1067
|
+
frame: T,
|
|
1068
|
+
lineNumber: number,
|
|
1069
|
+
): T => {
|
|
1070
|
+
invariant(
|
|
1071
|
+
frame != null && typeof frame === 'object',
|
|
1072
|
+
'Bad stack frame at line %d, expected object, received: %s',
|
|
1073
|
+
lineNumber,
|
|
1074
|
+
typeof frame,
|
|
1075
|
+
);
|
|
1076
|
+
const frameFile = frame.file;
|
|
1077
|
+
if (typeof frameFile === 'string' && frameFile.includes('://')) {
|
|
1056
1078
|
return {
|
|
1057
1079
|
...frame,
|
|
1058
|
-
file: this.
|
|
1080
|
+
file: this._rewriteAndNormalizeUrl(frameFile),
|
|
1059
1081
|
};
|
|
1060
1082
|
}
|
|
1061
1083
|
return frame;
|
|
1062
|
-
}
|
|
1084
|
+
};
|
|
1085
|
+
|
|
1086
|
+
const stack = parsedBody.stack.map(rewriteAndNormalizeStackFrame);
|
|
1063
1087
|
// In case of multiple bundles / HMR, some stack frames can have different URLs from others
|
|
1064
1088
|
const urls = new Set();
|
|
1065
1089
|
|
|
1066
1090
|
stack.forEach(frame => {
|
|
1091
|
+
// These urls have been rewritten and normalized above.
|
|
1067
1092
|
const sourceUrl = frame.file;
|
|
1068
1093
|
// Skip `/debuggerWorker.js` which does not need symbolication.
|
|
1069
1094
|
if (
|
|
@@ -1078,8 +1103,11 @@ class Server {
|
|
|
1078
1103
|
|
|
1079
1104
|
debug('Getting source maps for symbolication');
|
|
1080
1105
|
const sourceMaps = await Promise.all(
|
|
1081
|
-
|
|
1082
|
-
|
|
1106
|
+
Array.from(urls.values()).map(normalizedUrl =>
|
|
1107
|
+
this._explodedSourceMapForBundleOptions(
|
|
1108
|
+
this._parseOptions(normalizedUrl),
|
|
1109
|
+
),
|
|
1110
|
+
),
|
|
1083
1111
|
);
|
|
1084
1112
|
|
|
1085
1113
|
debug('Performing fast symbolication');
|
|
@@ -1106,20 +1134,16 @@ class Server {
|
|
|
1106
1134
|
}
|
|
1107
1135
|
}
|
|
1108
1136
|
|
|
1109
|
-
async
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
new Set(this._config.resolver.platforms),
|
|
1113
|
-
BYTECODE_VERSION,
|
|
1114
|
-
);
|
|
1115
|
-
|
|
1137
|
+
async _explodedSourceMapForBundleOptions(
|
|
1138
|
+
bundleOptions: BundleOptions,
|
|
1139
|
+
): Promise<ExplodedSourceMap> {
|
|
1116
1140
|
const {
|
|
1117
1141
|
entryFile,
|
|
1118
1142
|
transformOptions,
|
|
1119
1143
|
serializerOptions,
|
|
1120
1144
|
graphOptions,
|
|
1121
1145
|
onProgress,
|
|
1122
|
-
} = splitBundleOptions(
|
|
1146
|
+
} = splitBundleOptions(bundleOptions);
|
|
1123
1147
|
|
|
1124
1148
|
/**
|
|
1125
1149
|
* `entryFile` is relative to projectRoot, we need to use resolution function
|
|
@@ -13,6 +13,8 @@ const parsePlatformFilePath = require("../node-haste/lib/parsePlatformFilePath")
|
|
|
13
13
|
|
|
14
14
|
const parseCustomTransformOptions = require("./parseCustomTransformOptions");
|
|
15
15
|
|
|
16
|
+
const jscSafeUrl = require("jsc-safe-url");
|
|
17
|
+
|
|
16
18
|
const nullthrows = require("nullthrows");
|
|
17
19
|
|
|
18
20
|
const path = require("path");
|
|
@@ -38,11 +40,11 @@ const getTransformProfile = (transformProfile) =>
|
|
|
38
40
|
: "default";
|
|
39
41
|
|
|
40
42
|
module.exports = function parseOptionsFromUrl(
|
|
41
|
-
|
|
43
|
+
normalizedRequestUrl,
|
|
42
44
|
platforms,
|
|
43
45
|
bytecodeVersion
|
|
44
46
|
) {
|
|
45
|
-
const parsedURL = nullthrows(url.parse(
|
|
47
|
+
const parsedURL = nullthrows(url.parse(normalizedRequestUrl, true)); // `true` to parse the query param as an object.
|
|
46
48
|
|
|
47
49
|
const query = nullthrows(parsedURL.query);
|
|
48
50
|
const pathname =
|
|
@@ -82,7 +84,7 @@ module.exports = function parseOptionsFromUrl(
|
|
|
82
84
|
platform != null && platform.match(/^(android|ios)$/) ? "http" : "",
|
|
83
85
|
pathname: pathname.replace(/\.(bundle|delta)$/, ".map"),
|
|
84
86
|
}),
|
|
85
|
-
sourceUrl:
|
|
87
|
+
sourceUrl: jscSafeUrl.toJscSafeUrl(normalizedRequestUrl),
|
|
86
88
|
unstable_transformProfile: getTransformProfile(
|
|
87
89
|
query.unstable_transformProfile
|
|
88
90
|
),
|
|
@@ -14,6 +14,7 @@ import type {BundleOptions} from '../shared/types.flow';
|
|
|
14
14
|
|
|
15
15
|
const parsePlatformFilePath = require('../node-haste/lib/parsePlatformFilePath');
|
|
16
16
|
const parseCustomTransformOptions = require('./parseCustomTransformOptions');
|
|
17
|
+
const jscSafeUrl = require('jsc-safe-url');
|
|
17
18
|
const nullthrows = require('nullthrows');
|
|
18
19
|
const path = require('path');
|
|
19
20
|
const url = require('url');
|
|
@@ -57,11 +58,11 @@ const getTransformProfile = (
|
|
|
57
58
|
: 'default';
|
|
58
59
|
|
|
59
60
|
module.exports = function parseOptionsFromUrl(
|
|
60
|
-
|
|
61
|
+
normalizedRequestUrl: string,
|
|
61
62
|
platforms: Set<string>,
|
|
62
63
|
bytecodeVersion: number,
|
|
63
64
|
): BundleOptions {
|
|
64
|
-
const parsedURL = nullthrows(url.parse(
|
|
65
|
+
const parsedURL = nullthrows(url.parse(normalizedRequestUrl, true)); // `true` to parse the query param as an object.
|
|
65
66
|
const query = nullthrows(parsedURL.query);
|
|
66
67
|
const pathname =
|
|
67
68
|
query.bundleEntry ||
|
|
@@ -101,7 +102,7 @@ module.exports = function parseOptionsFromUrl(
|
|
|
101
102
|
platform != null && platform.match(/^(android|ios)$/) ? 'http' : '',
|
|
102
103
|
pathname: pathname.replace(/\.(bundle|delta)$/, '.map'),
|
|
103
104
|
}),
|
|
104
|
-
sourceUrl:
|
|
105
|
+
sourceUrl: jscSafeUrl.toJscSafeUrl(normalizedRequestUrl),
|
|
105
106
|
unstable_transformProfile: getTransformProfile(
|
|
106
107
|
query.unstable_transformProfile,
|
|
107
108
|
),
|