Closed marandaneto closed 8 months ago
Hey hey @marandaneto 👋
Am I using the right commands with the right parameters? npx react-native bundle, hermesc and compose-source-maps.js?
Yes those commands are correct (are the same we're generating during an app build).
Am I uploading the right files?
Yes you are.
Did this behavior change across RN versions? such as 0.63.x - 0.68.x?
Not that I'm aware. It's going to change in 0.69.x though. The significant change is that the path of hermesc will change:
// Before
node_modules/hermes-engine/osx-bin/hermesc
// After
node_modules/react-native/sdks/hermesc/osx-bin/hermesc
Is there any official documentation around generating bundles manually with Hermes?
Sadly the docs on this are scarce as we don't expect users to manually generate sourcemaps. This is what we have on symbolicating JS stacktraces: https://reactnative.dev/docs/symbolication
@cortinico Hey hey :)
Awesome, thank you for letting me know the hermes
path change, I've added a note on our docs.
So the question is: if we're using the right commands and uploading the files correctly.
Why does it work if I upload the generated bundles by the tooling, but it does not if I bundle myself?
I can reproduce this issue with a simple template using npx react-native init
, Adding Sentry, generating the Bundles, and uploading them to Sentry, so it's not a bug on our end as it works OOTB if I upload the automatically-generated files.
Can I provide you with more info to find a solution for this?
Thanks a lot for keeping improving React Native :)
Can I provide you with more info to find a solution for this?
I would suggest to try to verify that the source map is valid first.
metro-symbolicate
package to verify that you're able to see the symbolicated stacktrace.Also is this issue happening only for Hermes?
On Android, I've noticed that you have to upload the output (index.android.bundle
) of the command 2 instead of command 1, so the .hbc
file and then it works.
On iOS, it does not work at all, stack trace and line numbers still don't match.
I've noticed that the output of the command 1 (main.jsbundle
) for iOS does not match the auto-generated bundle under /Users/$user/Library/Developer/Xcode/DerivedData/$projectName-$projectId/Build/Products/Release-iphonesimulator/main.jsbundle
E.g. using the command 2359677 bytes
The auto-generated file 2359629 bytes
So either the build isn't deterministic or the commands need to be adjusted for iOS.
Again, if you don't bundle yourself, everything works as expected.
@marandaneto
What seems to be working for me for ios is to skip the hermesc
and the compose-source-maps.js
steps
So just generate source-maps using
npx react-native bundle --platform ios --dev false --entry-file index.js --reset-cache --bundle-output main.jsbundle --sourcemap-output main.jsbundle.packager.map --minify false
Then you can check some stack traces locally to verify they are getting decoded
npx metro-symbolicate main.jsbundle.packager.map < ios.stacktrace.txt
Hermes for iOS is enabled (react-native 0.66.4)
I don't know why but combining the packager and the hbc source maps results it metro-symbolicate
replacing everything with null
E.g.
npx metro-symbolicate main.jsbundle.map < ios.stacktrace.txt
0 ??? 0x0 shouldComponentUpdate + 199284 (null:null:null)
1 ??? 0x0 checkShouldComponentUpdate + 5581 (null:null:null)
2 ??? 0x0 updateClassComponent + 6842 (null:null:null)
While using just the .package.map
file I get
npx metro-symbolicate main.jsbundle.packager.map < ios.stacktrace.txt
0 ??? 0x0 shouldComponentUpdate + 199284 ([redacted]\src\pages\home\report\ReportActionsView.js:114:constructor)
1 ??? 0x0 checkShouldComponentUpdate + 5581 ([redacted]\node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-prod.js:2527:checkShouldComponentUpdate)
2 ??? 0x0 updateClassComponent + 6842 ([redacted]\node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-prod.js:4461:updateClassComponent)
3
@kidroca awesome, let me try this workaround, thanks.
It didn't work for me on iOS, RN 0.67.4
, even if uploading the main.jsbundle.packager.map
.
It didn't work for me on iOS, RN
0.67.4
, even if uploading themain.jsbundle.packager.map
.
From the looks of it the manual setup that uses react-native's own react-native-xcode.sh
script uses only the packager map:
See this here: https://docs.sentry.io/platforms/react-native/manual-setup/manual-setup/#bundle-react-native-code-and-images
export NODE_BINARY=node
export EXTRA_PACKAGER_ARGS="--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map"
export SENTRY_PROPERTIES=../sentry.properties
../node_modules/@sentry/cli/bin/sentry-cli react-native xcode \
../node_modules/react-native/scripts/react-native-xcode.sh
EXTRA_PACKAGER_ARGS
are only for the packager so the output map is only from the packager and not the combined map from the hermes compiler and the packager
To make a combined map automatically through the build phase we need to export SOURCEMAP_FILE
Which then instructs the script to make 2 maps (if using Hermes) and combine them, but for some reason the combined map doesn't work to decode stack traces, only the packager map works. I guess that's why by default ios build does not generate a source map
Perhaps something goes wrong while the maps are merged because the combined map size is smaller than any of the two maps, I'd expect it'll be as big as the two maps combined
If I export SOURCEMAP_FILE=main.jsbundle.map
, the map
file is generated automatically in the temporary folder, also the bundle.
If I upload both files, symbolication still does not work, the same result as the screenshot in the Snack, code example, screenshot, or link to a repository
section.
So on iOS, we're using the $DERIVED_FILE_DIR
env. var to output the main.jsbundle.map
file and that goes to /Users/$user/Library/Developer/Xcode/DerivedData/$projectName-$projectId/Build/Intermediates.noindex/$projectName.build/Release-iphonesimulator/$projectName.build/DerivedSources/main.jsbundle.map
If I upload the bundle and this main.jsbundle.map
file, it works on iOS, but again, it depends on the automatically generated files and not the manually bundled.
If I upload the bundle and this
main.jsbundle.map
file, it works on iOS, but again, it depends on the automatically generated files and not the manually bundled.
What I'm trying to say is because of these packager args, the generated main.jsbundle.map
is not the combined map but the packager's map saved as main.jsbundle.map
export EXTRA_PACKAGER_ARGS="--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map"
If that works for you, you can generate the same manually Run only the first step here: https://docs.sentry.io/platforms/react-native/manual-setup/hermes/#compile-sourcemaps and ignore the rest
npx react-native bundle --platform ios --dev false --entry-file index.js --reset-cache --bundle-output main.jsbundle --sourcemap-output main.jsbundle.packager.map --minify false
I'm working on decoding js stacktraces from Firebase Crashlytics and tried this in both existing and a new RN project The js tacktraces I get from Crashlytics can only be decoded by the packager map and not the hbc or the combined map
@kidroca Yep, I understood what you meant, still, output is the same, line numbers are all wrong.
So just calling npx react-native bundle --platform ios --dev false --entry-file index.js --reset-cache --bundle-output main.jsbundle --sourcemap-output main.jsbundle.packager.map --minify false
and uploading both files to Sentry won't help, the problem still lies.
If I upload the auto generated files (using EXTRA_PACKAGER_ARGS
), it works, so I believe the tooling still does something more than just this command and I have no idea what.
Btw what you said, the file main.jsbundle.packager.map
matches in size with the one generated by using the EXTRA_PACKAGER_ARGS
.
The problem is the bundle itself, main.jsbundle
differs in size, maybe that's where the problem lies.
The problem is the bundle itself,
main.jsbundle
differs in size, maybe that's where the problem lies.I've noticed that the output of the command 1 (
main.jsbundle
) for iOS does not match the auto-generated bundle under/Users/$user/Library/Developer/Xcode/DerivedData/$projectName-$projectId/Build/Products/Release-iphonesimulator/main.jsbundle
E.g. using the command 2359677 bytes The auto-generated file 2359629 bytes
Can you diff the 2 outputs? For me the difference is just due to the source map comment appended at the end
react-native bundle
vs xcode build phase
Depending on whether you've touched the build phase there might be no source map comment at all
@kidroca that was the trick, this comment is likely used within the symbolication process or within the file itself.
63301c63301
< //# sourceMappingURL=main.jsbundle.packager.map
\ No newline at end of file
---
> //# sourceMappingURL=main.jsbundle.map
\ No newline at end of file
Setting the sourceMappingURL
to main.jsbundle.map
worked out.
Or just set the file name correctly in command 1 for iOS:
npx react-native bundle --platform ios --dev false --entry-file index.js --reset-cache --bundle-output main.jsbundle --sourcemap-output main.jsbundle.map --minify false
Thanks @kidroca So apparently there's a way out of generating the bundles manually, strange thing is that iOS skips some steps.
So for you - you had to have both files named main.jsbundle
and main.jsbundle.map
I guess because you upload both
For me, though, it seems I can name the sourcemap output to anything, this just works:
npx metro-symbolicate my-ios-map-file.map < ios.cralyitics.stacktrace.txt
I'm having an issue even getting the bundle to run on Android. I've created a script to handle this:
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
OS_BIN="linux64-bin" # osx-bin, win64-bin, or linux64-bin
elif [[ "$OSTYPE" == "darwin"* ]]; then
OS_BIN="osx-bin" # osx-bin, win64-bin, or linux64-bin
fi
ARTIFACT_FILEPATH="android/app/src/main/assets/"
npx react-native bundle --platform android --dev false --entry-file index.js --reset-cache --bundle-output "$ARTIFACT_FILEPATH"index.android.bundle --sourcemap-output "$ARTIFACT_FILEPATH"index.android.bundle.packager.map --minify false
node_modules/hermes-engine/"$OS_BIN"/hermesc -O -emit-binary -output-source-map -out="$ARTIFACT_FILEPATH"index.android.bundle.hbc "$ARTIFACT_FILEPATH"index.android.bundle
rm -f "$ARTIFACT_FILEPATH"index.android.bundle
mv "$ARTIFACT_FILEPATH"index.android.bundle.hbc "$ARTIFACT_FILEPATH"index.android.bundle
node node_modules/react-native/scripts/compose-source-maps.js "$ARTIFACT_FILEPATH"index.android.bundle.packager.map "$ARTIFACT_FILEPATH"index.android.bundle.hbc.map -o "$ARTIFACT_FILEPATH"index.android.bundle.map
This looks the same to me as what's recommended here (albeit with a different directory). When I try and open up the resulting .apk, I get AndroidRuntime: com.facebook.jni.CppException: Could not get BatchedBridge, make sure your bundle is packaged correctly
, so the bundle clearly isn't right.
Has anyone else seen this?
EDIT: I think perhaps I misunderstood here. I think the outputted bytecode bundle is just to be uploaded to sentry, not to actually be used in the .apk. So I need to output this somewhere else.
I didn't investigate deeply, but now, Android and iOS with hermes work well without any hermesc
or compose source map
.
RN: 0.71.2
Is it possible that the source maps work without hermesc
and compose source map
because the React Native tooling doesn'texecute the hermesc
and compose source map
?
I've created a new app using npx react-native init ... --version 0.70.6
and hermes
is enabled by default. The app template shows the "Engine: Hermes" label because global.HermesInternal exists. But the react-native-xcode.sh
did not use hermesc
and compose source map
as the env USE_HERMES
is empty.
This was changed in 0.71.2
and by default hermesc
is executed. I'm surprised that the source maps work without it.
Yes, also, it works well not only in the binary release but also code push release (Android, iOS both and both are using Hermes).
I bundled assets manually(2) because, appcenter cli is using hermesc, compose source map
internally, and it causes a failure with sourcemap flag.
I can't sure why this works, but it shows the correct stack trace in Sentry with code push release.
run: npm install -g appcenter-cli
// 1
appcenter codepush release-react -a {{Your Project}} -d {{Deployment}} -t {{Target Binary Version}} --token {{ Your TOKEN }}
// 2
node node_modules/.bin/react-native bundle --platform ios --dev false --entry-file index.js --bundle-output main.jsbundle --sourcemap-output main.jsbundle.map
node_modules/@sentry/cli/bin/sentry-cli releases files {{ Your Release }} upload-sourcemaps --dist {{ Your dist }} main.jsbundle main.jsbundle.map
I did some more testing and this is what I've found.
Hermesc -output-source-map
has a side effect on the bundle.
If hermes byte code bundle is generated without a source map the packager source map will work.
If hermes byte code bundle is generated with the source map the combined source map will work.
❯ hermesc -O -emit-binary -output-source-map -out=main.jsbundle.hbc.with.source.maps main.jsbundle
❯ ls -lh main.jsbundle.hbc.with.source.maps
-rw-r--r-- 1 krystofwoldrich staff 1.6M Mar 29 10:36 main.jsbundle.hbc.with.source.maps
❯ hermesc -O -emit-binary -out=main.jsbundle.hbc.without.source.maps main.jsbundle
❯ ls -lh main.jsbundle.hbc.without.source.maps
-rw-r--r-- 1 krystofwoldrich staff 2.1M Mar 29 10:36 main.jsbundle.hbc.without.source.maps
@krystofwoldrich This seems to be true.
Recently, I bundled manually with sourcrmap and it didn't cause any error with combine sourcemap script(Android). And it works in sentry stacktrace.
In past, I didn't generate sourcemap in bundling process.
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.
Hello! I'm having same issue with upload manually. Any update?
Description
I'd like to generate the bundles of an RN App with Hermes enabled manually, so I could upload them manually to 3rd tools such as Sentry.io in order to symbolicate stack traces.
I've not found official documentation about that so I've tried to do reverse engineering myself.
Linked issue https://github.com/getsentry/sentry-react-native/issues/2244 Sentry's docs: https://docs.sentry.io/platforms/react-native/manual-setup/hermes/
Version
0.67.4
Output of
npx react-native info
System: OS: macOS 12.4 CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz Memory: 132.30 MB / 32.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 18.3.0 - /usr/local/bin/node Yarn: 1.22.19 - ~/.yarn/bin/yarn npm: 8.11.0 - /usr/local/bin/npm Watchman: 2022.06.13.00 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.3 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5 Android SDK: Not Found IDEs: Android Studio: Chipmunk 2021.2.1 Patch 1 Chipmunk 2021.2.1 Patch 1 Xcode: 13.4.1/13F100 - /usr/bin/xcodebuild Languages: Java: 11.0.10 - /Users/user/.sdkman/candidates/java/current/bin/javac npmPackages: @react-native-community/cli: Not Found react: 17.0.2 => 17.0.2 react-native: 0.67.4 => 0.67.4 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found
Steps to reproduce
If I do it on Android:
cd android
Bundle: android/app/build/generated/assets/react/release/index.android.bundle Bundle.map: android/app/build/generated/sourcemaps/react/release/index.android.bundle.map
Everything works as expected, in this case, I'm using the generated bundles by the RN tooling.
If I do it on iOS:
In this case, I've generated the bundles myself, now I have to upload it:
sentry-cli releases files $release upload-sourcemaps --dist $dist --strip-prefix $fullRootFolder main.jsbundle main.jsbundle.map
See screenshots in the
Snack, code example, screenshot, or link to a repository section
.So my question is:
Am I using the right commands with the right parameters?
npx react-native bundle
,hermesc
andcompose-source-maps.js
? Am I uploading the right files? Did this behavior change across RN versions? such as0.63.x
-0.68.x
? Is there any official documentation around generating bundles manually with Hermes?Thanks a bunch.
Snack, code example, screenshot, or link to a repository
How it is:
How it should be: