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。要創建嵌套路由,我們可以相互嵌套文件夾。

文件夾結構

Remix

Remix v2 使用基於平面文件的路由系統。在我們的 /app/routes 文件夾中,我們可以通過添加新組件來創建新路由。使用文件名中的句點分隔符(.)來創建嵌套路由。例如,如果我們想在 Remix 應用中創建一個 /concerts/trending 路由,我們會添加一個名爲 concerts.trending.tsx 的新文件。

視角

現在,如果我們比較這兩個框架的路由機制,它們都選擇了基於文件系統的路由幾乎相同的方向,感覺這是正確的方式前進。

Remix 似乎更直觀,我們可以通過查看文件 / 佈局來了解它表示的路由。但根據 Next.js,將相關的路由文件放在一個文件夾中也是有道理的,這有助於爲每個路由段定義我們的加載 / 錯誤狀態。

  1. 數據獲取

Next.js

Next.js 提供了幾種數據獲取方法:

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 的數據獲取方法允許更精細地控制數據加載和依賴關係。

  1. 數據變更

處理變更時,我們通常通過向後端服務器發送 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"  />
      <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"  />
      <button type="submit">Submit</button>
    </form>
  );
}

Remix

Remix 自動將 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
        
        defaultValue={user.displayName}
      />
      <input  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 路由動作文檔。

視角

  1. 錯誤處理

Next.js and Remix 提供了在我們的 Web 應用程序中優雅處理錯誤的機制。

Next.js

每個路由段中都有一個獨立的 error.js 文件,用於渲染該路由段的錯誤狀態。error.js 文件約定允許我們通過自動將路由段及其嵌套子元素包裝在 React 錯誤邊界中,優雅地處理嵌套路由中的意外運行時錯誤。它處理在服務器端或瀏覽器中可能發生的意外錯誤以及如 404 等預期錯誤。

Remix

要渲染路由段的錯誤狀態,我們可以導出 ErrorBoundary。它處理在服務器端或瀏覽器中可能發生的意外錯誤以及如 404 等預期錯誤。

  1. 社區支持

Next.js

Next.js 是一個經過良好建立的框架,擁有 11.8 萬顆 GitHub stars(撰寫時)。它擁有龐大的社區和生態系統,在尋找解決問題、插件或集成時具有重大優勢。

Remix

Remix 在撰寫時擁有約 2.66 萬顆 GitHub stars ,並且社區正在不斷壯大。

觀點

如果應用程序不太複雜且不需要社區的太多幫助,則更喜歡 Remix。如果一個應用程序需要一個擁有更廣泛功能範圍和龐大用戶社區的框架,那麼 Next.js 是一個不錯的選擇。

  1. 學習曲線

Next.js

相對較難學習。它提供了很多選擇,如果開發者沒有正確使用,低級別控制可能會顯得過度。

Remix

相對較簡單。它提供了一種做事情的方式,並將很多內容抽象出來。

  1. 部署

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 執行的任何平臺上。這在很大程度上是由於它專注於標準。

  1. 價格

Next.js

對許多人來說,Vercel 的定價似乎是一個大問題。這可能是一個重要的考慮因素。

Remix

由於 Remix 可以在支持 JavaScript 執行的任何平臺上部署,因此我們可以根據自己的選擇自由選擇平臺。

  1. 與大品牌的合作

Next.js

Next.js 由 Vercel 維護。React 團隊與 Next.js 團隊密切合作,推出新功能,如 React Server Components。

Remix

Remix 在 2022 年與 Shopify 合作!在 Shopify 的支持下,Remix 獲得了來自一個成熟的商業領導者的長期支持和支持。

  1. 公司

Next.js

詳細列表可見 https://nextjs.org/showcase

Remix

詳細列表可見 https://remix.run/showcase

那麼,誰會獲得冠軍呢?

獲勝者是…

平局!Next.js 和 Remix 在不同領域都表現出色。

然而,“最佳” 框架取決於項目的獨特需求:

對於:大型項目、功能豐富的框架、以及擁有廣泛支持的快速勝利 - Next.js 可能是冠軍。

對於:性能關鍵項目、流暢的用戶體驗、解決較不復雜的問題以及願意探索現代方法 - Remix 可能是冠軍。

記住:

這兩個框架都擁有活躍的社區和不斷增長的資源池。親身實驗至關重要。使用每個框架構建小型項目,以發現個人適合性。團隊的技能和偏好很重要。選擇與團隊開發風格相符的框架。

本文翻譯自 https://blog.saeloun.com/2024/02/21/next.js-vs-remix。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/8JhWjHW1TOQ695obi1dDJw