DEV Community

stereobooster
stereobooster

Posted on • Originally published at stereobooster.com on

react-native-web with Vite

react-native-web itself doesn't require any tricky configuration to work with Vite.

import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], alias: { "react-native": "react-native-web", }, }); 
Enter fullscreen mode Exit fullscreen mode

But in order to use any library for react-native or react-native-web this would be not enough.

First of all react-native packages use convention to put web specific code in .web.js files:

const extensions = [ ".web.tsx", ".tsx", ".web.ts", ".ts", ".web.jsx", ".jsx", ".web.js", ".js", ".css", ".json", ".mjs", ]; export default defineConfig({ resolve: { extensions, } optimizeDeps: { esbuildOptions: { resolveExtensions: extensions, } } }) 
Enter fullscreen mode Exit fullscreen mode

Often react-native packages assume webpack and global values defined by it:

const development = process.env.NODE_ENV === "development"; export default defineConfig({ define: { global: "window", __DEV__: JSON.stringify(development), DEV: JSON.stringify(development), "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), }, }); 
Enter fullscreen mode Exit fullscreen mode

One more unpleasant surprise is that react-native packages can distribute jsx files with .js extension:

export default defineConfig({ optimizeDeps: { esbuildOptions: { loader: { ".js": "jsx" }, }, }, }); 
Enter fullscreen mode Exit fullscreen mode

And if you see ReferenceError: React is not defined cause by react-native package, try:

export default defineConfig({ optimizeDeps: { esbuildOptions: { jsx: "automatic", }, }, }); 
Enter fullscreen mode Exit fullscreen mode

Other issues which can happen (but I don't have examples for it): js files may contain Flow syntax:

import { esbuildFlowPlugin } from "@bunchtogether/vite-plugin-flow"; export default defineConfig({ optimizeDeps: { esbuildOptions: { plugins: [ esbuildFlowPlugin(/\.(flow|jsx?)$/, (path) => /\.jsx$/.test(path) ? "jsx" : "jsx" ), ], }, }, }); 
Enter fullscreen mode Exit fullscreen mode

Final config

import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; // import { esbuildFlowPlugin } from "@bunchtogether/vite-plugin-flow"; // https://tamagui.dev/docs/intro/installation const extensions = [ ".web.tsx", ".tsx", ".web.ts", ".ts", ".web.jsx", ".jsx", ".web.js", ".js", ".css", ".json", ".mjs", ]; const development = process.env.NODE_ENV === "development"; // https://vitejs.dev/config/ export default defineConfig({ clearScreen: true, plugins: [react()], define: { // https://github.com/bevacqua/dragula/issues/602#issuecomment-1296313369 global: "window", __DEV__: JSON.stringify(development), // https://tamagui.dev/docs/intro/installation DEV: JSON.stringify(development), "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV), }, resolve: { extensions: extensions, alias: { "react-native": "react-native-web", }, }, optimizeDeps: { esbuildOptions: { resolveExtensions: extensions, // https://github.com/vitejs/vite-plugin-react/issues/192#issuecomment-1627384670 jsx: "automatic", // need either this or the plugin below loader: { ".js": "jsx" }, // plugins: [ // esbuildFlowPlugin(/\.(flow|jsx?)$/, (path) => // /\.jsx$/.test(path) ? "jsx" : "jsx" // ), // ], }, }, }); 
Enter fullscreen mode Exit fullscreen mode

Packages issues

Example

Vite + react-native-web + TypeScript

Top comments (0)