首页指南参考教程

将 Next.js 与 Expo for Web 结合使用

将 Next.js 与 Expo 网页版集成的指南。


使用 Next.js 并不是 Expo 通用应用开发工作流程的官方部分。

Next.js 是一个 React 框架,提供简单的基于页面的路由以及服务器端渲染。要将 Next.js 与 Expo SDK 结合使用,我们建议使用 @expo/next-adapter 库来处理配置。

¥Next.js is a React framework that provides simple page-based routing as well as server-side rendering. To use Next.js with the Expo SDK, we recommend using @expo/next-adapter library to handle the configuration.

将 Expo 与 Next.js 结合使用意味着你可以在移动和 Web 应用中共享一些现有组件和 API。Next.js 有自己的 CLI,你在为 Web 平台进行开发时需要使用它,因此你需要使用 Next.js CLI 而不是使用 npx expo start 来启动你的 Web 项目。

¥Using Expo with Next.js means you can share some of your existing components and APIs across your mobile and web app. Next.js has its own CLI that you'll need to use when developing for the web platform, so you'll need to start your web projects with the Next.js CLI and not with npx expo start.

Next.js 只能与 Expo for Web 一起使用,因为不支持原生应用的服务器端渲染 (SSR)。

¥Next.js can only be used with Expo for web as there is no support for Server-Side Rendering (SSR) for native apps.

自动设置

¥Automatic setup

要快速开始,请使用 with-nextjs 模板创建一个新项目:

¥To quickly get started, create a new project using with-nextjs template:

Terminal
npx create-expo-app -e with-nextjs
  • 本国的:npx expo start - 启动 Expo 项目

    ¥Native: npx expo start — start the Expo project

  • 网址:npx next dev — 启动 Next.js 项目

    ¥Web: npx next dev — start the Next.js project

手动设置

¥Manual setup

安装依赖

¥Install dependencies

确保你的项目中安装了 exponext@expo/next-adapter

¥Ensure you have expo, next, @expo/next-adapter installed in your project:

Terminal
yarn add expo next @expo/next-adapter

转译

¥Transpilation

配置 Next.js 来转换语言特性:

¥Configure Next.js to transform language features:

Next.js 配置

¥Next.js configuration

将以下内容添加到你的 next.config.js 中:

¥Add the following to your next.config.js:

next.config.js
const { withExpo } = require('@expo/next-adapter');

module.exports = withExpo({
  // transpilePackages is a Next.js +13.1 feature.
  // older versions can use next-transpile-modules
  transpilePackages: [
    'react-native',
    'expo',
    // Add more React Native/Expo packages here...
  ],
});

完全合格的 Next.js 配置可能如下所示:

¥The fully qualified Next.js config may look like:

next.config.js
const { withExpo } = require('@expo/next-adapter');

/** @type {import('next').NextConfig} */
const nextConfig = withExpo({
  reactStrictMode: true,
  swcMinify: true,
  transpilePackages: [
    'react-native',
    'expo',
    // Add more React Native/Expo packages here...
  ],
  experimental: {
    forceSwcTransforms: true,
  },
});

module.exports = nextConfig;

React Native Web 样式

¥React Native Web styling

react-native-web 包建立在重置 CSS 样式的假设之上。以下是如何使用页面目录重置 Next.js 中的样式。

¥The package react-native-web builds on the assumption of reset CSS styles. Here's how you reset styles in Next.js using the pages directory.

pages/_document.js
import { Children } from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { AppRegistry } from 'react-native';

// Follows the setup for react-native-web:
// https://necolas.github.io/react-native-web/docs/setup/#root-element
// Plus additional React Native scroll and text parity styles for various
// browsers.
// Force Next-generated DOM elements to fill their parent's height
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 {
  /* Allows you to scroll below the viewport; default value is 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>
    );
  }
}
pages/_app.js
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} />
    </>
  );
}

转译模块

¥Transpiling modules

默认情况下,React Native 生态系统中的模块不会转译为在 Web 浏览器中运行。React Native 依赖 Metro 中的高级缓存来快速重新加载。Next.js 使用 webpack,它没有相同级别的缓存,因此默认情况下不会转译任何节点模块。你必须使用 next.config.js 中的 transpilePackages 选项手动标记要转译的每个模块:

¥By default, modules in the React Native ecosystem are not transpiled to run in web browsers. React Native relies on advanced caching in Metro to reload quickly. Next.js uses webpack, which does not have the same level of caching, so no node modules are transpiled by default. You will have to manually mark every module you want to transpile with the transpilePackages option in next.config.js:

next.config.js
const { withExpo } = require('@expo/next-adapter');

module.exports = withExpo({
  experimental: {
    transpilePackages: [
      // NOTE: Even though `react-native` is never used in Next.js,
      // you need to list `react-native` because `react-native-web`
      // is aliased to `react-native`. Adding `react-native-web` will not work.
      'react-native',
      'expo',
      // Add more React Native/Expo packages here...
    ],
  },
});

部署到 Vercel

¥Deploy to Vercel

这是 Vercel 将 Next.js 项目部署到生产环境的首选方法。

¥This is Vercel's preferred method for deploying Next.js projects to production.

1

build 脚本添加到你的 package.json:

¥Add a build script to your package.json:

package.json
{
  "scripts": {
    "build": "next build"
  }
}

2

安装 Vercel CLI:

¥Install the Vercel CLI:

Terminal
npm i -g vercel

3

部署到 Vercel:

¥Deploy to Vercel:

Terminal
vercel

与默认 Web 版 Expo 相比的限制或差异

¥Limitations or differences compared to the default Expo for Web

在 Web 中使用 Next.js 意味着你将与 Next.js webpack 配置打包在一起。这将导致你开发应用与网站的方式存在一些核心差异。

¥Using Next.js for the web means you will be bundling with the Next.js webpack config. This will lead to some core differences in how you develop your app vs your website.

  • Expo Next.js 适配器不支持实验应用目录。

    ¥Expo Next.js adapter does not support the experimental app directory.

  • 对于原生上基于文件的路由,我们建议使用 Expo 路由

    ¥For file-based routing on native, we recommend using Expo Router.

贡献

¥Contributing

如果你想帮助改善 Expo 中的 Next.js 支持,请随时打开 PR 或提交问题:

¥If you would like to help make Next.js support in Expo better, feel free to open a PR or submit an issue:

  • @expo/next-adapter

故障排除

¥Troubleshooting

不能在模块外部使用 import 语句

¥Cannot use import statement outside a module

找出哪个模块有 import 语句并将其添加到 next.config.js 中的 transpilePackages 选项中:

¥Figure out which module has the import statement and add it to the transpilePackages option in next.config.js:

next.config.js
const { withExpo } = require('@expo/next-adapter');

module.exports = withExpo({
  experimental: {
    transpilePackages: [
      'react-native',
      'expo',
      // Add the failing package here, and restart the server...
    ],
  },
});
Expo 中文网 - 粤ICP备13048890号