Skip to main content

从 Vite 迁移

本指南将帮助你将现有的 Vite 应用迁移到 Next.js。

¥This guide will help you migrate an existing Vite application to Next.js.

为什么要切换?

¥Why Switch?

你可能想从 Vite 切换到 Next.js 有几个原因:

¥There are several reasons why you might want to switch from Vite to Next.js:

初始页面加载时间慢

¥Slow initial page loading time

如果你使用 React 的默认 Vite 插件 构建了应用,则你的应用是纯粹的客户端应用。仅客户端应用,也称为单页应用 (SPA),通常会遇到初始页面加载时间缓慢的情况。发生这种情况有以下几个原因:

¥If you have built your application with the default Vite plugin for React, your application is a purely client-side application. Client-side only applications, also known as single-page applications (SPAs), often experience slow initial page loading time. This happens due to a couple of reasons:

  1. 浏览器需要等待 React 代码和整个应用包下载并运行,然后你的代码才能发送加载某些数据的请求。

    ¥The browser needs to wait for the React code and your entire application bundle to download and run before your code is able to send requests to load some data.

  2. 你的应用代码会随着你添加的每个新功能和额外依赖而增长。

    ¥Your application code grows with every new feature and extra dependency you add.

没有自动代码分割

¥No automatic code splitting

上一个加载时间慢的问题可以通过代码分割来解决。但是,如果你尝试手动进行代码分割,通常会导致性能变差。手动代码分割时很容易无意中引入网络瀑布。Next.js 提供内置于其路由中的自动代码分割。

¥The previous issue of slow loading times can be somewhat managed with code splitting. However, if you try to do code splitting manually, you'll often make performance worse. It's easy to inadvertently introduce network waterfalls when code-splitting manually. Next.js provides automatic code splitting built into its router.

网络瀑布

¥Network waterfalls

当应用发出连续的客户端-服务器请求来获取数据时,会出现性能不佳的常见原因。SPA 中获取数据的一种常见模式是首先渲染占位符,然后在安装组件后获取数据。不幸的是,这意味着获取数据的子组件在父组件完成加载自己的数据之前无法开始获取。

¥A common cause of poor performance occurs when applications make sequential client-server requests to fetch data. One common pattern for data fetching in an SPA is to initially render a placeholder, and then fetch data after the component has mounted. Unfortunately, this means that a child component that fetches data can't start fetching until the parent component has finished loading its own data.

虽然 Next.js 支持在客户端获取数据,但它还为你提供了将数据获取转移到服务器的选项,这可以消除客户端-服务器瀑布。

¥While fetching data on the client is supported with Next.js, it also gives you the option to shift data fetching to the server, which can eliminate client-server waterfalls.

快速且有意的加载状态

¥Fast and intentional loading states

借助对 通过 React Suspense 进行流式传输 的内置支持,你可以更加有意识地了解要首先加载 UI 的哪些部分以及按什么顺序加载,而无需引入网络瀑布。

¥With built-in support for streaming through React Suspense, you can be more intentional about which parts of your UI you want to load first and in what order without introducing network waterfalls.

这使你能够构建加载速度更快的页面并消除 布局变化

¥This enables you to build pages that are faster to load and eliminate layout shifts.

选择数据获取策略

¥Choose the data fetching strategy

根据你的需求,Next.js 允许你在页面和组件的基础上选择数据获取策略。你可以决定在构建时、在服务器上请求时或在客户端上获取。例如,你可以从 CMS 获取数据并在构建时渲染你的博客文章,然后可以将其有效地缓存在 CDN 上。

¥Depending on your needs, Next.js allows you to choose your data fetching strategy on a page and component basis. You can decide to fetch at build time, at request time on the server, or on the client. For example, you can fetch data from your CMS and render your blog posts at build time, which can then be efficiently cached on a CDN.

中间件

¥Middleware

Next.js 中间件 允许你在请求完成之前在服务器上运行代码。当用户通过将用户重定向到登录页面来访问仅经过身份验证的页面时,这对于避免出现未经身份验证的内容特别有用。该中间件对于实验和 internationalization 也很有用。

¥Next.js Middleware allows you to run code on the server before a request is completed. This is especially useful to avoid having a flash of unauthenticated content when the user visits an authenticated-only page by redirecting the user to a login page. The middleware is also useful for experimentation and internationalization.

内置优化

¥Built-in Optimizations

图片fonts第三方脚本 通常对应用的性能有重大影响。Next.js 附带内置组件,可以自动为你优化这些组件。

¥Images, fonts, and third-party scripts often have significant impact on an application's performance. Next.js comes with built-in components that automatically optimize those for you.

迁移步骤

¥Migration Steps

我们此次迁移的目标是尽快获得可用的 Next.js 应用,以便你可以逐步采用 Next.js 功能。首先,我们将其保留为纯粹的客户端应用 (SPA),而无需迁移现有路由。这有助于最大限度地减少迁移过程中遇到问题的机会并减少合并冲突。

¥Our goal with this migration is to get a working Next.js application as quickly as possible, so that you can then adopt Next.js features incrementally. To begin with, we'll keep it as a purely client-side application (SPA) without migrating your existing router. This helps minimize the chances of encountering issues during the migration process and reduces merge conflicts.

步骤 1:安装 Next.js 依赖

¥Step 1: Install the Next.js Dependency

你需要做的第一件事是将 next 安装为依赖:

¥The first thing you need to do is to install next as a dependency:

npm install next@latest

步骤 2:创建 Next.js 配置文件

¥Step 2: Create the Next.js Configuration File

在项目的根目录下创建一个 next.config.mjs。该文件将保存你的 Next.js 配置选项

¥Create a next.config.mjs at the root of your project. This file will hold your Next.js configuration options.

/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // Outputs a Single-Page Application (SPA).
distDir: './dist', // Changes the build output directory to `./dist/`.
}

export default nextConfig

很高兴知道:你可以使用 .js.mjs 作为 Next.js 配置文件。

¥Good to know: You can use either .js or .mjs for your Next.js configuration file.

步骤 3:更新 TypeScript 配置

¥Step 3: Update TypeScript Configuration

如果你使用的是 TypeScript,则需要使用以下更改来更新 tsconfig.json 文件,以使其与 Next.js 兼容。如果你不使用 TypeScript,则可以跳过此步骤。

¥If you're using TypeScript, you need to update your tsconfig.json file with the following changes to make it compatible with Next.js. If you're not using TypeScript, you can skip this step.

  1. 删除 项目引用tsconfig.node.json

    ¥Remove the project reference to tsconfig.node.json

  2. ./dist/types/**/*.ts./next-env.d.ts 添加到 include 数组

    ¥Add ./dist/types/**/*.ts and ./next-env.d.ts to the include array

  3. ./node_modules 添加到 exclude 数组

    ¥Add ./node_modules to the exclude array

  4. { "name": "next" } 添加到 compilerOptions 中的 plugins 数组"plugins": [{ "name": "next" }]

    ¥Add { "name": "next" } to the plugins array in compilerOptions: "plugins": [{ "name": "next" }]

  5. esModuleInterop 设置为 true"esModuleInterop": true

    ¥Set esModuleInterop to true: "esModuleInterop": true

  6. jsx 设置为 preserve"jsx": "preserve"

    ¥Set jsx to preserve: "jsx": "preserve"

  7. allowJs 设置为 true"allowJs": true

    ¥Set allowJs to true: "allowJs": true

  8. forceConsistentCasingInFileNames 设置为 true"forceConsistentCasingInFileNames": true

    ¥Set forceConsistentCasingInFileNames to true: "forceConsistentCasingInFileNames": true

  9. incremental 设置为 true"incremental": true

    ¥Set incremental to true: "incremental": true

以下是经过这些更改后工作的 tsconfig.json 的示例:

¥Here's an example of a working tsconfig.json with those changes:

{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"incremental": true,
"plugins": [{ "name": "next" }]
},
"include": ["./src", "./dist/types/**/*.ts", "./next-env.d.ts"],
"exclude": ["./node_modules"]
}

你可以找到有关在 Next.js 文档 上配置 TypeScript 的更多信息。

¥You can find more information about configuring TypeScript on the Next.js docs.

步骤 4:创建根布局

¥Step 4: Create the Root Layout

Next.js 应用路由 应用必须包含 根布局 文件,该文件是一个 React 服务器组件 文件,它将封装应用中的所有页面。该文件定义在 app 目录的顶层。

¥A Next.js App Router application must include a root layout file, which is a React Server Component that will wrap all pages in your application. This file is defined at the top level of the app directory.

与 Vite 应用中的根布局文件最接近的等效项是 index.html file,其中包含 <html><head><body> 标签。

¥The closest equivalent to the root layout file in a Vite application is the index.html file, which contains your <html>, <head>, and <body> tags.

在此步骤中,你将把 index.html 文件转换为根布局文件:

¥In this step, you'll convert your index.html file into a root layout file:

  1. src 目录中创建一个新的 app 目录。

    ¥Create a new app directory in your src directory.

  2. app 目录中创建一个新的 layout.tsx 文件:

    ¥Create a new layout.tsx file inside that app directory:

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return null
}
export default function RootLayout({ children }) {
return null
}

很高兴知道:.js.jsx.tsx 扩展名可用于布局文件。

¥Good to know: .js, .jsx, or .tsx extensions can be used for Layout files.

  1. index.html 文件的内容复制到之前创建的 <RootLayout> 组件中,同时用 <div id="root">{children}</div> 替换 body.div#rootbody.script 标签:

    ¥Copy the content of your index.html file into the previously created <RootLayout> component while replacing the body.div#root and body.script tags with <div id="root">{children}</div>:

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My App</title>
<meta name="description" content="My App is a..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My App</title>
<meta name="description" content="My App is a..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
  1. Next.js 默认情况下已包含 元字符集元视口 标签,因此你可以安全地从 <head> 中删除这些标签:

    ¥Next.js already includes by default the meta charset and meta viewport tags, so you can safely remove those from your <head>:

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>My App</title>
<meta name="description" content="My App is a..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>My App</title>
<meta name="description" content="My App is a..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
  1. 任何 元数据文件(例如 favicon.icoicon.pngrobots.txt)只要将它们放入 app 目录的顶层,就会自动添加到应用 <head> 标记中。将 所有支持的文件 移动到 app 目录后,你可以安全地删除其 <link> 标签:

    ¥Any metadata files such as favicon.ico, icon.png, robots.txt are automatically added to the application <head> tag as long as you have them placed into the top level of the app directory. After moving all supported files into the app directory you can safely delete their <link> tags:

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<title>My App</title>
<meta name="description" content="My App is a..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<head>
<title>My App</title>
<meta name="description" content="My App is a..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
  1. 最后,Next.js 可以使用 元数据 API 管理你最后的 <head> 标签。将最终元数据信息移至导出的 metadata 对象 中:

    ¥Finally, Next.js can manage your last <head> tags with the Metadata API. Move your final metadata info into an exported metadata object:

import type { Metadata } from 'next'

export const metadata: Metadata = {
title: 'My App',
description: 'My App is a...',
}

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
export const metadata = {
title: 'My App',
description: 'My App is a...',
}

export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<div id="root">{children}</div>
</body>
</html>
)
}

通过上述更改,你从在 index.html 中声明所有内容转变为使用框架 (元数据 API) 中内置的 Next.js 基于约定的方法。这种方法使你能够更轻松地提高页面的 SEO 和网络共享性。

¥With the above changes, you shifted from declaring everything in your index.html to using Next.js' convention-based approach built into the framework (Metadata API). This approach enables you to more easily improve your SEO and web shareability of your pages.

步骤 5:创建入口点页面

¥Step 5: Create the Entrypoint Page

在 Next.js 上,你通过创建 page.tsx 文件来声明应用的入口点。Vite 上与此文件最接近的等效文件是你的 main.tsx 文件。在此步骤中,你将设置应用的入口点。

¥On Next.js you declare an entrypoint for your application by creating a page.tsx file. The closest equivalent of this file on Vite is your main.tsx file. In this step, you’ll set up the entrypoint of your application.

  1. app 目录中创建 [[...slug]] 目录。

    ¥Create a [[...slug]] directory in your app directory.

由于在本指南中,我们的目标首先是将 Next.js 设置为 SPA(单页应用),因此你需要页面入口点来捕获应用的所有可能路径。为此,请在 app 目录中创建一个新的 [[...slug]] 目录。

¥Since in this guide we're aiming first to set up our Next.js as an SPA (Single Page Application), you need your page entrypoint to catch all possible routes of your application. For that, create a new [[...slug]] directory in your app directory.

该目录就是所谓的 可选的包罗万象的路由段。Next.js 使用基于文件系统的路由,其中 目录用于定义路由。这个特殊目录将确保你的应用的所有路由都将定向到其包含的 page.tsx 文件。

¥This directory is what is called an optional catch-all route segment. Next.js uses a file-system based router where directories are used to define routes. This special directory will make sure that all routes of your application will be directed to its containing page.tsx file.

  1. app/[[...slug]] 目录中创建一个新的 page.tsx 文件,内容如下:

    ¥Create a new page.tsx file inside the app/[[...slug]] directory with the following content:

import '../../index.css'

export function generateStaticParams() {
return [{ slug: [''] }]
}

export default function Page() {
return '...' // We'll update this
}
import '../../index.css'

export function generateStaticParams() {
return [{ slug: [''] }]
}

export default function Page() {
return '...' // We'll update this
}

很高兴知道:.js.jsx.tsx 扩展名可用于页面文件。

¥Good to know: .js, .jsx, or .tsx extensions can be used for Page files.

该文件是 服务器组件。当你运行 next build 时,该文件将被预渲染为静态资源。它不需要任何动态代码。

¥This file is a Server Component. When you run next build, the file is prerendered into a static asset. It does not require any dynamic code.

该文件导入我们的全局 CSS 并告诉 generateStaticParams 我们只会生成一条路由,即 / 处的索引路由。

¥This file imports our global CSS and tells generateStaticParams we are only going to generate one route, the index route at /.

现在,让我们移动 Vite 应用的其余部分,该应用将仅运行客户端。

¥Now, let's move the rest of our Vite application which will run client-only.

'use client'

import React from 'react'
import dynamic from 'next/dynamic'

const App = dynamic(() => import('../../App'), { ssr: false })

export function ClientOnly() {
return <App />
}
'use client'

import React from 'react'
import dynamic from 'next/dynamic'

const App = dynamic(() => import('../../App'), { ssr: false })

export function ClientOnly() {
return <App />
}

该文件是 客户端组件,由 'use client' 指令定义。客户端组件在发送到客户端之前在服务器上仍然是 预渲染为 HTML

¥This file is a Client Component, defined by the 'use client' directive. Client Components are still prerendered to HTML on the server before being sent to the client.

由于我们希望启动仅客户端应用,因此我们可以配置 Next.js 以禁用从 App 组件开始的预渲染。

¥Since we want a client-only application to start, we can configure Next.js to disable prerendering from the App component down.

const App = dynamic(() => import('../../App'), { ssr: false })

现在,更新你的入口点页面以使用新组件:

¥Now, update your entrypoint page to use the new component:

import '../../index.css'
import { ClientOnly } from './client'

export function generateStaticParams() {
return [{ slug: [''] }]
}

export default function Page() {
return <ClientOnly />
}
import '../../index.css'
import { ClientOnly } from './client'

export function generateStaticParams() {
return [{ slug: [''] }]
}

export default function Page() {
return <ClientOnly />
}

步骤 6:更新静态图片导入

¥Step 6: Update Static Image Imports

Next.js 处理静态图片导入的方式与 Vite 略有不同。使用 Vite,导入图片文件将返回其公共 URL 作为字符串:

¥Next.js handles static image imports slightly different from Vite. With Vite, importing an image file will return its public URL as a string:

import image from './img.png' // `image` will be '/assets/img.2d8efhg.png' in production

export default function App() {
return <img src={image} />
}

使用 Next.js,静态图片导入会返回一个对象。然后,该对象可以直接与 Next.js <Image> 组件 一起使用,或者你可以将该对象的 src 属性与现有的 <img> 标记一起使用。

¥With Next.js, static image imports return an object. The object can then be used directly with the Next.js <Image> component, or you can use the object's src property with your existing <img> tag.

<Image> 组件具有 自动图片优化 的附加优点。<Image> 组件根据图片的尺寸自动设置生成的 <img>widthheight 属性。这可以防止图片加载时布局发生变化。但是,如果你的应用包含的图片仅其中一个尺寸设置了样式,而其他尺寸没有设置为 auto 样式,则这可能会导致问题。当样式未设置为 auto 时,尺寸将默认为 <img> 尺寸属性值,这可能会导致图片出现扭曲。

¥The <Image> component has the added benefits of automatic image optimization. The <Image> component automatically sets the width and height attributes of the resulting <img> based on the image's dimensions. This prevents layout shifts when the image loads. However, this can cause issues if your app contains images with only one of their dimensions being styled without the other styled to auto. When not styled to auto, the dimension will default to the <img> dimension attribute's value, which can cause the image to appear distorted.

保留 <img> 标签将减少应用中的更改量并防止上述问题。然后,你可以选择稍后迁移到 <Image> 组件,以利用 配置加载器 优化图片的优势,或者迁移到具有自动图片优化功能的默认 Next.js 服务器。

¥Keeping the <img> tag will reduce the amount of changes in your application and prevent the above issues. You can then optionally later migrate to the <Image> component to take advantage of optimizing images by configuring a loader, or moving to the default Next.js server which has automatic image optimization.

  1. 将从 /public 导入的图片的绝对导入路径转换为相对导入:

    ¥Convert absolute import paths for images imported from /public into relative imports:

// Before
import logo from '/logo.png'

// After
import logo from '../public/logo.png'
  1. 将图片 src 属性而不是整个图片对象传递给 <img> 标记:

    ¥Pass the image src property instead of the whole image object to your <img> tag:

// Before
<img src={logo} />

// After
<img src={logo.src} />

或者,你可以根据文件名引用图片资源的公共 URL。例如,public/logo.png 将在 /logo.png 处为你的应用提供图片,这将是 src 值。

¥Alternatively, you can reference the public URL for the image asset based on the filename. For example, public/logo.png will serve the image at /logo.png for your application, which would be the src value.

警告:如果你使用 TypeScript,则在访问 src 属性时可能会遇到类型错误。你现在可以安全地忽略这些。它们将在本指南结束时修复。

¥Warning: If you're using TypeScript, you might encounter type errors when accessing the src property. You can safely ignore those for now. They will be fixed by the end of this guide.

步骤 7:迁移环境变量

¥Step 7: Migrate the Environment Variables

Next.js 与 Vite 类似,支持 .env 环境变量。主要区别在于用于在客户端公开环境变量的前缀。

¥Next.js has support for .env environment variables similar to Vite. The main difference is the prefix used to expose environment variables on the client-side.

  • 将所有前缀为 VITE_ 的环境变量更改为 NEXT_PUBLIC_

    ¥Change all environment variables with the VITE_ prefix to NEXT_PUBLIC_.

Vite 在特殊的 import.meta.env 对象上公开了一些内置环境变量,Next.js 不支持这些变量。你需要按如下方式更新它们的用法:

¥Vite exposes a few built-in environment variables on the special import.meta.env object which aren’t supported by Next.js. You need to update their usage as follows:

  • import.meta.env.MODEprocess.env.NODE_ENV

  • import.meta.env.PRODprocess.env.NODE_ENV === 'production'

  • import.meta.env.DEVprocess.env.NODE_ENV !== 'production'

  • import.meta.env.SSRtypeof window !== 'undefined'

Next.js 也不提供内置的 BASE_URL 环境变量。但是,如果需要,你仍然可以配置一个:

¥Next.js also doesn't provide a built-in BASE_URL environment variable. However, you can still configure one, if you need it:

  1. 将以下内容添加到你的 .env 文件中:

    ¥Add the following to your .env file:

# ...
NEXT_PUBLIC_BASE_PATH="/some-base-path"
  1. next.config.mjs 文件中将 basePath 设置为 process.env.NEXT_PUBLIC_BASE_PATH

    ¥Set basePath to process.env.NEXT_PUBLIC_BASE_PATH in your next.config.mjs file:

/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // Outputs a Single-Page Application (SPA).
distDir: './dist', // Changes the build output directory to `./dist/`.
basePath: process.env.NEXT_PUBLIC_BASE_PATH, // Sets the base path to `/some-base-path`.
}

export default nextConfig
  1. import.meta.env.BASE_URL 用法更新为 process.env.NEXT_PUBLIC_BASE_PATH

    ¥Update import.meta.env.BASE_URL usages to process.env.NEXT_PUBLIC_BASE_PATH

步骤 8:更新 package.json 中的脚本

¥Step 8: Update Scripts in package.json

你现在应该能够运行应用来测试是否成功迁移到 Next.js。但在此之前,你需要使用 Next.js 相关命令更新 package.json 中的 scripts,并将 .nextnext-env.d.ts 添加到你的 .gitignore

¥You should now be able to run your application to test if you successfully migrated to Next.js. But before that, you need to update your scripts in your package.json with Next.js related commands, and add .next and next-env.d.ts to your .gitignore:

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
# ...
.next
next-env.d.ts
dist

现在运行 npm run dev,并打开 http://localhost:3000。你应该看到你的应用现在在 Next.js 上运行。

¥Now run npm run dev, and open http://localhost:3000. You should see your application now running on Next.js.

示例:查看 这个拉取请求,了解迁移到 Next.js 的 Vite 应用的工作示例。

¥Example: Check out this pull request for a working example of a Vite application migrated to Next.js.

步骤 9:清理

¥Step 9: Clean Up

你现在可以清理代码库中的 Vite 相关工件:

¥You can now clean up your codebase from Vite related artifacts:

  • 删除 main.tsx

    ¥Delete main.tsx

  • 删除 index.html

    ¥Delete index.html

  • 删除 vite-env.d.ts

    ¥Delete vite-env.d.ts

  • 删除 tsconfig.node.json

    ¥Delete tsconfig.node.json

  • 删除 vite.config.ts

    ¥Delete vite.config.ts

  • 卸载 Vite 依赖

    ¥Uninstall Vite dependencies

下一步

¥Next Steps

如果一切按计划进行,你现在就有了一个作为单页应用运行的正常运行的 Next.js 应用。但是,你尚未利用 Next.js 的大部分优势,但你现在可以开始进行增量更改以获得所有优势。以下是你接下来可能想要执行的操作:

¥If everything went according to plan, you now have a functioning Next.js application running as a single-page application. However, you aren't yet taking advantage of most of Next.js' benefits, but you can now start making incremental changes to reap all the benefits. Here's what you might want to do next: