跳到內容
返回 Blog

2020 年 10 月 27 日,星期二

Next.js 10

發布者

我們很高興推出 Next.js 10,其特色包含

內建影像元件與自動影像最佳化

我們使用 Next.js 的目標是改善兩件事:開發者體驗與使用者體驗。

今年,我們已在開發者體驗和改善所有 Next.js 應用程式的效能方面投入大量資金。我們專注於減少瀏覽器必須載入的 JavaScript 數量。

我們推出了超過 20 項新功能,以改善效能和開發者體驗。同時,Next.js 核心的 JavaScript 大小減少了 16%

一月份,我們與 Google Chrome 團隊合作,推出了一種新的同類最佳 JavaScript 程式碼分割策略。

例如,Barnebys 的應用程式大小減少了 23%,而 Sumup 的最大 Javascript 套件大小減少了 70%。這些改進是在未變更其 Next.js 應用程式中的任何程式碼的情況下實現的。

公司只需將 Next.js 升級到最新版本,即可自動採用此新策略。

網路上的影像

雖然我們專注於減少瀏覽器必須載入的 JavaScript 數量已取得成效,但網路不僅僅是 Javascript:它還包含標記和影像。

影像佔網頁總位元組數的 50%。

影像對最大內容繪製 (Largest Contentful Paint) 有很大的影響,因為它們通常是頁面載入時最大的可見元素。最大內容繪製是一項核心網頁指標 (Core Web Vital),Google 將在他們的搜尋排名中很快使用

所有影像中有一半以上的大小超過一百萬位元組,這表示它們未針對在網路上顯示進行最佳化。

現今使用者使用他們的手機、平板電腦和筆記型電腦瀏覽網路,但影像仍然是單一尺寸適合所有裝置。例如:網站載入 2000 x 2000 像素的影像,但手機僅將其顯示為 100 x 100 像素。

此外,網頁上 30% 的影像位於初始視窗範圍之外,這表示瀏覽器會載入使用者在向下捲動頁面之前不會看到的影像。

影像通常沒有 widthheight 屬性,導致它們在頁面載入時跳動。這會損害累計版面配置偏移 (Cumulative Layout Shift) 核心網頁指標。

網站上 99.7% 的影像未使用現代影像格式,例如 WebP。

為了以高效能的方式在網頁上使用影像,必須考量許多方面:大小、重量、延遲載入和現代影像格式。

開發人員必須設定複雜的建置工具來最佳化影像,但是這些工具通常不涵蓋來自外部資料來源的使用者提交影像,因此無法最佳化所有影像。

這種不可能的開發任務不可避免地導致令人沮喪的最終使用者體驗。

Next.js 影像元件

我們很高興宣布我們針對網路上高效能影像的解決方案:Next.js 影像元件和自動影像最佳化。

在最基本的情況下,Next.js 影像元件只是 HTML <img> 元素的直接替代品,為了現代網路而發展。

<img
  src="/profile-picture.jpg"
  width="400"
  height="400"
  alt="Profile Picture"
/>
import Image from 'next/image';
<Image
  src="/profile-picture.jpg"
  width="400"
  height="400"
  alt="Profile Picture"
/>;

Google Chrome 團隊協助建立此 React 元件,透過將最佳實務設為預設值來改善頁面效能。

當使用 next/image 元件時,影像會自動延遲載入,這表示它們僅在使用者接近看到影像時才會呈現。這可防止載入初始視窗範圍之外的 30% 影像。

影像尺寸是強制執行的,允許瀏覽器立即呈現影像所需的空間,而不是在載入時跳入,從而防止版面配置偏移。

雖然 HTML <img> 元素上的 widthheight 可能會導致回應式版面配置的問題,但使用 next/image 時並非如此。當使用 next/image 時,影像會根據提供的 widthheight 的長寬比自動進行回應式調整。

開發人員可以標記位於初始視窗範圍內的影像,允許 Next.js 自動預先載入這些影像。預先載入初始視窗範圍內的影像已顯示可將最大內容繪製改善高達 50%。

自動影像最佳化

即使與 HTML <img> 元素相比有這些改進,仍然存在一個主要問題。2000 x 2000 像素的影像會傳送到呈現較小影像的手機。

透過 Next.js 10,我們也正在解決這個問題。next/image 元件將透過內建的影像最佳化自動產生較小的尺寸。

內建影像最佳化會自動以現代影像格式 (例如 WebP) 提供影像,如果瀏覽器支援,WebP 比 JPEG 小約 30%。它還允許 Next.js 自動採用未來的影像格式,並將它們提供給支援這些格式的瀏覽器。

影像最佳化適用於任何影像來源。即使影像來自外部資料來源 (例如 CMS),它們也會被最佳化。

Next.js 10 不是在建置時最佳化影像,而是在使用者請求時隨需最佳化影像。與靜態網站產生器和僅限靜態解決方案不同,無論是發布 10 個影像還是 1000 萬個影像,您的建置時間都不會增加。

結論

新的 next/image 元件和自動影像最佳化是強大的新基礎組件,將大幅改善使用者體驗。

next/image 元件處理自動延遲載入、預先載入關鍵影像、跨裝置的正確尺寸調整,並自動支援現代格式。這些功能適用於來自任何來源的影像。

我們期待看到您的使用者體驗透過這些新的基礎組件變得更快。

如需更多詳細資訊,請查看Next.js 影像元件和自動影像最佳化文件

國際化路由

今年,一些企業和社群成員協助我們的團隊了解國際化的重要性。

例如,我們了解到,如果您的網站已翻譯,則有 72% 的消費者更可能留在您的網站上,而 55% 的消費者表示他們僅從其母語的電子商務網站購買商品。

如果您計劃在不同的國家/地區上市,則專案的國際化對於成功至關重要。

專案國際化有兩大支柱:翻譯和路由。

許多 React 程式庫準備將應用程式翻譯成多種語言,但它們大多數都希望您手動處理路由,並且通常僅適用於一種呈現策略。

這就是為什麼作為 Next.js 10 的一部分,我們發布了對國際化路由和語言偵測的內建支援。

此對國際化路由的內建支援支援 Next.js 的混合策略,因此您可以在每個頁面的基礎上選擇靜態產生或伺服器端呈現。

Next.js 10 支援兩種最常見的路由策略:子路徑路由和網域路由。

對於這兩種策略,您都從在 Next.js 設定中設定語言環境開始。

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'nl'],
    defaultLocale: 'en',
  },
};

語言環境是UTS 語言環境識別碼,這是一種用於定義語言環境的標準化格式。

通常,語言環境識別碼由語言、地區和文字組成,並以破折號分隔:language-region-script。地區和文字是選填的。範例

  • en-US - 美式英語
  • nl-NL - 荷蘭語 (荷蘭)
  • nl - 荷蘭語,無特定地區

設定語言環境後,您可以選擇子路徑或網域路由。

子路徑路由

子路徑路由將語言環境放在 URL 中。這允許所有語言存在於單一網域上。

例如,您可以將語言環境插入 URL 中,例如 /nl-nl/blog/en/blog

網域路由

網域路由使您可以將語言環境對應到頂層網域。例如 example.nl 可以對應到 nl 語言環境,而 example.com 可以對應到 en 語言環境。

網域路由需要一些額外的設定,才能知道如何路由網域

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'nl'],
    domains: [
      {
        domain: 'example.com',
        defaultLocale: 'en',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl',
      },
    ],
  },
};

語言偵測

Next.js 10 在 / 路由上具有內建的語言偵測功能,該功能基於所有現代瀏覽器都支援的 Accept-Language 標頭。設定的語言環境將與 Accept-Language 標頭進行比對,然後根據設定的策略進行重新導向。

搜尋引擎最佳化

由於 Next.js 知道使用者造訪頁面的語言,它會自動將 lang 屬性新增至 <html> 標籤。

Next.js 不知道頁面的變體,因此由您使用 next/head 新增 hreflang meta 標籤。您可以在Google 網站管理員文件中了解有關 hreflang 的更多資訊。

Next.js 中國際化的未來

國際化路由是一系列功能的首個功能,這些功能將使專案的國際化和本地化更加容易。國際化路由允許與大多數 React 國際化程式庫整合。

若要深入了解國際化路由,請查看國際化路由文件

Next.js Speed Insights

在 Vercel,我們知道您無法修正無法衡量的問題。

您的訪客對網站效能越來越敏感。超過 50% 的訪客會在網站載入時間超過 3 秒時放棄造訪。如果您從事電子商務,許多人發現將載入時間縮短十分之一秒會導致轉換率提高 1%

由於效能對於您的成功至關重要,因此我們很榮幸發布 Next.js Speed Insights。此解決方案用於追蹤真實世界的效能指標,並將這些見解回饋到您的開發工作流程中。

透過 Next.js Speed Insights

您現在將持續衡量,而不是衡量一次。

量測結果將來自您的訪客正在使用的實際裝置,而不是在您的開發裝置上量測。

Next.js Speed Insights 旨在關注整體情況,深入了解您的受眾,以及您的應用程式對使用者的效能表現。

我們如此堅決地收集真實資料,是因為效能不佳的原因並不總是那麼明顯。效能衰退可能來自各種地方 — 第三方指令碼和樣式表,或第一方字型、影像和影片過大或速度緩慢。

核心網頁指標

Google 與 Web Performance Working Group 合作,建立了一組指標,以準確衡量使用者體驗您網站效能的方式:恰如其名,Web Vitals。Web Vitals 是追蹤網站的感知載入速度、回應速度和視覺穩定性的指標 — 這三者對於網站的整體健康狀況至關重要!

感知載入速度可以使用最大內容繪製來衡量,或是當頁面的所有內容都已顯示時。例如,當我開啟購買一雙運動鞋的連結時 — 在我看到我的運動鞋、價格和新增至購物車按鈕之前經過的時間量就是 LCP。

頁面回應速度可以使用首次輸入延遲 (First Input Delay) 來衡量,首次輸入延遲衡量您的使用者必須等待多久才能看到他們與頁面首次互動的反應。例如,我按一下「新增至購物車」與我的購物車中商品數量增加之間的時間量就是 FID。

最後,視覺穩定性可以使用累計版面配置偏移來衡量,或是元素在顯示給使用者後移動了多少。例如,我們都經歷過嘗試點擊一個按鈕,但由於影像載入延遲而移動的挫敗感 — 這就是版面配置偏移。

圍繞這些 Web Vitals 為您的真實使用者進行持續衡量和一致性至關重要。這是真正了解您的網站對使用者效能表現的唯一方法。您網站的效能可能會根據使用者的裝置及其網路狀況,或他們與頁面互動的方式而有很大的差異。載入個人化內容或廣告的網站也可能在使用者之間體驗到截然不同的效能。

模擬測試無法捕捉到這些重要訊號。

Next.js Speed Insights 允許您捕捉真實世界的見解,而不是合成基準。它啟用持續的量測串流,而不是依賴偶爾的測試,確保它是您開發工作流程的一部分。

Next.js Speed Insights 允許您捕捉真實世界的見解,而不是合成基準。它啟用持續的量測串流,而不是依賴偶爾的測試,確保它是您開發工作流程的一部分

造訪 nextjs.org/analytics 以了解如何立即在您的應用程式中啟用它。

Next.js Commerce

電子商務是網路最重要的用途之一。全新的 Next.js 10 功能是強大的電子商務新工具。

這就是為什麼今天我們與 BigCommerce 合作發布了 Next.js Commerce,這是一體化的 React 電商網站入門套件。只需點擊幾下,Next.js 開發人員就可以複製、部署和完全自訂它。立即前往 nextjs.org/commerce 開始使用。

React 17 支援

React 17 對於 Next.js 沒有重大變更,但仍有一些維護性的變更需要進行,例如更新 peer dependencies。當使用 React 17 時,新的 JSX 轉換 會自動啟用,無需進行任何設定變更。

您只需升級 Next.js 和 React 即可開始使用 React 17

終端機
npm install next@latest react@latest react-dom@latest

getStaticProps / getServerSideProps 快速重新整理

當您編輯 getStaticPropsgetServerSideProps 函數時,Next.js 現在會自動重新執行該函數並套用新資料。這讓您可以更快地迭代,而無需重新整理頁面。

若要深入瞭解 getStaticPropsgetServerSideProps,您可以閱讀資料獲取文件

MDX 的快速重新整理

當透過 @next/mdx 將 Next.js 與 MDX 一起使用時,變更 MDX 內容現在將利用快速重新整理,確保瀏覽器不必在編輯時重新載入頁面。

@next/mdx 文件 將引導您瞭解如何設定 Next.js 的 MDX。

從第三方 React 元件匯入 CSS

您現在可以從 React 元件內部匯入第三方 CSS。這樣可以針對僅用於單一元件的 CSS 進行程式碼分割。例如,您現在可以使用 react-datepicker 程式庫,而無需在 _app.js 中匯入 CSS

components/MyComponent.js
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
 
function MyComponent() {}

您可以參考內建 CSS 支援文件,以深入瞭解 Next.js 如何處理 CSS 匯入。

自動解析 href

如果您之前使用過動態路由,您可能曾經遇到過需要為 next/link 提供 hrefas 屬性的情況。它看起來會像這樣

<Link href="/categories/[slug]" as="/categories/books" />

這讓 Next.js 可以為動態參數內插 href,但是,當開發人員忘記新增 as 或在 href 中新增 as 時,會導致頁面轉換無法使用用戶端路由,進而造成摩擦。

幾個月前,我們著手解決開發人員的這種摩擦,主要目標是改善開發人員體驗和終端使用者體驗。我們逐步努力尋找一種允許自動解析 href 的解決方案。

我們很高興宣布,作為 Next.js 10 的一部分,您不再需要在大多數使用案例中使用 as 屬性。減少開發人員的摩擦並改善終端使用者體驗。

此變更完全向後相容,如果您目前同時使用 hrefas,則現有行為將會保留。

為了採用自動 href 解析,您只需變更 next/link 的用法,使其僅使用 href 來保存您先前在 as 屬性中擁有的值即可。

<Link href="/categories/books" />

若要深入瞭解 next/link 和用戶端路由,您可以參考 next/link 文件

@next/codemod CLI

我們致力於透過廣泛的向後相容性,確保 Next.js 升級盡可能順暢。此承諾首先是謹慎地棄用功能,同時在其位置引入新的和更好的解決方案。除了此承諾之外,我們還針對所有 Next.js 功能進行了廣泛的整合測試,包括複製本機開發的測試。

當 Next.js 中的某個功能被棄用並需要大量程式碼庫變更時,我們的團隊會為其建立 codemod。Codemod 是一種自動化的程式碼轉換,您可以在專案上執行它來更新原始碼。

例如:我們發布了一個 codemod,用於將箭頭函數和匿名函數更新為具名函數。此轉換是必要的,因為否則 React Fast Refresh 無法偵測到該函數是有效的 React 元件。同樣地,React hooks eslint 規則也無法將該函數識別為 React 元件。

在 Next.js 10 中,我們發布了一個新的 Next.js codemods CLI 工具,讓您可以執行單一命令來更新您的應用程式:npx @next/codemod <transform> <path>

若要深入瞭解 codemods,您可以查看 Next.js Codemods 文件

getStaticPaths 的封鎖式回退

在 Next.js 9.3 中,我們推出了 getStaticPropsgetStaticPaths,以及在 getStaticPaths 中傳回 fallback 屬性的功能。fallback 屬性允許產生額外的靜態頁面,而無需完全重建,最初提供一個靜態 HTML 檔案,然後在後續請求中被完全呈現的內容取代。在過去的幾個月裡,我們收到了許多公司的回饋,他們希望獲得類似但略有不同的行為:當使用者首次請求頁面時進行封鎖式預先呈現。在初始呈現之後,頁面將重複用於後續請求。

在 Next.js 10 中,我們正在解決這個問題。

我們很高興宣布 getStaticPaths 的新 fallback: 'blocking' 模式,它啟用了封鎖行為,其中沒有靜態回退傳送到瀏覽器。相反,初始請求會等待預先呈現。

pages/posts/[id].js
export function getStaticPaths() {
  return {
    // enables blocking mode for the fallback behavior
    fallback: 'blocking',
  };
}

若要深入瞭解用於逐步產生額外靜態頁面的 fallback 行為,您可以參考 fallback 文件

getStaticProps / getServerSideProps 的重新導向和 notFound 支援

自從推出 getStaticPropsgetServerSideProps 以來,我們注意到使用者在某些情況下需要傳回重新導向和 404 回應。為了協助簡化這些情況,我們現在允許從 getStaticPropsgetServerSideProps 傳回兩個新欄位:notFoundredirect

notFound 支援

當傳回 notFound 欄位並將其設為 true 時,將傳回預設的 404 頁面,狀態碼為 404。這可讓您避免使用 SSG 產生額外頁面,並避免必須手動處理呈現 404 頁面。

pages/posts/[id].js
export function getStaticProps() {
  return {
    // returns the default 404 page with a status code of 404
    notFound: true,
  };
}

redirect 支援

現在可以傳回重新導向,其中包含 destination 以及重新導向是否應為永久性,例如 permanent: true。在您需要使用特定狀態而非預設狀態的情況下,也可以傳回選用的 statusCode 來取代 permanent 欄位。

pages/posts/[id].js
export function getStaticProps() {
  return {
    // returns a redirect to an internal page `/another-page`
    redirect: {
      destination: '/another-page',
      permanent: false,
    },
  };
}
pages/posts/[id].js
export function getServerSideProps() {
  return {
    // returns a redirect to an external domain `example.com`
    redirect: {
      destination: 'https://example.com',
      permanent: false,
    },
  };
}

結論

我們很高興看到 Next.js 的採用持續成長

  • 我們已經有超過 1,300 位獨立貢獻者,自 9.5 版本發布以來,新增了超過 120 位貢獻者
  • 在 GitHub 上,該專案已被標註星號超過 54,800 次。

加入 Next.js 社群的 GitHub Discussions。 Discussions 是一個社群空間,可讓您與其他 Next.js 使用者聯繫,並自由提問或分享您的作品。

鳴謝

我們感謝我們的社群,包括所有外部回饋和貢獻,這些都幫助塑造了此版本的發布。

此版本由以下人員的貢獻所帶來:@ijjk, @adebiyial, @elliottsj, @saintmalik, @HaNdTriX, @prateekbh, @amirsaeed671, @paambaati, @imagentleman, @gregrickaby, @Janpot, @atcastle, @Kirkhammetz, @remorses, @davidsonsns, @kmkzt, @slawekkolodziej, @Timer, @styfle, @timneutkens, @ykzts, @ashconnell, @orYoffe, @lfades, @justinwhall, @fbaiodias, @ludofischer, @felipeguilhermefs, @gr-qft, @TasukuUno, @YichiZ, @weichienhung, @seosmmbusiness, @HsuTing, @gsimone, @peduarte, @ztanner, @neighborhood999, @chibicode, @merceyz, @opudalo, @lunchboxav, @mohsen1, @akd-io, @justman00, @helloworld, @devknoll, @borekb, @ArthurMaverick, @sakito21, @TrySound, @omBratteng, @svenheden, @hallaji, @kettanaito, @vvo, @m-lautenbach, @jensmeindertsma, @Zeko369, @longlho, @stefanprobst, @laugharn, @sdornan, @daneroo, @mohd-akram, @austingmhuang, @sphilee, @devinekadeni, @Bacher, @nghiepit, @tomasdisk, @leader22, @paulogdm, @284km, @belgattitude, @geritol, @stigkj, @sampoder, @samrobbins85, @Pitasi, @digitalPlayer1125, @timfee, @plug-n-play, @philihp, @leerob, @dylanjha, @Kerumen, @rdimaio, @jorisw, @zerbinidamata, @jamesgeorge007, @Jashnm, 和 @futantan!