Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
2 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
3 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
4 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
5 |
--------------------------------------------------------------------------------
/examples/DempApp/hooks/useColorScheme.web.ts:
--------------------------------------------------------------------------------
1 | // NOTE: The default React Native styling doesn't support server rendering.
2 | // Server rendered styles should not change between the first render of the HTML
3 | // and the first render on the client. Typically, web developers will use CSS media queries
4 | // to render different styles on the client and server, these aren't directly supported in React Native
5 | // but can be achieved using a styling library like Nativewind.
6 | export function useColorScheme() {
7 | return 'light';
8 | }
9 |
--------------------------------------------------------------------------------
/docs/web/react/functions/webViewCreateRoot.md:
--------------------------------------------------------------------------------
1 | [**API**](../../../API.md)
2 |
3 | ***
4 |
5 | # Function: webViewCreateRoot()
6 |
7 | > **webViewCreateRoot**(`root`): `string`
8 |
9 | Defined in: [src/web/react.ts:26](https://github.com/inokawa/react-native-react-bridge/blob/a54748fc9a4bfd9c93c7e9a7c5213de725bd9170/src/web/react.ts#L26)
10 |
11 | [webViewRender](webViewRender.md) but initiated with React's createRoot
12 |
13 | ## Parameters
14 |
15 | ### root
16 |
17 | `ReactElement`
18 |
19 | ## Returns
20 |
21 | `string`
22 |
--------------------------------------------------------------------------------
/examples/DempApp/components/navigation/TabBarIcon.tsx:
--------------------------------------------------------------------------------
1 | // You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
2 |
3 | import Ionicons from '@expo/vector-icons/Ionicons';
4 | import { type IconProps } from '@expo/vector-icons/build/createIconSet';
5 | import { type ComponentProps } from 'react';
6 |
7 | export function TabBarIcon({ style, ...rest }: IconProps['name']>) {
8 | return ;
9 | }
10 |
--------------------------------------------------------------------------------
/src/plugin/html.ts:
--------------------------------------------------------------------------------
1 | import { WEB_ROOT_ID } from "../constants";
2 |
3 | /**
4 | * @internal
5 | */
6 | export const wrapWithWebViewHTML = (js: string): string => `
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | `;
19 |
--------------------------------------------------------------------------------
/examples/DempApp/components/ThemedView.tsx:
--------------------------------------------------------------------------------
1 | import { View, type ViewProps } from 'react-native';
2 |
3 | import { useThemeColor } from '@/hooks/useThemeColor';
4 |
5 | export type ThemedViewProps = ViewProps & {
6 | lightColor?: string;
7 | darkColor?: string;
8 | };
9 |
10 | export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
11 | const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
12 |
13 | return ;
14 | }
15 |
--------------------------------------------------------------------------------
/docs/web/react/functions/emit.md:
--------------------------------------------------------------------------------
1 | [**API**](../../../API.md)
2 |
3 | ***
4 |
5 | # Function: emit()
6 |
7 | > **emit**\<`T`\>(`message`): `void`
8 |
9 | Defined in: [src/web/core.ts:13](https://github.com/inokawa/react-native-react-bridge/blob/a54748fc9a4bfd9c93c7e9a7c5213de725bd9170/src/web/core.ts#L13)
10 |
11 | A function to send a message to React Native
12 |
13 | ## Type Parameters
14 |
15 | • **T**
16 |
17 | ## Parameters
18 |
19 | ### message
20 |
21 | [`WebViewMessage`](../../../index/interfaces/WebViewMessage.md)\<`T`\>
22 |
23 | ## Returns
24 |
25 | `void`
26 |
--------------------------------------------------------------------------------
/docs/web/react/functions/useNativeMessage.md:
--------------------------------------------------------------------------------
1 | [**API**](../../../API.md)
2 |
3 | ***
4 |
5 | # Function: useNativeMessage()
6 |
7 | > **useNativeMessage**\<`T`\>(`onSubscribe`): `void`
8 |
9 | Defined in: [src/web/react.ts:34](https://github.com/inokawa/react-native-react-bridge/blob/a54748fc9a4bfd9c93c7e9a7c5213de725bd9170/src/web/react.ts#L34)
10 |
11 | A hook to subscribe messages from React Native.
12 |
13 | ## Type Parameters
14 |
15 | • **T**
16 |
17 | ## Parameters
18 |
19 | ### onSubscribe
20 |
21 | (`message`) => `void`
22 |
23 | ## Returns
24 |
25 | `void`
26 |
--------------------------------------------------------------------------------
/docs/web/preact/functions/useNativeMessage.md:
--------------------------------------------------------------------------------
1 | [**API**](../../../API.md)
2 |
3 | ***
4 |
5 | # Function: useNativeMessage()
6 |
7 | > **useNativeMessage**\<`T`\>(`onSubscribe`): `void`
8 |
9 | Defined in: [src/web/preact.ts:25](https://github.com/inokawa/react-native-react-bridge/blob/a54748fc9a4bfd9c93c7e9a7c5213de725bd9170/src/web/preact.ts#L25)
10 |
11 | A hook to subscribe messages from React Native.
12 |
13 | ## Type Parameters
14 |
15 | • **T**
16 |
17 | ## Parameters
18 |
19 | ### onSubscribe
20 |
21 | (`message`) => `void`
22 |
23 | ## Returns
24 |
25 | `void`
26 |
--------------------------------------------------------------------------------
/docs/web/react/functions/webViewRender.md:
--------------------------------------------------------------------------------
1 | [**API**](../../../API.md)
2 |
3 | ***
4 |
5 | # Function: webViewRender()
6 |
7 | > **webViewRender**(`root`): `string`
8 |
9 | Defined in: [src/web/react.ts:18](https://github.com/inokawa/react-native-react-bridge/blob/a54748fc9a4bfd9c93c7e9a7c5213de725bd9170/src/web/react.ts#L18)
10 |
11 | The entry point of web file
12 |
13 | This statement is detected by babelTransformer as an entry point
14 | All dependencies are resolved, compressed and stringified into one file
15 |
16 | ## Parameters
17 |
18 | ### root
19 |
20 | `ReactElement`
21 |
22 | ## Returns
23 |
24 | `string`
25 |
--------------------------------------------------------------------------------
/docs/web/preact/functions/webViewRender.md:
--------------------------------------------------------------------------------
1 | [**API**](../../../API.md)
2 |
3 | ***
4 |
5 | # Function: webViewRender()
6 |
7 | > **webViewRender**(`root`): `string`
8 |
9 | Defined in: [src/web/preact.ts:17](https://github.com/inokawa/react-native-react-bridge/blob/a54748fc9a4bfd9c93c7e9a7c5213de725bd9170/src/web/preact.ts#L17)
10 |
11 | The entry point of web file
12 |
13 | This statement is detected by babelTransformer as an entry point
14 | All dependencies are resolved, compressed and stringified into one file
15 |
16 | ## Parameters
17 |
18 | ### root
19 |
20 | `ComponentChild`
21 |
22 | ## Returns
23 |
24 | `string`
25 |
--------------------------------------------------------------------------------
/fixtures/issue144.jsx:
--------------------------------------------------------------------------------
1 | import { webViewRender } from "react-native-react-bridge/lib/web";
2 |
3 | let Root = () => {
4 | // prettier-ignore
5 | let issue = function inspect(value) {
6 | switch (typeof value) {
7 | case 'string':
8 | if (value.includes("'")) {
9 | if (!value.includes('"')) {
10 | return `"${value}"`;
11 | } else if (!value.includes('`') && !value.includes('${')) {
12 | return `\`${value}\``;
13 | }
14 | }
15 | }
16 | };
17 | console.log(issue);
18 |
19 | return
37 | );
38 | };
39 |
40 | export default webViewRender();
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 inokawa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/examples/DempApp/app/(tabs)/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Tabs } from 'expo-router';
2 | import React from 'react';
3 |
4 | import { TabBarIcon } from '@/components/navigation/TabBarIcon';
5 | import { Colors } from '@/constants/Colors';
6 | import { useColorScheme } from '@/hooks/useColorScheme';
7 |
8 | export default function TabLayout() {
9 | const colorScheme = useColorScheme();
10 |
11 | return (
12 |
17 | (
22 |
23 | ),
24 | }}
25 | />
26 | (
31 |
32 | ),
33 | }}
34 | />
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/examples/DempApp/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
2 | import { useFonts } from 'expo-font';
3 | import { Stack } from 'expo-router';
4 | import * as SplashScreen from 'expo-splash-screen';
5 | import { useEffect } from 'react';
6 | import 'react-native-reanimated';
7 |
8 | import { useColorScheme } from '@/hooks/useColorScheme';
9 |
10 | // Prevent the splash screen from auto-hiding before asset loading is complete.
11 | SplashScreen.preventAutoHideAsync();
12 |
13 | export default function RootLayout() {
14 | const colorScheme = useColorScheme();
15 | const [loaded] = useFonts({
16 | SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
17 | });
18 |
19 | useEffect(() => {
20 | if (loaded) {
21 | SplashScreen.hideAsync();
22 | }
23 | }, [loaded]);
24 |
25 | if (!loaded) {
26 | return null;
27 | }
28 |
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/fixtures/assets/twitter.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
--------------------------------------------------------------------------------
/e2e/index.spec.tsx-snapshots/smoke-webview-with-json-jsx-2-chromium.txt:
--------------------------------------------------------------------------------
1 |
82 | I'm a paragraph! Edit me in <p> to add your own content and make
83 | changes to the style and font. It's easy! Just change the text between
84 | <p> ... </p> and change the style in <style>. You can
85 | make it as long as you wish. The browser will automatically wrap the
86 | lines to accommodate the size of the browser window.
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/fixtures/assets/example.md:
--------------------------------------------------------------------------------
1 | # Header 1
2 |
3 | ## Header 2
4 |
5 | ### Header 3 ### (Hashes on right are optional)
6 |
7 | ## Markdown plus h2 with a custom ID ## {#id-goes-here}
8 |
9 | [Link back to H2](#id-goes-here)
10 |
11 | ```js
12 | var x = "string";
13 | function f() {
14 | return x;
15 | }
16 | ```
17 |
18 |
19 |
20 |
21 | nested div
22 |
23 |
26 | This is a div _with_ underscores
27 | and a & bold element.
28 |
31 |
32 |
33 | - Bullet lists are easy too
34 |
35 | * Another one
36 |
37 | - Another one
38 |
39 | This is a paragraph, which is text surrounded by
40 | whitespace. Paragraphs can be on one
41 | line (or many), and can drone on for hours.
42 |
43 | Now some inline markup like _italics_, **bold**,
44 | and `code()`. Note that underscores
45 | in_words_are ignored.
46 |
47 | ```application/json
48 | { value: ["or with a mime type"] }
49 | ```
50 |
51 | > Blockquotes are like quoted text in email replies
52 | >
53 | > > And, they can be nested
54 |
55 | 1. A numbered list
56 | 2. Which is numbered
57 | 3. With periods and a space
58 |
59 | And now some code:
60 |
61 | // Code is just text indented a bit
62 | which(is_easy) to_remember();
63 |
64 | And a block
65 |
66 | ```
67 | // Markdown extra adds un-indented code blocks too
68 |
69 | if (this_is_more_code == true && !indented) {
70 | // tild wrapped code blocks, also not indented
71 | }
72 | ```
73 |
74 | Text with
75 | two trailing spaces
76 | (on the right)
77 | can be used
78 | for things like poems
79 |
80 | ### Horizontal rules
81 |
82 | ---
83 |
84 | ---
85 |
86 | ---
87 |
88 | 
89 |
90 | ## Markdown plus tables
91 |
92 | | Header | Header | Right |
93 | | ------ | ------ | ----: |
94 | | Cell | Cell | $10 |
95 | | Cell | Cell | $20 |
96 |
97 | - Outer pipes on tables are optional
98 | - Colon used for alignment (right versus left)
99 |
100 | ## Markdown plus definition lists
101 |
102 | Bottled water
103 | : $ 1.25
104 | : $ 1.55 (Large)
105 |
106 | Milk
107 | Pop
108 | : $ 1.75
109 |
110 | - Multiple definitions and terms are possible
111 | - Definitions can include multiple paragraphs too
112 |
113 | \*[ABBR]: Markdown plus abbreviations (produces an tag)
114 |
--------------------------------------------------------------------------------
/fixtures/assets/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | HTML Sample
7 |
8 |
9 |
10 |
65 |
66 |
67 |
73 |
74 |
75 |
76 |
77 |
NAME OF SITE
78 |
79 |
80 |
I'm h2 Header! Edit me in <h2>
81 |
82 | I'm a paragraph! Edit me in <p> to add your own content and make
83 | changes to the style and font. It's easy! Just change the text between
84 | <p> ... </p> and change the style in <style>. You can
85 | make it as long as you wish. The browser will automatically wrap the
86 | lines to accommodate the size of the browser window.
87 |
# Header 1
2 |
3 | ## Header 2
4 |
5 | ### Header 3 ### (Hashes on right are optional)
6 |
7 | ## Markdown plus h2 with a custom ID ## {#id-goes-here}
8 |
9 | [Link back to H2](#id-goes-here)
10 |
11 | \`\`\`js
12 | var x = "string";
13 | function f() {
14 | return x;
15 | }
16 | \`\`\`
17 |
18 | <!-- html madness -->
19 | <div class="custom-class" markdown="1">
20 | <div>
21 | nested div
22 | </div>
23 | <script type='text/x-koka'>
24 | function( x: int ) { return x*x; }
25 | </script>
26 | This is a div _with_ underscores
27 | and a & <b class="bold">bold</b> element.
28 | <style>
29 | body { font: "Consolas" }
30 | </style>
31 | </div>
32 |
33 | - Bullet lists are easy too
34 |
35 | * Another one
36 |
37 | - Another one
38 |
39 | This is a paragraph, which is text surrounded by
40 | whitespace. Paragraphs can be on one
41 | line (or many), and can drone on for hours.
42 |
43 | Now some inline markup like _italics_, **bold**,
44 | and \`code()\`. Note that underscores
45 | in_words_are ignored.
46 |
47 | \`\`\`application/json
48 | { value: ["or with a mime type"] }
49 | \`\`\`
50 |
51 | > Blockquotes are like quoted text in email replies
52 | >
53 | > > And, they can be nested
54 |
55 | 1. A numbered list
56 | 2. Which is numbered
57 | 3. With periods and a space
58 |
59 | And now some code:
60 |
61 | // Code is just text indented a bit
62 | which(is_easy) to_remember();
63 |
64 | And a block
65 |
66 | \`\`\`
67 | // Markdown extra adds un-indented code blocks too
68 |
69 | if (this_is_more_code == true && !indented) {
70 | // tild wrapped code blocks, also not indented
71 | }
72 | \`\`\`
73 |
74 | Text with
75 | two trailing spaces
76 | (on the right)
77 | can be used
78 | for things like poems
79 |
80 | ### Horizontal rules
81 |
82 | ---
83 |
84 | ---
85 |
86 | ---
87 |
88 | 
89 |
90 | ## Markdown plus tables
91 |
92 | | Header | Header | Right |
93 | | ------ | ------ | ----: |
94 | | Cell | Cell | $10 |
95 | | Cell | Cell | $20 |
96 |
97 | - Outer pipes on tables are optional
98 | - Colon used for alignment (right versus left)
99 |
100 | ## Markdown plus definition lists
101 |
102 | Bottled water
103 | : $ 1.25
104 | : $ 1.55 (Large)
105 |
106 | Milk
107 | Pop
108 | : $ 1.75
109 |
110 | - Multiple definitions and terms are possible
111 | - Definitions can include multiple paragraphs too
112 |
113 | \*[ABBR]: Markdown plus abbreviations (produces an <abbr> tag)
114 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-native-react-bridge
2 |
3 |   
4 |
5 | An easy way to integrate your [React](https://github.com/facebook/react) (or [Preact](https://github.com/preactjs/preact)/[React Native Web](https://github.com/necolas/react-native-web)) app into [React Native](https://github.com/facebook/react-native) app with WebView.
6 |
7 | > [!NOTE]
8 | > You may also like [Expo DOM components](https://docs.expo.dev/guides/dom-components/)
9 |
10 | ## Why?
11 |
12 | If you'd like to run your React web app in React Native, rewriting it for React Native or using [react-native-web](https://github.com/necolas/react-native-web) is preferred way in most cases.
13 | But sometimes rewriting is overkill, when you are just prototyping, or when the app includes something not available on React Native, like rich text editor with contenteditable or complicated logic with WebAssembly.
14 |
15 | So how we run React app in React Native app as it is? It's logically possible if you run your web code in WebView using [react-native-webview](https://github.com/react-native-webview/react-native-webview).
16 | However bundling React code with React Native is troublesome and implementing communication between React Native and WebView is so hard.
17 |
18 | This library gives a bridge to make it easy.
19 | This will bundle the whole React app by some additional codes and it will be automatically re-compiled if you edit it.
20 | You rarely need to think which code you are editing for React or React Native, like isomorphic.
21 | The communication between React app and React Native app will be also simplified by this.
22 |
23 |
24 |
25 | ## Features
26 |
27 | - Create React (or Preact/React Native Web) app bundle for WebView automatically in build process of React Native
28 | - All JS modules (with or without JSX/TypeScript) will be bundled with [esbuild](https://github.com/evanw/esbuild).
29 | - **NOTE: Only the edits in the entry file of web will invoke rebuild because of the limitation of [metro](https://github.com/facebook/metro)'s build process.**
30 | - Handle communication between React Native and WebView with React hook style
31 | - With `useWebViewMessage` hook, you can subscribe messages from WebView.
32 | - With `useNativeMessage` hook, you can subscribe messages from React Native.
33 | - `emit` function sends message.
34 | - Support bundling some assets in web side with [ES6 import syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
35 | - `.json` is imported as an object, like require in Node.js.
36 | - `.txt` and `.md` are imported as string, like [raw-loader](https://github.com/webpack-contrib/raw-loader).
37 | - `.css` is injected to the HTML head of WebView, like [css-loader](https://github.com/webpack-contrib/css-loader) with [style-loader](https://github.com/webpack-contrib/style-loader).
38 | - `.bmp`, `.gif`, `.png`, `.jpg`, `.jpeg`, `.webp` and `.svg` are loaded as base64 encoded url, like [url-loader](https://github.com/webpack-contrib/url-loader).
39 | - `.htm` and `.html` are loaded as string, which can be rendered with React's [dangerouslySetInnerHTML](https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml).
40 | - `.wasm` is imported like [Node.js](https://nodejs.org/api/esm.html#esm_wasm_modules), which is compatible with [ES Module Integration Proposal for WebAssembly](https://github.com/WebAssembly/esm-integration).
41 |
42 | If you have some feature requests or improvements, please create a [issue](https://github.com/inokawa/react-native-react-bridge/issues) or [PR](https://github.com/inokawa/react-native-react-bridge/pulls).
43 |
44 | ## Install
45 |
46 | ```sh
47 | npm install react-native-react-bridge react-native-webview
48 |
49 | # Necessary only if you render React app in WebView
50 | npm install react-dom
51 |
52 | # Necessary only if you render Preact app in WebView
53 | # preact >= 10.0
54 | npm install preact
55 |
56 | # Necessary only if you render React Native Web app in WebView
57 | npm install react-dom react-native-web
58 | ```
59 |
60 | ### Requirements
61 |
62 | - react >= 16.14
63 | - react-native >= 0.60
64 |
65 | ## Usage
66 |
67 | ### 1. Fix `metro.config.js` to use babelTransformer from this library.
68 |
69 | #### React Native
70 |
71 | ```javascript
72 | module.exports = {
73 | transformer: {
74 | // This detects entry points of React app and transforms them
75 | // For the other files this will switch to use default `metro-react-native-babel-transformer` for transforming
76 | babelTransformerPath: require.resolve('react-native-react-bridge/lib/plugin'),
77 | ...
78 | },
79 | /*
80 | // optional config
81 | rnrb: {
82 | // Set `true` if you use Preact in web side.
83 | // This will alias imports from `react` and `react-dom` to `preact/compat` automatically.
84 | preact: true,
85 | // Set `true` if you use react-native-web in web side.
86 | // This will alias imports from `react-native` to `react-native-web` automatically.
87 | web: true
88 | },
89 | */
90 | ...
91 | };
92 | ```
93 |
94 | #### Expo
95 |
96 | ```javascript
97 | const { getDefaultConfig } = require("expo/metro-config");
98 |
99 | const config = getDefaultConfig(__dirname);
100 |
101 | config.transformer.babelTransformerPath = require.resolve(
102 | "react-native-react-bridge/lib/plugin"
103 | );
104 |
105 | module.exports = config;
106 | ```
107 |
108 | #### Projects with Multiple Transformers
109 |
110 | If your project at some point requires a metro configuration with additional transformers, consider making a separate `customTransformer.js` file in the project root with logic for delegating files types to the appropriate transformer, and modifying `metro.config.js` file to reference the customer transformer file. For example, if you are using `react-native-svg-transformer`, this would be your custom transformer file:
111 |
112 | ```js
113 | // root/customTransformer.js
114 | const reactNativeReactBridgeTransformer = require("react-native-react-bridge/lib/plugin");
115 | const svgTransformer = require("react-native-svg-transformer");
116 |
117 | module.exports.transform = function ({ src, filename, options }) {
118 | if (filename.endsWith(".svg")) {
119 | return svgTransformer.transform({ src, filename, options });
120 | } else {
121 | return reactNativeReactBridgeTransformer.transform({
122 | src,
123 | filename,
124 | options,
125 | });
126 | }
127 | };
128 | ```
129 |
130 | And this would be your metro config:
131 |
132 | ```js
133 | // root/metro.config.js
134 | const { getDefaultConfig } = require("metro-config");
135 |
136 | module.exports = (async () => {
137 | const {
138 | resolver: { sourceExts, assetExts },
139 | } = await getDefaultConfig();
140 | return {
141 | transformer: {
142 | babelTransformerPath: require.resolve("./customTransformer.js"),
143 | },
144 | resolver: {
145 | assetExts: assetExts.filter((ext) => ext !== "svg"),
146 | sourceExts: [...sourceExts, "svg"],
147 | },
148 | };
149 | })();
150 | ```
151 |
152 | #### Custom Esbuild options
153 |
154 | To support custom Esbuild options, we can use Multiple Transformers method and replace the customTransformer.js file with the following code:
155 |
156 | ```tsx
157 | // root/customTransformer.js
158 | const reactNativeReactBridgeTransformer = require("react-native-react-bridge/lib/plugin");
159 |
160 | const esbuildOptions = {
161 | pluglins: [],
162 | };
163 | const transform =
164 | reactNativeReactBridgeTransformer.createTransformer(esbuildOptions);
165 |
166 | module.exports.transform = function ({ src, filename, options }) {
167 | return transform({ src, filename, options });
168 | };
169 | ```
170 |
171 | ### 2. Make entry file for web app.
172 |
173 | - If you use React, React Native Web or Preact with React alias, import modules `react-native-react-bridge/lib/web`.
174 | - If you use Preact, import modules from `react-native-react-bridge/lib/web/preact`.
175 |
176 | ```jsx
177 | // WebApp.js
178 |
179 | import React, { useState } from "react";
180 | import {
181 | webViewRender,
182 | emit,
183 | useNativeMessage,
184 | } from "react-native-react-bridge/lib/web";
185 | // Importing css is supported
186 | import "./example.css";
187 | // Images are loaded as base64 encoded string
188 | import image from "./foo.png";
189 |
190 | const Root = () => {
191 | const [data, setData] = useState("");
192 | // useNativeMessage hook receives message from React Native
193 | useNativeMessage((message) => {
194 | if (message.type === "success") {
195 | setData(message.data);
196 | }
197 | });
198 | return (
199 |
200 |
201 |
{data}
202 |
211 | );
212 | };
213 |
214 | // This statement is detected by babelTransformer as an entry point
215 | // All dependencies are resolved, compressed and stringified into one file
216 | export default webViewRender();
217 | ```
218 |
219 | ### 3. Use the entry file in your React Native app with WebView.
220 |
221 | ```jsx
222 | // App.js
223 |
224 | import React from "react";
225 | import WebView from "react-native-webview";
226 | import { useWebViewMessage } from "react-native-react-bridge";
227 | import webApp from "./WebApp";
228 |
229 | const App = () => {
230 | // useWebViewMessage hook create props for WebView and handle communication
231 | // The argument is callback to receive message from React
232 | const { ref, onMessage, emit } = useWebViewMessage((message) => {
233 | // emit sends message to React
234 | // type: event name
235 | // data: some data which will be serialized by JSON.stringify
236 | if (message.type === "hello" && message.data === 123) {
237 | emit({ type: "success", data: "succeeded!" });
238 | }
239 | });
240 |
241 | return (
242 |
249 | );
250 | };
251 | ```
252 |
253 | ### 4. Start your React Native app!
254 |
255 | ## Documentation
256 |
257 | - [API reference](./docs/API.md)
258 |
259 | ### FAQs
260 |
261 | #### My webview displays a blank page.
262 |
263 | react-native-webview has some ways to show errors occurred in webview. This may be helpful to troubleshoot it.
264 |
265 | https://github.com/react-native-webview/react-native-webview/blob/master/docs/Reference.md#onerror
266 |
267 | ## Demo
268 |
269 | This repository includes demo app.
270 |
271 | ```sh
272 | git clone git@github.com:inokawa/react-native-react-bridge.git
273 | cd examples/DemoApp
274 | npm install
275 | npm run ios # or npm run android
276 | ```
277 |
278 | ## Contribute
279 |
280 | All contributions are welcome.
281 | If you find a problem, feel free to create an [issue](https://github.com/inokawa/react-native-react-bridge/issues) or a [PR](https://github.com/inokawa/react-native-react-bridge/pulls).
282 |
283 | ### Making a Pull Request
284 |
285 | 1. Fork this repo.
286 | 2. Run `npm install`.
287 | 3. Commit your fix.
288 | 4. Add tests to cover the fix.
289 | 5. Make a PR and confirm all the CI checks passed.
290 |
--------------------------------------------------------------------------------
/e2e/index.spec.tsx-snapshots/smoke-webview-with-image-png-jsx-2-chromium.txt:
--------------------------------------------------------------------------------
1 |