Back返回部落格

Next.js 9.2

Next.js 9.2 引入了對 CSS 的原生支援、更激進的程式碼分割 (code-splitting)、萬用動態路由 (catch-all dynamic routes) 等功能!

我們非常興奮地宣布推出 Next.js 9.2,主要功能包括:

  • 全域樣式表的內建 CSS 支援:應用程式現在可以直接導入 .css 檔案作為全域樣式表。
  • 元件級樣式的內建 CSS 模組支援:透過 .module.css 命名約定,可以在應用程式中任何地方導入和使用局部作用域的 CSS。
  • 改進的程式碼分割策略:Google Chrome 團隊深度優化了 Next.js 的程式碼分割策略,使客戶端套件 (bundle) 顯著縮小。此外,他們還最大化利用了 HTTP/2 來提升頁面載入速度,同時不影響 HTTP/1.1 的效能。
  • 萬用動態路由:Next.js 的動態路由現在支援萬用路由,可滿足各種新用例,例如由 CMS 驅動的網站。

所有這些改進都是非破壞性且完全向後兼容的。您只需執行以下指令即可更新:

Terminal
npm i next@latest react@latest react-dom@latest

全域樣式表的內建 CSS 支援

Next.js 5 通過名為 next-css 的自訂插件引入了對導入 CSS 的支援,該插件擴展了 Next.js 的行為。

隨著時間推移,我們從 Next.js 的公司和用戶那裡獲得了持續的反饋,提到他們經常需要在應用程式中添加 next-css

此外,next-css 在導入 CSS 時有一些缺失的限制。例如,您可以在專案的每個檔案中導入 CSS 檔案,但這個導入的 CSS 檔案會成為整個應用程式的全域樣式。

為了改善開發者體驗並解決這些不一致性,我們開始著手將 CSS 導入支援預設整合到 Next.js 中。

我們很高興地宣布,Next.js 現在原生支援將樣式表導入您的應用程式。

要開始在應用程式中使用 CSS 導入,請在 pages/_app.js 中導入 CSS 檔案。

例如,考慮專案根目錄中名為 styles.css 的樣式表:

body {
  padding: 20px 20px 60px;
  margin: 0;
}

如果尚未存在,請建立一個 pages/_app.js 檔案

然後,導入 styles.css 檔案:

pages/_app.js
import '../styles.css';
 
// 在新的 `pages/_app.js` 檔案中必須有這個預設導出。
export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

由於樣式表本質上是全域的,它們必須在 自訂 <App> 元件 中導入。這對於避免全域樣式的類名和順序衝突是必要的。

在開發環境中,這種表達樣式表的方式允許您在編輯時自動更新頁面上的樣式。

在生產環境中,所有 CSS 檔案將自動串接成一個壓縮後的 .css 檔案。這個 CSS 檔案將通過 <link> 標籤載入,並自動注入到 Next.js 生成的預設 HTML 標記中。

這個新功能完全向後兼容。如果您正在使用 @zeit/next-css 或其他 CSS 相關插件,該功能將被禁用以避免衝突。

如果您目前正在使用 @zeit/next-css,我們建議從您的 next.config.jspackage.json 中移除該插件,從而升級後使用內建的 CSS 支援。

元件級樣式的內建 CSS 模組支援

Next.js 現在支援使用 [name].module.css 檔案命名約定的 CSS 模組

與 Next.js 5 中使用 next-css 提供的支援不同,全域 CSS 和 CSS 模組現在可以 共存next-css 要求應用程式中所有的 .css 檔案都作為全域或局部處理,但不能同時兩者。

CSS 模組通過自動建立唯一的類名來局部作用域 CSS。這允許您在不同的檔案中使用相同的 CSS 類名,而不用擔心衝突。

這種行為使 CSS 模組成為包含元件級 CSS 的理想方式。CSS 模組檔案 可以在應用程式的任何地方導入

例如,考慮 components/ 資料夾中的可重用 Button 元件:

首先,建立包含以下內容的 components/Button.module.css

/*
您無需擔心 .error {} 與任何其他 `.css` 或 `.module.css` 檔案衝突!
*/
.error {
  color: white;
  background-color: red;
}

然後,建立 components/Button.js,導入並使用上述 CSS 檔案:

components/Button.js
import styles from './Button.module.css';
 
export function Button() {
  return (
    <button
      type="button"
      // 注意 "error" 類是如何作為導入的 `styles` 物件的屬性被訪問的。
      className={styles.error}
    >
      Destroy
    </button>
  );
}

CSS 模組是一個 可選 功能,僅對具有 .module.css 副檔名的檔案啟用。常規的 <link> 樣式表全域 CSS 檔案 仍然支援。

在生產環境中,所有 CSS 模組檔案將自動串接成 多個壓縮且程式碼分割後的 .css 檔案。這些 .css 檔案代表了應用程式中的熱門執行路徑,確保為您的應用程式繪製每個頁面載入的 CSS 量最小。

與上述相同,這個新功能完全向後兼容。如果您正在使用 @zeit/next-css 或其他 CSS 相關插件,該功能將被禁用以避免衝突。

如果您目前正在使用 @zeit/next-css,我們建議從您的 next.config.jspackage.json 中移除該插件,從而使用內建的 CSS 支援。

改進的程式碼分割策略

Next.js 9.2 之前的版本有一組固定的 JavaScript 套件 (bundles) 需要載入並使頁面互動:

  • 頁面的 JavaScript 檔案
  • 包含通用 JavaScript 的檔案
  • Next.js 客戶端運行時套件
  • Webpack 客戶端運行時套件
  • 動態導入(使用 next/dynamic 時添加)

為了使頁面互動,所有這些套件都必須載入,因為它們彼此依賴以在瀏覽器中啟動 React。

由於所有這些套件都是應用程式變得互動所必需的,因此它們必須盡可能優化。實際上,這意味著不要從應用程式的其他部分過度下載程式碼。

因此,Next.js 使用了一個 commons 套件,其中包含頁面之間的通用 JavaScript。舊的套件分割策略生成 commons 的計算是一種使用率啟發式方法。如果一個模組在超過 50% 的頁面中使用,它將被標記為通用模組。否則,它將被打包到頁面的 JavaScript 檔案中。

然而,應用程式可以包含許多不同類型的頁面。例如,行銷頁面、部落格和儀表板。如果行銷頁面的數量比其他頁面類型多得多,則通用計算將導致優化主要集中在行銷頁面上。

我們的目標是優化單一應用程式中的所有頁面類型。

Alex Castle 提出了一種新的分塊方法(建立獨立的 JavaScript 檔案),允許在涉及多種頁面類型時進行優化的通用分塊。

今天,我們很高興地宣布這種新的分塊行為在 Next.js 9.2 中預設啟用。我們要深深感謝 Google Chrome 團隊Alex Castle 貢獻了這一變更。這一變更反映了數週的研究、實驗室測試、實際測試和實施的累積努力。

新的分塊實現利用 HTTP/2 來傳遞更多數量的小型分塊。

在新的啟發式方法下,分塊為:

  • 每個頁面的最小分塊。
  • 包含 React、ReactDOM、React 的 Scheduler 等的框架分塊。
  • 任何大於 160kb(預壓縮/最小化前)的 node_module 依賴的函式庫分塊。
  • 用於所有頁面之間共用程式碼的通用分塊。
  • 盡可能多的共用分塊(由 2 個或更多頁面使用),優化整體應用程式大小和初始載入速度。
  • Next.js 的客戶端運行時。
  • Webpack 運行時。

讓我們看看這在實際應用程式中的意義:

早期採用的行業合作夥伴 Barnebys® 看到整體應用程式大小減少了 23%。

此外,他們最大的 JS 套件減少了 30% — 從 605kB 減少到 425kB — 無需任何程式碼變更。

另一個行業合作夥伴 SumUp® 看到他們最大的 JS 套件減少了 70% — 從 395kB 減少到 122kB — 無需任何程式碼變更。

最大的 JavaScript 套件

之前之後差異
Barnebys605kB425kB30% 更小
SumUp395kB122kB70% 更小

新的分塊行為不僅減少了您的整體和初始載入大小,還減少了連續的客戶端導航。Barnebys® 看到在六 (6) 次頁面導航後載入的 JavaScript 量減少了 87%:

多次客戶端轉換載入的 JavaScript

之前之後差異
Barnebys136kB18kB87% 更小

這種新行為完全向後兼容。升級到最新版本的 Next.js 是您利用此效能改進所需做的一切。

萬用動態路由

隨著 Next.js 9 的發布,我們引入了 動態路由分段,目標是在不需要自訂伺服器的情況下簡化 Next.js 中的動態分段。這一功能已被 Next.js 用戶廣泛採用。

但仍有一些情況是動態路由分段功能未涵蓋的。

其中之一是萬用路由。例如,將像 /post/** 這樣的萬用字元路由為頁面。這在您有一個由內容源(如 CMS)定義的嵌套結構時特別有用。

您現在可以使用 [...name] 語法建立萬用動態路由。

例如,pages/post/[...slug].js 將匹配 /post/a/post/a/b/post/a/b/c 等。

slug 將在路由查詢物件中作為單獨路徑部分的陣列提供。因此,對於路徑 /post/foo/bar,查詢物件將是 { slug: ['foo', 'bar'] }

社群

我們非常高興看到 Next.js 的採用持續增長:

  • 我們已經有超過 880 位獨立貢獻者。
  • 在 GitHub 上,該專案已經被加星超過 44,000 次。
  • 範例目錄 有超過 220 個範例。

Next.js 社群現在有超過 13,800 名成員。加入我們!

我們感謝我們的社群以及所有幫助塑造此版本的外部反饋和貢獻。