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

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-cssというカスタムプラグインを通じてCSSのインポートをサポートし、Next.jsの動作を拡張しました。

時間の経過とともに、企業や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} />;
}

スタイルシートは本質的にグローバルであるため、カスタム<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を以下の内容で作成します。

/*
You do not need to worry about .error {} colliding with any other `.css` or
`.module.css` files!
*/
.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"
      // Note how the "error" class is accessed as a property on the imported
      // `styles` object.
      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バンドルセットが必要でした。

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

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

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

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

しかし、アプリケーションはマーケティングページ、ブログ、ダッシュボードなど、さまざまな種類のページで構成されることがあります。他のページタイプと比較してマーケティングページの数が多かった場合、共通モジュールの計算結果はマーケティングページに大きく焦点を当てた最適化になっていました。

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

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

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

新しいチャンク実装は、より多くの小さなサイズのチャンクを配信するためにHTTP/2を活用しています。

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

  • 各ページごとの最小限のチャンク。
  • React、ReactDOM、ReactのSchedulerなどを含むフレームワークチャンク。
  • 160KBを超える(minify/gzip前)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ユーザーに広く採用されています。

しかし、動的ルーティングセグメント機能ではカバーしきれないケースもまだいくつかありました。

その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人以上のメンバーがいます。ぜひご参加ください!

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