Penambahan dependensi tanpa audit sering memicu pembengkakan ukuran JavaScript (JS) bundle pada aplikasi React Native. Regresi ukuran bundle berdampak langsung ke pengguna: konsumsi memori membengkak, waktu cold start melambat, dan proses eksekusi awal JavaScript engine terhambat. Melakukan inspeksi manual pada berkas package.json saat code review tidak cukup untuk mendeteksi dependensi transitif berukuran masif.

Solusi deterministik untuk masalah ini adalah menerapkan budget gating otomatis pada pipeline Continuous Integration (CI). Panduan ini memaparkan implementasi size-limit pada pipeline GitHub Actions untuk menguji artefak Metro bundle produksi sebelum kode digabungkan ke cabang utama.

1. Isolasi Build Metro Bundle Produksi

Pemeriksaan ukuran bundle tidak mewajibkan kompilasi menyeluruh menjadi APK atau AAB. Kompilasi penuh native code memakan waktu CI 5–10 menit, sedangkan Metro dapat mengekspor JS bundle murni dalam hitungan detik.

Tambahkan skrip generasi bundle Android pada package.json:

{
  "scripts": {
    "bundle:android": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output ./build-output/index.android.bundle --assets-dest ./build-output/assets"
  }
}

Opsi --dev false mematikan modul debugging dan mengaktifkan minifikasi bawaan Metro. Output disimpan ke direktori khusus ./build-output agar mudah ditargetkan oleh linter ukuran berkas.

2. Konfigurasi Ambang Batas dengan Size-Limit

Pasang modul size-limit dan plugin pendukung berkas lokal sebagai devDependencies:

npm install --save-dev size-limit @size-limit/file

Buat berkas konfigurasi .size-limit.json di root repositori:

[
  {
    "name": "Android Production JS Bundle",
    "path": "./build-output/index.android.bundle",
    "limit": "2.2 MB"
  }
]

Catatan teknis: jika menggunakan Hermes, bytecode dikompilasi oleh hermesc dari bundle JS ini. Membatasi ukuran index.android.bundle tetap valid karena ukuran bytecode berbanding lurus dengan representasi AST dan token pada berkas JavaScript sumber.

3. Otomasi CI via GitHub Actions

Buat berkas alur kerja di .github/workflows/bundle-size.yml. Pipeline ini mengeksekusi build bundle pada setiap Pull Request, memeriksa ambang batas ukuran, lalu menulis komentar status secara otomatis.

name: Performance Budget Check

on:
  pull_request:
    branches: [main, master]

permissions:
  pull-requests: write
  contents: read

jobs:
  size-limit:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Generate Android JS Bundle
        run: |
          mkdir -p build-output
          npm run bundle:android

      - name: Evaluate Size Budget
        uses: andresz1/size-limit-action@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

Alur kerja tersebut otomatis menggagalkan pipeline jika ukuran berkas melebihi nilai limit pada .size-limit.json. Action juga menampilkan rincian komparasi byte langsung pada tab komentar PR.

4. Investigasi Regresi via Bundle Visualizer

Ketika batas ukuran terlampaui, identifikasi dependensi penyebab lonjakan byte menggunakan react-native-bundle-visualizer. Jalankan analisis secara lokal tanpa modifikasi kode aplikasi:

npx react-native-bundle-visualizer --platform android

Perintah ini memicu build Metro, memetakan hierarki dependensi, dan membuka laporan interaktif visual berbasis treemap di peramban web. Fokus investigasi:

  • Dependensi Duplikat: Modul yang terpasang pada dua versi berbeda akibat dependensi transitif dari library pihak ketiga.
  • Kegagalan Tree-shaking: Modul utilitas besar seperti lodash atau date-fns yang terimpor seluruhnya alih-alih sub-jalur fungsional spesifik.
  • Aset Tak Sengaja Ter-bundle: Berkas mock JSON atau aset data statis besar yang terimpor langsung ke dalam modul JavaScript runtime.

Pencegahan dan Solusi Lanjutan

Jika dependensi bermasalah ditemukan:

  1. Ganti pustaka berat dengan alternatif ringan (misal: ganti moment dengan dayjs).
  2. Gunakan modul deep-import untuk utilitas: import debounce from 'lodash/debounce' bukan import { debounce } from 'lodash'.
  3. Terapkan lazy-loading berbasis React.lazy atau integrasi dinamis jika modul hanya diperlukan pada alur spesifik dalam aplikasi.