跳至內容
返回部落格

2018 年 9 月 19 日,星期三

Next.js 7

發佈者
Giuseppe Gurgone
Giuseppe Gurgone@giuseppegurgone
...(保留其他作者資訊,翻譯方式同上)

經過 26 個 Canary 版本和 340 萬次下載,我們很自豪地推出正式版 Next.js 7,其特色包含:

最後,我們很興奮能在全新的 Nextjs.org 上分享這個消息

開發體驗提升

Next.js 的主要目標之一是提供最佳的生產效能和最佳的開發體驗。此版本對建置和除錯流程進行了許多重大改進。

編譯速度

由於 Webpack 4、Babel 7 以及我們程式碼庫的許多改進和優化,Next.js 現在在開發期間的啟動速度提升了 57%。

由於我們新的增量編譯快取,您對程式碼所做的更改現在將建置速度提升 40%

以下是一些我們收集到的範例數據

6.07.0變化
啟動時間(基本應用程式)1947 毫秒835 毫秒提升 57%
程式碼更改(基本應用程式)304 毫秒178 毫秒提升 42%

此外,在開發和建置時,您現在會看到更好的即時回饋,這要歸功於 webpackbar

使用 React 錯誤覆蓋顯示更完善的錯誤回報

呈現準確且有助益的錯誤訊息對於良好的開發和除錯體驗至關重要。到目前為止,我們只會呈現錯誤訊息及其堆疊追蹤。展望未來,我們將利用 react-error-overlay 來豐富堆疊追蹤,包含以下資訊:

  • 伺服器端和用戶端錯誤的精確錯誤位置
  • 原始碼的醒目顯示,以提供上下文
  • 完整的豐富堆疊追蹤

以下是我們錯誤訊息的前後比較

The previous overlay left, react-error-overlay right
左邊是之前的覆蓋顯示,右邊是 react-error-overlay

此外,react-error-overlay 讓您可以輕鬆地透過點擊特定的程式碼區塊來開啟文字編輯器。

Webpack 4

Next.js 從第一個版本發佈以來,就一直使用 webpack 來打包程式碼,並重複利用其豐富的插件和擴充生態系統。我們很高興地宣布,Next.js 現在採用最新的 webpack 4,它帶來了許多改進和錯誤修復。

其中包含:

  • 支援 .mjs 原始程式碼檔案
  • 程式碼分割的改進
  • 更好的 Tree-shaking(移除未使用的程式碼)支援

另一個新功能是 WebAssembly 支援,Next.js 甚至可以伺服器端渲染 WebAssembly,這裡有一個範例

注意事項:此升級**完全向下相容**。但是,如果您正在透過 next.config.js 使用自訂的 webpack loaders 或 plugins,您可能需要升級它們。

CSS 導入

Webpack 4 引入了一種從 bundles 中提取 CSS 的新方法,稱為 mini-extract-css-plugin

@zeit/next-css@zeit/next-less@zeit/next-sass@zeit/next-stylus 現在都由 mini-extract-css-plugin 提供支援。

這些 Next.js 插件的新版本**解決了 20 個與 CSS 導入相關的現有問題**;例如,現在支援在動態 import() 中導入 CSS

components/my-dynamic-component.js
import './my-dynamic-component.css';
 
export default function MyDynamicComponent() {
  return <h1>My dynamic component</h1>;
}
pages/index.js
import dynamic from 'next/dynamic'
 
const MyDynamicComponent = dynamic(import('../components/my-dynamic-component'))
 
export default function Index() {
  return () {
    <div>
      <MyDynamicComponent/>
    </div>
  }
}

一個主要的改進是您不再需要在 pages/_document.js 中添加以下內容

<link rel="stylesheet" href="/_next/static/style.css" />

Next.js 會自動注入 CSS 檔案,而不是手動引入。在生產環境中,Next.js 也會自動在 CSS 網址加上內容雜湊值,這樣一來,如果有任何變更,就能確保您的終端使用者永遠不會取得過時的檔案版本,並且能夠導入不可變的永久快取。

簡而言之,要在 Next.js 專案中支援導入 .css 檔案,您只需next.config.js 中註冊 withCSS 外掛程式即可。

const withCSS = require('@zeit/next-css');
module.exports = withCSS({
  /* my next config */
});

標準化動態導入

Next.js 從版本 3 開始就已透過 next/dynamic 支援動態導入。

作為這項技術的早期採用者,我們必須自行編寫解決方案來處理 import()

結果,Next.js 開始與 webpack 後來提供的支援產生分歧,並且缺少了一些功能。

因此,Next.js 不支援 webpack 後來引入的一些 import() 功能。

例如,無法手動命名和捆綁某些檔案。

import(/* webpackChunkName: 'my-chunk' */ '../lib/my-library');

另一個例子是在沒有 next/dynamic 模組包裝的情況下使用 import()

從 Next.js 7 開始,我們不再修改預設的 import() 行為。這表示您可以立即獲得完整的 import() 支援

這個變更也完全向下相容。使用動態元件仍然很簡單:

pages/index.js
import dynamic from 'next/dynamic';
 
const MyComponent = dynamic(import('../components/my-component'));
 
export default function Index() {
  return (
    <div>
      <MyComponent />
    </div>
  );
}

此範例會為 my-component 建立一個新的 JavaScript 檔案,並且僅在渲染 <MyComponent /> 時才載入它。

最重要的是,如果未渲染它,則初始 HTML 文件有效負載中不會包含 <script> 標籤

為了進一步簡化我們的程式碼庫並利用優秀的 React 生態系統,在 Next.js 7 中,next/dynamic 已被改寫為在幕後使用 react-loadable(並進行一些小幅修改)。這也為動態元件引入了兩個很棒的新功能:

  • 使用 next/dynamic 上的 timeout 選項設定逾時。
  • 載入元件延遲,使用 next/dynamic 上的 delay 選項。此延遲允許您的 loading 元件等待 x 時間後再渲染載入狀態,例如,如果導入速度非常快。

Babel 7

Next.js 6 在 Babel 7 仍處於測試階段時就引入了它。從那時起,Babel 7 的穩定版本已發布,而 Next.js 7 現在使用這個版本。

如需變更的完整列表,您可以參考 Babel 的發行說明

主要功能包含:

  • 支援 TypeScript,在 Next.js 中,您可以使用 @zeit/next-typescript
  • 支援 Fragment 語法 <>
  • 支援 babel.config.js
  • 使用 overrides 屬性僅將預設/插件應用於部分檔案或目錄

如果您的 Next.js 專案中沒有自訂 Babel 設定,則沒有重大變更。

但是,如果您有自訂 Babel 設定,則必須將各自的自訂插件/預設升級到最新版本。

如果您是從 Next.js 6 以下的版本升級,您可以執行優秀的 babel-upgrade 工具。

除了升級到 Babel 7 之外,Next.js Babel 預設 (next/babel) 現在預設在 NODE_ENV 設定為 test 時,將 modules 選項設定為 commonjs

此設定選項通常是在 Next.js 專案中建立自訂 .babelrc 的唯一原因。

.babelrc
{
  "env": {
    "development": {
      "presets": ["next/babel"]
    },
    "production": {
      "presets": ["next/babel"]
    },
    "test": {
      "presets": [["next/babel", { "preset-env": { "modules": "commonjs" } }]]
    }
  }
}

使用 Next.js 7 後變成

.babelrc
{
  "presets": ["next/babel"]
}

此時,可以移除 .babelrc,因為當沒有 Babel 設定時,Next.js 將會自動使用 next/babel

更小的初始 HTML 負載

由於 Next.js 會預先渲染 HTML,因此它會將頁面包裝在包含 <html><head><body> 和渲染頁面所需的 JavaScript 檔案的預設結構中。

先前的初始負載約為 1.62kB。在 Next.js 7 中,我們已最佳化初始 HTML 負載,現在為 1.5kB,減少了 7.4%,使您的頁面更精簡。

6.07.0變化
文件大小(伺服器渲染)1.62kb1.50kb7.4% 更小

我們縮減程式碼大小的主要方法有:

  • 移除 __next-error 區塊
  • 已將內嵌程式碼縮小,在未來的版本中它們將被完全移除。
  • 當未使用的 __NEXT_DATA__ 屬性(例如 nextExportassetPrefix 屬性)將被編譯移除。

靜態 CDN 支援

在 Next.js 5 中,我們引入了 assetPrefix 支援,這是一種讓 Next.js 自動從特定位置(通常是 CDN)載入資源的方式。如果您的 CDN 支援代理,這個選項會非常有效,您可以請求像這樣的 URL:

https://cdn.example.com/_next/static/<buildid>/pages/index.js

通常,CDN 會檢查其快取中是否有該檔案,否則會直接從來源請求該檔案。

代理資源正是 邊緣網路 的運作方式。

然而,有些解決方案需要將目錄直接預先上傳到 CDN。這樣做的問題是 Next.js 的 URL 結構與 .next 資料夾內的資料夾結構不符。例如,我們之前的例子

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// mapped to:
.next/page/index.js

在 Next.js 7 中,我們已更改 .next 的目錄結構以符合 URL 結構。

https://cdn.example.com/_next/static/<buildid>/pages/index.js
// mapped to:
.next/static/<buildid>/pages/index.js

雖然我們建議使用代理類型的 CDN,但這種新結構允許使用不同類型 CDN 的使用者將 .next 目錄上傳到他們的 CDN。

樣式化 JSX v3

我們很高興推出 styled-jsx 3,Next.js 中預設包含的 CSS-in-JS 解決方案現在已準備好支援 React Suspense

一件經常不清楚的事情是如何設定子元件的樣式,如果該元件不是當前元件範圍的一部分,例如,如果您包含一個子元件,該子元件僅在父元件內使用時才需要特定樣式。

pages/index.js
const ChildComponent = () => (
  <div>
    <p>some text</p>
  </div>
);
 
export default function Index() {
  return (
    <div>
      <ChildComponent />
      <style jsx>{`
        p {
          color: black;
        }
      `}</style>
    </div>
  );
}

以上程式碼嘗試選取 p 標籤,但不起作用,因為 styled-jsx 樣式的作用域限定於當前元件,它們不會洩漏到子元件中。解決此問題的一種方法是使用 :global 方法,從 p 標籤中移除前綴。然而,這會引入一個新問題,即樣式會洩漏到整個頁面。

在 styled-jsx 3 中,這個問題已透過引入新的 API css.resolve 得到解決,它將為給定的 styled-jsx 字串產生 className<style> 標籤(styles 屬性)。

pages/index.js
import css from 'styled-jsx/css';
 
const ChildComponent = ({ className }) => (
  <div>
    <p className={className}>some text</p>
  </div>
);
 
const { className, styles } = css.resolve`
  p {
    color: black;
  }
`;
 
export default function Index() {
  return (
    <div>
      <ChildComponent className={className} />
      {styles}
    </div>
  );
}

這個新的 API 允許透明地將自定義樣式傳遞給子組件。

由於這是 styled-jsx 的一個主要版本,因此有一個重大更改,如果您使用的是 styles-jsx/css,它可以改善套件大小。在 styled-jsx 2 中,我們會產生外部樣式的「scoped」和「global」版本,即使只使用了「scoped」版本,我們仍然會包含這些外部樣式的「global」版本。

在 styled-jsx 3 中,全域樣式必須使用 css.global 標籤而不是 css,這樣 styled-jsx 才能最佳化套件大小。

有關所有變更,請參考發行說明

應用程式與頁面之間的 React Context 與 SSR

從 Next.js 7 開始,我們現在支援在 pages/_app.js 和頁面組件之間使用新的 React Context API。

以前在伺服器端無法在頁面之間使用 React Context。原因是 webpack 保留了內部模組快取而不是使用 require.cache,我們編寫了一個自定義 webpack 外掛程式來更改此行為,以便在頁面之間共享模組實例。

這樣做不僅允許使用新的 React Context,而且在頁面之間共享程式碼時,還可以減少 Next.js 的記憶體佔用。

6.07.0變化
記憶體使用量57.5MB48.1MB-16% 記憶體

nextjs.org

隨著 Next.js 7 的發佈,我們也推出了全新設計的 nextjs.org

部落格

您目前正在閱讀的部落格文章已經是 nextjs.org 上新部落格區塊的一部分。這個部落格將成為與 Next.js 相關訊息的新家,例如新版本公告。

The new nextjs.org
全新的 nextjs.org

尋找靈感

隨著使用 Next.js 的應用程式數量不斷增長,我們需要一種方式來集中展示所有這些精美的應用程式。歡迎來到新的 /showcase 頁面

Get inspired on nextjs.org/showcase
在 nextjs.org/showcase 尋找靈感

這個新的展示區允許我們持續新增使用 Next.js 建構的應用程式。

我們邀請您造訪 /showcase 頁面來尋找靈感,或提交您使用 Next.js 開發的應用程式!

社群

自首次發布以來,Next.js 已被廣泛應用於各種領域,從財富 500 強企業到個人部落格。我們非常興奮地看到 Next.js 使用率的增長。

  • 目前,有超過 12,500 個公開索引的網域使用 Next.js。
  • 我們有超過 500 位貢獻者至少提交了 1 次 commit。
  • 在 GitHub 上,該專案已獲得超過 29,000 個星標。
  • 自首次發布以來,已提交了近 2200 個 pull request。

Next.js 社群擁有近 2000 名成員。加入我們!