Aplikasi React Native yang mengaktifkan Hermes engine mengompilasi JavaScript menjadi bytecode sebelum didistribusikan ke pengguna. Ketika terjadi crash di production, Sentry sering kali hanya menampilkan un-symbolicated stack trace berupa offset heksadesimal bytecode (misal: HermesRuntimeImpl::dumpCrashLog offset 0x1a2b3c) alih-alih baris file JavaScript/TypeScript asli. Masalah ini diselesaikan dengan menghasilkan composite source map dan mengunggahnya ke Sentry secara otomatis melalui pipeline Continuous Integration (CI).
Akar Masalah: Dual Source Map pada Hermes
Hermes tidak mengeksekusi plain JavaScript, melainkan bytecode biner (.hbc). Proses kompilasi aplikasi melibatkan dua fase pemetaan:
- Metro Bundler: Memetakan kode sumber asli (TypeScript/JavaScript) ke minified bundle JavaScript (
bundle.packager.map). - Hermes Compiler (
hermesc): Mengompilasi minified bundle menjadi bytecode dan menghasilkan map kedua yang menghubungkan instruksi bytecode ke minified bundle (bundle.hbc.map).
Sentry memerlukan satu representasi tunggal yang memetakan bytecode langsung ke file sumber asli. Jika build runner CI hanya mengunggah source map dari Metro, Sentry gagal menerjemahkan offset runtime Hermes.
Sinkronisasi Identifier Release dan Dist
Sentry mencocokkan crash event dengan source map berdasarkan pasangan atribut release dan dist. Nilai ini harus identik antara inisialisasi runtime di aplikasi dan parameter upload pada CI.
Format penamaan standar yang direkomendasikan:
- Release:
<package_name>@<version>+<build_number>(contoh:[email protected]+45) - Dist:
<build_number>(contoh:45)
Konfigurasi di sisi aplikasi (runtime):
import * as Sentry from "@sentry/react-native";
import { Platform } from "react-native";
import VersionInfo from "react-native-version-info";
const releaseId = `${VersionInfo.bundleIdentifier}@${VersionInfo.appVersion}+${VersionInfo.buildVersion}`;
Sentry.init({
dsn: "https://[email protected]/0",
release: releaseId,
dist: VersionInfo.buildVersion,
});Skrip Otomasi: Ekstraksi dan Penggabungan Source Map
Gunakan skrip Node.js/CLI untuk membundel Metro, mengeksekusi hermesc, menggabungkan map via compose-source-maps, lalu mengirimkannya via @sentry/cli. Simpan sebagai scripts/build-and-upload-sourcemap.sh:
#!/usr/bin/env bash
set -euo pipefail
PLATFORM=$1 # android atau ios
RELEASE=$2
DIST=$3
BUNDLE_DIR="./build/sourcemaps/${PLATFORM}"
mkdir -p "${BUNDLE_DIR}"
BUNDLE_FILE="${BUNDLE_DIR}/index.android.bundle"
if [ "$PLATFORM" = "ios" ]; then
BUNDLE_FILE="${BUNDLE_DIR}/main.jsbundle"
fi
PACKAGER_MAP="${BUNDLE_FILE}.packager.map"
HERMES_BYTECODE="${BUNDLE_FILE}.hbc"
HERMES_MAP="${HERMES_BYTECODE}.map"
FINAL_MAP="${BUNDLE_FILE}.map"
# 1. Generate JS bundle via Metro
npx react-native bundle \
--platform "${PLATFORM}" \
--dev false \
--entry-file index.js \
--bundle-output "${BUNDLE_FILE}" \
--sourcemap-output "${PACKAGER_MAP}"
# 2. Kompilasi bytecode Hermes & emit source map Hermes
HERMESC_BIN="./node_modules/react-native/sdks/hermesc/linux64-bin/hermesc"
if [[ "$OSTYPE" == "darwin"* ]]; then
HERMESC_BIN="./node_modules/react-native/sdks/hermesc/osx-bin/hermesc"
fi
"${HERMESC_BIN}" -emit-binary -O \
-out "${HERMES_BYTECODE}" \
"${BUNDLE_FILE}" \
-output-source-map
# 3. Gabungkan Metro map dan Hermes map
node ./node_modules/react-native/scripts/compose-source-maps.js \
"${PACKAGER_MAP}" \
"${HERMES_MAP}" \
-o "${FINAL_MAP}"
# 4. Upload ke Sentry
npx @sentry/cli releases new "${RELEASE}"
npx @sentry/cli releases set-commits "${RELEASE}" --auto || true
npx @sentry/cli releases files "${RELEASE}" upload-sourcemaps \
--dist "${DIST}" \
--strip-prefix "$(pwd)" \
"${FINAL_MAP}" \
"${BUNDLE_FILE}"
npx @sentry/cli releases finalize "${RELEASE}"Pipeline GitHub Actions
Konfigurasi workflow CI untuk mengeksekusi pipeline release Android dan otomasi upload source map Hermes. Masukkan secret repository: SENTRY_AUTH_TOKEN, SENTRY_ORG, dan SENTRY_PROJECT.
name: Android Release & Sentry Upload
on:
push:
tags:
- 'v*'
jobs:
build-android:
runs-on: ubuntu-latest
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'yarn'
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Set Release Identifiers
id: versioning
run: |
VERSION=$(node -p "require('./package.json').version")
DIST=${{ github.run_number }}
RELEASE="com.example.app@${VERSION}+${DIST}"
echo "RELEASE=${RELEASE}" >> $GITHUB_ENV
echo "DIST=${DIST}" >> $GITHUB_ENV
- name: Build and Upload Hermes Source Maps
run: |
chmod +x ./scripts/build-and-upload-sourcemap.sh
./scripts/build-and-upload-sourcemap.sh android "${RELEASE}" "${DIST}"
- name: Build Android Release APK/AAB
run: |
cd android
./gradlew bundleRelease -x bundleReleaseJsAndAssets
# Flag -x bundleReleaseJsAndAssets opsional jika JS bundle sudah dibuat manualCatatan Keamanan: Berikan hak akses terbatas (least privilege) padaSENTRY_AUTH_TOKEN. Token hanya memerlukan scope:project:releases,project:write, danorg:read. Jangan gunakan user account auth token pribadi; gunakan Dedicated Integration/Internal Bot Token.
Verifikasi Artifact pada Sentry Dashboard
Setelah CI pipeline selesai, validasi kelengkapan artifact sebelum merilis binary aplikasi ke publik:
- Masuk ke akun Sentry, buka menu Settings > Projects > pilih project React Native.
- Navigasi ke panel Source Maps atau Releases di sidebar utama.
- Pilih release tag yang baru dibuat (misal:
[email protected]+45). - Buka tab Artifacts. Pastikan file berikut terdaftar dan berada di bawah
distyang sama:index.android.bundle(ataumain.jsbundleuntuk iOS)index.android.bundle.map(composite map)
- Trigger test crash di device menggunakan build release:
throw new Error("Sentry Hermes Verification");. - Pastikan issue baru di Sentry menampilkan function name, file name (
.ts/.tsx), dan baris asli tanpa pesan "Source map was not found" atau "Hermes bytecode offset".
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!