Next.js vs Remix - 開發者的困境
React 生態系統是一個繁榮的景觀,充滿了承諾革新網絡開發的框架。今天,我們將深入探討兩個流行的競爭者:Next.js 和 Remix。
Next.js 是最流行的用于服務器端渲染的 React 框架之一。它已經存在相當長的時間了,并且提供了開發者所需的所有功能,提供了出色的開發體驗。
Remix 是一個較新的參與者,由 React Router 的創始人創建。它倡導全棧開發方法,并引入了幾個創新特性。隨著 Remix 在 2022 年的開源推出,開發者開始思考哪個框架更適合他們的應用。兩者都擁有令人印象深刻的特性和充滿激情的社區,但哪一個應該成為我們下一個項目的首選呢?
讓我們分析它們的優勢和劣勢,以幫助我們選擇優勝者。
1. 路由
Next.js
Next.js 有兩種不同的路由器:App Router 和 Pages Router。App Router 是一個較新的路由器,允許我們使用 React 的最新功能,比如 Server Components 和 Streaming。Pages Router 是原始的 Next.js 路由器,它允許我們構建服務器端渲染的 React 應用程序,并繼續支持用于較舊的 Next.js 應用程序。
對于應用程序路由,Next.js 13 使用基于目錄的路由,其中任何在 /app 下的文件稱為 page.tsx 的文件都會被構建為路由。應用目錄中的文件夾可以包含用于布局的 layout.tsx,用于公開訪問該路由的 page.tsx,用于定義加載狀態的 loading.tsx,以及用于錯誤處理的 error.tsx。要創建嵌套路由,我們可以相互嵌套文件夾。
圖片
路由
來源:Next.js 文檔
文件夾結構
來源:Next.js 文檔
Remix
Remix v2 使用基于平面文件的路由系統。在我們的 /app/routes 文件夾中,我們可以通過添加新組件來創建新路由。使用文件名中的句點分隔符(.)來創建嵌套路由。例如,如果我們想在 Remix 應用中創建一個 /concerts/trending 路由,我們會添加一個名為 concerts.trending.tsx 的新文件。
來源:Next.js 文檔
視角
現在,如果我們比較這兩個框架的路由機制,它們都選擇了基于文件系統的路由幾乎相同的方向,感覺這是正確的方式前進。
Remix 似乎更直觀,我們可以通過查看文件/布局來了解它表示的路由。但根據 Next.js,將相關的路由文件放在一個文件夾中也是有道理的,這有助于為每個路由段定義我們的加載/錯誤狀態。
2.數據獲取
Next.js
Next.js 提供了幾種數據獲取方法:
- getServerSideProps:在每個請求期間在服務器上獲取數據。這用于服務器端渲染(SSR),在客戶端請求頁面時獲取數據。
- getStaticProps:在構建時獲取數據,生成帶有預渲染內容的靜態 HTML 頁面。
- getInitialProps:在服務器和客戶端上都運行,用于初始渲染和客戶端填充數據。這是一個遺留的 API。
- fetch:Next.js 擴展了本地的 fetch Web API,允許我們配置每個在服務器上的 fetch 請求的緩存和重新驗證行為。fetch 與 async/await 可以在 Server Component* Route Handlers 和 Server Actions 中使用。
async function getUsers() {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
if (!res.ok) {
throw new Error('Failed to fetch data')
}
return res.json()
}
export default async function Page() {
const users = await getUsers()
return (
<div>
<h1>Users</h1>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
Remix
在 Remix 中,數據是在加載器中獲取的。每個路由可以定義一個加載器函數,在渲染時為路由提供相關數據。useLoaderData 將加載器的數據提供給組件。加載器僅在服務器上運行。
import { useLoaderData } from "@remix-run/react";
export const loader = async () => {
const users = await getUsers();
return json({ users });
};
export default function Page() {
const users = useLoaderData<typeof loader>();
return (
<div>
<h1>Users</h1>
{users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
視角
Next.js 似乎非常適合具有靜態和動態內容混合的應用程序,其中靈活性和定制性被優先考慮。Remix 的數據獲取方法允許更精細地控制數據加載和依賴關系。
3.數據變更
處理變更時,我們通常通過向后端服務器發送 API 請求,然后更新本地狀態以反映更改。
這兩個框架的目標是通過將變更處理直接集成到其核心功能中來徹底改變變更處理方式。
Next.js
在 Next.js 13.4 之前,創建并在服務器上執行操作的唯一方法是創建 API 路由并更新狀態。
Next.js 13.4 引入了服務器動作以處理數據變更,以簡化開發者體驗并改善用戶體驗。
使用 API 路由
export default function Page() {
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const response = await fetch('/api/submit', {
method: 'POST',
body: formData,
});
// Handle response if necessary
const data = await response.json();
// ...
}
return (
<form onSubmit={onSubmit}>
<input type="text" name="name" />
<button type="submit">Submit</button>
</form>
);
}
使用 server actions
export default function Page() {
async function create(formData: FormData) {
'use server';
const id = await createItem(formData);
}
return (
<form action={create}>
<input type="text" name="name" />
<button type="submit">Submit</button>
</form>
);
}
來自 Next.js 14 表單和變更的示例
Remix
Remix 自動將 UI 與持久服務器狀態同步。這發生在三個步驟中:
- 路由加載器向 UI 提供數據
- 表單提交數據到路由動作,更新持久狀態
- 頁面上的加載器數據自動重新驗證
圖片
Remix 鼓勵將用戶采取行動的每個部分都保持為 HTML 表單。每當用戶觸發表單提交時,它調用動作。一旦動作執行完畢,Remix 通過瀏覽器的 fetch 請求重新獲取該路由的所有加載器,并刷新 UI,確保 UI 始終與數據庫同步。這被稱為 Remix 的“全棧數據流”。
export async function loader({
request,
}: LoaderFunctionArgs) {
const user = await getUser(request);
return json({
displayName: user.displayName,
email: user.email,
});
}
export default function Component() {
const user = useLoaderData<typeof loader>();
return (
<Form method="post" action="/account">
<h1>Settings for {user.displayName}</h1>
<input
name="displayName"
defaultValue={user.displayName}
/>
<input name="email" defaultValue={user.email} />
<button type="submit">Save</button>
</Form>
);
}
export async function action({
request,
}: ActionFunctionArgs) {
const formData = await request.formData();
const user = await getUser(request);
await updateUser(user.id, {
email: formData.get("email"),
displayName: formData.get("displayName"),
});
return json({ ok: true });
}
這個示例來自 Remix 路由動作文檔。
視角
- Next.js server actions 與 React 生態系統和 React 的 API 相關聯。而 Remix 是基于 Web 平臺的功能實現的,并且與 Web 的工作方式密切相關。
- Next.js 的動作是以組件為中心的。而 Remix 的動作是以路由為中心的,因此不像組件那樣易于組合。
- 在 Next.js 中,我們需要手動告訴路徑重新驗證,而 Remix 則進行自動重新驗證。這些是 Next.js 和 Remix 的權衡,我們可以決定我們可以接受哪些,我們需要哪些,并相應地做出決定。
4.錯誤處理
Next.js and Remix 提供了在我們的 Web 應用程序中優雅處理錯誤的機制。
Next.js
每個路由段中都有一個獨立的 error.js 文件,用于渲染該路由段的錯誤狀態。error.js 文件約定允許我們通過自動將路由段及其嵌套子元素包裝在 React 錯誤邊界中,優雅地處理嵌套路由中的意外運行時錯誤。它處理在服務器端或瀏覽器中可能發生的意外錯誤以及如 404 等預期錯誤。
Remix
要渲染路由段的錯誤狀態,我們可以導出 ErrorBoundary。它處理在服務器端或瀏覽器中可能發生的意外錯誤以及如 404 等預期錯誤。
5.社區支持
Next.js
Next.js 是一個經過良好建立的框架,擁有 11.8 萬顆 GitHub stars(撰寫時)。它擁有龐大的社區和生態系統,在尋找解決問題、插件或集成時具有重大優勢。
Remix
Remix 在撰寫時擁有約 2.66 萬顆 GitHub stars ,并且社區正在不斷壯大。
觀點
如果應用程序不太復雜且不需要社區的太多幫助,則更喜歡 Remix。如果一個應用程序需要一個擁有更廣泛功能范圍和龐大用戶社區的框架,那么 Next.js 是一個不錯的選擇。
6.學習曲線
Next.js
相對較難學習。它提供了很多選擇,如果開發者沒有正確使用,低級別控制可能會顯得過度。
Remix
相對較簡單。它提供了一種做事情的方式,并將很多內容抽象出來。
7.部署
Next.js
在 Vercel 之外部署 Next.js 可能會有挑戰,Vercel 是一個出色的平臺,但如果我們的基礎設施在 AWS 上,則可能并不理想。將 Next.js 托管在我們的 AWS 賬戶中可以更輕松地與我們的后端集成,并且通常比在 Vercel 上更具成本效益。雖然 Next.js 沒有原生支持使用無服務器方式自托管,但我們可以將其作為 Node 應用程序運行。但是,這種方法可能無法提供與使用 Vercel 相同的好處。
幸運的是,有一個新的開源 Next.js 無服務器適配器 - OpenNext。該適配器接收 Next.js 構建輸出并將其轉換為可部署到任何函數即服務(FaaS)平臺的包,使部署更加靈活。
Kent Dodds 在他的博客中表達了對部署的擔憂。
Remix
Remix 被設計用于部署在支持 JavaScript 執行的任何平臺上。這在很大程度上是由于它專注于標準。
8.價格
Next.js
對許多人來說,Vercel 的定價似乎是一個大問題。這可能是一個重要的考慮因素。
Remix
由于 Remix 可以在支持 JavaScript 執行的任何平臺上部署,因此我們可以根據自己的選擇自由選擇平臺。
9. 與大品牌的合作
Next.js
Next.js 由 Vercel 維護。React 團隊與 Next.js 團隊密切合作,推出新功能,如 React Server Components。
Remix
Remix 在 2022 年與 Shopify 合作!在 Shopify 的支持下,Remix 獲得了來自一個成熟的商業領導者的長期支持和支持。
10. 公司
Next.js
- Netflix Jobs
- TikTok
- Notion
- Loom
詳細列表可見 https://nextjs.org/showcase。
Remix
- NASA
- Docker - Docker Scout 是一個統一的容器安全解決方案,旨在幫助開發人員快速識別并修復所有存儲庫中的漏洞。
- Shopify
- react-admin - 用于提供私有 npm 注冊表和企業用戶儀表板。
詳細列表可見 https://remix.run/showcase。
那么,誰會獲得冠軍呢?
獲勝者是…
平局!Next.js 和 Remix 在不同領域都表現出色。
然而,“最佳”框架取決于項目的獨特需求:
對于:大型項目、功能豐富的框架、以及擁有廣泛支持的快速勝利 - Next.js 可能是冠軍。
對于:性能關鍵項目、流暢的用戶體驗、解決較不復雜的問題以及愿意探索現代方法 - Remix 可能是冠軍。
記?。?/p>
這兩個框架都擁有活躍的社區和不斷增長的資源池。親身實驗至關重要。使用每個框架構建小型項目,以發現個人適合性。團隊的技能和偏好很重要。選擇與團隊開發風格相符的框架。
本文翻譯自 https://blog.saeloun.com/2024/02/21/next.js-vs-remix。