Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2024新卒技術研修_FE③

 2024新卒技術研修_FE③

DMM.comの24新卒エンジニア技術研修_フロントエンド研修の資料③です。

Avatar for DMM.com_新卒採用

DMM.com_新卒採用

September 17, 2024
Tweet

More Decks by DMM.com_新卒採用

Other Decks in Technology

Transcript

  1. © DMM.com タイムテーブル 2 コンテンツ 時間 概要 午前の部 10:30~11:30 ※途中5分休憩

    座学後半 11:30〜13:00 演習 お昼 13:00~14:00 休憩 午後の部 14:00~18:00ごろ 演習
  2. © DMM.com もくじ • Next.jsの基礎概念 • SPAの課題 • キーワード整理 •

    SSR, SG • Next.jsのルーティング • App Router, Page Router • テスト技術の紹介 • テストツールの紹介 • サンプルコードの紹介 3
  3. © DMM.com Next.jsの基礎概念 主な機能 • Routing • Rendering • Data

    Fetching • Styling • Optimizations(最適化) • TypeScript 4
  4. © DMM.com 補足:MPA / SPA 10 ※ SPAの定義は人によって違う。「CSRしかしていないアプリ」を意味することもあるので、注意。 ※ SGはSSG(Static

    Site Generation)と呼ぶこともある。 MPA (Multiple Page Application) SPA (Single Page Application) CSR (Client Side Rendering) SSR (Server Side Rendering) SG (Static Generation) HTMLが いつ生成されるか ページ遷移のたびに毎回 ブラウザでJSを実行し て生成 ページ読み込み時のみ サーバーで生成 ※ページ遷移はCSRと同じ挙動 ビルド時 ※ページ遷移はCSRと同じ挙動 DMMでの利用例 通販 DMM競輪 (CSRしかしていない) ヘルプセンター コーポレートサイトの 企業情報ページ (他のページではSSRもしてる) メリット 従来からあるやり方 リッチでインタラク ティブな表現がしやすい ページ遷移時が早い 初回表示が早くな る SEOに強い 初回表示が早くな る SEOに強い サーバーの負担軽 い デメリット 共通ヘッダーなども毎 回送信する必要あり CSRのみの場合、 初回表示が遅く、SEO に弱くなる サーバーを運用す る必要がある ページ数が膨大だ とビルドに時間がかか る
  5. © DMM.com SPAの課題 クローラーはURL単位でページを区別する GoogleはRFC 3986で定義されたURLをサポートしている クローラーが解釈できない:example.com/#hogehoge クローラーが解釈できる:example.com/hogehoge 16 ☞Google

    の URL 構造ガイドライン | Google 検索セントラル | ドキュメント ☞EC サイトの URL 構造 ベスト プラクティス | Google 検索セントラル | ドキュメント | Google for Developers
  6. © DMM.com Next.jsの基礎概念 zero-config Babel+Webpackなどの複雑な環境設定が不要 • webpackの設定をフレームワーク側(Next.js)がdefaultでいい 感じにチューニング&隠蔽してくれている • ☞

    実装箇所 • フレームワークに依存しない(設定を自前で行う)場合 • プラグインアップデートなど定期的なメンテナンスが必須 • ☞保守・運用コストの属人化・肥大化が課題 20
  7. © DMM.com Next.jsの基礎概念 zero-config Babel+Webpackなどの複雑な環境設定が不要 • webpackの設定をフレームワーク側(Next.js)がdefaultでいい 感じにチューニング&隠蔽してくれている • ☞

    実装箇所 • もしフレームワークに依存しない(設定を自前で行う)場合 • プラグインアップデートなど定期的なメンテナンスが必須 • ☞保守・運用コストの属人化・肥大化が課題 21
  8. © DMM.com 設定拡張もフレームワーク内部で完結 // next.config.js module.exports = { webpack: (config,

    options) => { config.module.rules.push({ test: /¥.mdx/, use: [ options.defaultLoaders.babel, { loader: '@mdx-js/loader', 22 options: pluginOptions.options, }, ], }) return config }, }
  9. © DMM.com Next.jsの基礎概念 コード分割とプリフェッチ SPAの課題であるバンドル肥大化を避けられる • ページ単位の各ファイルが、ビルドステップで自動的に独自の JavaScriptバンドルにCode Splittingされる(コード分割) •

    初期表示に必要ないものをbundleから別のchunkに分割 • getLayout が _app 肥大化を防いでくれる • ブラウザが遷移先のページをバックグラウンドで取得し、キャッ シュに保存してくれる(プリフェッチ) • <Link>コンポーネントまたは router.prefetch()で実行可能 23 ☞Routing: Pages and Layouts | Next.js
  10. © DMM.com 補足:バンドラー 25 役割 概要 bundle 複数のJSファイルをブラウザ用に最適化された単位にまとめる 例:1ページごとなど minify

    変数名を1文字にしたり、改行・スペースを削除して容量を小さくする tree shaking 使われていないコードを削除する 主なバンドラー • Webpack (Next.jsだと裏でこれが動いている) • Rollup • Esbuild
  11. © DMM.com Next.jsの基礎概念 コード分割とプリフェッチ SPAの課題であるバンドル肥大化を避けられる • ページ単位の各ファイルが、ビルドステップで自動的に独自の JavaScriptバンドルにCode Splittingされる(コード分割) •

    初期表示に必要ないものをbundleから別のchunkに分割 • getLayout が _app 肥大化を防いでくれる • ブラウザが遷移先のページをバックグラウンドで取得し、キャッ シュに保存してくれる(プリフェッチ) • <Link>コンポーネントまたは router.prefetch()で実行可能 26 ☞Learn Next.js: Navigating Between Pages
  12. © DMM.com Server Side Rendering(SSR) • コンテンツ表示速度が高速 • Web ServerでリクエストごとにHTMLを生成(Pre-rendering)

    ☞従来のSPAではフロント側で行う処理(JavaScriptの実行と読み 込み)をWeb Server側で行うため、初期描画の表示速度が高速 ☞ユーザーの通信環境に左右されにくい 29
  13. © DMM.com Server Side Rendering(SSR) • SEO対策 • SSRはサーバーが完全にレンダリングされたページをクライアント に提供する

    ☞クローラーがサイトを正しく認識できる ☞レイアウトシフトが安定する(CLSのスコアが良くなる) ☞CLSスコアはSEOに影響する 31
  14. © DMM.com Server Side Rendering(SSR) 課題 • Web Serverを用意する必要がある •

    JavaScriptを実行するため、Node.jsが乗ったWeb Serverが必要 32
  15. © DMM.com Static Generation(SG) • プリレンダリング • あらかじめWebページのレンダリング(ビルド)を行う • クライアントからリクエストがあったとき、サーバーは事前に生成

    した静的ファイルを返却する • コンテンツ表示速度 • ビルド済み静的ファイルを返すだけ ☞表示速度がSSR よりも高速 ☞クローラー向けにより最適化 33
  16. © DMM.com Static Generation(SG) • プリレンダリング • あらかじめWebページのレンダリング(ビルド)を行う • クライアントからリクエストがあったとき、サーバーは事前に生成

    した静的ファイルを返却する • コンテンツ表示速度 • ビルド済み静的ファイルを返すだけ ☞表示速度がSSRよりも高速 ☞クローラー向けにより最適化 34
  17. © DMM.com Next.jsのルーティング 40 Before Next.js 13, the Pages Router

    was the main way to create routes in Next.js. It used an intuitive file-system router to map each file to a route. The Pages Router is still supported in newer versions of Next.js, but we recommend migrating to the new App Router to leverage React's latest features. ☞Pages Router | Next.js
  18. © DMM.com App Router 42 特徴 • サーバー側で事前レンダリン グ 記法

    • App Routerでは初期の全ての コンポーネントがRSC 特徴 • クライアント側でレンダリング 記法 • App Routerでは、各ファイル の1行目に ”use client” と記述して使用 Server Components(RSC) Client Components
  19. © DMM.com • ページ読み込みの高速化 • サーバー側で事前レンダリングしキャッシュするため • onClick や onChange

    などのイベントリスナーは使用できない ☞イベント処理はServer Actionを使う • サーバーからデータをフェッチする方法が変わった • async / awaitの導入 • 状態管理(useState)と効果管理(useEffect)などのフックは 使用できない 43 Server Components(RSC)の特徴
  20. © DMM.com • ページ読み込みの高速化 • サーバー側で事前レンダリングしキャッシュするため • onClick や onChange

    などのイベントリスナーは使用できない ☞イベント処理はServer Actionを使う • サーバーからデータをフェッチする方法が変わった • async / awaitの導入 • 状態管理(useState)と効果管理(useEffect)などのフックは 使用できない 44 Server Components(RSC)の特徴
  21. © DMM.com Client Side Click Events const items = [

    {id:"1",name:"Item 1"}, {id:"2",name:"Item 2"}, ]; export default function MyComponent() { const handleDelete = async(id) => { // API call to delete an item }; 45 return ( <div> {items.map((el, i) => ( <> <div key={i}>{el.name}</div> <button onClick={()=>handleDelete(el.id)}>Delete</button> </> ))} </div> ); } ☞Effortless Next.js 14 Server-Side Click Handling | Practical Guide for Developers | by Dan Tulpa | Nov, 2023 | Medium
  22. © DMM.com Server-Side Click Events const items = [ {

    id: "1", name: "Item 1" }, { id: "2", name: "Item 2" }, ]; export default function DiscoverTabs() { const handleDelete = async (data : FormData) => { "use server"; const itemId = data.get("itemId"); // API call to delete an item }; 46 return ( <div> {items.map((el, i) => ( <> <div key={i}>{el.name}</div> <form action={handleDelete}> <input name="itemId" className="hidden" value={el.id}/> <button type="submit">Delete</button> </form> </> ))} </div> ); } ☞Effortless Next.js 14 Server-Side Click Handling | Practical Guide for Developers | by Dan Tulpa | Nov, 2023 | Medium
  23. © DMM.com • ページ読み込みの高速化 • サーバー側で事前レンダリングしキャッシュするため • onClick や onChange

    などのイベントリスナーは使用できない ☞イベント処理はServer Actionを使う • サーバーからデータをフェッチする方法が変わった • async / awaitの導入 • 状態管理(useState)と効果管理(useEffect)などのフックは 使用できない 47 Server Components(RSC)の特徴
  24. © DMM.com RSCはコンポーネント単位で非同期的にデータが取得できる ☞データ取得はコンポーネントで直接 async / await (非同期関数)を 使ってフェッチ •

    (SSG)getStaticPaths()☞generateStaticParams() • (SSG)getStaticPaths()☞generateStaticParams() • (SSR)getServerSideProps()☞getStaticProps() 48 Server Components(RSC)の特徴 ☞Server Components: React.js and Next.js | by Hugo Ramon Pereira | Medium
  25. © DMM.com useEffect() フックを使用してデータをフェッチ "use client" import React, { useEffect,

    useState } from "react"; export default function Home() { const [data, setData] = useState([]); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/posts/") .then((response) => response.json()) .then((data) => { setData(data); }); }, []); 49 return ( <div> {data.map((post) => ( <div> <h1>{post.title}</h1> <p>{post.body}</p> </div> ))} </div> ); } ☞Server Components: React.js and Next.js | by Hugo Ramon Pereira | Medium
  26. © DMM.com await / async と fetch関数 を使ってデータをフェッチ export default

    async function Home() { const response = await fetch('https://jsonplaceholder.typicode.com/posts') const posts = await response.json(); return ( <> <ul> {posts.map(post => ( <div> <h1>{post.title}</h1> <p>{post.body}</p> </div> ))} </ul> </> ) } 50 ☞Server Components: React.js and Next.js | by Hugo Ramon Pereira | Medium
  27. © DMM.com テスト技術の紹介 Jest • Facebook製のテストツール • ユニットテスト〜インテグレーションテ ストまで React

    Testing Library • 実装の詳細に依存せず、Reactコンポー ネントをテストすることができるツール セット 52
  28. © DMM.com 正常系のテストを書く jest.mock("../../../features/statuses/api", () => ({ deleteStatus: jest.fn(), }));

    jest.mock("@mantine/modals", () => ({ modals: { openConfirmModal: jest.fn((args) => args.onConfirm()), }, })); describe("投稿削除モーダルが表示されたとき", () => { 53 it("指定した投稿が削除されること", () => { const mockArgs = { title: "ピヨピヨサンダルほげほげ", text: "テストテキスト", id: 1, username: "大臣", }; openDeleteModal(mockArgs); expect(deleteStatus).toHaveBeenCalledWith(mo ckArgs.id, mockArgs.username); expect(modals.openConfirmModal).toHaveBeenCa lled(); }); });
  29. © DMM.com 異常系のテストを書く it("投稿の削除に失敗した場合、エラーが適切に処理され ること", async () => { const

    mockArgs = { title: "ピヨピヨサンダルほげほげ", text: "テストテキスト", id: 1, username: "大臣", }; (deleteStatus as jest.Mock).mockImplementation(() => { throw new Error("投稿の削除に失敗しました "); 54 await expect(openDeleteModal(mockArgs)).rejects.to ThrowError( "投稿の削除に失敗しました" ); });
  30. © DMM.com テストがこけた expect(received).rejects.toThrowError() Received promise resolved instead of rejected

    Resolved to value: undefined 39 | }); 40 | > 41 | await expect(openDeleteModal(mockArgs)).rejects.toThrowErr or( | ^ 42 | "投稿の削除に失敗しました" 43 | ); 44 | }); 55 at expect (node_modules/expect/build/index.js:105:15) at Object.expect (src/components/elements/modal/index.test.tsx:41:11) PASS src/__tests__/index.spec.tsx Test Suites: 1 failed, 1 passed, 2 total Tests: 1 failed, 2 passed, 3 total Snapshots: 0 total Time: 1.064 s Ran all test suites.
  31. © DMM.com モーダルコンポーネントの実装を確認する type Props = { title: string; text:

    string; id?: number; username?: string; }; export const openDeleteModal = (props: Props) => { // ... 56 onConfirm: async () => { try { await deleteStatus(id ? id : 0, username ? username : ""); } catch (error) { // 「errorをキャッチしたらエラーメッセ ージをユーザーに表示する」ような処理が存在して いてほしい }
  32. © DMM.com モーダルコンポーネントの実装を修正する type Props = { title: string; text:

    string; id?: number; username?: string; }; export const openDeleteModal = (props: Props) => { const [errorMessage, setErrorMessage] = useState(null); // ... 58 // ... } catch (error) { setErrorMessage(error.message || '投稿の 削除に失敗しました'); } } // ... return ( {/* ... */} {errorMessage && <div>{errorMessage}</div>} {/* ... */} ); };
  33. © DMM.com テストが通った PASS src/components/elements/modal/index.test.tsx PASS src/__tests__/index.spec.tsx Test Suites: 2

    passed, 2 total Tests: 3 passed, 3 total Snapshots: 0 total Time: 1.611 s Ran all test suites. 59
  34. © DMM.com ESModuleとCommonJS 62 ESModule CommonJS export export default foo

    module.exports = foo import import foo from ‘.foo’ const foo = require(‘./foo’) 実行環境 • ブラウザとNode.jsの両方で動く • 先にブラウザ用に作られ、後にNode.jsでも 動くようになった • Node.jsのみで動く 特徴 • 実行前に依存を解決する • 未使用コードを取り除くTree Shakingなどが 可能 • 実行時に依存を解決する • Tree Shakingできない 使い所 アプリコードを書くときは基本的にこっち next.config.jsなど設定ファイル
  35. © DMM.com 名称 概要 EsLint コードが規約に従っているかチェック・自動修正する Prettier コードのフォーマットをチェック・自動修正する Jest Facebook製のテストツール。ユニットテスト〜インテグレーシ

    ョンテストまで Storybook コンポーネントのカタログを表示する CSS in JS ReactアプリでCSSを書くときの選択肢の一つ。 代表的なライブラリ: - emotion, styled components (ランタイムでJSを実行してCSSを生成する) - linaria, vanilla-extract (ビルド時にCSSを生成(ゼロランタイム)) フロントエンドの周辺技術 63