react-native-web with Vite

stereobooster - Sep 7 '23 - - Dev Community

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

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .