如何在 React Native for Production 中添加 sourcemap?

How to add sourcemap in React Native for Production?

我在应用程序崩溃时收到如下错误日志:

Fatal Exception: com.facebook.react.modules.core.JavascriptException: onSelect index.android.bundle:20:7148 onPress index.android.bundle:20:2435

但是对我排查问题并没有多大帮助。我怎样才能启用 source map 以便我可以找到问题所在?

2018 年更新 https://docs.expo.io/versions/latest/guides/using-sentry.html 看起来很有前途!

对于源映射,这是我的处理方式:

在我的生产构建包命令中,我告诉它生成一个源映射:

iOS:

react-native bundle --platform ios --entry-file index.ios.js --dev false --bundle-output ./ios/main.jsbundle --assets-dest ./ios --sourcemap-output ./sourcemap.js

Android - 我不得不实际修改 android/app/react.gradle 文件以获得在发布编译时生成的源映射。可能有更简单的方法,但基本上您可以找到它在 bundleReleaseJsAndAssets 方法中构建 bundle 命令的位置,并向其中添加源映射位:

if (Os.isFamily(Os.FAMILY_WINDOWS)) {
    commandLine "cmd","/c", "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
        entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease, "--sourcemap-output", file("$buildDir/../../../sourcemap.js")
} else {
    commandLine "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
        entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease, "--sourcemap-output", file("$buildDir/../../../sourcemap.js")
}

输出路径看起来有点奇怪,但它位于您的根级别(与 iOS 相同的位置。我想要那样。您显然可以将它放在任何地方)。

然后,一旦您遇到行号错误,这意味着您 运行 它通过 "source-map" NPM 包。您的方法可能会非常详尽,但我只是选择了:

var sourceMap = require('source-map');
var fs = require('fs');

fs.readFile('./sourcemap.js', 'utf8', function (err, data) {
    var smc = new sourceMap.SourceMapConsumer(data);

    console.log(smc.originalPositionFor({
        line: 16,
        column: 29356
    }));
});

行和列应替换为上面示例输出中的行和列号。

如果您将源映射存储在某处,因为行号和列号随着您的代码更改而从构建更改到构建,这显然效果最好。如果您可以使用您选择的源代码控制设置返回到用于构建有问题的应用程序的提交,并且 re-generate 捆绑包和用于生成源代码的命令的附加位,它应该会非常接近地图.

Android 灵感来自@chetstone 的回答

从 android 的 v0.32 开始,您可以修改 android/app/build.gradle 来完成此操作。 查找行

apply from: "../../node_modules/react-native/react.gradle"

在此之上,您会看到如下内容:

project.ext.react = [
    entryFile: "index.js",
]

修改它以匹配以下内容

project.ext.react = [
    entryFile: "index.js",
    extraPackagerArgs: ["--sourcemap-output", file("$buildDir/../../../sourcemap.android.js")]
]

上iOS

转到 Xcode 中的 "Bundle React Native code and images" 构建阶段并添加:

export EXTRA_PACKAGER_ARGS="--sourcemap-output sourcemap.ios.js"

如前所述,没有明显的方法可以在 iOS 上为 React Native 生成​​ sourcemap 文件。 bundle 命令是从 react-native-xcode.sh 调用的,并且没有向 bundle 命令行添加参数的规定。但是我找到了一种干净的方法来做到这一点。

react-native-xcode.sh 使用环境变量 BUNDLE_CONFIG 指定配置文件。如果您创建一个空的配置文件,它没有任何效果,然后您可以添加其他 CLI 参数。

创建一个空的配置文件。

touch null_config

使用您的配置文件设置 BUNDLE_CONFIG,并搭载 --sourcemap-output 参数。

export BUNDLE_CONFIG="null_config --sourcemap-output ./sourcemap.js.map"

构建时,将创建文件 sourcemap.js.map

这仅适用于 iOS。

第 1 步:使用以下命令生成 sourcemap.js 文件。

在 package.json 文件中添加这一行

 "bundle:ios": "mkdir -p ios/{Bundle,source-map}; react-native bundle --platform ios --entry-file index.js --dev false --bundle-output ios/Bundle/main.jsbundle --assets-dest ios/Bundle --sourcemap-output ios/source-map/sourcemap.js" 

运行这个命令,它会在$PROJECT_DIR/ios/source-map/文件夹下创建sourcemap.js文件

$ yarn bundle:ios

第二步:在$PROJECT_DIR/ios/source-map/

下创建文件sourcemap-decoder.js
$ cd ios/source-map/

$ touch sourcemap-decoder.js

sourcemap-decoder.js的内容是

const sourceMap = require('source-map'); //(install- npm i source-map)
const fs = require('fs');
const path = require('path');

fs.readFile(path.resolve(__dirname, 'sourcemap.js'), 'utf8', async (err, data) => {
  if (err) {
    console.log('err', err,);
  }
  const consumer = await new sourceMap.SourceMapConsumer(JSON.parse(data));

  console.log(consumer.originalPositionFor({
    line: 1408,
    column: 7762
  }));
});

第三步:执行解码脚本

$ node ios/source-map/sourcemap-decoder.js