Skip to main content

Overview

Open Mushaf Native can be deployed as a web application using Expo’s web support and Firebase Hosting. The app uses Metro bundler with static output for optimal performance.

Prerequisites

1

Install Firebase CLI

npm install -g firebase-tools
2

Login to Firebase

firebase login
3

Initialize Firebase

If not already initialized:
firebase init hosting

Web Configuration

The web configuration is defined in app.json:
{
  "expo": {
    "web": {
      "bundler": "metro",
      "output": "static",
      "favicon": "./assets/images/favicon.png"
    }
  }
}

Firebase Configuration

The Firebase Hosting configuration is defined in firebase.json:
{
  "hosting": {
    "site": "open-mushaf-native",
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*"
    ],
    "rewrites": [
      { "source": "**", "destination": "/index.html" }
    ]
  }
}
The rewrite rule ensures that Expo Router’s client-side routing works correctly.

Build Process

Standard Web Build

To build the web app without PWA features:
yarn web:export
# or
expo export -p web
This creates a static build in the dist directory.

PWA Build

To build with Progressive Web App features:
yarn web:export:pwa
# or
expo export -p web && npx workbox-cli generateSW workbox-config.js
This exports the web app and generates a service worker for offline support.

Production Build with PWA

The production build process includes optimizations:
yarn predeploy
This script:
  • Allocates more memory for large builds (NODE_OPTIONS=--max-old-space-size=8192)
  • Disables React Compiler during export (EXPO_NO_REACT_COMPILER=1)
  • Clears previous builds (--clear)
  • Generates and injects the service worker manifest
{
  "scripts": {
    "predeploy": "cross-env NODE_OPTIONS=--max-old-space-size=8192 EXPO_NO_REACT_COMPILER=1 expo export -p web --clear && npx workbox-cli injectManifest workbox-config.js"
  }
}

Deployment

Local Testing

Test the Firebase hosting locally before deploying:
yarn deploy:local
# or
firebase emulators:start --only hosting
This runs the Firebase emulator and serves your build locally.

Preview Deployment

Deploy to a Firebase preview channel:
yarn deploy:preview
# or
firebase hosting:channel:deploy preview
Preview channels are perfect for testing before going live.

Production Deployment

Deploy to your live Firebase hosting site:
yarn deploy:live
# or
firebase deploy --only hosting
Always test your build locally or on a preview channel before deploying to production.

Development Server

For active development with hot reloading:
yarn web
# or
expo start --web

Performance Optimizations

Font Preloading

The app preloads critical fonts in app/+html.tsx:
{/* Preload Amiri and Tajawal fonts */}
<link
  rel="preload"
  href="https://fonts.gstatic.com/s/amiri/v24/J7aRnpd8CGxBHpUrtLMA7w.woff2"
  as="font"
  type="font/woff2"
  crossOrigin="anonymous"
/>

Asset Bundling

All assets are bundled with the app:
{
  "expo": {
    "assetBundlePatterns": ["**/*"]
  }
}

RTL Support

The app is configured for right-to-left (RTL) languages:
<html lang="ar" dir="rtl">

Static File Serving

You can also serve the built files using any static file server:
yarn web:serve
# or
npx serve dist
This is useful for quick testing without Firebase.

Custom Domain

To use a custom domain with Firebase Hosting:
1

Add Domain in Firebase Console

Go to Firebase Console > Hosting > Add custom domain
2

Configure DNS

Add the provided DNS records to your domain registrar
3

Wait for Verification

Firebase will automatically provision an SSL certificate once DNS is verified

Troubleshooting

Build Failures

If the build runs out of memory:
# Increase Node memory limit
cross-env NODE_OPTIONS=--max-old-space-size=8192 expo export -p web

Routing Issues

Ensure your firebase.json includes the rewrite rule:
{
  "rewrites": [
    { "source": "**", "destination": "/index.html" }
  ]
}

Asset Loading Issues

Clear the build cache:
expo start --web --clear

Service Worker Not Updating

Force a clean build:
rm -rf dist
yarn web:export:pwa

Build docs developers (and LLMs) love