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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metro",
3
- "version": "0.72.3",
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.3",
40
- "metro-cache": "0.72.3",
41
- "metro-cache-key": "0.72.3",
42
- "metro-config": "0.72.3",
43
- "metro-core": "0.72.3",
44
- "metro-file-map": "0.72.3",
45
- "metro-hermes-compiler": "0.72.3",
46
- "metro-inspector-proxy": "0.72.3",
47
- "metro-minify-uglify": "0.72.3",
48
- "metro-react-native-babel-preset": "0.72.3",
49
- "metro-resolver": "0.72.3",
50
- "metro-runtime": "0.72.3",
51
- "metro-source-map": "0.72.3",
52
- "metro-symbolicate": "0.72.3",
53
- "metro-transform-plugins": "0.72.3",
54
- "metro-transform-worker": "0.72.3",
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.3",
74
- "metro-memory-fs": "0.72.3",
75
- "metro-react-native-babel-preset": "0.72.3",
76
- "metro-react-native-babel-transformer": "0.72.3",
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._config.server.rewriteRequestUrl(req.url);
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 stack = JSON.parse(body).stack.map((frame) => {
1064
- if (frame.file && frame.file.includes("://")) {
1065
- return {
1066
- ...frame,
1067
- file: this._config.server.rewriteRequestUrl(frame.file),
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
- }); // In case of multiple bundles / HMR, some stack frames can have different URLs from others
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
- // $FlowFixMe[method-unbinding] added when improving typing for this parameters
1090
- Array.from(urls.values()).map(this._explodedSourceMapForURL, this)
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 _explodedSourceMapForURL(reqUrl) {
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(options);
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.
@@ -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._config.server.rewriteRequestUrl(req.url);
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 stack = JSON.parse(body).stack.map(frame => {
1149
- if (frame.file && frame.file.includes('://')) {
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._config.server.rewriteRequestUrl(frame.file),
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
- // $FlowFixMe[method-unbinding] added when improving typing for this parameters
1176
- Array.from(urls.values()).map(this._explodedSourceMapForURL, this),
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 _explodedSourceMapForURL(reqUrl: string): Promise<ExplodedSourceMap> {
1204
- const options = parseOptionsFromUrl(
1205
- reqUrl,
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(options);
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
- requestUrl,
45
+ normalizedRequestUrl,
44
46
  platforms,
45
47
  bytecodeVersion
46
48
  ) {
47
- const parsedURL = nullthrows(url.parse(requestUrl, true)); // `true` to parse the query param as an object.
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: requestUrl,
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
- requestUrl: string,
51
+ normalizedRequestUrl: string,
51
52
  platforms: Set<string>,
52
53
  bytecodeVersion: number,
53
54
  ): BundleOptions {
54
- const parsedURL = nullthrows(url.parse(requestUrl, true)); // `true` to parse the query param as an object.
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: requestUrl,
96
+ sourceUrl: jscSafeUrl.toJscSafeUrl(normalizedRequestUrl),
96
97
  unstable_transformProfile: getTransformProfile(
97
98
  query.unstable_transformProfile,
98
99
  ),