Static HTML
In this guide, you’ll learn how to embed a web app directly into a React Native application without deploying it separately. you’ll bundle the web app into a single HTML file, convert it into a string, and display it in a WebView.
Example: static-html
Installation
React Native Project
$ npm add @webview-bridge/react-native @webview-bridge/web react-native-webview$ pnpm add @webview-bridge/react-native @webview-bridge/web react-native-webview$ yarn add @webview-bridge/react-native @webview-bridge/web react-native-webviewCreating the Web App - New Project
In your React Native project, run the following commands to set up a Vite project:
> pnpm create vite web
> cd web
> rm .gitignore eslint.config.js package.json tsconfig.json tsconfig.app.json # remove unused file
> mv vite.config.ts ../vite.config.ts
> pnpm add vite -D
> pnpm add react react-dom # (Optional) Other frameworks can be used as well.Move vite.config.ts from the web folder to the parent React Native project. Since you deleted package.json, you may need to install core libraries like react or react-dom.
vite.config.ts
You use vite-plugin-singlefile to bundle everything into a single HTML file and vite-plugin-html-stringify to convert the HTML into exportable code.
$ npm add vite-plugin-singlefile vite-plugin-html-stringify -D$ pnpm add vite-plugin-singlefile vite-plugin-html-stringify -D$ yarn add vite-plugin-singlefile vite-plugin-html-stringify -DWARN
Q. Why do you export static HTML as a string again?
A. You cannot properly load static HTML with require in react-native-webview.
Please refer to the following issue: react-native-webview#746
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import { viteSingleFile } from "vite-plugin-singlefile";
import { viteHtmlStringify } from "vite-plugin-html-stringify";
export default defineConfig({
root: "./web",
plugins: [
react(),
viteSingleFile({
deleteInlinedFiles: true,
removeViteModuleLoader: true,
}),
viteHtmlStringify({
output: "./web/html.ts",
}),
],
});package.json
{
"scripts": {
// ...
"build:web": "vite build",
"dev:web": "vite"
}
}During development, use dev:web, and before deploying to production, generate static HTML code with build:web.
Setting Up the Bridge
React Native Part
// src/bridge.ts
import { createWebView, bridge } from "@webview-bridge/react-native";
import InAppBrowser from "react-native-inappbrowser-reborn";
// Register functions in the bridge object in your React Native code
export const appBridge = bridge({
async getMessage() {
return "Hello, I'm native";
},
async sum(a: number, b: number) {
return a + b;
},
async openInAppBrowser(url: string) {
if (await InAppBrowser.isAvailable()) {
await InAppBrowser.open(url);
}
},
// ... Add more functions as needed
});
export type AppBridge = typeof appBridge;Create a WebView Component by combining the previously defined bridge with createWebView.
// src/App.tsx
import html from "../web/html"; // Generated HTML
import { appBridge } from "./bridge";
export const { WebView } = createWebView({
bridge: appBridge,
debug: true, // Enable console.log visibility in the native WebView
});
// Use the WebView component in your app
function App(): JSX.Element {
return (
<SafeAreaView style={{ height: "100%" }}>
<WebView
source={
__DEV
? {
uri: "http://localhost:5173",
}
: {
html, // Use the built HTML in production
}
}
style={{ height: "100%", flex: 1, width: "100%" }}
/>
</SafeAreaView>
);
}
export default App;NOTE
When running in development mode, you can take advantage of HMR (Hot Module Replacement) for development. Before deployment, you need to generate html.ts using the build:web command in your CI configuration.
// src/App.tsx
import html from "../web/html"; // generate html;
import { appBridge } from "./bridge";
export const { WebView } = createWebView({
bridge: appBridge,
debug: true, // Enable console.log visibility in the native WebView
});
// Use the WebView component in your app
function App(): JSX.Element {
return (
<SafeAreaView style={{ height: "100%" }}>
<WebView
source={
__DEV
? {
uri: "http://localhost:5173",
}
: {
html, // production일 때 빌드 된 html로 작동
}
}
style={{ height: "100%", flex: 1, width: "100%" }}
/>
</SafeAreaView>
);
}
export default App;Web Part
Now, let's setting up the web project that will be displayed in the WebView. Utilize the previously exported AppBridge as a generic in linkBridge.
That's all there is to it!
You can directly use bridge as shown below and receive the results.
// web/bridge.ts
import { linkBridge } from "@webview-bridge/web";
import type { AppBridge } from "../src/bridge.ts";
const bridge = linkBridge<AppBridge>({
onReady: async (method) => {
console.log("bridge is ready");
const version = await method.getBridgeVersion();
console.log("currentBridgerVersion", version);
},
});
bridge.getMessage().then((message) => console.log(message)); // Expecting "Hello, I'm native"
bridge.sum(1, 2).then((num) => console.log(num)); // Expecting 3
bridge.openInAppBrowser("https://google.com"); // Open google in the native inAppBrowser