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
3k
Parsing Javascript
brn
14
9.2k
JSON & Object Tips
brn
1
490
CA 1Day Youth Bootcamp for Frontend LT
brn
0
940
Modern TypeScript
brn
2
800
javascript - behind the scene
brn
3
740
tc39 proposals
brn
0
870
プロダクト開発とTypeScript
brn
8
2.9k
React-Springでリッチなアニメーション
brn
1
690
Other Decks in Programming
See All in Programming
ドメインモデリングにおける抽象の役割、tagless-finalによるDSL構築、そして型安全な最適化
knih
11
1.9k
事業戦略を理解してソフトウェアを設計する
masuda220
PRO
22
6.2k
Elixir で IoT 開発、 Nerves なら簡単にできる!?
pojiro
1
150
複数アプリケーションを育てていくための共通化戦略
irof
10
4k
地方に住むエンジニアの残酷な現実とキャリア論
ichimichi
2
540
Effect の双対、Coeffect
yukikurage
5
1.4k
2度もゼロから書き直して、やっとブラウザでぬるぬる動くAIに辿り着いた話
tomoino
0
160
KotlinConf 2025 現地参加の土産話
n_takehata
0
100
型付きアクターモデルがもたらす分散シミュレーションの未来
piyo7
0
800
Javaに鉄道指向プログラミング (Railway Oriented Pro gramming) のエッセンスを取り入れる/Bringing the Essence of Railway-Oriented Programming to Java
cocet33000
2
580
「ElixirでIoT!!」のこれまでとこれから
takasehideki
0
370
エラーって何種類あるの?
kajitack
5
260
Featured
See All Featured
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Why Our Code Smells
bkeepers
PRO
337
57k
YesSQL, Process and Tooling at Scale
rocio
173
14k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
920
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
35
2.3k
Visualization
eitanlees
146
16k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
16
940
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.9k
The World Runs on Bad Software
bkeepers
PRO
68
11k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Testing 201, or: Great Expectations
jmmastey
42
7.5k
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זךַ䠐陎ׅךָ⦜կ ׀幠耮ָ֮הֲ׀ְׂת׃կ