Metro: Generated source map is broken in React Native 0.59 on Android

Created on 22 Mar 2019  路  13Comments  路  Source: facebook/metro

Do you want to request a feature or report a bug?
It's most likely a bug

The metro bundler is producing a wrong source map on Android in 0.59.1 and 0.59.0. At least it is consistently happening in my React Native project, but works fine on iOS. I tried to disable JS deltas, it doesn't help.

It could be related to JSC upgrade, but because I don't know how source maps are generated and mapped to running javascript on a device, I don't know exactly what is causing it.

Related issue - https://github.com/facebook/react-native/issues/23955

Last working version

Worked up to version: v0.58.6

Stopped working in version: v0.59.0, still happening in v0.59.1

If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can yarn install and yarn test.

To Reproduce

  1. Create a new demo app via react-native init rn059 --version [email protected]
  2. Add a debugger statement in the beginning of the render() method in App.js
  3. Launch the app on Android react-native run-android
  4. Enable debug mode via the in-app debug menu "Debug JS Remotely"
  5. Notice the debugger coming up and stopping somewhere that doesn't look like the App.js file. In my case, the debugger stops at file:line ReactFabric-prod.js:7030

Link to repo with example code: https://github.com/hypest/rn-059-stacktrace-mess-demo-app

What is the expected behavior?

In step No5 above, the debugger should stop in file App.js, right at the beginning of the render() method where the debugger; statement is.

Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system.

$ react-native info
info
  React Native Environment Info:
    System:
      OS: macOS 10.14.3
      CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
      Memory: 607.81 MB / 32.00 GB
      Shell: 4.4.19 - /usr/local/bin/bash
    Binaries:
      Node: 8.11.3 - ~/.nvm/versions/node/v8.11.3/bin/node
      Yarn: 1.10.1 - ~/.nvm/versions/node/v8.11.3/bin/yarn
      npm: 6.3.0 - ~/.nvm/versions/node/v8.11.3/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.0, macOS 10.14, tvOS 12.0, watchOS 5.0
      Android SDK:
        API Levels: 23, 26, 27, 28
        Build Tools: 19.1.0, 23.0.1, 26.0.2, 26.0.3, 27.0.3, 28.0.2, 28.0.3
        System Images: android-23 | Google APIs Intel x86 Atom_64, android-26 | Google Play Intel x86 Atom, android-28 | Google Play Intel x86 Atom, android-28 | Google Play Intel x86 Atom_64
    IDEs:
      Xcode: 10.0/10A255 - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.3 => 16.8.3
      react-native: 0.59.1 => 0.59.1
    npmGlobalPackages:
      create-react-native-app: 1.0.0
      react-native-cli: 2.0.1
      react-native-create-library: 3.1.2
      react-native-git-upgrade: 0.2.7

Most helpful comment

With @mjesun's help I was able to figure out what's going on here:

  1. Metro orders the source map by module ID (as of 5a770dd48a3290b3ad01298a31c2a558823a5117), matching the order in which they appear in plain bundles.
  2. In delta bundles, Metro does not put modules in any particular order. The actual order is slightly randomised because of parallelism.
  3. The debugger's delta client (which lives in react-native-cli) concatenates modules in whatever order they come in from Metro.
  4. As a side note, turning off delta bundles with a remote debugger attached doesn't seem to do anything.

As a quick fix, I will send a PR to the CLI repo changing the debugger to always sort the modules before concatenating them. I'll follow up with React Native to make sure the (separate) delta client implementation there does the same, as this can affect stack traces in dev mode even without the debugger being attached.

More fundamentally, in the long run, the delta bundling protocol should manage source maps as a first-class entity alongside code, instead of assuming that the combined bundle will always match some fixed version of the source map.

All 13 comments

For reference: React Native 0.58 uses Metro 0.49.x whereas 0.59, uses 0.51.

Using --reset-cache has no effect, so it's not a cache issue but the source maps are completely messed up. Debugging react-native on Android is not possible.

I'm investigating this. Thanks @yurykorzun for the repro code!

With @mjesun's help I was able to figure out what's going on here:

  1. Metro orders the source map by module ID (as of 5a770dd48a3290b3ad01298a31c2a558823a5117), matching the order in which they appear in plain bundles.
  2. In delta bundles, Metro does not put modules in any particular order. The actual order is slightly randomised because of parallelism.
  3. The debugger's delta client (which lives in react-native-cli) concatenates modules in whatever order they come in from Metro.
  4. As a side note, turning off delta bundles with a remote debugger attached doesn't seem to do anything.

As a quick fix, I will send a PR to the CLI repo changing the debugger to always sort the modules before concatenating them. I'll follow up with React Native to make sure the (separate) delta client implementation there does the same, as this can affect stack traces in dev mode even without the debugger being attached.

More fundamentally, in the long run, the delta bundling protocol should manage source maps as a first-class entity alongside code, instead of assuming that the combined bundle will always match some fixed version of the source map.

Fixed by https://github.com/react-native-community/react-native-cli/pull/279 which has been released in @react-native-community/cli v1.5.2.

Still happening on Android 0.59.3

"react": "16.8.3",
"react-native": "0.59.3",
"react-test-renderer": "16.6.3",
"metro-react-native-babel-preset": "^0.53.1",

@Darksoulsong, double check your version of @react-native-community/cli is resolving to v1.5.2. Depending on how you took the upgrade, lockfiles, etc, you might not have the fix.

Still doesn't work for me with cli v1.6.0 installed in my node_modules

I'm looking into this again, but so far I can't reproduce the problem. I'm using a clean checkout of @hypest's updated branch of the repro repo, after rm -rf node_modules && yarn install && yarn start:reset. Remote JS debugging on an attached Android device seems to work.

Can anyone who's still having this problem share their repro code?

Sorry, my fault. Resetting a cache seems to do the trick.

I'm looking into this again, but so far I can't reproduce the problem. I'm using a clean checkout of @hypest's updated branch of the repro repo, after rm -rf node_modules && yarn install && yarn start:reset. Remote JS debugging on an attached Android device seems to work.

Tried my branch again @motiz88 and seems to _work_ when using Chrome (Macos 10.14.3, Version 73.0.3683.86 (Official Build) (64-bit)) as the debugger (opened by default via the app and if no debugger is active)!

What doesn't work for me is when using https://github.com/jhen0409/react-native-debugger as the debugger, which used to work with React Native v0.58.x. I guess that at this point, this might be an issue with the particular debugger instead. Sorry for the noise!

React Native Debugger works with this fix (copied from the react-native-community/cli fix)

I have the same problem for me deleting apk file from emulator works

Was this page helpful?
0 / 5 - 0 ratings