metro 0.72.3 → 0.72.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 +22 -21
- 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.72.
|
|
3
|
+
"version": "0.72.4",
|
|
4
4
|
"description": "🚇 The JavaScript bundler for React Native.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": "src/cli.js",
|
|
@@ -35,23 +35,24 @@
|
|
|
35
35
|
"image-size": "^0.6.0",
|
|
36
36
|
"invariant": "^2.2.4",
|
|
37
37
|
"jest-worker": "^27.2.0",
|
|
38
|
+
"jsc-safe-url": "^0.2.2",
|
|
38
39
|
"lodash.throttle": "^4.1.1",
|
|
39
|
-
"metro-babel-transformer": "0.72.
|
|
40
|
-
"metro-cache": "0.72.
|
|
41
|
-
"metro-cache-key": "0.72.
|
|
42
|
-
"metro-config": "0.72.
|
|
43
|
-
"metro-core": "0.72.
|
|
44
|
-
"metro-file-map": "0.72.
|
|
45
|
-
"metro-hermes-compiler": "0.72.
|
|
46
|
-
"metro-inspector-proxy": "0.72.
|
|
47
|
-
"metro-minify-uglify": "0.72.
|
|
48
|
-
"metro-react-native-babel-preset": "0.72.
|
|
49
|
-
"metro-resolver": "0.72.
|
|
50
|
-
"metro-runtime": "0.72.
|
|
51
|
-
"metro-source-map": "0.72.
|
|
52
|
-
"metro-symbolicate": "0.72.
|
|
53
|
-
"metro-transform-plugins": "0.72.
|
|
54
|
-
"metro-transform-worker": "0.72.
|
|
40
|
+
"metro-babel-transformer": "0.72.4",
|
|
41
|
+
"metro-cache": "0.72.4",
|
|
42
|
+
"metro-cache-key": "0.72.4",
|
|
43
|
+
"metro-config": "0.72.4",
|
|
44
|
+
"metro-core": "0.72.4",
|
|
45
|
+
"metro-file-map": "0.72.4",
|
|
46
|
+
"metro-hermes-compiler": "0.72.4",
|
|
47
|
+
"metro-inspector-proxy": "0.72.4",
|
|
48
|
+
"metro-minify-uglify": "0.72.4",
|
|
49
|
+
"metro-react-native-babel-preset": "0.72.4",
|
|
50
|
+
"metro-resolver": "0.72.4",
|
|
51
|
+
"metro-runtime": "0.72.4",
|
|
52
|
+
"metro-source-map": "0.72.4",
|
|
53
|
+
"metro-symbolicate": "0.72.4",
|
|
54
|
+
"metro-transform-plugins": "0.72.4",
|
|
55
|
+
"metro-transform-worker": "0.72.4",
|
|
55
56
|
"mime-types": "^2.1.27",
|
|
56
57
|
"node-fetch": "^2.2.0",
|
|
57
58
|
"nullthrows": "^1.1.1",
|
|
@@ -70,10 +71,10 @@
|
|
|
70
71
|
"babel-jest": "^26.6.3",
|
|
71
72
|
"dedent": "^0.7.0",
|
|
72
73
|
"jest-snapshot": "^26.5.2",
|
|
73
|
-
"metro-babel-register": "0.72.
|
|
74
|
-
"metro-memory-fs": "0.72.
|
|
75
|
-
"metro-react-native-babel-preset": "0.72.
|
|
76
|
-
"metro-react-native-babel-transformer": "0.72.
|
|
74
|
+
"metro-babel-register": "0.72.4",
|
|
75
|
+
"metro-memory-fs": "0.72.4",
|
|
76
|
+
"metro-react-native-babel-preset": "0.72.4",
|
|
77
|
+
"metro-react-native-babel-transformer": "0.72.4",
|
|
77
78
|
"mock-req": "^0.2.0",
|
|
78
79
|
"mock-res": "^0.6.0",
|
|
79
80
|
"stack-trace": "^0.0.10"
|
|
@@ -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');
|
|
@@ -50,7 +51,7 @@ function generateModules(
|
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
const sourceMappingURL = getURL('map');
|
|
53
|
-
const sourceURL = getURL('bundle');
|
|
54
|
+
const sourceURL = jscSafeUrl.toJscSafeUrl(getURL('bundle'));
|
|
54
55
|
const code =
|
|
55
56
|
prepareModule(module, graph, options) +
|
|
56
57
|
`\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 },
|
|
@@ -414,9 +418,15 @@ class Server {
|
|
|
414
418
|
);
|
|
415
419
|
}
|
|
416
420
|
|
|
421
|
+
_rewriteAndNormalizeUrl(requestUrl) {
|
|
422
|
+
return jscSafeUrl.toNormalUrl(
|
|
423
|
+
this._config.server.rewriteRequestUrl(jscSafeUrl.toNormalUrl(requestUrl))
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
417
427
|
async _processRequest(req, res, next) {
|
|
418
428
|
const originalUrl = req.url;
|
|
419
|
-
req.url = this.
|
|
429
|
+
req.url = this._rewriteAndNormalizeUrl(req.url);
|
|
420
430
|
const urlObj = url.parse(req.url, true);
|
|
421
431
|
const { host } = req.headers;
|
|
422
432
|
debug(
|
|
@@ -741,7 +751,7 @@ class Server {
|
|
|
741
751
|
};
|
|
742
752
|
},
|
|
743
753
|
|
|
744
|
-
finish({ req, mres, result }) {
|
|
754
|
+
finish({ req, mres, serializerOptions, result }) {
|
|
745
755
|
if (
|
|
746
756
|
// We avoid parsing the dates since the client should never send a more
|
|
747
757
|
// recent date than the one returned by the Delta Bundler (if that's the
|
|
@@ -758,6 +768,15 @@ class Server {
|
|
|
758
768
|
String(result.numModifiedFiles)
|
|
759
769
|
);
|
|
760
770
|
mres.setHeader(DELTA_ID_HEADER, String(result.nextRevId));
|
|
771
|
+
|
|
772
|
+
if (
|
|
773
|
+
(serializerOptions === null || serializerOptions === void 0
|
|
774
|
+
? void 0
|
|
775
|
+
: serializerOptions.sourceUrl) != null
|
|
776
|
+
) {
|
|
777
|
+
mres.setHeader("Content-Location", serializerOptions.sourceUrl);
|
|
778
|
+
}
|
|
779
|
+
|
|
761
780
|
mres.setHeader("Content-Type", "application/javascript; charset=UTF-8");
|
|
762
781
|
mres.setHeader("Last-Modified", result.lastModifiedDate.toUTCString());
|
|
763
782
|
mres.setHeader(
|
|
@@ -1060,19 +1079,29 @@ class Server {
|
|
|
1060
1079
|
/* $FlowFixMe: where is `rawBody` defined? Is it added by the `connect` framework? */
|
|
1061
1080
|
|
|
1062
1081
|
const body = await req.rawBody;
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1082
|
+
const parsedBody = JSON.parse(body);
|
|
1083
|
+
|
|
1084
|
+
const rewriteAndNormalizeStackFrame = (frame, lineNumber) => {
|
|
1085
|
+
invariant(
|
|
1086
|
+
frame != null && typeof frame === "object",
|
|
1087
|
+
"Bad stack frame at line %d, expected object, received: %s",
|
|
1088
|
+
lineNumber,
|
|
1089
|
+
typeof frame
|
|
1090
|
+
);
|
|
1091
|
+
const frameFile = frame.file;
|
|
1092
|
+
|
|
1093
|
+
if (typeof frameFile === "string" && frameFile.includes("://")) {
|
|
1094
|
+
return { ...frame, file: this._rewriteAndNormalizeUrl(frameFile) };
|
|
1069
1095
|
}
|
|
1070
1096
|
|
|
1071
1097
|
return frame;
|
|
1072
|
-
}
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1100
|
+
const stack = parsedBody.stack.map(rewriteAndNormalizeStackFrame); // In case of multiple bundles / HMR, some stack frames can have different URLs from others
|
|
1073
1101
|
|
|
1074
1102
|
const urls = new Set();
|
|
1075
1103
|
stack.forEach((frame) => {
|
|
1104
|
+
// These urls have been rewritten and normalized above.
|
|
1076
1105
|
const sourceUrl = frame.file; // Skip `/debuggerWorker.js` which does not need symbolication.
|
|
1077
1106
|
|
|
1078
1107
|
if (
|
|
@@ -1086,8 +1115,11 @@ class Server {
|
|
|
1086
1115
|
});
|
|
1087
1116
|
debug("Getting source maps for symbolication");
|
|
1088
1117
|
const sourceMaps = await Promise.all(
|
|
1089
|
-
|
|
1090
|
-
|
|
1118
|
+
Array.from(urls.values()).map((normalizedUrl) =>
|
|
1119
|
+
this._explodedSourceMapForBundleOptions(
|
|
1120
|
+
this._parseOptions(normalizedUrl)
|
|
1121
|
+
)
|
|
1122
|
+
)
|
|
1091
1123
|
);
|
|
1092
1124
|
debug("Performing fast symbolication");
|
|
1093
1125
|
const symbolicatedStack = await await symbolicate(
|
|
@@ -1116,12 +1148,7 @@ class Server {
|
|
|
1116
1148
|
}
|
|
1117
1149
|
}
|
|
1118
1150
|
|
|
1119
|
-
async
|
|
1120
|
-
const options = parseOptionsFromUrl(
|
|
1121
|
-
reqUrl,
|
|
1122
|
-
new Set(this._config.resolver.platforms),
|
|
1123
|
-
getBytecodeVersion()
|
|
1124
|
-
);
|
|
1151
|
+
async _explodedSourceMapForBundleOptions(bundleOptions) {
|
|
1125
1152
|
const {
|
|
1126
1153
|
entryFile,
|
|
1127
1154
|
graphOptions,
|
|
@@ -1129,7 +1156,7 @@ class Server {
|
|
|
1129
1156
|
resolverOptions,
|
|
1130
1157
|
serializerOptions,
|
|
1131
1158
|
transformOptions,
|
|
1132
|
-
} = splitBundleOptions(
|
|
1159
|
+
} = splitBundleOptions(bundleOptions);
|
|
1133
1160
|
/**
|
|
1134
1161
|
* `entryFile` is relative to projectRoot, we need to use resolution function
|
|
1135
1162
|
* to find the appropriate file with supported extensions.
|
package/src/Server.js.flow
CHANGED
|
@@ -65,6 +65,8 @@ const {codeFrameColumns} = require('@babel/code-frame');
|
|
|
65
65
|
const MultipartResponse = require('./Server/MultipartResponse');
|
|
66
66
|
const debug = require('debug')('Metro:Server');
|
|
67
67
|
const fs = require('graceful-fs');
|
|
68
|
+
const invariant = require('invariant');
|
|
69
|
+
const jscSafeUrl = require('jsc-safe-url');
|
|
68
70
|
const {
|
|
69
71
|
Logger,
|
|
70
72
|
Logger: {createActionStartEntry, createActionEndEntry, log},
|
|
@@ -474,14 +476,19 @@ class Server {
|
|
|
474
476
|
);
|
|
475
477
|
}
|
|
476
478
|
|
|
479
|
+
_rewriteAndNormalizeUrl(requestUrl: string): string {
|
|
480
|
+
return jscSafeUrl.toNormalUrl(
|
|
481
|
+
this._config.server.rewriteRequestUrl(jscSafeUrl.toNormalUrl(requestUrl)),
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
|
|
477
485
|
async _processRequest(
|
|
478
486
|
req: IncomingMessage,
|
|
479
487
|
res: ServerResponse,
|
|
480
488
|
next: (?Error) => mixed,
|
|
481
489
|
) {
|
|
482
490
|
const originalUrl = req.url;
|
|
483
|
-
req.url = this.
|
|
484
|
-
|
|
491
|
+
req.url = this._rewriteAndNormalizeUrl(req.url);
|
|
485
492
|
const urlObj = url.parse(req.url, true);
|
|
486
493
|
const {host} = req.headers;
|
|
487
494
|
debug(
|
|
@@ -835,7 +842,7 @@ class Server {
|
|
|
835
842
|
bundle: bundleCode,
|
|
836
843
|
};
|
|
837
844
|
},
|
|
838
|
-
finish({req, mres, result}) {
|
|
845
|
+
finish({req, mres, serializerOptions, result}) {
|
|
839
846
|
if (
|
|
840
847
|
// We avoid parsing the dates since the client should never send a more
|
|
841
848
|
// recent date than the one returned by the Delta Bundler (if that's the
|
|
@@ -852,6 +859,9 @@ class Server {
|
|
|
852
859
|
String(result.numModifiedFiles),
|
|
853
860
|
);
|
|
854
861
|
mres.setHeader(DELTA_ID_HEADER, String(result.nextRevId));
|
|
862
|
+
if (serializerOptions?.sourceUrl != null) {
|
|
863
|
+
mres.setHeader('Content-Location', serializerOptions.sourceUrl);
|
|
864
|
+
}
|
|
855
865
|
mres.setHeader('Content-Type', 'application/javascript; charset=UTF-8');
|
|
856
866
|
mres.setHeader('Last-Modified', result.lastModifiedDate.toUTCString());
|
|
857
867
|
mres.setHeader(
|
|
@@ -1145,19 +1155,34 @@ class Server {
|
|
|
1145
1155
|
debug('Start symbolication');
|
|
1146
1156
|
/* $FlowFixMe: where is `rawBody` defined? Is it added by the `connect` framework? */
|
|
1147
1157
|
const body = await req.rawBody;
|
|
1148
|
-
const
|
|
1149
|
-
|
|
1158
|
+
const parsedBody = JSON.parse(body);
|
|
1159
|
+
|
|
1160
|
+
const rewriteAndNormalizeStackFrame = <T>(
|
|
1161
|
+
frame: T,
|
|
1162
|
+
lineNumber: number,
|
|
1163
|
+
): T => {
|
|
1164
|
+
invariant(
|
|
1165
|
+
frame != null && typeof frame === 'object',
|
|
1166
|
+
'Bad stack frame at line %d, expected object, received: %s',
|
|
1167
|
+
lineNumber,
|
|
1168
|
+
typeof frame,
|
|
1169
|
+
);
|
|
1170
|
+
const frameFile = frame.file;
|
|
1171
|
+
if (typeof frameFile === 'string' && frameFile.includes('://')) {
|
|
1150
1172
|
return {
|
|
1151
1173
|
...frame,
|
|
1152
|
-
file: this.
|
|
1174
|
+
file: this._rewriteAndNormalizeUrl(frameFile),
|
|
1153
1175
|
};
|
|
1154
1176
|
}
|
|
1155
1177
|
return frame;
|
|
1156
|
-
}
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
const stack = parsedBody.stack.map(rewriteAndNormalizeStackFrame);
|
|
1157
1181
|
// In case of multiple bundles / HMR, some stack frames can have different URLs from others
|
|
1158
1182
|
const urls = new Set();
|
|
1159
1183
|
|
|
1160
1184
|
stack.forEach(frame => {
|
|
1185
|
+
// These urls have been rewritten and normalized above.
|
|
1161
1186
|
const sourceUrl = frame.file;
|
|
1162
1187
|
// Skip `/debuggerWorker.js` which does not need symbolication.
|
|
1163
1188
|
if (
|
|
@@ -1172,8 +1197,11 @@ class Server {
|
|
|
1172
1197
|
|
|
1173
1198
|
debug('Getting source maps for symbolication');
|
|
1174
1199
|
const sourceMaps = await Promise.all(
|
|
1175
|
-
|
|
1176
|
-
|
|
1200
|
+
Array.from(urls.values()).map(normalizedUrl =>
|
|
1201
|
+
this._explodedSourceMapForBundleOptions(
|
|
1202
|
+
this._parseOptions(normalizedUrl),
|
|
1203
|
+
),
|
|
1204
|
+
),
|
|
1177
1205
|
);
|
|
1178
1206
|
|
|
1179
1207
|
debug('Performing fast symbolication');
|
|
@@ -1200,13 +1228,9 @@ class Server {
|
|
|
1200
1228
|
}
|
|
1201
1229
|
}
|
|
1202
1230
|
|
|
1203
|
-
async
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
new Set(this._config.resolver.platforms),
|
|
1207
|
-
getBytecodeVersion(),
|
|
1208
|
-
);
|
|
1209
|
-
|
|
1231
|
+
async _explodedSourceMapForBundleOptions(
|
|
1232
|
+
bundleOptions: BundleOptions,
|
|
1233
|
+
): Promise<ExplodedSourceMap> {
|
|
1210
1234
|
const {
|
|
1211
1235
|
entryFile,
|
|
1212
1236
|
graphOptions,
|
|
@@ -1214,7 +1238,7 @@ class Server {
|
|
|
1214
1238
|
resolverOptions,
|
|
1215
1239
|
serializerOptions,
|
|
1216
1240
|
transformOptions,
|
|
1217
|
-
} = splitBundleOptions(
|
|
1241
|
+
} = splitBundleOptions(bundleOptions);
|
|
1218
1242
|
|
|
1219
1243
|
/**
|
|
1220
1244
|
* `entryFile` is relative to projectRoot, we need to use resolution function
|
|
@@ -15,6 +15,8 @@ const parseCustomResolverOptions = require("./parseCustomResolverOptions");
|
|
|
15
15
|
|
|
16
16
|
const parseCustomTransformOptions = require("./parseCustomTransformOptions");
|
|
17
17
|
|
|
18
|
+
const jscSafeUrl = require("jsc-safe-url");
|
|
19
|
+
|
|
18
20
|
const nullthrows = require("nullthrows");
|
|
19
21
|
|
|
20
22
|
const path = require("path");
|
|
@@ -40,11 +42,11 @@ const getTransformProfile = (transformProfile) =>
|
|
|
40
42
|
: "default";
|
|
41
43
|
|
|
42
44
|
module.exports = function parseOptionsFromUrl(
|
|
43
|
-
|
|
45
|
+
normalizedRequestUrl,
|
|
44
46
|
platforms,
|
|
45
47
|
bytecodeVersion
|
|
46
48
|
) {
|
|
47
|
-
const parsedURL = nullthrows(url.parse(
|
|
49
|
+
const parsedURL = nullthrows(url.parse(normalizedRequestUrl, true)); // `true` to parse the query param as an object.
|
|
48
50
|
|
|
49
51
|
const query = nullthrows(parsedURL.query);
|
|
50
52
|
const pathname =
|
|
@@ -85,7 +87,7 @@ module.exports = function parseOptionsFromUrl(
|
|
|
85
87
|
platform != null && platform.match(/^(android|ios)$/) ? "http" : "",
|
|
86
88
|
pathname: pathname.replace(/\.(bundle|delta)$/, ".map"),
|
|
87
89
|
}),
|
|
88
|
-
sourceUrl:
|
|
90
|
+
sourceUrl: jscSafeUrl.toJscSafeUrl(normalizedRequestUrl),
|
|
89
91
|
unstable_transformProfile: getTransformProfile(
|
|
90
92
|
query.unstable_transformProfile
|
|
91
93
|
),
|
|
@@ -16,6 +16,7 @@ import type {TransformProfile} from 'metro-babel-transformer';
|
|
|
16
16
|
const parsePlatformFilePath = require('../node-haste/lib/parsePlatformFilePath');
|
|
17
17
|
const parseCustomResolverOptions = require('./parseCustomResolverOptions');
|
|
18
18
|
const parseCustomTransformOptions = require('./parseCustomTransformOptions');
|
|
19
|
+
const jscSafeUrl = require('jsc-safe-url');
|
|
19
20
|
const nullthrows = require('nullthrows');
|
|
20
21
|
const path = require('path');
|
|
21
22
|
const url = require('url');
|
|
@@ -47,11 +48,11 @@ const getTransformProfile = (transformProfile: string): TransformProfile =>
|
|
|
47
48
|
: 'default';
|
|
48
49
|
|
|
49
50
|
module.exports = function parseOptionsFromUrl(
|
|
50
|
-
|
|
51
|
+
normalizedRequestUrl: string,
|
|
51
52
|
platforms: Set<string>,
|
|
52
53
|
bytecodeVersion: number,
|
|
53
54
|
): BundleOptions {
|
|
54
|
-
const parsedURL = nullthrows(url.parse(
|
|
55
|
+
const parsedURL = nullthrows(url.parse(normalizedRequestUrl, true)); // `true` to parse the query param as an object.
|
|
55
56
|
const query = nullthrows(parsedURL.query);
|
|
56
57
|
const pathname =
|
|
57
58
|
query.bundleEntry ||
|
|
@@ -92,7 +93,7 @@ module.exports = function parseOptionsFromUrl(
|
|
|
92
93
|
platform != null && platform.match(/^(android|ios)$/) ? 'http' : '',
|
|
93
94
|
pathname: pathname.replace(/\.(bundle|delta)$/, '.map'),
|
|
94
95
|
}),
|
|
95
|
-
sourceUrl:
|
|
96
|
+
sourceUrl: jscSafeUrl.toJscSafeUrl(normalizedRequestUrl),
|
|
96
97
|
unstable_transformProfile: getTransformProfile(
|
|
97
98
|
query.unstable_transformProfile,
|
|
98
99
|
),
|