📘

Next.js + Storybook + TailwindCSSのテンプレートを作ってみた

2022/09/14に公開

最近Next.jsを使い始めたので、自分の知識をまとめるためにテンプレートリポジトリを作りました
StorybookやTailwindCSSといった最近人気のリポジトリを構成に含んでいます
特にStorybookの設定はよくつまづきやすいので、参考になれば幸いです

完成品はこちら
https://github.com/revoltage-inc/tmp-nextjs

Next.jsを採用した理由

以前はVueをメインに利用していましたが、下記の不満を抱えていました

  • 未だにVue3に非対応もしくはバグを抱えているライブラリが多い
  • TypeScriptで書きやすくはなったが、ドキュメントが混在して探しにくい
  • コンポーネント化で双方向バインドが逆に足枷になることが増えてきた
  • Composition APIで書き方が変わりすぎて、学習コストが高い
  • SSR対応したい

Vue3対応のNuxt.jsロードマップを見る限り、もうそろそろリリースされそうですが、
もうVueで苦労したくない現在はベータなので見送るとして、AstroSolidJSFreshはまだまだ成長途中といった感じなので、
豊富な機能とゼロコンフィグで管理しやすく、安定している業界リードのNext.jsを採用することにしました

他にも、TypeScriptやファイルシステムルーティングのデフォルトサポート、
imageコンポーネントを使っていれば、下記のように設定1つで簡単にWebpやAVIF形式などの最新の画像形式に対応させやすいなどの細かい理由もあります

next-env.d.js
/** @type {import('next').NextConfig} */
module.exports = {
  swcMinify: true,
  reactStrictMode: true,
  images: {
    formats: ['image/avif', 'image/webp'],
  },
}

個人的に、最近リリースされたNext.js 12.3.0からStableになったnext/future/imageコンポーネントが、変にspanタグとかを挟まずにimgタグだけ出力してスタイリングしやすくなったのが、地味に嬉しいです
このテンプレートはNext.js 12.3.0に対応させています

Storybookを採用した理由

Web制作だと、結合テストのみを行うことが常態化しがちですが、
ある程度のWeb開発になると、チーム開発での作業の分業のしやすさや、コンポーネントの再利用性を求められるようになり、コンポーネント駆動開発(CDD)に行き着くようになりました

そこでプロダクトの品質も担保するために、コンポーネントレベルの単体のリグレッションテストや、ドキュメントの必要性に駆られて、Storybookを採用することにしました

ただし、Storybookのビルドでは少しアンチパターンな実装をしています
Next.jsとの実装差異をできるだけ少なくするために、Storybookのビルドツールは本来Webpackで揃えるべきなのですが、Webpackがあまりに遅すぎるので、Viteで設定の互換性を持たせて無理やり動かしています

しかし、Storybookのバージョンを7.0.0-alpha.29 → 7.0.0-alpha.33にしてからは
Storybookの起動がWebpackで20秒→12秒に改善されていたので、7.0が正式リリースされ次第、Webpackに戻すことを検討しています

Storybookのalpha版を使っているのは、過去にStorybookでインラインSVGを扱う際にbabel-plugin-inline-react-svgを上手く動作させることができなかったため、バージョンアップした名残です
インラインSVGの扱いは、WebpackとViteで同様に扱えるCSSO系のプラグインに移行することで動作させることができました

一般的にalpha版は本番利用するべきではないですが、Storybook自体は本番環境に直接影響せず、Storybookがalpha版の方がまだ動作が安定しているのでそのまま利用しています

TailwindCSS(+ CSS Modules)を採用した理由

単一のCSSフレームワークのみで完結したいのであれば、CSS in JSのEmotionが良いと考えていますが、
昔からBootstrapなどのUtility FirstなCSSフレームワークに慣れており、CSS名が長くなってもそこまで嫌悪感がなかったので、自分はTailwindCSSを採用しました

TailwindCSSだけで無理やり完結しようとして、採用を見送ったケースをよく見かけるのですが、
個人的にTailwindCSSだけで無理に完結させるものではないと思っているため、下記のケースなどの場合はCSS Modulesも併せて使用することにしています

  • 疑似要素に付けるPropertyが多い
  • アニメーションを付ける
  • liタグなど繰り返し要素のCSSを共通化したい

CSS Modulesは、過去にcss-loaderのメンテナーが「将来的にdeprecatedにしたい」という発言があったため、不安があったのですが下記の理由で採用しました

  • Next.jsが敢えてサポートしたこと
  • 2年以上未だにdeprecatedにならず、メンテナンスモードでサポートされていること
  • css-loaderのメンテナーがもしメンテナンス対象から外れる場合は別プラグインとして切り出すと発言していることこと
  • CSS in JSと違い、JSを挟まなくていい分パフォーマンスが良いため、見直されている風潮がある

http://web.archive.org/web/20201130060942/https://github.com/vercel/next.js/issues/15542
https://nextjs.org/docs/basic-features/built-in-css-support
https://github.com/webpack-contrib/css-loader/issues/1050#issuecomment-729606066

少し昔だと、CSS in JSやTailwindCSSで、ページファイルにCSSを書くという発想は、
インラインスタイルで書いてるようで、関心の分離的に少し抵抗があったのですが、
それに対する解答は、Vueの公式ドキュメントのSingle File Component(SFC)の項目で上手く言語化されていました

関心の分離はファイルタイプの分離と等しくない ということに同意することが重要です。エンジニアリング原則の究極の目標は、コードベースの保守性を向上させることです。関心の分離は、ファイルタイプの分離のように独断的に適用された場合、ますます複雑化するフロントエンドアプリケーションという文脈で、その目標を達成する助けにはなりません。

今はコンポーネントの概念がある以上、ページファイルやCSSファイルと分けるより、ある程度まとまっていた方が、管理が楽でファイルを行き来しなくて済むので良いと考えています

所感

最近、T3 StackというNext.jsのテンプレートがあることを知りました
https://github.com/t3-oss/create-t3-app

tRPCやNextAuth.jsなどAPI周りや認証周りの便利ライブラリがパッケージングされていてとても良い感じです
ここら辺の技術スタックが溜まり次第、自分のテンプレートリポジトリに反映させたいなと思います

Discussion

ログインするとコメントできます