Skip to main content

Overview

Open Mushaf Native is a modern cross-platform Quran Mushaf application built with Expo and React Native. The app provides a native reading experience on iOS, Android, and Web platforms with RTL (Right-to-Left) support optimized for Arabic content.

Tech Stack

Framework

React Native 0.81.5 with React 19.1.0

Platform

Expo SDK 54 for cross-platform development

Routing

Expo Router 6 for file-based navigation

State Management

Jotai 2.12.4 with MMKV for persistence

Core Dependencies

package.json (key dependencies)
{
  "expo": "54.0.30",
  "react": "19.1.0",
  "react-native": "0.81.5",
  "expo-router": "~6.0.21",
  "jotai": "^2.12.4",
  "jotai-effect": "^2.0.2",
  "react-native-mmkv": "^3.2.0",
  "react-native-reanimated": "~4.1.6",
  "@gorhom/bottom-sheet": "^5.1.4"
}

Project Structure

The application follows Expo’s recommended folder structure with clear separation of concerns:
open-mushaf-native/
├── app/                    # Expo Router file-based routing
│   ├── (tabs)/            # Tab-based navigation group
│   │   ├── (more)/        # More menu nested routes
│   │   ├── index.tsx      # Mushaf reading screen
│   │   └── lists.tsx      # Surah/Juz index
│   ├── _layout.tsx        # Root layout with providers
│   ├── search.tsx         # Search modal
│   ├── navigation.tsx     # Quick navigation
│   ├── tracker.tsx        # Daily tracker
│   └── tutorial.tsx       # Tutorial screen
├── components/            # Reusable UI components
│   ├── navigation/        # Navigation components
│   └── __tests__/         # Component tests
├── jotai/                 # State management
│   ├── atoms.ts           # Global state atoms
│   └── createAtomWithStorage.ts
├── hooks/                 # Custom React hooks
├── utils/                 # Utility functions
│   └── storage/           # Storage abstraction
├── constants/             # App constants and configs
├── types/                 # TypeScript type definitions
├── assets/                # Static assets
│   ├── mushaf-data/       # Quran page images
│   ├── tafaseer/          # Tafseer (interpretation) data
│   ├── quran-metadata/    # Quran structure metadata
│   └── search/            # Search index data
└── widgets/               # Android home screen widgets
The app/ directory uses Expo Router’s file-based routing convention. File and folder names directly map to app routes.

Design Decisions

1. Cross-Platform Architecture

Uses MMKV for high-performance persistent storage with native bindings.
utils/storage/createStorage.ts
import { MMKV } from 'react-native-mmkv';

const mmkv = new MMKV();

const storage = {
  getItem: (key: string): string | null => mmkv.getString(key) ?? null,
  setItem: (key: string, value: string): void => mmkv.set(key, value),
  removeItem: (key: string): void => mmkv.delete(key),
};

2. RTL (Right-to-Left) Support

The app enforces RTL layout for Arabic content at the root level:
app/_layout.tsx
I18nManager.allowRTL(true);
I18nManager.forceRTL(true);

// Web-specific RTL setup
if (Platform.OS === 'web') {
  document.documentElement.setAttribute('dir', 'rtl');
  document.documentElement.setAttribute('lang', 'ar');
}

3. Performance Optimizations

  • React Compiler: Enabled via Babel plugin for automatic optimization
  • Reanimated: Used for 60fps animations and gestures
  • MMKV: Synchronous, ultra-fast key-value storage
  • Image Optimization: Expo Image for optimized image loading
  • Code Splitting: Automatic with Expo Router
babel.config.js (excerpt)
{
  "plugins": [
    "babel-plugin-react-compiler",
    "react-native-reanimated/plugin"
  ]
}

4. Progressive Web App (PWA)

The app supports PWA deployment with offline capabilities:
  • Service worker with Workbox for caching
  • Web manifest for installability
  • Offline fallback page
# Build PWA with service worker
yarn web:export:pwa

Typography

The app uses Google Fonts optimized for Arabic:
app/_layout.tsx
import { Amiri_400Regular, Amiri_700Bold } from '@expo-google-fonts/amiri';
import { Tajawal_400Regular, Tajawal_500Medium, Tajawal_700Bold } from '@expo-google-fonts/tajawal';

const [fontLoaded] = useFonts({
  Amiri_400Regular,
  Amiri_700Bold,
  Tajawal_400Regular,
  Tajawal_500Medium,
  Tajawal_700Bold,
});
  • Amiri: Traditional Arabic font for Quranic text
  • Tajawal: Modern Arabic font for UI elements

Build & Deployment

Android

EAS Build with internal testing and production tracks
yarn android:build:production:local

iOS

EAS Build for App Store distribution
yarn ios:prod

Web

Firebase Hosting with PWA support
yarn deploy:live

Development

Expo Go for rapid iteration
yarn start

Testing Strategy

  • Unit Tests: Jest with jest-expo preset
  • Linting: ESLint with Expo config + Prettier
  • Type Checking: TypeScript strict mode
  • Pre-commit Hooks: Husky + lint-staged
package.json (scripts)
{
  "test": "jest --watchAll",
  "lint": "eslint .",
  "lint:fix": "eslint . --fix"
}

Environment Variables

Configuration is managed through Expo’s environment variables:
  • EXPO_PUBLIC_TOP_MENU_HIDE_DURATION_MS: Auto-hide duration for top menu
  • Platform-specific builds via EAS profiles
All public environment variables must be prefixed with EXPO_PUBLIC_ to be accessible in the app.

Build docs developers (and LLMs) love