All skills

Complete React Native and Expo optimization guide combining Callstack profiling with Vercel code patterns. Covers FPS, TTI, bundle size, memory, lists, animations, state, UI, and React Compiler. Use for any React Native performance, debugging, or best practices task.

Use this Skill: https://skilld.dev/gh/gigs-slc/react-native-skills/react-native

This session only. Nothing lands on disk.

referencesbundle-tree-shaking.md

≈1.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Skill: Tree Shaking

Enable dead code elimination to remove unused exports from your JavaScript bundle.

Quick Config

# .env (Expo SDK 52+)
EXPO_UNSTABLE_METRO_OPTIMIZE_GRAPH=1
EXPO_UNSTABLE_TREE_SHAKING=1
// metro.config.js
config.transformer.getTransformOptions = async () => ({
  transform: { experimentalImportSupport: true },
});
// babel.config.js (non-Expo projects must set `disableImportExportTransform`)
module.exports = {
  presets: [
    [
      'module:@react-native/babel-preset',
      { disableImportExportTransform: true },
    ],
  ],
};

When to Use

  • Bundle includes unused library code
  • Want automatic barrel export optimization
  • Using Expo SDK 52+ (recommended approach)
  • Project already uses Re.Pack (@callstack/repack)

Platform Support

Bundler Tree Shaking Notes
Metro ❌ No Use metro-serializer-esbuild
Expo (SDK 52+) ✅ Experimental Requires config
Re.Pack ✅ Yes Built-in via Webpack/Rspack

Setup: Expo SDK 52+

1. Enable Import Support

// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');

const config = getDefaultConfig(__dirname);

config.transformer.getTransformOptions = async () => ({
  transform: {
    experimentalImportSupport: true,
  },
});

module.exports = config;

2. Enable Tree Shaking

Create/edit .env:

EXPO_UNSTABLE_METRO_OPTIMIZE_GRAPH=1
EXPO_UNSTABLE_TREE_SHAKING=1

Note: Only applies in production builds.

Setup: Metro with ESBuild

npm install @rnx-kit/metro-serializer-esbuild

Configure in metro.config.js.

Setup: Re.Pack (Only If Already Installed)

Important: Re.Pack (@callstack/repack) is a custom bundler using Rspack/Webpack. Only apply these instructions if the project already has Re.Pack configured. Do not suggest migrating a codebase to Re.Pack—it's rarely necessary and requires significant setup.

If project has @callstack/repack in dependencies:

Tree shaking is enabled by default with Rspack. Verify in config:

// rspack.config.js or webpack.config.js
module.exports = {
  optimization: {
    usedExports: true, // Mark unused exports
    minimize: true, // Remove during minification
  },
};

Platform Shaking

Code inside Platform.OS and Platform.select checks is removed for other platforms:

// IMPORTANT: import Platform directly from 'react-native'
import { Platform } from 'react-native';

if (Platform.OS === 'ios') {
  // Removed from Android bundle
}

if (Platform.select({ ios: true, android: false }) === 'ios') {
  // Removed from Android bundle
}

Critical: Must use direct import. This does NOT work:

import * as RN from 'react-native';
if (RN.Platform.OS === 'ios') {
  // NOT removed - optimization fails
}

For non-Expo projects, requires both experimentalImportSupport: true in Metro config and disableImportExportTransform: true in Babel config.

Impact: Savings from enabling platform shaking on a bare React Native Community CLI project are:

  • 5% smaller Hermes bytecode (2.79 MB → 2.64 MB)
  • 15% smaller minified JS bundle (1 MB → 0.85 MB)

Requirements for Tree Shaking

ESM Imports Required

// ✅ ESM - Tree shakeable
import { foo } from './module';

// ❌ CommonJS - Not tree shakeable
const { foo } = require('./module');

Side Effects Declaration

Libraries must declare side-effect-free in package.json:

{
  "sideEffects": false
}

Or specify files with side effects:

{
  "sideEffects": ["*.css", "./src/polyfills.js"]
}

Size Impact

Bundle Type Metro (MB) Re.Pack (MB) Change
Production 35.63 38.48 +8%
Prod Minified 15.54 13.36 -14%
Prod HBC 21.79 19.35 -11%
Prod Minified HBC 21.62 19.05 -12%

Expected improvement: 10-15% bundle size reduction.

Verification

  1. Build production bundle (see bundle-analyze-js.md)
  2. Analyze with source-map-explorer (see bundle-analyze-js.md)
  3. Search for functions you know are unused
  4. If found → tree shaking not working

Test Example

// test-treeshake.js
export const usedFunction = () => 'used';
export const unusedFunction = () => 'unused'; // Should be removed

// app.js
import { usedFunction } from './test-treeshake';

After building, search bundle for unusedFunction. Should not exist.

Common Pitfalls

  • Not using production build: Tree shaking only in prod
  • CommonJS modules: Need ESM for full effectiveness
  • Side effects not declared: Library may not be shakeable
  • Dynamic imports: require(variable) prevents analysis
  • Babel/Metro config mismatch: disableImportExportTransform must match experimentalImportSupport

Related Skills

Source: SKILL.md on GitHub

2 alerts6mo4 checks · Risk HIGH
  • Gen Agent Trust Hub7mo

    The skill is a technical React Native guide that includes a high-risk remote code execution pattern for installing a performance tool.

  • Socket6mo

    No alerts

  • Snyk7mo

    Risk: MEDIUM · No issues

  • Runlayer7mo

    7/67 files flagged

Signed by skilld at 1d299ca. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Dormantupdated 8 months ago
Other metadata
metadata
{
  "author": "Callstack + Vercel",
  "version": "1.0.0",
  "tags": "react-native, expo, performance, optimization, patterns"
}

README badge

README badge for gigs-slc/react-native-skills/react-native