Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
はじめてのSSR
Search
Taketoshi Aono(青野健利 a.k.a brn)
August 31, 2017
Programming
3
1.2k
はじめてのSSR
React + ReduxでSSR+Isomorphicなアプリケーションを作ったときにつまづいた点をまとめました。
Node学園27時限目
Taketoshi Aono(青野健利 a.k.a brn)
August 31, 2017
Tweet
Share
More Decks by Taketoshi Aono(青野健利 a.k.a brn)
See All by Taketoshi Aono(青野健利 a.k.a brn)
document.write再考
brn
6
3.1k
Parsing Javascript
brn
14
9.4k
JSON & Object Tips
brn
1
520
CA 1Day Youth Bootcamp for Frontend LT
brn
0
990
Modern TypeScript
brn
2
830
javascript - behind the scene
brn
3
760
tc39 proposals
brn
0
900
プロダクト開発とTypeScript
brn
8
3k
React-Springでリッチなアニメーション
brn
1
720
Other Decks in Programming
See All in Programming
Tangible Code
chobishiba
3
490
Blazing Fast UI Development with Compose Hot Reload (Bangladesh KUG, October 2025)
zsmb
2
490
エンジニアに事業やプロダクトを理解してもらうためにやってること
murabayashi
0
140
Inside of Swift Export
giginet
PRO
1
520
Vue 3.6 時代のリアクティビティ最前線 〜Vapor/alien-signals の実践とパフォーマンス最適化〜
hiranuma
2
410
予防に勝る防御なし(2025年版) - 堅牢なコードを導く様々な設計のヒント / Growing Reliable Code PHP Conference Fukuoka 2025
twada
PRO
32
9.9k
歴史から学ぶ「Why PHP?」 PHPを書く理由を改めて理解する / Learning from History: “Why PHP?” Rediscovering the Reasons for Writing PHP
seike460
PRO
0
130
Register is more than clipboard
satorunooshie
1
430
Private APIの呼び出し方
kishikawakatsumi
2
660
MCPサーバー「モディフィウス」で変更容易性の向上をスケールする / modifius
minodriven
7
1.2k
GitHub Copilotを使いこなせ!/mastering_github_copilot!
kotakageyama
2
850
フロントエンド開発のためのブラウザ組み込みAI入門
masashi
7
3.7k
Featured
See All Featured
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
Speed Design
sergeychernyshev
32
1.2k
Done Done
chrislema
186
16k
We Have a Design System, Now What?
morganepeng
54
7.9k
jQuery: Nuts, Bolts and Bling
dougneiner
65
8k
How STYLIGHT went responsive
nonsquared
100
5.9k
Unsuck your backbone
ammeep
671
58k
GitHub's CSS Performance
jonrohan
1032
470k
Designing Experiences People Love
moore
142
24k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Building a Scalable Design System with Sketch
lauravandoore
463
33k
Code Review Best Practice
trishagee
72
19k
Transcript
ⴱ ג ך S S R
せ: @brn (ꫬꅿ⨳ⵃa.k.a ـٕ٦ظ) 耵噟: ؿٗٝزؒٝسؒٝآص،٥iOSؒٝآص، ⠓爡: Cyberagent ،سذؙأةآؔRightSegment٥AI Messenger
ـؚٗ: http://abcdef.gets.b6n.ch/ Twitter: https://twitter.com/brn227 GitHub: https://github.com/brn
⡦⠗ְִךַ ְׂSSR׃״ֲהׅהꬊ䌢ח넝䏝זֿה׃גְ鎸✲כ״ֻ 鋅ַֽךָծ ⴱ娄涸ז㉏겗ח瘶ִגְךָ㼰זְ״ֲח䙼ִկ זךדծSSR+Isomorphicז圓䧭ד،فٔ⡲♳ד䝢ֿהծ 㹋ꥷח鍑寸׃倯岀⚛ץגկ
Language ְא鸐typescript鼅䫛׃կ ֿ荈⡤כNodeJS⩎הـٓؐؠ⩎דٌرٕךinterface㹀纏ָ⢪ְת ׇגꬊ䌢ח葺ַկַזىأָ幾կ 暴חAPIךٖأهٝأךأؗ٦وⰟ鸐ךٌآُ٦ٕחInterfaceה ׃ג㹀纏ׅהծ 涸חAPIךؒٓ٦鋅אֽךד葺ְկ
Library/Framework ـٓؐؠ⩎כReact(v16.0β) + Redux + React-Router v4 ؟٦غ؟؎سכExpress + Sequelize
+ MySQL NodeJSך湊鋔כsupervisord
Structure ֿֿכꬊ䌢ח䝢կָծ 如ل٦آך״ֲז圓䧭ח׃կ
server NodeJSך؟٦غ٦㹋鄲 DB،ؙإأהַ client ـٓؐؠ⩎ך㹋鄲 React + Redux isomorphic NodeJSהـٓؐؠ⩎דⰟ鸐ׅ㘗㹀纏הַ
Root rendering SSR欽ך؟٦غ٦
HTML Rendering Reactך؝ٝه٦طٝزכ֮ךָծHTMLةؚろⰋ⡤ךٖ ٝتؚٔٝוֲַׅ䝢կ 穠㽷HTMLةؚװHeadةؚReactד㹋鄲׃גծ؟٦غ؟؎سדٖ ٝتؚׅٔٝة؎ىؚٝךծך؝ٝه٦طٝز⢪կ
data-reactid HTMLⰋ⡤Reactדٖٝتؚׅٔٝהـٓؐؠ⩎דmountׅה ֹחdata-reactidָ׆גWarningָדָծ React v16ַכdata-reactid涪遤׃זֻזךדWarningָ嶊 ִկ
Redux State of SSR SSRדⴱ劍朐䡾ٖٝتؚׅٔٝחծ 剑ⴱכ؟٦غ؟؎سדdbַ《䖤׃ؒٝذ؍ذ؍湫䱸床׃גְ կ ׃ַ׃ծֿהAPIؒٝسه؎ٝزך✳ꅾ盖椚ָ涪欰ׅկ
viewָ《䖤ׅر٦ةָ㢌הֹחծ ؟٦غ⩎ךؒٝذ؍ذ؍《䖤鿇ⴓ⥜姻ָ䗳銲ד✳ꅾ盖椚חזկ APIエンドポイント DB React ؒٝذ؍ذ؍湫䱸《䖤 Reactח床ׅ ブラウザ
Redux State of SSR DRYחװծ 㹋ꥷחredux-saga⹛⡲ׇׁג؟٦غ٦ⰻדlocalhostד荈魦ךؒٝ سه؎ٝز〨ְկ fetch⢪גְךדծisomorphic-fetchػح؛٦آⵃ欽կ
ٖؔٝآ葿ך鿇ⴓָRedux-Sagaַךؿٗ٦ 㹋ꥷחlocalhostח،ؙإأ׃גծ ⰻ鿇דֲ♧䏝ずׄؒٝسه؎ٝز〨ֻկ APIエンドポイント DB React Redux-Saga⹛ַׅ X-Rest-Requestقحت➰♷׃ 㹋ꥷחAPIؒٝسه؎ٝز localhostחぢַג〨ֻ
ブラウザ JSON ؒٝذ؍ذ؍ך《䖤
Redux State of SSR ؟٦غ٦כ鵤ׅ⦼SSRךٖٝتؚٔٝ穠卓הծJSON勴⟝ח״ ג㢌ִזֽלזזְկ 剑ⴱכGetػًٓ٦ة⢪גְָծ 植㖈כقحتחX-Rest-Request: 1鏣㹀ֿׅהד㔐鼘׃גְկ ֮הծأومהPCד鵤ׅⰻ㺁ָ麩ֲךדծ
User-Agentقحتח䩛⹛ד؟٦غ٦ַ䒷ֹ竰ְUserAgent إحزׅկ
Redux Initial state SSRׅהׅדח歗חכStateָٖٝتׁؚٔٝגְ朐䡾זך דծⴱ劍朐䡾ך《䖤כأؗحف׃ְկ
State as JSON ת׆ծ؟٦غ؟؎سדٖٝتؚٔٝ׃穠卓ךReduxךStatehtml חJSONה׃ג㙵鴥דծinitialStateה׃גⵃ欽׃կ
const initialState = JSON.stringify(state);! ! <script type="text/javascript"! dangerouslySetInnerHTML={{! __html: `window.__INITIAL_STATE__
= ${initialState}}`! }} />!
State as JSON 如חծcomponentDidMountךة؎ىؚٝדhistory.stateָ瑞 ⴱ㔐ٖٝتؚٔٝהⴻ㹀׃גծ 植㖈ךstatehistory.replaceדhistory.stateח鏣㹀׃կ
Page1 history Page2 history state Page3 history state state וךل٦آחٓٝر؍ؚٝ׃גhistory.stateָ搀ְل٦آָծ
SPAך饯挿הזل٦آחזկ Page2 history Page1 history state Page3 history state state
React-Router V4 㹋ꥷח؟٦غ؟؎سדוך؝ٝه٦طٝز䲽歗ַׅծ וךAPI〨ַֻ寸חכծ React-Router v3דכmatch⢪ֲ鎸✲כְםְ֮ךָծ React-Router v4דכmatchָ䐖姺ׁגְկ זךד➿חmatchPath⢪ֲկ
import {! matchPath! } from 'react-router';! ! const match =
matchPath("/article/1", {! path: '/articel/:articleId',! exact: true! });! ! if (match) {! console.log(match.params)! // Object { articleId: 1 }! }!
React-Router V4 ׃ծֿך倯岀הـٓؐؠךٕ٦ذ؍ؚٝהNodeJSךٕ٦ذ؍ ؚٝד✳ꅾ盖椚חזג׃תֲךדזהַ׃ְ…
Webpack typescriptד㹋鄲׃ծNodeJS⩎typescriptד㹋鄲׃ְկ ׁחWebpackדcss-modules⢪גְךדծWebpack⢪ זְהSSRָ⹛ַזְկ זךדWebpackדכtargetnodeח䭷㹀ֿׅהדծ__dirname 笝䭯׃אאnode_modules⟃㢩ך؝٦سbundle׃կ
module.exports = { entry: { server: './server/index.ts' }, target: 'node',
externals: /^(?!^\.\.?\/)/, output: { path: `${__dirname}/dist`, filename: "[name].js", libraryTarget: "commonjs2" }, resolve: { extensions: [".js", ".ts"] } }
Watch Webpackדwatch׃גְךָծ♧אךؿ؋؎ָٕ㢌刿ׁ ֽד؟٦غ٦ծؙٓ؎،ٝز⚕倯ָⰋגⱄ؝ٝػ؎ׁٕג礵牞遹 欰♳״ֻזְךהծ SSR遤ֲ鿇ⴓך頾蚚ֽ넝ְךדծSSRֽׁח؟٦غג גفٗإأⴓꨄ׃կ
Requst SSR Response HTML Supervisord Renderingサーバ Renderingサーバ Renderingサーバ Supervisord APIサーバ
APIサーバ APIサーバ
Cache ⽃秪חNginxהAppךחmemcached 䮠דծ $request_uri--$is_mobile ְז䠬 ׄךؗ٦ד⥂㶷׃גⱄⵃ欽կ
Nginx memcached Node $host$request_uri--$is_mobile ؗ٦חٍؗحءُ嗚稊 זֽלٖٝتؚٔٝ x-memcached-keyח memcachedךؗ٦إحز x-memcached-keyقحت ך⦼ؗ٦ח⥂㶷
SEO react-lazyload⢪גְךדծ GoogleװBotך،ؙإأך㜥さכ lazyload㐣תׇזְ穠卓鵤ׅ״ֲ חծ react-lazyloadٓحف׃؝ٝه٦ طٝز⢪կ
public render() {! return !this.props.shouldRenderStatic! && this.props.isMobile ? (! <LazyLoad
{...this.props}>! {this.props.children}! </LazyLoad>! ) : this.props.children;! }!
תה SSRכװםזח؝أزָ䱦ַז֭הְֲ䠬䟝կ 葿ղ孡⢪ֲֿה㢳ְ׃ծ 劤䔲ח䗳銲חזתדכװץֹדכזְկ 暴חؿٗٝزؒٝسך؝٦سָ؟٦غד⹛ֻךדծ䌢ח➙ـٓؐ ؠזךַNodeJSזךַ䠐陎ׅךָ⦜կ ׀幠耮ָ֮הֲ׀ְׂת׃կ