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