# Next.jsについて掘り下げる ## 概要 Next.jsを用いて開発するに辺り、必要な知識を掘り下げていきたい。 ## 掘り下げたいと思う項目 * Next.js * レンダリングの種類や、良しなにやってるところを理解したい * 直近のアップデートや、今後のアップデートを踏まえて、今後どうなっていくのかを把握したい * React.js * CSS周り、ディレクトリ構成、hooksの使い方 * 直近のアップデートや、今後のアップデートを踏まえて、今後どうなっていくのかを把握したい # Next.js Next.jsとはReactをベースに開発されたJavaScriptフレームワーク ## Next.jsの特徴 主に5つ 1. SSR/SSG 2. ファイルベースルーティング 3. 開発サーバの部分的な高速リロード(Fast Refresh) 4. 画像最適化 5. ゼロコンフィグ 詳細はこちら https://qiita.com/Yuki_Oshima/items/5c0dfd8f7af8fb76af8f ## Next.jsのSSRが画面反映されるまでの具体的な流れ ![](https://i.imgur.com/b07ZPYG.png) https://nishinatoshiharu.com/next-server-render-flow/ ## _app, _documentの違い * _app * Next.jsではAppコンポーネントを使用して全てのページを初期化するようになっています。 * そのため、このコンポーネントを継承したクラスがあるファイル、_app.js(tsx) を作成することでデフォルトのAppコンポーネントを上書きできます。 * _document * _document.js(tsx)では、`<Html>`, `<Head />`, `<Main />`, <NextScript /> がページが適切にレンダリングするために必要となります。 * このHeadタグの中に`<title>` など、全ページ共通の設定を行います。 https://tyotto-good.com/blog/next-document-app ## _app, _documentのページ実行順番 ### getServerSidePropsとgetInitialPropsについて Next.jsではSSR用にgetServerSidePropsとgetInitialPropsの2つのメソッドが提供されています。 これらのメソッドをページコンポーネントに実装することで、サーバサイドで実行される処理を作ることができます。 * getServerSideProps * 必ずサーバサイドで実行される * getServerSidePropsが実装されたページにアクセスするときは、サーバへ問い合わせが走る * v9.3以降で使える * getInitialProps * ブラウザ側でも実行される * URLから直リンクでアクセスした場合などサーバへ問い合わせがあるときはサーバサイドで実行される AppコンポーネントやDocumentコンポーネントではgetInitialPropsを使うことはできますが、getServerSidePropsは使うことができません。 最新のNext.jsではgetInitialPropsよりもgetServerSidePropsを使うことが推奨されています。 ### _documentをカスタマイズする https://nextjs.org/docs/advanced-features/custom-document#customizing-renderpage Documentをextendsしてるが、Document自体の中身はあんまりない https://github.com/vercel/next.js/blob/canary/packages/next/pages/_document.tsx#L1099-L1123 ### 実行順番 getInitialPropsページ 1. _appの getInitialProps 2. pageの getInitialProps 3. _appの component 4. pageの component 5. _documentの getInitialProps getServerSidePropsページ 1. _appの getInitialProps 2. pageの getServerSideProps 3. _appの component 4. pageの component 5. _documentの getInitialProps ↓前提とか詳細はコッチ(ページ遷移とかの挙動も変わる模様) https://tech.commmune.jp/entry/2021/02/22/125610 ## getStaticProps と getStaticPaths の概要解説 Next.jsにvesrion 9.3から導入された以下の3つのAPIについて解説 * getStaticProps * ビルド時にデータを取得し静的なファイルを事前に生成するためのAPI * getStaticPaths * Dynamic Routes利用時に使える、静的なファイルを生成するためのAPI * getServerSideProps * getServerSidePropsは↑に書いてるので割愛 https://qiita.com/matamatanot/items/1735984f40540b8bdf91 ## Next.jsのgetServerSidePropsの登場が何を意味するか * getInitialProps * Next.js 9.3以降は非推奨 * サーバーサイドでもフロントエンドでもコールので便利だったが、責任範囲が分かりづらくなる * getServerSideProps * Next.js 9.3から登場 * getInitialPropsをサーバサイドだけで実行するようにしたもの * getInitialPropsと比べると、機能制限がある * SSRしたいときだけ使う * SWR * CSRでデータ取得したい時だけ使うやつ https://qiita.com/ryokkkke/items/1bd858a5d6f261a9342a ## Next.jsの独自コンポーネント * next/link * Next.jsでのサイト内ページ遷移方法 * https://qiita.com/IYA_UFO/items/f13577bad7dd9ef1ae89 * next/image * 使い方と注意点 * https://zenn.dev/catnose99/articles/883f7dbbe21632a5254e * next/script * next/script には JavaScript の基本がつまっていた * https://zenn.dev/aiji42/articles/9a6ab12ab5f6e6 * next/head * next/headの気を付けたい仕様 * https://zenn.dev/yukishinonome/articles/c9c8813f89eb80 https://nextjs.org/docs/api-reference/next/router ## 環境変数 * yarn dev * NODE_ENV=development * yarn build * NODE_ENV=production 3つのタイミングに合わせてしか環境を切り替えることができないので、 dev-1, dev-2, staging など複数の環境を切り替えたい場合は独自に実装する必要がある https://zenn.dev/aktriver/articles/2022-04-nextjs-env ## Next.jsでBuild時の環境変数 利用フェーズによって分岐を書くことができる * devで起動された時 * buildで起動された時 * startで起動された時 * exportで起動された時 https://lightgauge.net/language/javascript/next-config-js-use-evn 利用できるPHASEの種類 https://github.com/vercel/next.js/blob/canary/packages/next/shared/lib/constants.ts#L1-L5 → 手元で試した感じ、build時以外は `process.env.NEXT_PHASE` で値は取れない ## buildとexportの違い next exportは、サーバーサイドやインクリメンタルなデータを必要とするページがない場合を想定しています (ただし、静的レンダリングされたページは、クライアントサイドでデータを取得することができます)。 https://zenn.dev/unreact/articles/nextjs-advanced-features-static-html-export-jp ## Next.js のサーバが起動するまでを追う v11.1.2 の参考 https://zenn.dev/izumin/scraps/15c9ad1248154f → 時間がある時に掘り下げていきたい ★ ## build時の処理フロー https://github.com/vercel/next.js/blob/canary/packages/next/cli/next-build.ts https://github.com/vercel/next.js/blob/canary/packages/next/build/index.ts#L154-L2361 ↑2000行超え。長すぎるので、諦めた。 → 時間がある時に掘り下げていきたい ★ ## buildの成果物を掘り下げる % 前提 ```zsh % yarn create next-app % cd next-app % yarn build ``` して出来たデフォルト状態の成果物 ↓↓↓ ### .nextのディレクトリ構成 ``` % tree .next .next ├── BUILD_ID ← buildする度に変わる。内容がstaticディレクトリ以下のディレクトリ名と紐づいている。 ├── build-manifest.json ← buildの成果物のマップが入っている。取りまとめている役割に見える。 ├── cache │   ├── next-server.js.nft.json ← cacheキーと、node_modules/next以下のファイルのリストが入っている。特定ファイルだけキャッシュさせてる感じ? │   ├── swc │   │   └── plugins │   │   └── v2 ← 空。使ったら増えていくのかな? │   └── webpack │   ├── client-production │   │   ├── 0.pack ← 2回目のbuildで1.pack, 2.packってのが増える。それ以降のbuildでもドンドン増える │   │   └── index.pack ← 2回目のbuildでindex.pack.oldってのが増える │   └── server-production │   ├── 0.pack ← client-productionと同様で、どんどん増えてくけど、増えないこともあるのでトリガーが何か分からん │   └── index.pack ├── export-marker.json ← 良くわからん:中身 `{"version":1,"hasExportPathMap":false,"exportTrailingSlash":false,"isNextImageImported":true}` ├── images-manifest.json ← 画像まわりのconfigだけど、中身の意味はわからん ├── next-server.js.nft.json ← cacheの中のファイルと全く一緒 ├── package.json ← 中身 `{"type": "commonjs"}` ├── prerender-manifest.json ← prerenderまわりのconfigだけど、中身の意味はわからん ├── react-loadable-manifest.json ← 空だが、何をすると増えるんだろう? `{}` ├── required-server-files.json ← サーバーとして起動するときのconfig? ├── routes-manifest.json ← router。エンドポイントを増やして状態を見てみたい ├── server │   ├── chunks ← ファイルの数字とか、どういうルールでファイルが分割されてるか、今の所わからず。 │   │   ├── 105.js │   │   ├── 311.js │   │   ├── 675.js │   │   └── font-manifest.json │   ├── font-manifest.json │   ├── middleware-build-manifest.js │   ├── middleware-manifest.json │   ├── middleware-react-loadable-manifest.js │   ├── pages ← pagesディレクトリ以下のものがminifyされ出力されている │   │   ├── 404.html │   │   ├── 500.html │   │   ├── _app.js │   │   ├── _app.js.nft.json │   │   ├── _document.js │   │   ├── _document.js.nft.json │   │   ├── _error.js │   │   ├── _error.js.nft.json │   │   ├── api │   │   │   ├── hello.js │   │   │   └── hello.js.nft.json │   │   ├── index.html │   │   └── index.js.nft.json │   ├── pages-manifest.json ← pathとpagesのファイルを紐付けている │   ├── webpack-api-runtime.js ← 分からない、、 │   └── webpack-runtime.js ← 分からない、、 ├── static ← このディレクトリは、publicに公開される │   ├── RQ4-nE_iED4wiN48qnL4S ← buildする度に変わる │   │   ├── _buildManifest.js │   │   └── _ssgManifest.js │   ├── chunks │   │   ├── framework-e2b5cf9ca2d2a331.js ← 初期表示に必要なモノ。react-domが入ってた │   │   ├── main-3cf1b4d0a841b0b4.js ← 初期表示に必要なモノ │   │   ├── pages │   │   │   ├── _app-6e0f6f809c4ba91c.js │   │   │   ├── _error-7397496ca01950b1.js │   │   │   └── index-3ea9a7913c023add.js │   │   ├── polyfills-0d1b80a048d4787e.js ← polyfill │   │   └── webpack-34c76af51fb9f015.js ← 初期表示に必要なモノ │   └── css │   ├── 149b18973e5508c7.css ← ページごとのCSS │   └── 27d177a30947857b.css ← globalなcss。たぶん_app.tsxに読み込むように書いたからか最初に読み込まれる対象に。 └── trace 16 directories, 50 files ``` → 分からないモノが多いので更新していく★ ### SSR, SSGを試す ↓ `pages/index.js`は initial propsを設定していないので `automatically rendered as static HTML (uses no initial props)` って結果に。 ```zsh % yarn build ... Page Size First Load JS ┌ ○ / 5.84 kB 84 kB ├ └ css/f23c92def02214b6.css 681 B ├ /_app 0 B 78.1 kB ├ ○ /404 186 B 78.3 kB └ λ /api/hello 0 B 78.1 kB + First Load JS shared by all 78.1 kB ├ chunks/framework-e2b5cf9ca2d2a331.js 45.7 kB ├ chunks/main-3cf1b4d0a841b0b4.js 31.1 kB ├ chunks/pages/_app-6e0f6f809c4ba91c.js 509 B ├ chunks/webpack-34c76af51fb9f015.js 760 B └ css/27d177a30947857b.css 194 B λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps) ○ (Static) automatically rendered as static HTML (uses no initial props) ``` ↓`pages/getStaticProps.js`, `pages/getStaticProps.js` ってのを追加した場合(それぞれ相応の処理を入れる) ``` Page Size First Load JS ┌ ○ / 1.11 kB 84.1 kB ├ /_app 0 B 78.1 kB ├ ○ /404 186 B 78.3 kB ├ λ /api/hello 0 B 78.1 kB ├ λ /getServerSideProps 1.15 kB 84.2 kB └ ● /getStaticProps (605 ms) 1.15 kB 84.2 kB + First Load JS shared by all 78.1 kB ├ chunks/framework-e2b5cf9ca2d2a331.js 45.7 kB ├ chunks/main-3cf1b4d0a841b0b4.js 31.1 kB ├ chunks/pages/_app-6e0f6f809c4ba91c.js 509 B ├ chunks/webpack-34c76af51fb9f015.js 760 B └ css/27d177a30947857b.css 194 B λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps) ○ (Static) automatically rendered as static HTML (uses no initial props) ● (SSG) automatically generated as static HTML + JSON (uses getStaticProps) ``` * getServerSideProps * `λ (Server)` ってのになった * getStaticProps * `● (SSG) ` ってのになった 分かりやすい。 #### SSGのファイルたち ``` % tree .next ... │   ├── pages ... │   │   ├── getServerSideProps.js ← SSG、Static以外のものはjsファイルになってるのが分かる │   │   ├── getServerSideProps.js.nft.json │   │   ├── getStaticProps.html │   │   ├── getStaticProps.js │   │   ├── getStaticProps.js.nft.json │   │   ├── getStaticProps.json │   │   ├── index.html │   │   └── index.js.nft.json ... % more .next/server/pages/getStaticProps.json {"pageProps":{"stars":89915},"__N_SSG":true} ← 描画に最低限必要なものだけ取れてる % more .next/server/pages/getStaticProps.html ← 中を見ると、取得した内容が既に埋まってる ``` ## ファイルサイズを減らす ### ファイルサイズ build時に表示される "First Load JS shared by all" 以下は、すべてのページで最初に読み込まれるモノ ```zsh % yarn build ... Page Size First Load JS ┌ ○ / 1.08 kB 84.1 kB ├ /_app 0 B 78.1 kB ├ ○ /404 186 B 78.3 kB ├ λ /api/hello 0 B 78.1 kB ├ λ /getServerSideProps 1.12 kB 84.1 kB └ ● /getStaticProps (609 ms) 1.12 kB 84.1 kB === ★ここ★ + First Load JS shared by all 78.1 kB ├ chunks/framework-e2b5cf9ca2d2a331.js 45.7 kB ├ chunks/main-3cf1b4d0a841b0b4.js 31.1 kB ├ chunks/pages/_app-6e0f6f809c4ba91c.js 509 B ├ chunks/webpack-34c76af51fb9f015.js 760 B └ css/27d177a30947857b.css 194 B === λ (Server) server-side renders at runtime (uses getInitialProps or getServerSideProps) ○ (Static) automatically rendered as static HTML (uses no initial props) ● (SSG) automatically generated as static HTML + JSON (uses getStaticProps) ✨ Done in 5.11s. ``` ![](https://i.imgur.com/rI8K50k.png) * ファイルサイズがちょっと違うのは何で? * 緑のファイルも共通で読まれていたが表示されていない(中はchunkとかnext.js系の内容だったのでフレームワークの何か) 実際のファイルサイズ ``` % du -hs .next/static/chunks/* 12K .next/static/chunks/959-3984dfc5d513762c.js 140K .next/static/chunks/framework-e2b5cf9ca2d2a331.js 108K .next/static/chunks/main-3cf1b4d0a841b0b4.js 20K .next/static/chunks/pages 92K .next/static/chunks/polyfills-0d1b80a048d4787e.js 4.0K .next/static/chunks/webpack-34c76af51fb9f015.js ``` ブラウザで見る時は `Content-Encoding: gzip` なってるので 小さくなるのは分かるが、build時とブラウザの読み込みサイズが微妙にサイズ違うのは謎。 ### Bundleを分析する webpack-bundle-analyzerを使うとサイズがわかりやすく可視化できる ![](https://i.imgur.com/rZ4mK3N.gif) https://github.com/webpack-contrib/webpack-bundle-analyzer (ただし、build部分には注意が必要) https://zenn.dev/catnose99/scraps/661d77118aa2af ### Bundleサイズを測れる仕組みをCIに入れる Github ActionsでPRにコメントする仕組み ![](https://i.imgur.com/g1895v2.png) → GlobalのCSSに色々追加して、indexでjQuery読むようにしたらこうなった (ブランチの更新のたびに走るが、該当コメントがアップデートされる仕組みなので邪魔にならない。。) https://github.com/hashicorp/nextjs-bundle-analysis ### パフォーマンスバジェットをビルドプロセスに組み込む ビルドプロセスで警告を出したり、気付ける仕組みは作りたい。 → サイズによってCIを落とすようにしたい。 https://web.dev/incorporate-performance-budgets-into-your-build-tools/ ### splitChunks Next.jsのデフォルトの設定はコレ↓ https://github.com/vercel/next.js/blob/canary/packages/next/build/webpack-config.ts#L1063-L1166 ## パフォーマンス観点でみる Next.js の getLayout `_app.tsx`でアレコレ読み込んでると`chunks/pages/_app-xxxx` ファイルが膨らんでしまう。 そのファイルは全ページ共通のファイルで、ファイルロードの時間は、ユーザーが操作開始できるまでの時間(TTI)に繋がるためパフォーマンスが悪くなってしまう。 getLayoutを使うことでパフォーマンスチューニングができるってお話↓ https://zenn.dev/takepepe/articles/nextjs-getlayout-chunk-relation https://nextjs.org/docs/basic-features/layouts#with-typescript ## 開発環境ではコンポーネントが2度描画される StrictModeによる効果 → 意図しない副作用の検出のために、Appコンポーネントを2回呼び出している "これは将来導入されるOffscreenAPIが入ると、コンポーネントが生成されているが表示されていない状態が追加されることへの準備" https://www.ey-office.com/blog_archive/2021/06/30/i-found-out-why-the-component-is-drawn-twice-in-the-react/ ## next.jsでのファイルチャンク最適化の一例(GraphQLまわり) graphql-codegenはデフォルトでは1ファイルにすべて出力されますが、 それに対しnext.jsは各ページをchunksとして吐くため何も考えずに実装すると、 バンドルされるファイル量が膨大になる可能性がある その対策↓ https://blog.hiroppy.me/entry/2021/08/12/092839 ## 直近のバージョンアップ ### Next.js 10の変更点 * ビルトインの画像コンポーネントと画像の自動最適化: 新しい next/image コンポーネントを使用することで、自動的に画像を最適化します * 国際化に対応したルーティング: ビルトインの構成要素を使って Next.js アプリを国際化対応させましょう * Next.js アナリティクス: 実際のユーザーパフォーマンスを計測し、それに基づいて次のアクションを決めましょう * Next.js コマース: 高パフォーマンスな E コマースサイトを作るためのオールインワンのスターターキット * React 17 サポート: 最新の React のリリースは Next.js と完全に互換性があります * getStaticProps / getServerSideProps の Fast Refresh: データ取得のメソッドを編集したときにプロパティを自動的にリロード * MDX のための Fast Refresh: @next/mdx を使用したとき、ページ全体をリロードすることなく、Fast Refresh を利用して高速に変更を適用します * サードパーティの React コンポーネントからの CSS インポート: コンポーネントに必要な CSS を npm からインポートできるようになりました * href の自動解決: next/link において as 属性はもはや不要です * @next/codemod CLI: Next.js のあらゆる codemod に簡単にアクセスすることができます * getStaticPaths におけるフォールバックのブロック: 新しく静的なページを生成する際に、静的なフォールバックページを提供するのではなく、プリレンダリングが行われるまで待つようにできます https://qiita.com/thesugar/items/7e27a0f459d5981ed16e ### Next.js 11の変更点 * コンフォーマンス(Conformance、適合性) * パフォーマンスの向上 * next/scriptの最適化 * next/imageの改善 * Webpack 5 のサポート * Create React App からの移行 (実験的機能) * Next.js Live (プレビューリリース) https://nextjs.org/blog/next-11 ### Next.js 12の変更点 * Rustコンパイラー: Fast Refreshが3倍、そしてビルドが5倍速くなりました。 * ミドルウェア(beta): Next.jsの柔軟性を高めるために、設定よりもコードを優先します。 * React 18のサポート: ネイティブのNext.jsのAPIがサポートされ、サスペンスもサポートされています。 * <Image /> AVIFのサポート: 20%小さい画像のオプトイン * ボット対応ISRフォールバック: ウェブクローラー向けたSEOを最適化 * Native ES Modulesのサポート: 標準化されたモジュールシステムとの整合性 * URLインポート(alpha): インストールは不要で任意のURLからパッケージをインポート * React Serverコンポーネント(alpha): SSRストリーミングを含む、今すぐお試しください https://zenn.dev/web_tips/articles/81a6db12f7cb2f --- # React.js Reactは、Metaとコミュニティによって開発されているユーザインタフェース構築のためのJavaScriptライブラリ ### シェア シェア1位 Vue.jsと差が開いてきた https://trends.google.co.jp/trends/explore?q=%2Fm%2F012l1vxv,%2Fm%2F0j45p7w,%2Fg%2F11c0vmgx5d&geo=,,&date=today%205-y,today%205-y,today%205-y&cat=13#TIMESERIES ## クラスコンポーネントより関数コンポーネントを使うべき理由5選 Reactのバージョンアップで関数コンポーネントに Hooks という便利機能が追加されたことでクラスコンポーネントの出る幕が無くなった。 コンポーネントが複雑になるので、状態を持たないようにするって話。 https://tyotto-good.com/blog/reaseons-to-use-function-component ## Hooks React Hooks は React 16.8(2019 年 2 月リリース)で追加された機能 * useState * 関数型コンポーネントで状態(state)を扱うためのフック * 必要となるのは、利用者とインタラクティブにやり取りをする値を保持する必要がある場合に使う * useEffect * 関数型コンポーネントで副作用を実行するためのフック * コンポーネント内での「外部データの取得」「DOM の手動での更新」などの処理を、React では副作用と呼ぶ * 代表的なユースケースとしてはコンポーネントを呼び出したタイミングで外部 API からリソースを取得したい場合に使う * React v18 よりReact.Suspenseを使った非同期のデータ取得がサポートされる * アップデート後はこちらがベストプラクティスになっていく可能性も高い * useContext * コンポーネント間で横断的に利用したい状態を管理するためのフック * コンポーネント間で横断的に利用したい状態がある場合に使う * 代表的な場面として認証情報の管理 * ![](https://i.imgur.com/204C7e5.png) * useReducer * useStateよりも複雑な状態を管理するためのフック * useReducerを理解するためには 4 つの要素を理解する必要がある * State … 状態 * Reducer … State を更新するための関数 * Action … State を更新するのに必要なデータ * Dispatch … Action を Reducer に届ける関数 * ![](https://i.imgur.com/WEBR9rZ.png) * useMemo * 関数の返り値をメモ化するフック * メモ化はプログラムの最適化技法の 1 つで、計算結果を再利用するために保持して、再計算を防ぐもの * 基本的には最適化のためのフックですが、例えば配列を保持するstateで配列を走査する処理が頻繁に必要な場合などに使う * useCallback * 関数をメモ化するフック * 基本的にReact.memoと併用する必要がある * ![](https://i.imgur.com/ctj0BR5.png) * 通常では、図中の点線で示した子コンポーネントは親コンポーネントが再描画されるタイミングで常に再描画される * React.memoはこの親コンポーネントが再描画されるタイミングでの子コンポーネントの再描画を最適化するもの * React.memoでは子コンポーネントにおいて、親コンポーネントから受け取る props が再描画前の props と等価であれば、再描画をスキップする * 親コンポーネントから子コンポーネントに渡す props とその等価性が重要になる * useCallbackは props に渡す関数が等価であることを保証するためのフック ※ サンプルコードとかはこっち https://tech.isid.co.jp/entry/2021/12/13/React_Hooks_%E3%82%92%E7%90%86%E8%A7%A3%E3%81%97%E3%82%88%E3%81%86 ### React Hooks を正しく使うために フックは一見すると JavaScript の関数ですが、正しく使う際には、ルールに従う必要があります。 特にuseEffectやuseMemo、useCallbackといった依存配列を含むフックの使用では、依存関係の漏れによってバグを混入する恐れがあります。 フックを正しく利用するために、ESLint のeslint-plugin-react-hooksプラグインを導入しておくことがお勧めです。 exhaustive-depsルールを有効にすれば、依存配列が正しく記述されていない場合に警告を出すこともできます。 ## CSSまわり こんな選択肢があるので、現状のフェーズ・サイトに合うよう比較検討する必要がある * UIライブラリ(Chakra UI、MUIなど) * CSSフレームワーク(Tailwind CSSなど) * CSS in JS(styled-components、Emotion、CSS Modulesなど) * Zero Runtime CSS in JS(linaria、stichesなど) ### TailWindCSS bootstrapっぽいもの → 不要ファイルが多くなるのでは? → TailWindCSSは使用されているclassNameを検知して,必要最低限のCSSのみを生成する仕組みになっている https://zenn.dev/nbr41to/articles/276f40041ad9fe ### メルカリShopsはChakra * 標準でモーダルや テーブル、スケルトンなどの UI が整っている * フォント、スペースの値などのデザインルールが定義されている * アクセシビリティが考慮されている * CSS を素で書く必要がなく、拡張が容易 * Figma が提供されている https://engineering.mercari.com/blog/entry/20210823-a57631d32e/ ## ディレクトリ構成 ### コンポーネントの構成 コンポーネント名がディレクトリになり、見た目とロジックでファイルを明確に分ける。 ``` BlogItemTemplate ├── index.tsx // container層 (ロジック担当) ├── Presenter.tsx // Presentational層 (UI担当) └── styles.module.scss // css ``` ![](https://i.imgur.com/XZtLGyr.png) https://www.nochitoku-it.com/containr-1 ### 全体のディレクトリ構成 全体のディレクトリ構成は会社によって全然違うので、 まずはAtomic Designで試して、どう変更した方が良いかは現場で話して変えていく感じで良いんじゃないか?と思った。 → SSRなサイト・SPAなサイトとかの差だったりサービスの内容でも変わっていきそう 参考に食べログさんの全体のディレクトリ構成↓ https://note.com/tabelog_frontend/n/n07b4077f5cf3 ## ファイルの分離と自動チェック Code Splittingで初期表示に必要ないものをbundleから別のchunkに分割できる。 https://dwango-js.github.io/performance-handbook/startup/reduce-size/ ### コードの分離(Script) こういうコードだと分離されない ```ts import { add } from '../libs/math' add() ``` こういうコードだと分離される ```ts import('../libs/math').then(math => { math.add() }) ``` ![](https://i.imgur.com/EUv2vJz.png) → DOMContentLoadedの直前に読まれる ### コードの分離(Component) こういうコードだと分離されない ```tsx import RazyComponent from '../components/RazyComponent' export default function Home() { return ( <div> <RazyComponent /> ... ``` こういうコードだと分離される ```tsx import React from 'react' const RazyComponent = React.lazy(() => import('../components/RazyComponent')) export default function Home() { return ( <div> <RazyComponent /> ... ``` ![](https://i.imgur.com/ICCd4pq.png) → DOMContentLoadedのちょい後に読まれる https://reactjs.org/docs/code-splitting.html ## 状態管理 ### 歴史 https://zenn.dev/shimpeiws/articles/afcc43990d13c0 ### justInCaseTechnologies2021年7月時点での大まかな方針 * 小規模のプロダクトには Recoil / Jotai を使っていく * 中規模以上のプロジェクトでは Redux Toolkit を使っていく https://qiita.com/takkyun/items/f1107269b3004bae8c3a ### Recoil Reactの提供元であるFacebook改めMetaが開発中の新しい状態管理ライブラリ 特徴 * アプリケーション内に複数のデータストアを持てる * 非同期対応 * React hooks前提 https://nulab.com/ja/blog/nulab/recoil-example/ ### Apollo Client #### 世のフロントエンドエンジニアにApollo Clientを布教したい 古い記事だけど、めっちゃ推されてる https://qiita.com/seya/items/26c8a0dc549a10efcdf8 #### あなたのプロダクトに Apollo Client は必要ないかもしれない Apollo Clientは高機能なのでオーバースペックかもとのこと https://user-first.ikyu.co.jp/entry/2022/07/01/121325 ## 直近のバージョンアップ https://ja.reactjs.org/blog/2022/03/29/react-v18.html ### 16 * fragments * Error Boundaries * Portals * カスタムDOM属性の対応 * 改良したサーバーサイドレンダリング * ファイルサイズの縮小 など https://mae.chab.in/archives/59858 16.8でHooksが追加されたり、マイナーでも大きな変更がある ### 17 新しい機能はなし https://qiita.com/irico/items/1129cf233562a668670a ただし、既存機能に破壊的変更をしている https://zenn.dev/uhyo/articles/react17-useeffect ### 18 * 自動バッチング * トランジション * サスペンス * Internet Explorerのサポート終了 * 今後の追加実装 * マイナーリリースで色々追加されるらしい https://and-engineer.com/articles/YnxujBAAACAAv4uF # Webpack webpackとは、モジュールバンドラ。 モジュールバンドラとは、 複数のファイルを1つにまとめて出力してくれるツールのこと。 (複数ファイルをまとめることを「バンドル」と呼ぶ) ## Next.jsでの利用 next.config.js の中でその設定を拡張する関数を定義することができる `webpack`関数は、サーバーとクライアントで2回実行される。 これにより、`isServer`プロパティを用いてクライアントとサーバの設定を区別することができる。 https://nextjs-ja-translation-docs.vercel.app/docs/api-reference/next.config.js/custom-webpack-config ## webpack@5の主な変更点まとめ * Persistent Caching * Module Federation * assetModules typeの追加 * チャンク名がIDへ変更 * import.metaのサポート * data, file, http(s)のプロトコルのサポート * Native Workerのサポート * publicPathの自動化 * Tree Shakingの最適化 * output.filename, output. chunkFilenameの関数化 * externalsTypeの追加 * targetの詳細化とbrowserslistのサポート * TypeScript型定義ファイルの提供 * splitChunksでのサイズ設定値の変更 https://blog.hiroppy.me/entry/webpack5 # よいリンク * Design Doc for react-boilerplate-2022 https://zenn.dev/shimpeiws/articles/3ef4416b7fe2f6 * 2020年に立ち上げたWebフロントエンド構成の振り返り https://zenn.dev/yoshiko/articles/32371c83e68cbe * Edge Side Frontend という新領域 https://speakerdeck.com/mizchi/edge-side-frontend-toiuxin-ling-yu