HotupdaterHot Updater
Build Plugins

Expo Plugin

Build plugin for Expo projects. Bundles your Expo app using Expo's native export command.

Installation

npm install @hot-updater/expo --save-dev

Configuration

interface ExpoPluginConfig {
  outDir?: string;      // Output directory (default: "dist")
  sourcemap?: boolean;  // Generate sourcemaps (default: false)
  resetCache?: boolean; // Reset Metro cache before bundling (default: true)
}

Usage

import { expo } from '@hot-updater/expo';
import { defineConfig } from 'hot-updater';

export default defineConfig({
  build: expo({
    sourcemap: false
  }),
  // ... other config
});

Expo Configuration

Add the plugin to your app.json file as shown below:

app.json
{
  "expo": {
    "plugins": [
      [
        "@hot-updater/react-native", 
        { 
          "channel": "production"
        } 
      ] 
    ]
  }
}

Run prebuild to apply the changes:

npx expo prebuild

Expo DOM Components (use dom)

Note: This setup is only required for Expo SDK < 55. Expo SDK 55+ includes native overrideUri support (PR #40397).

Expo DOM components are designed for EAS Update. Hot Updater uses overrideUri internally (via Babel plugin) to redirect DOM components to the correct bundle path.

Babel plugin

Add the Babel plugin only when you use Expo DOM components:

npx expo customize babel.config.js
babel.config.js
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    '@hot-updater/expo/babel-plugin', 
  ],
};

Apply patch

Modify node_modules/expo/src/dom/dom.types.ts:

export interface DOMProps extends Omit<RNWebViewProps, 'source'> {
   /**
    * Whether to resize the native WebView size based on the DOM content size.
    * @default false
    */
   matchContents?: boolean;

   /**
    * Whether to use the `@expo/dom-webview` as the underlying WebView implementation.
    * @default false
    */
   useExpoDOMWebView?: boolean;
+
+  /**
+   * Allows dynamically redirecting a component to a different source, for example a prebuilt version.
+   * @internal
+   */
+  overrideUri?: string;
 }

Modify node_modules/expo/build/dom/dom.types.d.ts:

export interface DOMProps extends Omit<RNWebViewProps, 'source'> {
     /**
      * @default false
      */
     matchContents?: boolean;
     /**
      * Whether to use the `@expo/dom-webview` as the underlying WebView implementation.
      * @default false
      */
     useExpoDOMWebView?: boolean;
+    /**
+     * Allows dynamically redirecting a component to a different source, for example a prebuilt version.
+     * @internal
+     */
+    overrideUri?: string;
 }

Modify node_modules/expo/src/dom/webview-wrapper.tsx:

 const RawWebView = React.forwardRef<object, Props>((props, ref) => {
-  const { children, dom, filePath, ref: _ref, ...marshalProps } = props as Props;
+  const { children, dom: domProps, filePath, ref: _ref, ...marshalProps } = props as Props;
+  const { overrideUri, ...dom } = domProps || {};
   if (__DEV__) {
     if (children !== undefined) {
       throw new Error(
   const webView = resolveWebView(dom?.useExpoDOMWebView ?? false);
   const webviewRef = React.useRef<WebViewRef>(null);
   const domImperativeHandlePropsRef = React.useRef<string[]>([]);
-  const source = { uri: `${getBaseURL()}/${filePath}` };
+  const source = { uri: overrideUri ?? `${getBaseURL()}/${filePath}` };
   const [containerStyle, setContainerStyle] = React.useState<WebViewProps['containerStyle']>(null);

Persist changes

Use patch-package, yarn patch, or pnpm patch to persist these changes across installs.

Using patch-package:

npm install patch-package --save-dev
npx patch-package expo

Add postinstall script:

package.json
{
  "scripts": {
    "postinstall": "patch-package"
  }
}

Using pnpm patch:

pnpm patch expo
# Make the changes above, then:
pnpm patch-commit <path-shown-in-output>

Using yarn patch:

yarn patch expo
# Make the changes above, then follow yarn's instructions

Once configured, the Babel plugin automatically handles overrideUri for all DOM components. No additional code changes required.

Key Features

  • Uses Expo's expo export:embed command
  • Auto-detects Hermes from app.json configuration
  • Supports both managed and bare Expo workflows
  • Compatible with Expo prebuild for native builds
  • Automatically configures bundler based on Expo settings