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

はてなCMSのアーキテクチャ; 巨大な既存システムと共存して最新技術を取り入れる

NanimonoDemonai
February 24, 2025
370

はてなCMSのアーキテクチャ; 巨大な既存システムと共存して最新技術を取り入れる

はてなCMSは、はてなブログと共存しています。複雑かつ歴史のあるプロダクトのはてなブログを壊さずに、最新技術を取り入れてはてなCMSを開発した方法とそのアーキテクチャを紹介します。Perlで作られたページからNext.jsで作られたページへのシームレスな以降、既存のプロダクトと認証認可を連携させる方法について、なぜこの選択をしたのか、どのように開発したのかをお話しします。

NanimonoDemonai

February 24, 2025
Tweet

Transcript

  1. ࣗݾ঺հ • id: nanimono_demonai • @NanimonoDaemon • େֶͰ͸ػցֶशͷݚڀ • ʮגࣜձࣾ͸ͯͳʯʹ2020೥ʹब৬

    • ϒϩάͷϑϩϯτΤϯυͷվળΛଓ͚͍ͯ·͢ • ͸ͯͳCMSͷ։ൃϦʔμʔͱͯ͠͸ͯͳCMSΛ࡞Γ·ͨ͠ 3 ·Ί͖ͪ͠ ݕূ༻ΞΧ΢ϯτͷJE͸JEFOHJ@EFNPOBJͰ͢
  2. ଓ: ͸ͯͳCMSͱ͸ 7 ·Ί͖ͪ͠ ͸ͯͳϒϩά.FEJB͸೥։࢝ͷαʔϏεͰ͢ • ͸ͯͳϒϩάͷϒϩάهࣄʹՃ͑ͯɺαΠτ্ͷ͞·͟·ͳϖʔδΛ؅ཧ • ΋ͪΖΜɺ͸ͯͳϒϩάͷهࣄ΋׆༻ͨ͠ϖʔδ΋࡞ΕΔΑ͏ʹ •

    ͸ͯͳϒϩάMediaͷίϯςϯπͷ؅ཧͷ͠΍͢͞Λܧঝͭͭ͠ɺ ɹɹɹɹɹɹɹϥϯσΟϯάϖʔδʢLPʣͳͲ΋࡞ΕΔΑ͏ʹ͢Δ • هࣄͷ؅ཧ͔Βɺίϯςϯπͷ؅ཧ΁ Φ΢ϯυϝσΟΞઐ༻CMSΛϊʔίʔυCMSʹ!
  3. ͸ͯͳCMSͷΞʔΩςΫνϟ֓؍ 14 ·Ί͖ͪ͠ %#͸ಉ͡ΠϯελϯεͷผσʔλϕʔεΛ࢖͍ͬͯ·͢ Ϣʔβʔ ϩʔυόϥϯαʔ ϓϩΩγ ͸ͯͳϒϩάόοΫΤϯυ 3&45"1* Ͱ௨৴

    ͸ͯͳ $.4 όοΫΤϯυ ͸ͯͳϒϩάهࣄ ͸ͯͳϒϩά؅ཧը໘ ͸ͯͳ $.4 ؅ཧը໘ ͸ͯͳ $.4 ؅ཧը໘΁ ͸ͯͳ $.4 ͷίϯςϯπ΁ ͸ͯͳϒϩά؅ཧը໘ PS Ϣʔβʔͷهࣄ PSίϯςϯπ΁ ͸ͯͳ $.4 ίϯςϯπ
  4. ͸ͯͳCMSͷΞʔΩςΫνϟ֓؍ 15 ·Ί͖ͪ͠ ͸ͯͳϒϩάํ໘ͷϩʔυόϥϯαʔ͕ೋछྨ͋Δͷ͸ྺ࢙తܦҢͰ͢ɻ Ϣʔβʔ ϩʔυόϥϯαʔ ϓϩΩγ ͸ͯͳϒϩάόοΫΤϯυ 3&45"1* Ͱ௨৴

    ͸ͯͳ $.4 όοΫΤϯυ ͸ͯͳϒϩάهࣄ ͸ͯͳϒϩά؅ཧը໘ ͸ͯͳ $.4 ؅ཧը໘ ͸ͯͳ $.4 ؅ཧը໘΁ ͸ͯͳ $.4 ͷίϯςϯπ΁ ͸ͯͳϒϩά؅ཧը໘ PS Ϣʔβʔͷهࣄ PSίϯςϯπ΁ ͸ͯͳ $.4 ίϯςϯπ ผεϥΠυͰ঺հ ·ͨ͜ͷਤ͸ΠϥετͳͷͰҰ෦ϩʔυόϥϯαʔ΍Ωϟογϡαʔό͕লུ͞Ε͍ͯ·͢
  5. ͸ͯͳCMSͷΞʔΩςΫνϟ֓؍ 16 ·Ί͖ͪ͠ ࠓճ/FYUKTͷσϓϩΠʹ7FSDFM͸࢖͍ͬͯ·ͤΜɻ"NQMJGZΛࢼ͠͸͠·ͨ͠ Ϣʔβʔ ϩʔυόϥϯαʔ ϓϩΩγ ͸ͯͳϒϩάόοΫΤϯυ 3&45"1* Ͱ௨৴

    ͸ͯͳ $.4 όοΫΤϯυ ͸ͯͳϒϩάهࣄ ͸ͯͳϒϩά؅ཧը໘ ͸ͯͳ $.4 ؅ཧը໘ ͸ͯͳ $.4 ؅ཧը໘΁ ͸ͯͳ $.4 ͷίϯςϯπ΁ ͸ͯͳϒϩά؅ཧը໘ PS Ϣʔβʔͷهࣄ PSίϯςϯπ΁ ͸ͯͳ $.4 ίϯςϯπ ͸ͯͳCMSͷίϯςϯπͷϨϯμϦϯάͷ࿩୊͸ ผεϥΠυͰ঺հ
  6. લఏ: ͸ͯͳCMSͷલఏ • ૉૣ͍ࢢ৔౤ೖ͕ٻΊΒΕΔ • θϩ͔Β࢝ΊͯɺͦͷλΠϜϦϛοτ͸6ϲ݄ • ମݧ͕ॏࢹ͞ΕΔɺͦͯ͠ɺ࡞Γͳ͕ΒσβΠϯ΋ཁ݅΋٧Ί͍ͯ͘ • ϊʔίʔυΤσΟλΛඋ͑ͨCMSΛ࡞Δ͕ɺθϩ͔Β࢝ΊΔͷͰɺ

    ɹɹɹɹɹɹɹɹɹɹɹɹࡉ͔͍͜ͱ͸6ϲ݄ͷؒʹܾΊ͍ͯ͘ඞཁ͕͋Δ w w w w w w w w w w w w w w w w 18 ·Ί͖ͪ͠ σβΠφ͸໊Ͱ͕͢ɺര଎Ͱ։ൃͯ͠΋Β͑·ͨ͠ νʔϜͰಈ͘ΞϓϦέʔγϣϯΛ৮Γͳ͕Βɺ ٞ࿦Λͯ͠೔ʑվྑ͍ͯ͘͠
  7. લఏ: ։ൃ্ͷલఏ • ͸ͯͳϒϩά, ͸ͯͳϒϩάMediaͷϦιʔε, Πϯϑϥ͸׆͔͍ͨ͠ • ͸ͯͳϒϩά͸ྺ࢙ͷ͋ΔαʔϏεͰίʔυ͸ෳࡶ • ։ൃதʹ౰વɺ͸ͯͳϒϩάͷαʔϏε͸ಈ͔͠ଓ͚͍ͨ

    • ͔͠͠ɺ࢖͍͍ͨ৘ใ͸͋ΔʢϢʔβʔͷઃఆೝূೝՄ΍഑৴ΠϯϑϥͳͲʣ • ͜ΕΒ͸Ұ͔Β࡞͍ͬͯΔ༛༧͸ͳ͍ • গ਺ਫ਼ӶνʔϜͰͷ։ൃ • ࠓ೔ൃද͢Δϝϯόʔ͕ओཁ։ൃΤϯδχΞ + σβΠφ1໊ 19 ·Ί͖ͪ͠ ϒϩάνʔϜΛ͞Βʹಛ໋νʔϜʹ෼ׂ͢Δͱ͍͏ɺ͸ͯͳͰ͸௝͍͠έʔεͰͨ͠ ૣ͍Ŋ͏·͍Ŋ͍҆։ൃ͕Ͱ͖ͳ͍΋ͷ͔……ʁ
  8. νʔϜʹԠٕͨ͡ज़બఆ 21 ·Ί͖ͪ͠ σβΠφ͔Βͷٕज़બఆͷཁ๬ͱͯ͠MFTT͔ΒTBTT΁ͷมߋ΋͋Γ·ͨ͠ • νʔϜͷ࠷େެ໿਺͸TypeScript + React • νʔϜօϑϧελοΫΤϯδχΞΛͯ͠΋Β͏͜ͱʹͳΔ͕ɺ

    ϑϩϯτΤϯυΤϯδχΞدΓͷٕज़ελοΫͷ΋ͷ͕2໊͍Δঢ়ଶ • ɹ ͸TypeScriptͷ։ൃͷ஌͕ࣝਂ͘νʔϜΛݗҾͰ͖Δ • https://speakerdeck.com/nanimonodemonai • ͸ͯͳͰશࣾతʹNext.jsͷྲྀΕ͕͋ΔͷͰͷ͔͔ͬΔ • TypeScriptͰॻ͘ͱGitHub Copilot͕Α͘ؾΛར͔ͯ͘͠ΕΔ • ʢਖ਼௚ෆؾຯͳ͙Β͍ॻ͜͏ͱࢥ͍ͬͯΔίʔυॻ͍ͯ͘Εͯා͔ͬͨʣ
  9. Next.js App RouterΛ࢖ͬͨܦҢ 22 ·Ί͖ͪ͠ ॳΊͯ4FSWFS"DUJPO 34$ʹ৮Εͨϝϯόʔ΋ଟ͔ͬͨͰ͢ • App RouterͰ࢖͑ΔReactͷ࠷ઌ୺ػೳ͕։ൃΛߴ଎Խ͢ΔͨΊ

    • ଎͘ػೳΛ࣮૷Ͱ͖Δ → هࣄ؅ཧμογϡϘʔυͳͲʹ͸͏͚ͬͯͭ • ͦͷ͏ͪNext.js͸App RouterΛσϑΥϧτʹ͢ΔΒ͍͠ͷͰɺ ࠓճͷΑ͏ʹ΄΅৽ن։ൃͳΒ࢖͓͚ͬͯ͹কདྷͷҠߦίετ͸ͳ͍ϋζ • Server Action͸࡞Γ͍ͨػೳΛ؆୯ʹUIʹ݁ͼ͚ͭΒΕΔ • ͦͷ෼࢖͍ํʹ஫ҙ͠ͳ͍ͱ͍͚ͳ͍͕ɺര଎Ͱ։ൃͰ͖Δ • React Server Component΋ಉ༷ • React 19ͷػೳΛ࢖͑͹ɺզʑ͕ཉ͔ͬͨ͠΋ͷΛ௚ײతʹ࡞ΕΔ →ʮReact Server ComponentͰੜͷHTMLΛѻ͏ٕज़ʯεϥΠυ΁
  10. ͪΐͬͱ଴ͬͯɺϒϩάͱAppΛ෼ׂͯ͠ࠔΒͳ͍ͷʁɹͦͷ1 • Q. ίϯςϯπ഑৴γεςϜͷ։ൃΊͬͪΌେมʹͳΒͳ͍ʁ • A. • →ʲৄઆʳίϯςϯπ഑৴γεςϜͷෳ਺ػೳج൫΁ͷ֦ு ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ΁ଓ͘ •

    Q. ಉ͡Α͏ͳίʔυΛPerl͔ΒTypeScriptʹॻ͖௚͢ͱ͍͏͜ͱʹͳΒͳ͍ʁ • A. Ҋ֎ͳΒͳ͔ͬͨɻͱɺ͍͏ͷ΋ѻ͏΋ͷ͕ҧ͍͕େ͖͔͔ͬͨΒ 23 ·Ί͖ͪ͠ 6*෦෼͸ಉ͡ݟͨ໨ͷશ͘ผίʔυ͕͍͔ͭ͘Ͱ͖·ͨ͠
  11. ͪΐͬͱ଴ͬͯɺϒϩάͱAppΛ෼ׂͯ͠ࠔΒͳ͍ͷʁɹͦͷ2 • Q. ͸ͯͳϒϩάͱ͸ͯͳCMSͷ࿈ܞͷͨΊʹΤϯυϙΠϯτΛ͍ͬͺ͍ੜ΍ͨ͠ʁ • A. ͓Αͦ͜Ε͙Β͍ • ͸ͯͳϒϩάͷ؅ཧը໘ͷೝূͱೝՄͷϦετΛऔಘ͢Δ •

    ͸ͯͳϒϩάͷઃఆʢσϑΥϧτը૾ͳͲʣΛऔಘ͢Δ • ͸ͯͳϒϩάʹ͸ͯͳCMSͷهࣄ͕ߋ৽͞Εͨ͜ͱΛ௨஌͢Δ • ͸ͯͳϒϩάͷهࣄϦετΛऔಘ͢Δ 24 ·Ί͖ͪ͠ ͸ͯͳϒϩάͷόοΫΤϯυͰ͸ɺΤϯυϙΠϯτ͸3&45ʹ͢Δͷ͕࠷ળखͰͨ͠
  12. ϓϩτλΠϓΛى఺ʹΞδϟΠϧʹϓϩμΫτ΁࢓্͛Δ 26 ·Ί͖ͪ͠ ܭը͸(JU)VC1SPKFDUͰΨϯτνϟʔτ΋؅ཧ͠·ͨ͠ ܭը 2"࢓্͛ όάͱ ܰඍͳमਖ਼ ϓϩτλΠϓ࡞੒ ΤσΟλʹػೳΛ௥Ճ

    ػೳ௥Ճ ਐḿ֬ೝ ίϯςϯπ഑৴ "84΁σϓϩΠ ؅ཧը໘Λચ࿅ͤ͞Δ ΤσΟλݕ౼ ϖʔδදࣔ ϦϑΝΫλ ϢʔβʔೝূೝՄ ݄ ݄ ݄ ݄ ݄ ݄ ։ൃͷλΠϜϥΠϯ • 1िؒεϓϦϯτͷΞδϟΠϧ։ൃ • POͱ։ൃνʔϜͰߴ଎ṷ͖ͭͯ͠ɺϢʔβʔʹఏڙ͢Δ΂͖Ձ஋Λߟ͑Δ • ػೳΛ࡞ͬͨΒ͙͢ʹPO΋օ৮ΔνʔϜ • λΠϜϥΠϯΛݩʹʮ΍Δʯʮ΍Βͳ͍ʯΛνʔϜશһͰຖ೔࿩͢ੈք w w w w w Ϧ Ϧ ε 🎊
  13. ֩ͱͳΔϓϩτλΠϓͰԿΛ࡞͔ͬͨʁ ͦͷ1ʮΤσΟλʯ 27 ·Ί͖ͪ͠ 6OMBZFS΋։ൃதʹϦϒϥϯσΟϯάͨ͠ͱ͍͏ͷ͸ɺ·ͨผͷ࿩ • ϊʔίʔυͰ௚ײతͳฤूମݧΛϢʔβʔʹ༩͍͑ͨ • WYSIWYGͰυϥοά&υϩοϓͰ͖Δ •

    ΤσΟλબఆ • Unlayerͱ͍͏υϥοά&υϩοϓͰ͖ΔϓϩϓϥΠΤλϦϥΠϒϥϦΛར༻ • (ΤσΟλ·ͰࣗલͰ࡞Δͱઈରָ͍͠Μ͚ͩͲͶ…ऴΘΓ͕ͳ͍…) • → ԿΑΓՁ஋ͷఏڙ͕ॏཁ͔ͩΒ௻Δ͠ͷΤσΟλΛ࢖͏൑அΛ͠·ͨ͠ • ͱ͸͍͑ɺ͸ͯͳCMS޲͚ʹϑϧνϡʔϯ͍ͯ͠·͢ʂʂʂʂʂʂʂ https://unlayer.com/
  14. ϓϩτλΠϓͰػೳͷେମͷΞΠσΟΞΛݕূ͠·ͨ͠ 28 ·Ί͖ͪ͠ ϓϩτλΠϓ͸جຊతʹϖΞϓϩͰد͔ͬͯͨͬͯ࡞͍ͬͯ·ͨ͠ • ϓϩτλΠϓͷ࣌఺ʹग़དྷ্͕ͬͨػೳ͸ଟ͍ • ࣮ݱํ๏΋ͦΕͧΕ͓࿩͍ͨ͜͠͠ͱ͕͋Δ͕ɺ ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ·ͨผͷػձʹΏͬ͘ΓͰ͖Ε͹ •

    ͔ͩΒɺࠓ೔͸ૣޱͰ͝঺հͰ͝༰ࣻΛ • ͸ͯͳϒϩάͷΞʔΩςΫνϟΛܧঝ͍ͯͨ͠Βແཧͩͬͨ͜ͱ͕ଟ͍ϋζ • ͦΕ΋͜Ε΋͸ͯͳϒϩάͱ෼཭͔ͨ͠Βػೳ͕ͨ͘͞Μ࡞Εͨ • ૣ͍ஈ֊͔Βػೳ͕ग़དྷ্͕͍ͬͯͨͷͰPOͱͷػೳݕ౼΋ԁ׈ʹ
  15. ֩ͱͳΔϓϩτλΠϓͰԿΛ࡞͔ͬͨʁ ͦͷ2ʮCMSͷΨϫʯ 29 ·Ί͖ͪ͠ /FYUKTʹ͔ͯ͠ΒϋϚͬͨ݀͸4FDVSF"DUJPO*%Ͱͨ͠Ͷʜ • ϘΠϥʔϓϨʔτ͸turborepoͷNext.jsςϯϓϨ͔Β • ͸ͯͳϒϩάଆͰ࣮૷༧ఆͷΤϯυϙΠϯτΛmswͰϞοΫ͢Δ࢓૊Έ •

    Next.js 15ͳΒlayout.tsxͰmswΛlisten͢Ε͹αʔόʔαΠυͷfetch΋ϞοΫՄ • ϖʔδσβΠϯ͕Ͱ͖ΔલʹStorybookʹ࣮૷༧ఆͷίϯϙʔωϯτΛ࡞ͬͯ͠·͏ • React AriaͷΨϫΛ࡞ͬͨޙʹσβΠφʹελΠϧΛ͓೚ͤͨ͠ • PrismaͰޙ͔Βมߋ্౳Ͱσʔλϕʔεͷઃܭͯ͠CRUDͰ͖ΔΑ͏ʹ͢Δ • ೝূೝՄͷͳ͍Server ActionsΛ࡞ͬͯͱΓ͋͑ͣಈ͘΋ͷΛ࡞Δ • Ͱ΋valibotͰऔΓ͑ͳ͍ܕ͕ૹΒΕͳ͍Α͏ʹ஫ҙͨ͠ w w
  16. ֩ͱͳΔϓϩτλΠϓͰԿΛ࡞͔ͬͨʁ ͦͷ3ʮΤσΟλͷ޻෉ʯ 30 ·Ί͖ͪ͠ ͜ͷஈ֊͸શͯͷϖʔδͷͲ͔͜ʹ+40/จࣈྻ͕ฒΜͰ͍ͯͱͯ΋ࡶવͱ͍ͯͨ͠ • ΤσΟλʹϓϥάΠϯͱͯ͠ಡΈࠐΉJSΛϏϧυ͢Δ࢓૊Έ • tsupͰଈ࣮࣌ߦؔ਺ͱͯ͠Ϗϧυ͠·ͨ͠ •

    ֎෦ΤσΟλ(Unlayer)ͱ͸ͯͳCMSͱͷ࿈ܞ • ΤσΟλ͸iframeʹ͋ΔͷͰɺcomlinkͰpostMessage͢Δੈք • Ϩϯμʔͯ͠ϓϨϏϡʔ͢Δ࢓૊Έ • ΤσΟλ͕ు͖ग़ͨ͠HTMLΛJSDOMͰՃ޻ͯ͠ ɹɹɹɹɹɹɹɹɹɹɹhtml-react-parserͰReactίϯϙʔωϯτΛຒΊࠐΈ →ʮReact Server ComponentͰੜͷHTMLΛѻ͏ٕज़ʯεϥΠυ΁
  17. ࣮ࡍʹര଎ͰऴΘͬͯΑ͔ͬͨ 31 ·Ί͖ͪ͠ ͸ͯͳͰ͸ແࣄʹϦϦʔε͕Ͱ͖ΔͱༀۄΛഁΔश׳͕͋Γɺࠓճ΋ׂΓ·ͨ͠🎊 • ϓϩτλΠϓ͕ศརͳΒ͹ɺޙ͸࡞Ε͹࡞Δ͚ͩΑ͘ͳΔ • ʮ΍Δʯʮ΍Βͳ͍ʯ͕൑அ͠΍͍͢ • ࡞Δͷ͕ͲΕ΄Ͳ೉͍͔͠Πϝʔδ͕͔ͬͪΓ͢Δ

    • ि͝ͱʹػೳ͕ͲΜͲΜͰ͖Δ • ࡞Δͷ͸ָ͔ͬͨ͠ɺ͔͠͠εϐʔυʹऔΓጪ͔Ε͍ͯΔ͔΋͠Εͳ͍ • গਓ਺খن໛͔ͩΒɺ͓ޓ͍ʹԿΛ΍͍ͬͯΔͷ͔Θ͔͍ͬͯΔঢ়ଶ • ͕ͨͬͯ͠ϦϑΝΫλϦϯάແ͠Ͱ΋։ൃʹۤ͠Έ͕ͳ͍ • ϦϑΝΫλϦϯάͷ࣌ؒΛҙࣝͯ͠ͱΒͳ͍ͱ ɹɹɹͰ͔͍fat service͕ग़དྷ্͕ͬͯকདྷ΁ͷՒࠜΛ࢒͢ʢҰ౓΍ͬͨʣ • ୹ظ͔ؒͩΒɺԿΛ࡞͕ͬͨશͯ೴ʹೖ͍ͬͯΔ • ͜Ε΋ۤ͠Έ͕ͳ͍ͷͰυΩϡϝϯτ͕ޙखޙखʹͳ͍ͬͯΔ
  18. ·ͱΊ 33 ·Ί͖ͪ͠ ʮ·Ί͖ͪ͠ʯίʔφʔͷಋೖ͸ɺ • ͸ͯͳCMS͸ɺ͸ͯͳϒϩάMedia͔ΒϦϒϥϯσΟϯά • ߹ΘͤͯΞϓϦέʔγϣϯ΋࡮৽ • ద੾ʹΞϓϦέʔγϣϯΛ෼ׂͨ͠ͷͰগਓ਺Ͱ΋ര଎։ൃ

    • ૉૣ͘Ձ஋Λಧ͚Δ͜ͱ͕Ͱ͖ͨ • ։ൃʹ͓͚Δڵຯਂ͍ٕज़͸͜ͷޙ঺հ εϥΠυதʹεϥΠυ֎ͷ͜ͱΛޱ૸Βͳ͘ͳΔͱ͍͏ޮՌ͕͋Γ·͢