Slide 1

Slide 1 text

Next.js App Router 
 ࠾༻ͷৼΓฦΓ @Quramy 2024.04.30 #tng42

Slide 2

Slide 2 text

About me - id: @Quramy (GitHub, X) - ॴଐ: גࣜձࣾϦΫϧʔτ 
 (ΞϓϦέʔγϣϯιϦϡʔγϣϯ G) - ৬छ: ϑϩϯτΤϯυΤϯδχΞ

Slide 3

Slide 3 text

Agenda - ͸͡Ίʹ - App Router ͰͲͷΑ͏ʹΞϓϦέʔγϣϯΛ࡞ͬͨͷ͔ - App Router ʹऔΓ૊Ή্Ͱॏཁͱࢥ͏͜ͱ

Slide 4

Slide 4 text

Agenda - ͸͡Ίʹ - App Router ͰͲͷΑ͏ʹΞϓϦέʔγϣϯΛ࡞ͬͨͷ͔ - App Router ʹऔΓ૊Ή্Ͱॏཁͱࢥ͏͜ͱ

Slide 5

Slide 5 text

Next.js App Router is Կ - Next.js ʹ͓͚Δ৽͍͠ΞϓϦέʔγϣϯ։ൃελΠϧͷ͜ͱ - ඪ४Ͱ React Server Components (ҎԼ RSC) ٴͼ Server Actions (ҎԼ SA) ͕ར༻Մೳ

Slide 6

Slide 6 text

App Router ࠾༻ʹࢸͬͨഎܠ - ର৅Ҋ݅: ݁ࠗྖҬ(θΫγΟΛ΍͍ͬͯΔͱ͜Ζ) ʹ͓͚Δ৽نࣄۀ - ಉྖҬͷଞϓϩμΫτͰ͸ Next.js Pages Router Λ࢖ͬͨ։ൃΛߦͬ ͍ͯΔͨΊɺApp Router ͷ࢖͍৺஍Λຯݟͯ͠Έ͍ͨ 
 → Quramy ΋Ұຕט·ͤͯ΋Β͏͜ͱʹ - ։ൃظؒ: 2023.6݄ - 2023.12݄ - ϑϩϯτΤϯυن໛: ໿40ϖʔδ, 180 Component

Slide 7

Slide 7 text

ΞϓϦέʔγϣϯͷΠϝʔδ ॾൠͷࣄ৘ʹΑΓΩϟϓνϟͳͲ͸ඇެ։Ͱ͕͢ɺ͋Δछͷੑ֨਍அςε τͷΑ͏ͳϓϩμΫτͰ͢ 1. Ϣʔβʔ͸ఆΊΒΕ͍͔ͨͭ͘ͷ࣭໰ʹରͯ͠ճ౴Λߦ͏ 2. Ϣʔβʔͷճ౴ʹԊͬͨੑ֨਍அ݁Ռ͕දࣔ͞ΕΔ

Slide 8

Slide 8 text

App Router ʹର͢Δॴײ 2023.6 ʙ 2023.12 ·Ͱͷ໿̒ϲ݄ؒͷ։ൃظؒΛ௨ͨ͡ App Router ʹର ͢Δॴײ - ϙδςΟϒ: - Data Fetching ؔ࿈ʹ͍ͭͯɺैདྷΑΓ΋௚ײతͳ࣮૷͕ՄೳͰ͋Δɻ 
 ʮBFF ͷͨΊͷ API ΤϯυϙΠϯτʯͳͲͷதؒ੒Ռ෺ʹ͔͔Δઃ ܭɾ࣮૷ίετ͕࡟ݮ͞ΕΔ - νϡʔχϯάΛߦ͍ͬͯͳ͍ঢ়ଶͰ΋ɺे෼ʹߴ଎ͳΞϓϦέʔγϣ ϯΛߏஙͰ͖ͨ

Slide 9

Slide 9 text

App Router ʹର͢Δॴײ 2023.6 ʙ 2023.12 ·Ͱͷ໿̒ϲ݄ؒͷ։ൃظؒΛ௨ͨ͡ App Router ʹର ͢Δॴײ - ωΨςΟϒ: - पลΤίγεςϜ(e.g. Styling, UI Lib, Form lib, ςετ) ͕ RSC ʹ௥͍ ͍͍ͭͯͳ͍ - ͱ͸͍͑χʔζ͸͋ΔͷͰɺ͕࣌ؒղܾ͍ͯ͘͠ྨͷ࿩ͱࢥ͏

Slide 10

Slide 10 text

Agenda - ͸͡Ίʹ - App Router ͰͲͷΑ͏ʹΞϓϦέʔγϣϯΛ࡞ͬͨͷ͔ - App Router ʹऔΓ૊Ή্Ͱॏཁͱࢥ͏͜ͱ

Slide 11

Slide 11 text

શମతͳΞʔΩςΫνϟ CloudFront EKS Cluster k8s namespace Frontend SVC Backend API SVC RDS Next.js Spring Boot AWS Cloud - Πϯϑϥ: AWS (EKS) - Backend API: Spring Boot - Frontend: Next.js (ϝΠϯϢʔεέʔε͸ SSR) 


Slide 12

Slide 12 text

ϑϩϯτΤϯυελοΫ ओͳ Dependencies Data Fetching RSC / Server Actions HTTP Client WHATWG Fetch (undichi) API Client Open API Generator ελΠϦϯά (CSS) CSS Modules UI ϥΠϒϥϦ - UI State Management jotai Form ϥΠϒϥϦ - Scaffolding hygen Component Χλϩά @storybook/react Unit Testing Jest Component Testing Jest + RTL E2E Testing Playwright

Slide 13

Slide 13 text

ϑϩϯτΤϯυελοΫ Data Fetching App Router ͷ࠾༻͸ Data Fetching ʹ RSC / SA Λ༻͍Δ͜ͱΛҙຯ͍ͯ͠ Δ(ٯʹ͜ΕΒΛ࢖Θͳ͍ͷͰ͋Ε͹ɺٕज़ݕূͷҙຯ͕ബΕͯ͠·͏) - ʮσʔλΛදࣔ͢ΔʯʮσʔλΛߋ৽͢ΔʯͷͲͪΒͰ͋ͬͯ΋ɺSC / SA Ͱ׬݁͢Δ - SWR ΍ tRPCɺApollo Client ͷΑ͏ͳ Data Fetch ϥΠϒϥϦΛෆཁͱͰ ͖ΔͨΊɺඪ४Խָ͕ - SC / SA ͱ΋ʹʮReact ͷ࢖͍ํʯͷ࿩Ͱ͔͠ͳ͍ɻԾʹ Next.js Ͱͳ ͔ͬͨͱͯ͠΋Ԡ༻ͷޮ͘஌ࣝͱͳΔ͸ͣ

Slide 14

Slide 14 text

ϑϩϯτΤϯυελοΫ ελΠϦϯά(CSS) Runtime CSS in JS ܥ͕ݢฒΈ RSC Ͱಈ࡞͠ͳ͍ͨΊɺݕ౼࣌఺(2023.6݄) Ͱ࠷΋ރΕ͍ͯͨ CSS Modules Λ࠾༻ - ΋͍͠·બ୒͢ΔͷͰ͋Ε͹ Zero Runtime CSS in JS Λ΋͏গ͠ݕ౼͠ ͍͔ͯͨ΋ - ϏϧυπʔϧνΣʔϯ͕ա౉ظͰ͋Δ͜ͱΛߟ͑Δͱ PandaCSS ͷΑ͏ ͳɺτϥϯεύΠϧʹ৵ऻ͠ͳ͍Ξϓϩʔνͷ΋ͷΛબͼ͍ͨ

Slide 15

Slide 15 text

ϑϩϯτΤϯυελοΫ UI State Management State management ʹ jotai Λ࠾༻ - RSC Ͱ͸খཱࣗ͘͞෼ࢄͳ CC ಉ͕࢜૬ޓʹ࿈ܞ͢ΔੈքʹͳΔͷͰ͸ʁ 
 ͱ͍͏༧ײ͕͋ͬͨ - ྫ: Component X ͕ Viewport ʹަࠩ࣌ɺ Component A ͷදࣔঢ়ଶ͕มԽ - Pages Router ͷ৔߹ɺX ͱ A ྆ํΛؚΜͩҰݸͷComponent ͱͯ͠ه ड़͍ͯͨ͠Γ͢Δ => useState ͚ͩͰԿͱ͔ͯ͠͠·͏͜ͱ΋Ͱ͖ͨ - App Router Ͱ X / A ͕ CC ͱͯ͠෼ࢄ഑ஔ͞ΕΔͱɺͦ͏͸͍͔ͳ͘ͳΔ ͷͰ͸?

Slide 16

Slide 16 text

Page Component Component A ෦෼ Component X ෦෼ const [hoge, setHoge] = useState(true) hoge Λࢀর setHoge Λࢀর Page Component (Async SC) Component A (CC) Component X (CC) hoge Λࢀর hoge Λߋ৽ ͜ͷ component Λ SC ʹ͢ΔͷͰ͋Ε͹ Hooks ͸ར༻Ͱ͖ͳ͍ State ͢΂͕ͯ CC ͷੈք SC / CC Λؾʹ͢Δੈք ※ ͨͩͷσʔλදࣔ෦෼ ※ ͨͩͷσʔλදࣔ෦෼ (SC) ϑϩϯτΤϯυελοΫ UI State Management

Slide 17

Slide 17 text

ϑϩϯτΤϯυελοΫ UI State Management - jotai + Next.js Λ࢖͏্Ͱͷॾ஫ҙ: - SSR ࣌ʹ atomFamily ͕ϝϞϦϦʔΫ͢ΔͨΊɺ͓૟আ͕ඞཁ 
 https://jotai.org/docs/utilities/family#caveat-memory-leaks import { type Atom } from 'jotai' import { atomFamily as atomFamilyiDelegate } from 'jotai/utils' export function atomFamily>( initializeAtom: (param: Param) => AtomType, areEqual?: (a: Param, b: Param) => boolean, ) { const delegate = atomFamilyiDelegate(initializeAtom, areEqual) return new Proxy(delegate, { apply: (createAtom, _, [param]: [Param]) => { if (typeof document !== 'undefined') { return createAtom(param) } const atomItem = createAtom(param) queueMicrotask(() => createAtom.remove(param)) return atomItem }, }) }

Slide 18

Slide 18 text

ϑϩϯτΤϯυελοΫ ͦͷଞ Կ΋࠾༻͠ͳ͔ͬͨܥ౷ - Form ϥΠϒϥϦ - ͍ΘΏΔ react-hook-form ͳͲͷܥ౷ 
 ը໘ೖྗཁ͕݅ϥδΦϘλϯ/νΣοΫϘοΫεͷΈɻͦ΋ͦ΋ϥΠϒϥϦ͕ෆཁͳ ϨϕϧͩͬͨΊ - UI Component ϥΠϒϥϦ - બఆ͍ͯ͠Δ༨༟͕ͳ͔ͬͨͱ͍͏ফۃతͳཧ༝ 
 RSC ͱ૬ੑͷྑ͍ UI Component ϥΠϒϥϦ͕͋Ε͹஌Γ͍ͨͰ͢ʂ

Slide 19

Slide 19 text

ύϑΥʔϚϯε/Ωϟογϡઓུ Next.js Ͱආ͚ͯ௨Εͳ͍ͷ͕Ωϟογϡͷ࿩୊ https://nextjs.org/docs/app/building-your-application/caching#overview

Slide 20

Slide 20 text

ύϑΥʔϚϯε/Ωϟογϡઓུ Next.js Ͱආ͚ͯ௨Εͳ͍ͷ͕Ωϟογϡͷ࿩୊ https://nextjs.org/docs/app/building-your-application/caching#overview ΦϓτΞ΢τ

Slide 21

Slide 21 text

ύϑΥʔϚϯε/Ωϟογϡઓུ ͳͥ Next.js ͷ Cache Λར༻͍ͯ͠ͳ͍͔: - ΞϓϦέʔγϣϯಛੑ্ɺData / Full Route Cache ʹର͢Δ hit rate ͕ߴ͘ͳΒͳ͍͜ͱ ͕Θ͔͓ͬͯΓɺΩϟογϡΛؤுΔࢫຯ͕গͳ͔ͬͨ - EKS Pod ؒͰ Cache Λڞ༗͢Δ࢓૊Έʹ͍ͭͯະݕ౼ - σϑΥϧτͰ͸ Data Cache, Full Route Cache ͸ϑΝΠϧγεςϜ্ʹӬଓԽ͞Ε Δɻ͢ͳΘͪ Container Local ͳ σʔλͱͳΔ 
 ͜ͷͨΊɺ Custom Cache Handler + ElastiCache ͳͲΛ࢖ͬͯɺӬଓԽํࣜΛ AWS ϑϨϯυϦͳ΋ͷʹมߋ͢Δඞཁ͕͋Δ - https://nextjs.org/docs/app/api-reference/next-con fi g-js/ incrementalCacheHandlerPath

Slide 22

Slide 22 text

ύϑΥʔϚϯε/ଌఆ Next.js Cache ͸ফۃతͰ͋ͬͯ΋ɺ࣮ͦͦ͜͜༻తͳύϑΥʔϚϯε ಉྖҬͰͷ Pages Router ͳϓϩμΫτͱൺֱ͢Δͱɺ΍͸Γ First Load JavaScript ͷϘϦϡʔϜʹѹ౗తͳ͕ࠩग़Δ 
 (App Router Ҋ݅͸ґଘϥΠϒϥϦ͕গͳ͍ͨΊɺʮͦΕ͸ͦ͏ʯͱ΋ݴ͑Δ͚Ͳ) - App Router Ҋ݅: ໿ 200 kB 
 Pages Router Ҋ݅: ໿1,720 kB

Slide 23

Slide 23 text

ςετ খن໛͔ͭ৽ن։ൃҊ݅Ͱ͋ͬͨͨΊɺςετ͸ͦͦ͜͜ͷن໛ʹཹΊͨ ߏஙͨࣗ͠ಈςετ͸ҎԼͷ 2 छྨ - ཻ౓ͷࡉ͔͍ςετ: jest + RTL - ཻ౓ͷૈ͍ςετ: Playwright

Slide 24

Slide 24 text

ࡉཻ౓ͳςετ - શͯͷ Component Ͱ Storybook ͷ ϑΝΠϧ (.stories) ࡞੒Λڧ੍͓ͯ͘͠ - RSC ͷςετํ๏ʹ͍ͭͯ: - ඇಉظͳ SC ʹ͍ͭͯ͸ɺ Container / Presentation Ͱ෼ׂ͓͖ͯ͠ɺStorybook ΍ jest Ͱ࣮ߦ͞ΕΔͷ͸ Presentational ͳ෦෼ͷΈʹ͓ͯ͘͠ 
 ※ ৄࡉ: React Server Component ͷςετͱ Container / Presentation Separation - ͢΂ͯͷ Story ʹରͯ͠ɺjest + RTL Ͱ composeStories & render ͷಈ࡞อূΛ͓ͯ͘͠ - Storybook 8 ͷ experimentalRSC ͸࢖͍ͬͯͳ͍ 
 ※ ։ൃ౰ॳ͸ Storybook 7.x ͩͬͨͱ͍͏ͷ΋͋Δ͕ɺSC Λ ແཧ΍Γؾຯʹ CC ͱͯ͠ ѻ͍ͬͯΔ͜ͱࣗମ͕Πέͯͳ͍ͱࢥ͍ͬͯΔͨΊ

Slide 25

Slide 25 text

ૈཻ౓ͳςετ - Playwright ʹΑΔ E2E Λ࣮ࢪ - DB ͷ Seed + Spring Boot ͷىಈ + next start Λ͢΂ͯ CI Ͱ Service ࣮ߦ ͢ΔΑ͏ʹ͍ͯ͠Δ - Pros: E2E ͱͯ͠͸ਖ਼͍࢟͠ - Cons: CI ͕ॏ͍ͨ. SA ΛҰ౓࣮ߦͯ͠͠·͏ͱ DB ͷঢ়ଶ͕มߋ͞ΕΔ ͨΊɺFlaky Λ౿ΜͰ΋ Playright ͰಉҰ URL ʹϦτϥΠͯ͠΋ҙຯ͕ແ ͍ - Next.js ͷ Experimental Test Proxy ͸ར༻͍ͯ͠ͳ͍

Slide 26

Slide 26 text

ૈཻ౓ͳςετ - Next Server ͷڍಈͱີʹ࿈ಈ͢ΔՕॴ͸ E2E ଆͰಈ࡞Λ୲อ͢ΔΑ͏ ʹ͍ͯ͠Δ - ςετγφϦΦͷྫ: - લఏ: SA Ͱ revalidatePaths Λ༻͍ͯ Router Cache Λύʔδ͍ͯ͠Δ - γφϦΦ: ϖʔδදࣔ -> SA ࣮ߦͯ͠ը໘ભҠ -> ϒϥ΢βόοΫ - ֬ೝ؍఺: ϒϥ΢βόοΫޙͷදࣔͰ͸ Router Cache ͕࠷৽Խ͞Εͯ ͍Δ͔ʁ

Slide 27

Slide 27 text

Agenda - ͸͡Ίʹ - App Router ͰͲͷΑ͏ʹΞϓϦέʔγϣϯΛ࡞ͬͨͷ͔ - App Router ʹऔΓ૊Ή্Ͱॏཁͱࢥ͏͜ͱ

Slide 28

Slide 28 text

App Router ʹऔΓ૊Ή্Ͱॏཁͱ ࢥ͏͜ͱ - App Router Ҋ݅Λ௨ͯ͠গͣͭ͠ཧղ͖ͯͨ͜͠ͱୡ: - RSC ͷϝϯλϧϞσϧ - σʔλϑΣονͷཻ౓ - HTML / CSS ஌ࣝͷॏཁੑ

Slide 29

Slide 29 text

RSC ͷϝϯλϧϞσϧ ·ͣ͸ϑϩϯτΤϯυͷ։ൃऀશһ͕ RSC ʹ೴ΛΞοϓσʔτ͢΂͖ - RSC (App Router) ͸ Pages Router Ͱͷ SSR ͱຊ࣭తʹҙຯ͕ҟͳΔ - ʮSC ͸ࣄલܭࢉͰ͋ΔʯΛୟ͖ࠐΜͰ͓͘ - ࢀߟʹͳΔ΋ͷ - uhyo ͞Μͷهࣄ: https://zenn.dev/uhyo/articles/react-server- components-multi-stage

Slide 30

Slide 30 text

σʔλϑΣονͷཻ౓ - Pages Router ࣌୅ʹʮࣄલॲཧʯʹ૬౰͍ͯͨ͠΋ͷ: 
 getServerSideProps or getStaticProps - ͜ΕΒ͸ɺPage ୯Ґͷ Component ʹ͔͠࡞༻Ͱ͖ͳ͔ͬͨ - → gSSP Ͱར༻͢Δ API ͷઃܭ͕ϢʔεέʔεʹҾ͖ͣΒΕΔ

Slide 31

Slide 31 text

σʔλϑΣονͷཻ౓ - App Router Ͱ͸ SC ͕σʔλͷऔಘͱ͍͏ࣄલॲཧΛ୲͍ͬͯΔ - σʔλऔಘ͕ page ୯ҐͰ͋Δඞཁ͕ແ͍. ຤୺ͷ Component Ͱɺͦ ͷ Component ͕ඞཁͳσʔλΛ௚઀ϑΣονͰ͖Δ - Ϧιʔεࢤ޲ʹج͍ͮͨ API ઃܭͱ਌࿨͢Δ - ࡉཻ౓ API ͱ͓͍ͯͨ͠ํ͕ɺNext.js ͷ Data Cache ʹ΋ࡌͤ΍͍͢ ͸ͣ

Slide 32

Slide 32 text

HTML / CSS ͷ஌ࣝ - HTML + CSS ͷ஌ࣝ͸ෆඞཁͳ CC Λ࡟ݮ͢Δ্Ͱ΋ॏཁ - ྫ: ΧϧʔηϧͬΆ͍ݟͨ໨ͷίϯϙʔωϯτ - CC ͷ JavaScript ॻ͔ͳͯ͘΋ɺCSS ͷ scroll-snap Ͱ࣮ݱͰ͖·͢Α Ͷʁ - https://web.dev/blog/interop-2022

Slide 33

Slide 33 text

Thank you !