Skip to main content

Babel Plugin

Bundle icons at build time for 0ms first render - no network requests, no loading states.

info

The Babel plugin is optional. rn-iconify works out of the box with runtime fetching. Use this for production optimization.

Installationโ€‹

The Babel plugin is included with rn-iconify:

npm install rn-iconify

Configurationโ€‹

Add to your babel.config.js:

module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
['rn-iconify/babel', {
// Icons are auto-detected from your source code
// No manual configuration needed!
}],
],
};

How It Worksโ€‹

The Babel plugin automatically:

  1. Scans your code - Finds all icon usages like <Mdi name="home" />
  2. Collects icon names - Tracks which icons are used in each file
  3. Fetches at build time - Downloads SVG data from Iconify API
  4. Generates cache - Creates a local cache file with all icon data
  5. Instant runtime - Icons render immediately without network requests
// Your code - plugin detects these automatically
<Mdi name="home" />
<Heroicons name="user" />
prefetchIcons(['mdi:settings', 'lucide:camera'])

Configuration Optionsโ€‹

module.exports = {
plugins: [
['rn-iconify/babel', {
// Include specific patterns (supports wildcards)
include: [
'mdi:*', // All Material Design Icons
'heroicons:*', // All Heroicons
],

// Exclude patterns
exclude: [
'mdi:test-*', // Skip test icons
],

// Output path for generated cache
outputPath: '.rn-iconify-cache',

// Enable verbose logging
verbose: true,

// Disable the plugin temporarily
disabled: false,
}],
],
};

Options Referenceโ€‹

OptionTypeDefaultDescription
includestring[][]Icon patterns to include (wildcards supported)
excludestring[][]Icon patterns to exclude
outputPathstring.rn-iconify-cacheGenerated cache location
verbosebooleanfalseLog detected icons during build
disabledbooleanfalseDisable the plugin

Pattern Matchingโ€‹

Use glob patterns for flexible icon selection:

plugins: [
['rn-iconify/babel', {
include: [
'mdi:home*', // home, home-outline, home-variant, etc.
'mdi:arrow-*', // All arrow icons
'heroicons:*-solid', // All solid Heroicons
],
exclude: [
'mdi:*-off', // Exclude disabled variants
],
}],
],

Auto-Detectionโ€‹

By default, the plugin auto-detects icons from your code:

// All of these are automatically detected:

// JSX usage
<Mdi name="home" />
<Heroicons name="user" />
<Lucide name="camera" />

// prefetchIcons calls
prefetchIcons(['mdi:home', 'mdi:settings'])

Bundle Size Impactโ€‹

Bundled icons add to your JavaScript bundle:

Icons BundledApproximate Size
10 icons~5 KB
100 icons~50 KB
1,000 icons~500 KB
warning

The plugin only bundles icons it detects in your code. If you use dynamic icon names, consider using the include option to ensure they're bundled.

Dynamic Icon Namesโ€‹

Dynamic icon names aren't auto-detected. Use include to bundle them:

// Not detected (dynamic name)
const iconName = `mdi:${state}`;
<Mdi name={iconName} />

// Solution: Add to include list
['rn-iconify/babel', {
include: ['mdi:loading', 'mdi:success', 'mdi:error'],
}]

Expo Configurationโ€‹

For Expo projects, modify babel.config.js:

module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
['rn-iconify/babel', {
verbose: __DEV__, // Only log in development
}],
],
};
};

Clearing Cacheโ€‹

After changing configuration, clear Metro cache:

# React Native CLI
npx react-native start --reset-cache

# Expo
npx expo start --clear

Build Outputโ€‹

With verbose: true, you'll see detected icons during build:

[rn-iconify] Build started. Project root: /path/to/project
[rn-iconify] Detected 47 unique icons across 23 files
[rn-iconify] Icon sets: mdi (28), heroicons (12), lucide (7)
[rn-iconify] Generating bundle...
[rn-iconify] Bundle generated: .rn-iconify-cache/icons.json (15.2 KB)

Generated Filesโ€‹

The plugin creates a cache directory:

.rn-iconify-cache/
โ”œโ”€โ”€ icons.json # Icon data
โ””โ”€โ”€ icons.js # JavaScript module

Add to .gitignore:

.rn-iconify-cache/

CI/CD Integrationโ€‹

Ensure icons are bundled in CI:

# .github/workflows/build.yml
- name: Build App
run: |
npm install
npx react-native bundle \
--platform android \
--dev false \
--entry-file index.js \
--bundle-output ./android/app/src/main/assets/index.android.bundle

Troubleshootingโ€‹

Icons Not Bundlingโ€‹

  1. Check icon component names are correct (Mdi, not mdi)
  2. Clear Metro cache
  3. Enable verbose mode to see detected icons
['rn-iconify/babel', {
verbose: true,
}]

Network Errors During Buildโ€‹

The plugin needs network access to fetch icons. If behind a proxy:

# Set proxy environment variables
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080

Large Bundle Sizeโ€‹

  1. Review what icons are being bundled (use verbose: true)
  2. Use specific includes instead of wildcards
  3. Add excludes for unused icon variants

Performance Comparisonโ€‹

MethodFirst RenderBundle SizeNetwork
Runtime fetch~100-500msMinimalRequired
Prefetch~0ms (after prefetch)MinimalRequired
Babel plugin0msIncreasesNone
  1. Development: Let plugin auto-detect icons
  2. Production: Review bundled icons, optimize with includes/excludes
  3. Critical path: Ensure navigation and common UI icons are bundled
// babel.config.js
const isProduction = process.env.NODE_ENV === 'production';

module.exports = {
plugins: [
['rn-iconify/babel', {
verbose: !isProduction,
// In production, explicitly include only needed icons
include: isProduction ? [
'mdi:home',
'mdi:settings',
'mdi:account',
'mdi:arrow-left',
] : [],
}],
],
};

Next Stepsโ€‹