Closed7

【key-front】Next.js App Routerの素振り(環境構築・デプロイ・テスト・カタログ)

1zushun1zushun

モチベーション

  • 毎週木曜日Slackのkey_frontチャンネルでハドル機能を使いお題に対してメンバー同士ディスカッションをする時間を15〜30分程度設けている
  • 今回はNext.js App Routerについて取り上げる
  • ファシリテーターは筆者なので、事前に読み込んで気になった点などをスクラップに投げていく
  • 開催日は○○/○○(木)で最終的に議事録として結論をまとめる

過去に開催した関連してそうな内容

https://zenn.dev/shuuuuuun/scraps/7b2aaf746aec91

https://zenn.dev/shuuuuuun/scraps/9cd8d4c0a7be87

1zushun1zushun

環境構築

Next.jsのセットアップからVSCodeを開くまでを実施
$ npx create-next-app@latest
# 画像添付の操作
$ cd app-name
$ code .

https://nextjs.org/

ローカル環境の立ち上げ
$ npm run dev

1zushun1zushun

sampleリポジトリを作る程度なら以下はスキップする。
もしclientリポジトリを作る場合は本スクラップに記述している内容を消化すること。

Voltaでバージョンのピン留めをする

ターミナル
$ volta pin node@20.15.0
$ volta pin npm@10.7.0

https://zenn.dev/shuuuuuun/scraps/cc98baf4787ef2

ディレクトリ構成を整える

チームで検討する。
必要なければ個人の好みで整える。

https://zenn.dev/link/comments/d5f91937c516d5

.vscode/settings.jsonの設定を追加をする

以下はextenstions.jsonの記事になるがsettings.jsonも設定する。

https://zenn.dev/shuuuuuun/scraps/bcc59eb2f7d640

tsconfig.jsonの設定を追加する

tsconfig.jsonはstrictestを導入して硬めに行く。
ついでにエイリアスも設定しておく。

ターミナル
$ npm install -D @tsconfig/next
$ npm install -D @tsconfig/strictest

https://zenn.dev/shuuuuuun/scraps/48ac73aeb3076c

静的解析の設定を追加する

ESLint、Prettier、Stylelint、コミット品質担保(husky + lint-staged)の設定をする。
ESLint周りは以下の記事にまとめている。

https://zenn.dev/shuuuuuun/articles/127728961f89a0

CSS周りを整える

基本はRadix UI(primitives) + CSS Modulesで進める。UIコンポーネントではなくHeadless UIコンポーネントを使用する理由は以下の記事で触れている。Headless UIコンポーネントはArk UIやReact Ariaなどいくつか素振りをしてみたが感触が良かったのがRadix UIだったというくらい温度感なので今後別のHeadless UIコンポーネントに変わる可能性はあり。

https://zenn.dev/shuuuuuun/scraps/744aa994686183

PR TIMES社とmicroCMS社がテックブログでRadix UI(primitives)について触れているので添付する

https://developers.prtimes.jp/2024/05/27/radix-ui-editor-component-tips/

https://blog.microcms.io/radix-ui-headless-ui/

リセットCSSは以前、制作チームからおすすめしてもらったものを使用する

https://github.com/elad2412/the-new-css-reset/blob/main/css/reset.css

bundle-analyzerを導入する

後々めんどくさくなって後回しになるので早めに導入する。
Next.jsの公式ドキュメントに案内があるので、こちらの案内に従う。
https://nextjs.org/docs/app/building-your-application/optimizing/bundle-analyzer

テストを導入する

react-testing-libraryを導入する。
詳細は後続のスクラップで触れている。
https://zenn.dev/link/comments/691a15acca9e89

カタログを導入する

Storybookを導入する。
詳細は後続のスクラップで触れている。
https://zenn.dev/link/comments/56b35245011b98

1zushun1zushun

Vercel

ホスティングはVercelを選択した。

本番環境が遅い

  • 開発環境ではprefetchがなし(以下参照・実際に確認済み)である程度早く処理されていたのに逆にprefetchされる本番環境では異様に遅い

Prefetching happens when a <Link /> component enters the user's viewport (initially or through scroll). Next.js prefetches and loads the linked route (denoted by the href) and its data in the background to improve the performance of client-side navigations. Prefetching is only enabled in production.

https://nextjs.org/docs/app/api-reference/components/link#prefetch

  • ネットワークタブを見るとcontent downloadにかなり持って行かれている
  • bundle-analyzerで確認してみたがバンドルサイズに問題はなさそう
  • 開発環境でnpm run build && npm run startを実行しprefetchできる環境で試してみた。これは期待値の速さになっていた

→ 恐らくVercel周りの設定で何かやらかしているはず

  • 上記の理由からVercel周りで調査を進めて、以下の記事を見つけた。本番環境が異様に遅い原因はVercelのリージョンがワシントンDCになっていたからだった。東京リージョンに修正して完了。
  • リージョンが違うだけでここまでパフォーマンスに影響が出るのかと知った

https://zenn.dev/sh1n4ps/articles/34df41ddc9957e

https://moldspoon.jp/blog/posts/vercel-changed-region-to-tokyo

https://stackoverflow.com/questions/66514628/why-does-prefetching-not-work-for-link-component-in-next-js

ドキュメントを見たらServerless FunctionはデフォルトでワシントンDCとして設定されるとのこと

By default, Serverless Functions execute in Washington, D.C., USA (iad1) for all new projects to ensure they are located close to most external data sources

https://vercel.com/docs/functions/configuring-functions/region

Vercel Functionsの詳細

  • 何も設定していないとVercel Functions・API Routes・Server Rendering・ISRの向きがワシントンDCになるのか

https://vercel.com/docs/functions

Speed Insights・Web Analyticsの導入

  • Vercelをいじっていく中でVercel謹製のSpeed InsightsとWeb Analyticsがあることを知った
  • どのプランでも使うことができる、詳細は下記記事から確認する
  • 極端な話、VercelのダッシュボードからWeb Vitalsの確認もウォッチできるからlighthouse使う必要がなくなるのかな。一旦運用してみてる。

https://vercel.com/docs/speed-insights

https://vercel.com/docs/analytics

1zushun1zushun

react-testing-libraryを導入する

以下はReact + Viteの時のセットアップ等だったのでNext.jsで組み込む時に変更があればメモしていく

https://zenn.dev/shuuuuuun/scraps/11262e3391599a

https://zenn.dev/shuuuuuun/scraps/69ac109126b60e

Next.jsのtesting-libraryのドキュメント

導入は以下に沿って進める

https://nextjs.org/docs/app/building-your-application/testing/jest

ドキュメントにインストールするパッケージの案内があるのでそちらに従う。npm init jest@latestでjestのセットアップが可能だが手直しが発生するのでマニュアルセットアップで対応する

ドキュメントで紹介されているパッケージ群

とりあえずドキュメントで紹介されているパッケージのインストールをする

ターミナル
$ npm install -D \
  jest \
  jest-environment-jsdom \
  @testing-library/react \
  @testing-library/jest-dom

追加で必要なパッケージパッケージ群

足りないパッケージを追加していく

ターミナル
$ npm install -D \
ts-jest \
@types/jest \
ts-node \
@testing-library/user-event \
next-router-mock

next-router-mock

next/linkのモックを作るために使用

https://www.npmjs.com/package/next-router-mock

この時にtsファイルにjestを書くと名前空間でエラーは発生するので次のts-jestと@types/jestを導入した

ts-jest & @types/jest

READMEに沿ってts-jestと@types/jestを導入した

https://github.com/kulshekhar/ts-jest

ts-node

jest.config.jsではなくjest.config.tsで動かすためにはts-nodeが必要になるため導入した(後でPrismaも入れる想定だったのでどちらにせよ必要になるので)

To read TypeScript configuration files Jest requires ts-node. Make sure it is installed in your project.

https://jestjs.io/docs/configuration

@testing-library/user-event

fireEventではなくuserEventを使いたいため

マニュアルセットアップ

マニュアルセットアップはこちらを参照する

preset: ts-jestとは?
https://blog.ojisan.io/ts-jest/

testEnvironmentとは?

https://testing-library.com/docs/react-testing-library/setup#jest-28

jest.config.ts
import type { Config } from 'jest'

// eslint-disable-next-line import/extensions
import nextJest from 'next/jest.js'

const createJestConfig = nextJest({
  // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
  dir: './',
})

// Add any custom config to be passed to Jest
const config: Config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  preset: 'ts-jest',
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/app/$1',
  },
  // Add more setup options before each test is run
  setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
}

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
export default createJestConfig(config)

jest.setup.ts
// Optional: configure or set up a testing framework before each test.
// If you delete this file, remove `setupFilesAfterEnv` from `jest.config.js`

// Used for __tests__/testing-library.js
// Learn more: https://github.com/testing-library/jest-dom

import '@testing-library/jest-dom'

react-testing-libraryのルールセットを導入する

ルールが効いているかの検証としてtesting-library/prefer-user-eventを有効にしてfireEventを使用した際に警告が出るか確認する

ターミナル
$ npm install -D eslint-plugin-testing-library

ESLintをオーバーライドさせてテストファイルに対してのみeslint-plugin-testing-libraryを実行する

.eslintrc.json
"overrides": [
    {
      "files": ["**/?(*.)+(spec|test).[jt]s?(x)"],
      "extends": ["plugin:testing-library/react"],
      "rules": {
        "testing-library/prefer-user-event": "error"
      }
    }
  ]

実際にtesting-library/prefer-user-eventで警告が表示されればok

https://github.com/testing-library/eslint-plugin-testing-library?tab=readme-ov-file#eslint-overrides

1zushun1zushun

Storybookを導入する

ターミナル
$ npx storybook@latest init

https://storybook.js.org/docs/get-started/frameworks/nextjs

アドオンの追加

ユーザー操作擬似クラスのアドオンを追加する。
全体に反映すると後々楽なのでpreviewのparameterに追加すると良いかも。
エイリアスの設定もやっておく。

https://zenn.dev/shuuuuuun/articles/55afbfef49360c

Storybookのルールセットを導入する

ESLintをオーバーライドさせてカタログファイルに対してのみeslint-plugin-storybookを実行する

.eslintrc.json
"overrides": [
    {
      "files": ["*.stories.@(ts|tsx)"],
      "extends": ["plugin:storybook/recommended"],
      "rules": {
        "storybook/hierarchy-separator": "error",
        "storybook/default-exports": "off"
      }
    }
  ]

実際にstorybook/hierarchy-separatorで警告が表示されればok

https://github.com/storybookjs/eslint-plugin-storybook?tab=readme-ov-file#overridingdisabling-rules

このスクラップは2024/03/19にクローズされました