This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
在 Web 中将 Next.js 与 Expo 搭配使用
将 Next.js 与 Expo 集成以用于 Web 的指南。
警告 使用 Next.js 并不是 Expo 通用应用开发工作流的官方组成部分。
Next.js 是一个 React 框架,提供了简单的基于页面的路由以及服务端渲染。要将 Next.js 与 Expo SDK 一起使用,我们建议使用 @expo/next-adapter 库来处理配置。
将 Expo 与 Next.js 结合使用意味着你可以在移动端和 Web 应用之间共享你现有的一些组件和 API。Next.js 有自己的 CLI,你在开发 Web 平台时需要使用它,所以你需要使用 Next.js CLI 启动 Web 项目,而不是使用 npx expo start。
Next.js 只能与 Expo 的 Web 端一起使用,因为原生应用不支持服务端渲染(SSR)。
自动设置
要快速开始,请使用 with-nextjs 模板创建一个新项目:
- npx create-expo-app -e with-nextjs
- yarn create expo-app -e with-nextjs
- pnpm create expo-app -e with-nextjs
- bun create expo -e with-nextjs
- 原生:
npx expo start — 启动 Expo 项目
- Web:
npx next dev — 启动 Next.js 项目
手动设置
安装依赖
确保你的项目中已安装 expo、next、@expo/next-adapter:
- npm install expo next @expo/next-adapter
- yarn add expo next @expo/next-adapter
- pnpm add expo next @expo/next-adapter
- bun add expo next @expo/next-adapter
转译
配置 Next.js 以转换语言特性:
带 swc 的 Next.js。(推荐)
推荐使用带 SWC 的 Next.js。你可以配置 babel.config.js 只针对原生端:
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
你还需要通过在 next.config.js 中添加以下内容来强制 Next.js 使用 SWC:
module.exports = {
experimental: {
forceSwcTransforms: true,
},
};
带 Babel 的 Next.js。(不推荐)
调整你的 babel.config.js,在使用 webpack 为 Web 打包时有条件地添加 next/babel:
module.exports = function (api) {
const isWeb = api.caller(
caller =>
caller && (caller.name === 'babel-loader' || caller.name === 'next-babel-turbo-loader')
);
return {
presets: [
isWeb && require('next/babel'),
'babel-preset-expo',
].filter(Boolean),
};
};
Next.js 配置
将以下内容添加到你的 next.config.js:
const { withExpo } = require('@expo/next-adapter');
module.exports = withExpo({
transpilePackages: [
'react-native',
'react-native-web',
'expo',
],
});
完整的 Next.js 配置可能如下所示:
const { withExpo } = require('@expo/next-adapter');
const nextConfig = withExpo({
reactStrictMode: true,
swcMinify: true,
transpilePackages: [
'react-native',
'react-native-web',
'expo',
],
experimental: {
forceSwcTransforms: true,
},
});
module.exports = nextConfig;
React Native Web 样式
react-native-web 包建立在重置 CSS 样式的假设之上。以下是在 Next.js 中使用 pages 目录重置样式的方法。
import { Children } from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { AppRegistry } from 'react-native';
const style = `
html, body, #__next {
-webkit-overflow-scrolling: touch;
}
#__next {
display: flex;
flex-direction: column;
height: 100%;
}
html {
scroll-behavior: smooth;
-webkit-text-size-adjust: 100%;
}
body {
/* 允许你滚动到视口下方;默认值是 visible */
overflow-y: auto;
overscroll-behavior-y: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-ms-overflow-style: scrollbar;
}
`;
export default class MyDocument extends Document {
static async getInitialProps({ renderPage }) {
AppRegistry.registerComponent('main', () => Main);
const { getStyleElement } = AppRegistry.getApplication('main');
const page = await renderPage();
const styles = [
<style key="react-native-style" dangerouslySetInnerHTML={{ __html: style }} />,
getStyleElement(),
];
return { ...page, styles: Children.toArray(styles) };
}
render() {
return (
<Html style={{ height: '100%' }}>
<Head />
<body style={{ height: '100%', overflow: 'hidden' }}>
<Main />
<NextScript />
</body>
</Html>
);
}
}
import Head from 'next/head';
export default function App({ Component, pageProps }) {
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<Component {...pageProps} />
</>
);
}
模块转译
默认情况下,React Native 生态系统中的模块不会被转译以在 Web 浏览器中运行。React Native 依赖 Metro 中的高级缓存来快速重新加载。Next.js 使用 webpack,它没有相同级别的缓存,因此默认不会转译任何 node 模块。你需要在 next.config.js 中使用 transpilePackages 选项手动标记每个你想要转译的模块:
const { withExpo } = require('@expo/next-adapter');
module.exports = withExpo({
experimental: {
transpilePackages: [
'react-native',
'react-native-web',
'expo',
],
},
});
部署到 Vercel
这是 Vercel 推荐的将 Next.js 项目部署到生产环境的方法。
1
将 build 脚本添加到你的 package.json:
{
"scripts": {
"build": "next build"
}
}
2
安装 Vercel CLI:
- npm install --global vercel
- pnpm add --global vercel
- bun add --global vercel
与默认的 Expo for Web 相比的限制或差异
在 Web 端使用 Next.js 意味着你将使用 Next.js 的 webpack 配置进行打包。这会导致你的应用与网站在开发方式上存在一些核心差异。
- Expo Next.js 适配器不支持实验性的 app 目录。
- 对于原生端的基于文件的路由,我们建议使用 Expo Router。
贡献
如果你想帮助改进 Expo 对 Next.js 的支持,欢迎提交 PR 或 issue:
故障排查
无法在模块外部使用 import 语句
找出哪个模块包含 import 语句,并将其添加到 next.config.js 中的 transpilePackages 选项:
const { withExpo } = require('@expo/next-adapter');
module.exports = withExpo({
experimental: {
transpilePackages: [
'react-native',
'react-native-web',
'expo',
],
},
});