コンテンツへスキップ
ブログに戻る

2020年1月15日(水)

Next.js 9.2

投稿者

本日、Next.js 9.2 のリリースを発表できることを嬉しく思います。今回のリリースでは、以下の機能が追加されています。

これらの利点はすべて非破壊的で、完全に後方互換性があります。アップデートするには、次のコマンドを実行するだけです。

ターミナル
npm i next@latest react@latest react-dom@latest

グローバルスタイルシートの組み込みCSSサポート

Next.js 5では、Next.jsの動作を拡張する`next-css`というカスタムプラグインを介してCSSのインポートをサポートしていました。

時間の経過とともに、Next.jsの企業やユーザーから、アプリケーションに`next-css`を追加することになることが多いというフィードバックを常に得てきました。

さらに、`next-css`にはCSSをインポートする際にいくつかの制約が欠けていました。たとえば、プロジェクトのすべてのファイルでCSSファイルをインポートできますが、このインポートされたCSSファイルはアプリケーション全体でグローバルになります。

開発者エクスペリエンスを向上させ、これらの不整合を解決するために、デフォルトでNext.jsにCSSインポートサポートを追加する作業を始めました。

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';
 
// This default export is required in a new `pages/_app.js` file.
export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

スタイルシートは本質的にグローバルであるため、カスタム``コンポーネントでインポートする必要があります。これは、グローバルスタイルのクラス名と順序の競合を回避するために必要です。

開発中は、このようにスタイルシートを表現することで、編集時にスタイルがページで自動的に更新されます。

本番環境では、すべてのCSSファイルは自動的に単一の圧縮された`.css`ファイルに連結されます。このCSSファイルは``タグを介してロードされ、Next.jsが生成するデフォルトのHTMLマークアップに自動的に挿入されます。

この新機能は完全に後方互換性があります。`@zeit/next-css`またはその他のCSS関連のプラグインを使用している場合、競合を回避するためにこの機能は無効になります。

現在`@zeit/next-css`を使用している場合は、`next.config.js`と`package.json`からプラグインを削除し、アップグレード時に組み込みのCSSサポートに移行することをお勧めします。

コンポーネントレベルスタイルの組み込みCSSモジュールサポート

Next.jsは、`[name].module.css`ファイル命名規則を使用してCSS Modulesをサポートするようになりました。

`next-css`を使用してNext.js 5で利用できたサポートとは異なり、グローバルCSSとCSSモジュールは共存できるようになりました。`next-css`では、アプリケーション内のすべての`.css`ファイルをグローバルまたはローカルとして処理する必要がありましたが、両方ではありませんでした。

CSSモジュールは、一意のクラス名を自動的に作成することでCSSをローカルスコープにします。これにより、異なるファイルで同じCSSクラス名を使用しても、衝突を心配する必要がなくなります。

この動作により、CSSモジュールはコンポーネントレベルのCSSを含めるための理想的な方法になります。CSSモジュールファイルは、アプリケーション内のどこからでもインポートできます

たとえば、`components/`フォルダーにある再利用可能な`Button`コンポーネントを考えてみましょう。

まず、次のコンテンツを含む`components/Button.module.css`を作成します。

/*
You do not need to worry about .error {} colliding with any other `.css` or
`.module.css` files!
*/
.error {
  color: white;
  background-color: red;
}

次に、上記のCSSファイルをインポートして使用する`components/Button.js`を作成します。

components/Button.js
import styles from './Button.module.css';
 
export function Button() {
  return (
    <button
      type="button"
      // Note how the "error" class is accessed as a property on the imported
      // `styles` object.
      className={styles.error}
    >
      Destroy
    </button>
  );
}

CSSモジュールはオプションの機能であり、`module.css`拡張子を持つファイルに対してのみ有効になります。通常の``スタイルシートグローバルCSSファイルは引き続きサポートされます。

本番環境では、すべてのCSSモジュールファイルは、多くの圧縮され、コード分割された`.css`ファイルに自動的に連結されます。これらの`.css`ファイルは、アプリケーション内のホット実行パスを表し、アプリケーションがレンダリングするためにページごとに最小限のCSSがロードされるようにします。

上記と同様に、この新機能は完全に後方互換性があります。`@zeit/next-css`またはその他のCSS関連のプラグインを使用している場合、競合を回避するためにこの機能は無効になります。

現在`@zeit/next-css`を使用している場合は、`next.config.js`と`package.json`からプラグインを削除し、組み込みのCSSサポートに移行することをお勧めします。

コード分割戦略の改善

9.2より前のNext.jsバージョンでは、ページをインタラクティブにするためにロードが必要なJavaScriptバンドルのセットが固定されていました。

  • ページのJavaScriptファイル
  • 共通のJavaScriptを含むファイル
  • Next.jsクライアントサイドランタイムバンドル
  • Webpackクライアントサイドランタイムバンドル
  • 動的インポート(`next/dynamic` を使用した場合に追加)

ページをインタラクティブにするには、これらのバンドルはすべてブラウザでReactを起動するために相互に依存しているため、ロードする必要があります。

これらのバンドルはすべてアプリケーションをインタラクティブにするために必要であるため、可能な限り最適化することが重要です。実際には、これはアプリケーションの他の部分からのコードの過剰なダウンロードを避けることを意味します。

このため、Next.jsはページ間で共通のJavaScriptを保持する`commons`バンドルを使用していました。`commons`を生成するための古いバンドル分割戦略の計算は、使用率のヒューリスティックでした。モジュールがすべてのページの50%以上で使用されている場合、共通モジュールとしてマークされました。それ以外の場合は、ページのJavaScriptファイルにバンドルされました。

しかし、アプリケーションは多くの異なるタイプのページで構成される場合があります。たとえば、マーケティングページ、ブログ、ダッシュボードなどです。他のページタイプと比較してマーケティングページの数が多い場合、commonsの計算により、マーケティングページに重点的に最適化が行われます。

私たちの目標は、1つのアプリケーション内のすべてのページタイプを最適化することです。

Alex Castle は、多くのページタイプが関与する場合でも、複数のファイルを含む最適化されたcommonsチャンク作成を可能にする新しいチャンク化方法(個別のJavaScriptファイルの作成)を提案しました。

本日、この新しいチャンク化動作がNext.js 9.2でデフォルトで有効になっていることを発表できることを嬉しく思います。Google ChromeチームAlex Castleへの深い感謝の意を表したいと思います。この変更は、数週間の調査、ラボテスト、現実世界のテスト、実装の累積的な努力を反映しています。

新しいチャンク化実装はHTTP/2を活用して、より多くの小さなチャンクを配信します。

新しいヒューリスティックの下では、チャンクは以下のように作成されます。

  • 各ページの最小チャンク。
  • React、ReactDOM、ReactのSchedulerなどを含むフレームワークチャンク。
  • 160kbを超える`node_module`依存関係のライブラリチャンク(minify/gzip前)。
  • すべてのページで使用される共通チャンク。
  • 可能な限り多くの共有チャンク(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ユーザーによって広く採用されています。

動的ルートセグメント機能がカバーしていないケースがいくつかまだありました。

その1つのケースがキャッチオールルートです。たとえば、` /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回以上スターされました。
  • examplesディレクトリには、220を超える例があります。

Next.jsコミュニティには現在、13,800人を超えるメンバーがいます。参加しましょう!

このリリースの形成に役立ったコミュニティとすべての外部からのフィードバックと貢献に感謝しています。