expo-native-safe-imports
v1.0.7
Published
Safely use native-only React Native libraries inside Expo Go.
Maintainers
Readme
🚀 expo-native-safe-imports
Safely use native-only React Native libraries inside Expo Go — no crashes, no config hacks.
✨ Why This Exists
Expo Go does not support custom native modules.
Normally, if you do:
import Pdf from "react-native-pdf";Expo Go will crash with:
Unable to resolve module react-native-pdfexpo-native-safe-imports automatically replaces unsupported native imports with safe stubs only in Expo Go, while using the real module on:
- Expo Dev Client
- EAS Build (APK / IPA)
- Real Devices
- Bare Workflow
➡️ No code changes.
➡️ No conditional imports.
➡️ No metro config editing.
📦 Installation
npm install --save-dev expo-native-safe-importsor
yarn add --dev expo-native-safe-imports⚙️ Usage
Simply register the plugin and list modules you want ignored in Expo Go:
// app.config.ts or app.json
export default {
name: "My App",
plugins: [
[
"expo-native-safe-imports",
{
ignore: ["react-native-pdf", "react-native-share"],
},
],
],
};📁 Metro config (Required)
Add this into your metro.config.js:
/** @type {import('expo/metro-config').MetroConfig} */
const { getDefaultConfig } = require("expo/metro-config");
const fs = require("fs"); // Add This
const path = require("path"); // Add This
const { createRequire } = require("module"); // Add This
const config = getDefaultConfig(__dirname);
const requireESM = createRequire(__filename); // Add This
// Add This
const resolverPath = path.join(
__dirname,
".expo",
"native-safe-imports",
"metro.mjs"
);
// Add This
const isExpoGo = process.env.npm_lifecycle_event === "start";
// Add This
if (isExpoGo && fs.existsSync(resolverPath)) {
const custom = requireESM(resolverPath);
config.resolver.resolveRequest = custom.resolveRequest;
}
module.exports = config;🔁 After Changing Plugin Configuration
If you update anything related to this plugin inside app.json or app.config.ts, run:
npx expo prebuild --clean
npx expo start🧠 How It Works
| Runtime Environment | Behavior | | ------------------------------- | ------------------------------------------------ | | Expo Go | Imports resolve to safe stub, preventing crashes | | Expo Dev Client / EAS Build | Imports resolve to the real native module | | Web | Stub fallback auto-applied (safe default) |
The stub module behaves like the real one:
- Rendering native components → returns
null(no crash) - Calling native methods → logs a dev warning instead of breaking the app
🧪 Example Usage
No wrapper functions or changes — write code normally:
import Pdf from "react-native-pdf";
import Share from "react-native-share";
export default function Screen() {
return <Pdf source={{ uri: "https://example.com/file.pdf" }} />;
}
Share.open({ message: "Hello world" });In Expo Go (Dev Mode)
[expo-native-safe-imports] react-native-share.open called in Expo Go.In Real Build or Dev Client
- PDF loads normally
- Share sheet opens
🔧 Configuration Options
| Option | Type | Required | Description |
| -------- | ---------- | -------- | -------------------------------------------- |
| ignore | string[] | ✅ | Native modules to safely fallback in Expo Go |
🛡 Features
- ✔ Zero runtime conditionals
- ✔ Zero metro edits
- ✔ Supports both components and functions
- ✔ Compatible with iOS, Android & Web
- ✔ Does not modify your source code or project structure
🪪 License
MIT License
Made for developers who want Expo convenience without native limitations ⚡
⭐ Star the repo if it helped you!
