To serve an Expo app's sign-up flow in a browser, what must be installed, and how does Expo alias react-native to react-native-web on Metro?
answer
- three packages via npx expo install
- Metro is the web bundler now
- the alias lives in Expo CLI's resolver
- .native files ignored on web
- browser field preferred on web
basics
~20 sInstall react-dom, react-native-web and @expo/metro-runtime with npx expo install, then run npx expo start --web. Expo CLI's Metro resolver aliases react-native to react-native-web for the web platform, so no webpack or Babel alias is needed.
solid answer
~40 sIn an Expo SDK 57 project, web support is three packages away: `npx expo install react-dom react-native-web @expo/metro-runtime`, which also picks versions matching the SDK (SDK 57 pins `react-native-web` to `~0.21.0`). `npx expo start --web`, or pressing `w` in the CLI, serves the app in a browser; `npx expo export -p web` writes a static build to `dist/`. Metro is the web bundler (`expo.web.bundler: "metro"`); the old `@expo/webpack-adapter` path is deprecated. The alias is not in your config: Expo CLI's Metro resolver maps `react-native` and `react-native/index` to `react-native-web` when the platform is `web`, disables `.native.*` files for web, and, for the browser bundle, prefers a package's `browser`, then `module`, then `main` field. So the sign-up screens import from `react-native` as usual, and web-only pieces go in `.web.tsx` files.
code
bash · 3 linesnpx expo install react-dom react-native-web @expo/metro-runtime
npx expo start --web
npx expo export -p webgo deeper
Recall the install command, how to start the web target, and that the same react-native imports work in the browser.
Explain that Expo CLI's Metro resolver performs the alias per platform, disables .native files on web and prefers browser fields.
Plan the web sign-up flow: which pieces go into .web.tsx files, how to export and host it, and how to diagnose libraries that crash only on web.
Decide whether marketing-facing flows such as sign-up belong in the shared app or in a web-first surface, weighing reuse against web conventions.
## The scenario The mobile app's sign-up flow (email, password, terms, verification code) should also be reachable at a web address, so the product can link to it from ads and emails. The team does not want a second codebase. In an Expo project this is mostly configuration that Expo already owns. ## What to install ```bash npx expo install react-dom react-native-web @expo/metro-runtime ``` - **`react-dom`** is the renderer React Native Web draws with. - **`react-native-web`** is the web implementation of `react-native`. Expo SDK 57's bundled-module list pins it to `~0.21.0`, which is why `npx expo install` (rather than a plain package-manager install) is used: it picks versions that match the SDK. - **`@expo/metro-runtime`** supplies the runtime pieces Metro needs in a browser. Before it starts a web session, Expo CLI checks for these packages: without `react-dom` it stops and tells you to run the install command; with `react-dom` present but `react-native-web` missing it only warns that some React Native components may not work on the web. ## Running and exporting 1. `npx expo start --web` (or press `w` in the running CLI) bundles for the web platform and opens the browser. 2. `npx expo export -p web` produces a static web build in `dist/`, copying the contents of `public/` alongside it. 3. A `public/index.html` file overrides the default HTML shell, for example to add meta tags for the sign-up landing page. The app config selects Metro as the web bundler: ```json { "expo": { "web": { "bundler": "metro" } } } ``` Expo's docs call Metro the recommended web bundler and describe the older webpack adapter as deprecated, with a migration guide. ## Where the alias actually happens There is no `resolve.alias` and no Babel alias in an Expo project. Expo CLI extends Metro's resolver, and for the `web` platform it: - maps **`react-native`** and **`react-native/index`** to **`react-native-web`**; - redirects React Native's asset-source helper to Expo's asset implementation; - turns off **`.native.*`** file resolution, so `Form.native.tsx` is never picked for the web while `Form.web.tsx` is; - resolves packages for the browser bundle using their **`browser`, then `module`, then `main`** fields, because many React Native packages' `react-native` field has no web support (server-rendering environments use their own field order). Because this is resolver logic rather than a string rewrite, it applies to dependencies in `node_modules` as well as to app code. ## Shaping the sign-up flow for the web - Shared screens import `View`, `Text`, `TextInput` and `Pressable` from `react-native` and work unchanged. - Pieces with no web equivalent go into platform files: a native SMS-code autofill helper in `CodeInput.native.tsx`, a plain field in `CodeInput.web.tsx`. - Web-only markup (for example a real `form` element so browser password managers recognise the page) can live in a `.web.tsx` file, since React DOM elements render there. - Static rendering for search engines is available through Expo Router's web output settings. ## Hosting the exported flow - `npx expo export -p web` writes plain static files to `dist/`, so any static host can serve the sign-up flow. - How routes map to HTML files (one shell for the whole app or one file per route) is decided by the router's web output setting, which is a separate topic from the alias. - `EXPO_PUBLIC_` environment variables, such as the API base URL the sign-up form posts to, are inlined into the bundle when `process.env.EXPO_PUBLIC_…` is read with dot notation, so each environment gets its own export. - The same screens keep shipping in the native app from the same commit, which is the point of serving the flow from the mobile codebase. ## Common problems | Symptom | Likely cause | |---|---| | CLI stops or warns about web dependencies | `react-dom` (blocking) or `react-native-web` (warning) missing | | A library crashes only on web | it has no web build and was imported from shared code | | A `.native.tsx` file seems ignored on web | expected: native files are disabled for the web platform | | Version warnings after an SDK upgrade | packages installed without `npx expo install` | ## Why this matters in an interview It shows you know the alias is still there, just owned by the framework: the same `react-native` import resolves to a native implementation on phones and to React Native Web in the browser, decided per platform inside Metro's resolver.
- In an Expo project, why might Form.native.tsx and Form.tsx behave differently from a plain Metro setup on the web?Expo CLI turns off `.native.*` resolution for the `web` platform, so the web bundle uses `Form.web.tsx` if it exists and otherwise `Form.tsx`, never `Form.native.tsx`. That is what lets `.native.tsx` hold code shared by iOS and Android that must not reach the browser.
- Why does Expo prefer a package's browser field over its react-native field when bundling for the web?Many React Native packages point their `react-native` field at native-only source. For the web platform Expo resolves `browser`, then `module`, then `main`, which is where packages publish their browser-compatible builds.
- Why use npx expo install rather than a plain package-manager install for react-native-web?Because `npx expo install` picks the version range the SDK was tested with; SDK 57's bundled-module list pins `react-native-web` to `~0.21.0`. A plain install can pull a newer major that Expo's tooling and other SDK packages were not built against.
saying these in an interview costs you the question
- An Expo project needs a webpack config with a react-native alias for web.
- Expo's web alias is a Babel rewrite that skips node_modules.
- .native.tsx files are used on web when no .web.tsx exists.
- npx expo export -p web requires EAS to build the site.
- react-native-web must be installed at its latest major regardless of the SDK.