從 Create React App 遷移
本指南將協助您將現有的 Create React App 網站遷移至 Next.js。
為何要轉換?
您可能想要從 Create React App 轉換到 Next.js 的原因有很多。
初始頁面載入時間過慢
Create React App 使用純粹的客戶端 React。僅限客戶端的應用程式,也稱為單頁應用程式 (SPA),通常初始頁面載入時間較慢。這有幾個原因:
- 瀏覽器需要等待 React 程式碼和整個應用程式套件下載並執行,然後您的程式碼才能發送請求以載入資料。
- 您的應用程式程式碼會隨著您新增的每個新功能和依賴項而增長。
沒有自動程式碼分割
先前提到的載入時間過慢的問題可以透過程式碼分割來改善。然而,如果您嘗試手動進行程式碼分割,通常會使效能變得更糟。手動進行程式碼分割時,很容易無意中造成網路瀑布流。Next.js 在其路由器中內建了自動程式碼分割功能。
網路瀑布流
您需要做的第一件事是將 next
安裝為相依套件
npm install next@latest
步驟 2:建立 Next.js 設定檔
在專案的根目錄建立一個 next.config.mjs
檔案。這個檔案將包含您的 Next.js 設定選項。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // Outputs a Single-Page Application (SPA).
distDir: './build', // Changes the build output directory to `./dist`.
}
export default nextConfig
步驟 3:建立根佈局
Next.js 應用程式路由器 應用程式必須包含一個 根佈局 檔案,它是一個 React 伺服器元件,它將包裝應用程式中的所有頁面。這個檔案定義在 app
目錄的最上層。
在 CRA 應用程式中最接近根佈局檔案的等效檔案是 index.html
檔案,其中包含您的 <html>
、<head>
和 <body>
標籤。
在此步驟中,您會將 index.html
檔案轉換為根佈局檔案
- 在您的
src
目錄中建立一個新的app
目錄。 - 在該
app
目錄內建立一個新的layout.tsx
檔案
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return '...'
}
注意事項:佈局檔案可以使用
.js
、.jsx
或.tsx
副檔名。
將 index.html
檔案的內容複製到先前建立的 <RootLayout>
元件中,同時將 body.div#root
和 body.noscript
標籤替換為 <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" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React App</title>
<meta name="description" content="Web site created..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
注意事項:Next.js 會忽略 CRA 的
public/manifest.json
檔案、額外的圖示(除了favicon
、icon
和apple-icon
)以及 測試設定,但如果這些是必要條件,Next.js 也支援這些選項。有關更多資訊,請參閱 Metadata API 和 測試 文件。
步驟 4:詮釋資料
Next.js 預設已包含 meta charset<head>
中移除它們。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<title>React App</title>
<meta name="description" content="Web site created..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
任何 中繼資料檔案,例如 favicon.ico
、icon.png
、robots.txt
,只要您將它們放置在 app
目錄的頂層,就會自動添加到應用程式的 <head>
標籤中。將 所有支援的檔案 移至 app
目錄後,您可以安全地刪除它們的 <link>
標籤。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<title>React App</title>
<meta name="description" content="Web site created..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
最後,Next.js 可以使用 Metadata API 管理您最後的 <head>
標籤。將您最終的中繼資料資訊移至匯出的 metadata
物件 中。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'React App',
description: 'Web site created with Next.js.',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
透過上述變更,您已從在 index.html
中宣告所有內容轉變為使用 Next.js 內建的基於慣例的方法(Metadata API)。這種方法使您能夠更輕鬆地改善網頁的 SEO 和網頁分享能力。
步驟 5:樣式
與 Create React App 相似,Next.js 內建支援 CSS 模組。
如果您使用的是全域 CSS 檔案,請將其匯入到您的 app/layout.tsx
檔案中。
import '../index.css'
// ...
如果您使用的是 Tailwind,則需要安裝 postcss
和 autoprefixer
。
npm install postcss autoprefixer
然後,在專案的根目錄建立一個 postcss.config.js
檔案。
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
步驟 6:建立進入點頁面
在 Next.js 上,您可以透過建立 page.tsx
檔案來宣告應用程式的進入點。這個檔案在 CRA 上最接近的等效檔案是您的 src/index.tsx
檔案。在此步驟中,您將設定應用程式的進入點。
在您的 app
目錄中建立一個 [[...slug]]
目錄。
由於本指南旨在先將 Next.js 設定為 SPA(單頁應用程式),因此您需要頁面進入點來攔截應用程式所有可能的路由。為此,請在您的 app
目錄中建立一個新的 [[...slug]]
目錄。
這個目錄就是所謂的可選的全域路由區段。Next.js 使用基於檔案系統的路由器,其中目錄用於定義路由。這個特殊的目錄會確保應用程式的所有路由都會導向到其包含的 page.tsx
檔案。
在 app/[[...slug]]
目錄內建立一個新的 page.tsx
檔案,內容如下:
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return '...' // We'll update this
}
這個檔案是一個伺服器元件。當您執行 next build
時,該檔案會被預渲染成靜態資源。它*不需要*任何動態程式碼。
這個檔案匯入了我們的全域 CSS,並告知generateStaticParams
我們只會產生一個路由,即 /
的索引路由。
現在,讓我們移動 CRA 應用程式的其餘部分,這些部分將僅在客戶端運行。
'use client'
import dynamic from 'next/dynamic'
const App = dynamic(() => import('../../App'), { ssr: false })
export function ClientOnly() {
return <App />
}
這個檔案是一個客戶端元件,由 'use client'
指令定義。客戶端元件在發送到客戶端之前,仍然會在伺服器上預渲染為 HTML。
由於我們希望啟動一個純客戶端應用程式,我們可以設定 Next.js 從 App
元件開始停用預渲染。
const App = dynamic(() => import('../../App'), { ssr: false })
現在,更新您的入口頁面以使用新的元件
import { ClientOnly } from './client'
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return <ClientOnly />
}
步驟 7:更新靜態圖片匯入
Next.js 處理靜態圖片匯入的方式與 CRA 略有不同。使用 CRA 時,匯入圖片檔案會以字串形式返回其公開 URL。
import image from './img.png'
export default function App() {
return <img src={image} />
}
使用 Next.js 時,靜態圖片匯入會返回一個物件。該物件可以直接與 Next.js 的<Image>
元件一起使用,或者您可以將物件的 src
屬性與現有的 <img>
標籤一起使用。
<Image>
元件具有自動圖片優化的額外好處。<Image>
元件會根據圖片的尺寸自動設定結果 <img>
的 width
和 height
屬性。這可以防止圖片載入時版面偏移。但是,如果您的應用程式包含的圖片只設定了一個維度的樣式,而另一個維度沒有設定為 auto
,則會導致問題。如果未設定為 auto
,則維度將預設為 <img>
維度屬性的值,這可能會導致圖片顯示失真。
保留 <img>
標籤將減少應用程式中的變更量,並防止上述問題。之後,您可以選擇遷移到 <Image>
元件,透過設定載入器或移至具有自動圖片優化的預設 Next.js 伺服器來利用圖片優化功能。
將從 /public
匯入的圖片的絕對匯入路徑轉換為相對匯入路徑
// Before
import logo from '/logo.png'
// After
import logo from '../public/logo.png'
將圖片的 src
屬性傳遞給 <img>
標籤,而不是整個圖片物件。
// Before
<img src={logo} />
// After
<img src={logo.src} />
或者,您可以根據檔名參考圖片資源的公開網址。例如,public/logo.png
將在您的應用程式中以 /logo.png
提供圖片,這將會是 src
的值。
警告:如果您使用 TypeScript,在存取
src
屬性時可能會遇到類型錯誤。要修復這些錯誤,您需要將next-env.d.ts
添加到tsconfig.json
檔案的include
陣列中。Next.js 將在您在步驟 9 執行應用程式時自動產生此檔案。
步驟 8:遷移環境變數
Next.js 支援 .env
環境變數,類似於 CRA。
主要區別在於用於在用戶端公開環境變數的前綴。將所有帶有 REACT_APP_
前綴的環境變數更改為 NEXT_PUBLIC_
。
步驟 9:更新 package.json
中的腳本
您現在應該可以執行您的應用程式來測試是否已成功遷移到 Next.js。但在這之前,您需要使用 Next.js 相關指令更新 package.json
中的 scripts
,並將 .next
和 next-env.d.ts
添加到 .gitignore
檔案中。
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "npx serve@latest ./build"
}
}
# ...
.next
next-env.d.ts
現在執行 npm run dev
,並開啟 https://127.0.0.1:3000
步驟 10:清理
您現在可以從程式碼庫中清理與 Create React App 相關的產物。
- 刪除
public/index.html
- 刪除
src/index.tsx
- 刪除
src/react-app-env.d.ts
- 刪除
reportWebVitals
設定 - 解除安裝 CRA 相依套件 (
react-scripts
)
Bundler 相容性
Create React App 和 Next.js 預設都使用 webpack 進行打包。
當您將 CRA 應用程式遷移到 Next.js 時,您可能想要遷移自訂的 webpack 設定。Next.js 支援提供自訂 webpack 設定。
此外,Next.js 也支援透過 next dev --turbo
使用 Turbopack 來提升本地開發效能。為了相容性和漸進式採用,Turbopack 也支援一些 webpack loaders。
後續步驟
如果一切按計劃進行,您現在擁有一個可以作為單頁應用程式執行的 Next.js 應用程式。然而,您尚未利用 Next.js 的大部分優勢,但您現在可以開始進行漸進式更改以獲得所有優勢。以下是您接下來可能想要做的事情
- 從 React Router 遷移到 Next.js App Router 以獲得
- 自動程式碼分割
- 串流伺服器渲染
- React 伺服器元件
- 使用
<Image>
元件最佳化圖片 - 使用
next/font
最佳化字體 - 使用
<Script>
元件最佳化第三方腳本 - 更新您的 ESLint 設定以支援 Next.js 規則
注意事項:使用靜態匯出目前不支援
使用 useParams
hook。
這有幫助嗎?