Next.js 9.4の変更点

遅れながらNext.js 9.4の変更点に触れていきます。基本的に公式に沿っていますが、割合した部分および多少コードの補足を加えています。

Fast Refresh

Next.jsはホットリロードが搭載されていましたが、9.4では新たにreact-refreshが搭載されました。react-refreshはホットリロード同様に自動リロード機能を持っていますが、加えてコードの変更前後でアプリケーションの状態を維持することができます

ブラウザプレビュー

スタイル、マークアップ、イベントハンドラ、エフェクトで状態維持がサポートされているようです。エラー位置を正確に出力してくれるなど利便性も上がっています。

環境変数

9.3以前の環境変数はnext.config.jsを用いてましたが、9.4からは以下も可能になりました。

  • NEXT_PUBLIC_で始まるインライン変数
  • .envファイルでカスタム環境変数を追加する

インライン変数

Next.jsはアプリケーション内でNEXT_PUBLIC_で始まる環境変数をインライン化(数値を値に置き換える)するようになりました。例えばページ内に以下が記述されているとします。

<p>hello, {process.env.NEXT_PUBLIC_NAME}</p>

NEXT_PUBLIC_NAME=mda yarn devと実行すると、<p>hello, mda</p>となります。

インライン変数はJavaScriptのバンドルに含まれるため、機密情報の埋め込みに適していません。

.envファイルによる環境変数

プロジェクトのルートに.envファイルを置くと、環境変数として公開することができます。ただし、環境変数はNode.js環境でのみ動作し、クライアント(ブラウザ)のJavaScriptバンドルには含まれません。変数を含めたい場合は、前述したようにインライン変数にする必要があります。

NEXT_PUBLIC_NAME='mda'
API_VALUE=10

上記の.envファイルの場合、クライアントコードではAPI_VALUEにアクセスできませんが、NEXT_PUBLIC_NAMEはクライアントのコードでアクセスできます。

// pages/index.js
function Home() {
  return (
    <>
      {/* ブラウザでアクセス可能 */}
      <p>{process.env.NEXT_PUBLIC_NAME}</p>
      {/* ブラウザでアクセス不可 */}
      <p>{process.env.API_VALUE}</p>
    </>
  )
}

export default Home

以下では、Node.js環境のためAPI_VALUE変数が動作します。

export default function Home({ post }) {
  return (
    <>
      <section id={post.id}>
        <h1>{post.title}</h1>
        <p>{post.body}</p>
      </section>
    </>
  )
}


export async function getServerSideProps(context) {
  const id = process.env.ID;
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  const post = await res.json();
  return { props: { post } }
}

.envファイルは実行時の環境に応じて、複数のファイルを用意できます。以下の[enviroment]には、develop, production, testが明記できます。実行時においてnext devdevelopmentnext buildnext startproductionと見なされます。

  • .env
  • .env.local
  • .env.[enviroment]
  • .env.[enviroment].local

localがつくものは変数の上書きに使います。localなし版はリポジトリの管理対象に入れ、local版は.gitignoreに記述するようです。このため、後者が機密情報を保管するのに適しています。また、適用される優先順位もあり、上記では下にいくほど優先順位が高くなります。

例えば先程のサンプルにおいて、以下の3つのファイルを用意したとします。

// 便宜上、3つのファイルを1箇所に記述しています

// .env
ID=1

// .env.development
ID=5

// .env.development.local
ID=10

これをnext devするとID=10が使用されます。next build後にnext startとするとproductionになりますが、production用の環境ファイルはないため、.envID=1が使用されます。

絶対インポート

jsconfig.jsonbaseUrlを設けると、絶対インポートが可能になりました。.はルートディレクトリを指しています。

// jsonconfig.json(TypeScriptの場合はtsconfig.json)
{
  "compilerOptions": {
    "baseUrl": "."
  }
}

例えば長々しい../../../components/buttonも以下で解決されます。

import Button from 'components/button';

エイリアス

baseUrlに加えてpathsオプションを使うと、エイリアスも設定できるようになります。

以下のようなディレクトリ構造を想定します。

(root)/
├── components/
│   └── nest/
│       ├── partsA.js
│       └── partsB.js
└── pages/
    └── index.js

通常、index.jsからpartsAとpartsBをインポートするには、以下のようになります。

import PartsA from '../components/nest/partsA';
import PartsB from '../components/nest/partsB';

jsconfig.jsonpathsを追加してみます。

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/parts/*": [
        "components/nest/*"
      ]
    }
  }
}

@/parts/*components/nest/*というパスをマップしたため、以下が可能になります。

import PartsA from '@/parts/partsA';
import PartsB from '@/parts/partsB';

VSCodeなどを使用していると、パス部分で補完が適用されるようにもなっています。

Web Vitals Reporting

Google Chromeが提供し出したWeb VitalsがNext.jsに組み込まれました。公式にあるようにpages/_app.jsreportWebVitalsというメソッドを配置し、メトリックを計測できます。

// pages/_app.js
export function reportWebVitals(metric) {
  console.log(metric);
}

function MyApp({ Component, pageProps }) {
  return <Comopnent {...pageProps} />
}

export default MyApp;

例えば、トップページにアクセスすると、以下が出力されました。

{
   "id":"1590175632294-1421296618188",
   "name":"Next.js-hydration",
   "startTime":537.2850000003382,
   "value":15.414999999848078,
   "label":"custom"
}
{
   "id":"1590175868092-9818419920942",
   "label":"web-vital",
   "name":"FCP",
   "startTime":452.3850000005041,
   "value":452.3850000005041
}
{
   "id":"1590175868092-9037373988752",
   "label":"web-vital",
   "name":"TTFB",
   "startTime":0,
   "value":19.775000000663567
}

nameに記載されているのがネットワークリソースの応答性の指標として使用される測定値名です。

FCPはFirst Contentful Paintの略で、ブラウザがDOMのコンテンツの最初のビット(テキストや画像など)がレンダリングされるポイントを示します。TTFBはTime To First Byteの略で、サーバへの接続が要求された後、最初のバイトが利用者のブラウザに到達するまでの時間を示します。Next.js-hydrationは、Next.jsが実際のドメインデータを埋め込んでいく段階のことだと思われます。そして、実際の参考値には、startTimevalueを利用します。

このようにNext.jsの固有値も含め、各種メトリックをキャプチャすることが容易になりました。

その他の変更点

  • Incremental Static Regeneration – 静的コンテンツを再レンダリングさせるメソッド。現在betaバージョンのため割合しますが、今後よく利用されそうな機能になると思われます
  • 組み込みfetchメソッドの改善 – ブラウザおよびNode.js環境で同じfetchメソッドが利用できるようになりました。node-fetchなどのモジュールを導入する必要がなくなります
  • Sassの設定オプション – next.config.jsでSassのオプション設定ができるようになりました
  • ログ出力 – ログの出力が再設計されました

Next.js 9.4は後方互換が保たれているため、特に問題なく移行できるはずです。