Oniguruma regex engine implementation for React Native, providing high-performance syntax highlighting capabilities through Shiki. This module implements a JSI-based native bridge to Oniguruma, enabling efficient pattern matching and syntax highlighting in React Native applications.
Important
React Native Shiki Engine requires the New Architecture to be enabled (react-native 0.71+)
- High-performance native regex engine using Oniguruma, optimized for syntax highlighting
- Fully synchronous pattern matching with no async/await, no Promises, no Bridge
- Uses JSI and C++ TurboModules for direct JavaScript-to-native communication
- Smart pattern caching system for optimal performance
- Memory efficient with automatic cleanup of unused patterns
- Full compatibility with Shiki's regex engine requirements
- Written in modern C++ with robust memory management
- Multiple pattern support with efficient cache management
yarn add react-native-shiki-engine @shikijs/core
cd ios && pod installYou'll also need to install the languages and themes you want to use:
yarn add @shikijs/langs @shikijs/themesnpx expo install react-native-shiki-engine @shikijs/core @shikijs/langs @shikijs/themes
npx expo prebuildFor web support in Expo, also install:
npx expo install @shikijs/engine-onigurumaimport { createHighlighterCore } from '@shikijs/core'
import javascript from '@shikijs/langs/javascript'
import nord from '@shikijs/themes/nord'
import { createNativeEngine, isNativeEngineAvailable } from 'react-native-shiki-engine'
if (!isNativeEngineAvailable()) {
throw new Error('Native engine is not available')
}
const highlighter = await createHighlighterCore({
themes: [nord],
langs: [javascript],
engine: createNativeEngine(),
})
const tokens = highlighter.codeToTokensBase(code, {
lang: 'javascript',
theme: 'nord',
})Important
Create and maintain a single Highlighter instance at the app level. Avoid instantiating new highlighters inside components or frequently called functions.
- Store the highlighter instance in a global singleton or context
- Initialize it during app startup
- Reuse the same instance across your entire React Native application
- Creating new instances inside component render methods
- Initializing highlighters inside useEffect or event handlers
- Multiple instances for the same language/theme combination
See the examples directory for reference implementations using React Context to maintain a single highlighter instance.
The native engine supports configuration options to optimize performance:
createNativeEngine({
// Maximum number of patterns to cache
maxCacheSize: 1000,
})For Expo apps targeting web, this native engine is not compatible as it relies on React Native's TurboModules and JSI. To support web platforms, use platform-specific files with Metro's .web.tsx extension.
- Install the WASM engine:
npx expo install @shikijs/engine-oniguruma- Create platform-specific context files:
Native platforms (contexts/highlighter/index.tsx):
import { createHighlighterCore } from '@shikijs/core'
import javascript from '@shikijs/langs/javascript'
import nord from '@shikijs/themes/nord'
import { createNativeEngine } from 'react-native-shiki-engine'
const highlighter = await createHighlighterCore({
themes: [nord],
langs: [javascript],
engine: createNativeEngine(),
})Web platform (contexts/highlighter/index.web.tsx):
import { createHighlighterCore } from '@shikijs/core'
import { createOnigurumaEngine } from '@shikijs/engine-oniguruma'
import javascript from '@shikijs/langs/javascript'
import nord from '@shikijs/themes/nord'
const highlighter = await createHighlighterCore({
themes: [nord],
langs: [javascript],
engine: createOnigurumaEngine(import('@shikijs/engine-oniguruma/wasm-inlined')),
})Metro will automatically use the .web.tsx file when bundling for web, and the regular .tsx file for native platforms.
See the expo-app example for a complete implementation.
The module uses a three-layer architecture optimizing for both performance and developer experience:
-
JavaScript Layer (
src/)- TypeScript interfaces and JS wrapper for type safety
- Efficient pattern lifecycle management with automatic cleanup
- Seamless integration with Shiki's API
- Error boundaries with graceful degradation
-
JSI Bridge (
cpp/)- Zero-copy JavaScript-to-native communication
- Smart pointer-based memory management
- Thread-safe pattern caching with LRU eviction
- Host object lifetime tracking
-
Oniguruma Core (vendored)
- High-performance native regex engine
- Optimized pattern matching with capture groups
- Full Unicode support with UTF-8/16 encoding
- Non-backtracking algorithm for predictable performance
The engine implements a sophisticated multi-level caching system:
-
L1 Cache: Hot patterns in JSI host objects
- Zero-copy access from JavaScript
- Reference-counted lifetime management
- Automatic cleanup on context destruction
-
L2 Cache: Compiled patterns in native memory
- LRU eviction with generational collection
- Adaptive sizing based on memory pressure
- Thread-safe concurrent access
- Configurable eviction policies
-
Memory Management
- Proactive cleanup of unused patterns
- Automatic defragmentation
- Memory pressure handling
- Configurable high/low watermarks
| Platform | Architecture | Description | Status |
|---|---|---|---|
| iOS Simulator | x86_64 | Intel-based simulators | ✅ |
| iOS Simulator | arm64 | Apple Silicon simulators | ✅ |
| iOS Device | arm64 | All modern iOS devices | ✅ |
| Android | arm64-v8a | Modern Android devices (64-bit ARM) | ✅ |
| Android | armeabi-v7a | Older Android devices (32-bit ARM) | ✅ |
| Android | x86 | Android emulators (32-bit Intel/AMD) | ✅ |
| Android | x86_64 | Android emulators (64-bit Intel/AMD) | ✅ |
Contributions are welcome! Please read our Contributing Guide for details on:
- Code of conduct
- Development workflow
- Pull request process
- Coding standards
MIT License - see the LICENSE file for details
- Shiki - The beautiful yet powerful syntax highlighter we bring to React Native
- Oniguruma - The blazing-fast regex engine powering our native implementation
- React Native - Making native module development possible with JSI and TurboModules
For questions, bug reports, or feature requests: