React+jQuery+Railsã®SPAããµã¼ããµã¤ãã¬ã³ããªã³ã°ã«ç§»è¡ãã件ï¼ãã®3ï¼è¨è¨å¤æ´ç·¨ï¼
2åã«æ¸¡ã£ã¦æ¸ãã¦ããSSRåã®ã話ããä»åã§ã©ã¹ãã§ã(`ï½¥Ï・´)
ï¼ååï¼
parrot.hatenadiary.jp
ï¼ãµã¤ãï¼
ccpts.parrot-studio.com
ï¼ä¿®æ£ããã³ã¼ãï¼
github.com
æ£ç´ãååã®è©±ã§ãSSRã®è¨è¨ã«ãããä¸çªã®èãã¯æ¸ãã¦ããã®ã§ããã
ä»æ¥ã®ä»¶ãããã¯ããã§éè¦ãªãã¤ã³ãã§ã¯ããã®ã§ã
é å¼µã£ã¦æ¸ãã¦ããã¾ã...Ï(ï½¥Ïï½¥ï½)
ååã®è©±ããSSRã«é¢ããããã¨ä¸è¬çãªè©±ãã ã£ãã®ã«æ¯ã¹ã
ä»åã®è©±ã¯ãccptsã®ä»æ§ãã¢ã¼ããã¯ãã£ã«ä¾åãã話ããå¤ãã®ã§ã
ä¸ã¤ã®åèäºä¾ã¨ãã¦æãã¦ããã ããã°
ããä¸åº¦æ®µåãã復ç¿ãã¦ããã¨ããããªæãã§ãã
- ãã©ã¦ã¶ç³»ãªãã¸ã§ã¯ãã®æé¤ï¼ã¨ããããå®è¡æã¨ã©ã¼ãæ¶ãï¼
- ãä»æ§ä¸ã®æ£ããåä½ãã«ãªãããã«ä¿®æ£
- ã¤ã³ãã©ã®èª¿æ´
ä»åã¯æ®ãã®STEP2ã¨STEP3ã®ã話ã§ã
STEP2ï¼SSRãåæã«ããè¨è¨ã®å¤æ´
STEP1ã®æç¹ã§ãã¨ããããã®è¡¨ç¤ºãã¯ã§ãã¦ããã®ã§ããã
å½ç¶ãã¢ããªã®ä»æ§ã¨ãã¦åé¡ã®ããç®æãå±±ã»ã©ããã¾ã
ä»æ§ã«ä¾åããé¨åã ã£ããã以åã®ææãã®ä¿®æ£ã ã£ããããã®ã§ã
ãã¾ãä¸è¬çã§ã¯ãªãããããã¾ããããä¸ã¤ãã¤ãã£ããã¨ãè¦ã¦ããã¾ã
(1) Cookieå¨ãã®è¨è¨å¤æ´
ååã¯ãparseããå¡ã丸ãã¨æ¸¡ããã¿ãããªéãªå®è£
ããã¾ãããã
ãã¡ããããã§ã¯ãã¡ã»ã»ã»ã£ã¦ãã¨ã¯ãªãã§ããã
ãæåã®æç»ãå
¨ã¦SSRåãããã¨ããæèã§ã¯ããããããã¾ãã
Cookieã管çãã¦ãããã¼ã¿ãparseãã
ããã«å¯¾å¿ãããã¼ã¿ãåå¾ããã¨ããã¾ã§ãµã¼ãã§ããå¿
è¦ãããããã§ã
ï¼ä»ã¾ã§ï¼
- ã¯ã©ã¤ã¢ã³ãã®åæå¦çã§Cookieãparse
- å¿ è¦ãªãã¼ã¿ããµã¼ãAPIã«åãåãã
- åãåããã®ãã£ãã¯ã¨ãªã«å¯¾ãããã¼ã¿ãåå¾
- APIã®å¿çã¨ãã¦ãªã¹ããè¿ã
- ã¯ã©ã¤ã¢ã³ãã®æä½ã«ããCookieãæ´æ°
ï¼æ°ããããæ¹ï¼
- ãµã¼ãå´ã§Cookieãparse
- Cookieã«å«ã¾ããæ å ±ã«å¯¾å¿ãããã¼ã¿ãåå¾
- Reactã®åæå¤ã¨ãã¦ãªã¹ãã渡ã
- ã¯ã©ã¤ã¢ã³ãã®æä½ã«ããCookieãæ´æ°
å¾ããæä½ã«ãã£ã¦åçã«å¤ããé¨åã¯ä»ã¾ã§éãã®ããæ¹ãªã®ã§ããã
æåã«ã¬ã³ããªã³ã°ããæ
å ±ã ãããµã¼ãã®ãã¼ã¿å¦çãå
è¡ããå½¢ã§ã
ãã ã¾ããããã«é¢ãã¦ã¯ãæ¬è³ªçã«å¤§ããªè¨è¨å¤æ´ã§
ãã¯ã©ã¤ã¢ã³ãã ããç¥ã£ã¦ããã°è¯ãã£ãæ
å ±ãããµã¼ããç¥ãå¿
è¦ããããã
è¨ããããã°ãããµã¼ãã»ã¯ã©ã¤ã¢ã³ãéã®ç·å¼ããå´©ãããã£ã¦è©±ãªãã§ãããã»ã»ã»
ãããããããµã¼ãã¯APIãæä¾ããã¯ã©ã¤ã¢ã³ãã§ä¸»è¦ãªãã¸ãã¯ãçµããã¨ããè¨è¨ã§ã
Cookieã管çããæ
å ±ã¯ã¾ãã«ãã¯ã©ã¤ã¢ã³ãã ããç¥ã£ã¦ããæ
å ±ãã ã£ãã®ã§ã*1
ï¼ä¾ï¼ããæ°ã«å
¥ãããPTæ§æä¿åãçï¼
æ¬å½ã¯ãã¾ãçãªé¢ä¿ã«ã§ããã°ããã¨æããã
ããæ¹ã¯ããã¨æãã®ã§ããã
ä»åã®ç®çã§ãããå®å
¨SSRåããåªå
ãã¾ãã
(2) ã¤ãã³ãã®è¦ç´ãï¼componentDidMountã®æé¤ï¼
ãjQuery.ready()ãã®æ代ããã³ã¼ããç©ã¿è¶³ãã¦ããã®ããã£ã¦ã
componentã®åæå¦çãcomponentDidMountã«æ¸ããã¦ããã±ã¼ã¹ãå¤æ°ããã¾ãã
ï¼ä¾ï¼componentDidMountã®ä¸ã§åæãã¼ã¿ãBacon.Busã«æµãï¼
ããã¯componentå士ãçã«ããããã«ã¯é½åãè¯ãã£ãã®ã§ããã
ãµã¼ããµã¤ãã§ã¯componentDidMountãåãã¨ãããã¤ãã³ããã¯åä½ãã¾ãã
ã¤ã¾ãããã®ã¾ã¾ã§ã¯åæåå¦çãèµ°ãã¾ãã(´-Ï-)
è¦ã¯ããå
¨ã¦ãSSRåãããããã«ã¯ã
ãæåã«è¡¨ç¤ºããããã¼ã¿ãã¯å
¨ã¦componentã®propsã«æ¸¡ããããªãããã§ã
ï¼å人çã«ã¯ããã¹ãã§ã¯ãªããã©ãç®çã®ããã«ã¯ãã¿ã¼ãããã®æãã§ï¼
constructor(props: AppViewProps) { super(props) // ... // constructorã§ãµã¼ãããåãåã£ãqueryStringãmodelã«å¤æ // queryStringããã©ã¦ã¶ã®æ¦å¿µãªã®ã§ããµã¼ãããæ示çã«ã¯ã©ã¤ã¢ã³ãã«æ¸¡ãå¿ è¦ãã this.query = Query.parse(this.props.queryString) // ... } private renderConditionView(): JSX.Element | null { if (!this.state.showConditionArea) { return null } return ( // ã¯ã¨ãªmodelããã©ã¼ã ã«æ¸¡ãã¦æç» // 以åã 㨠Bacon.Bus ãçµç±ãã¦ãã¼ã¿ãéã£ã¦ããã®ã§ãpropsã§æ¸¡ãå¿ è¦ããªãã£ã <ConditionView originTitle={this.props.originTitle} query={this.query} switchMainMode={this.switchMainMode.bind(this)} /> ) }
ã¾ããåæ表示以éã¯ä»ã¾ã§éãã
Bacon.Busçµç±ã§ã¹ããªã¼ã ã¨ãã¦ãã¼ã¿ãæµãã¦ããã®ã§ã
ç´ç²ãããé¨åã¨ç¾å®çãªé¨åã§è½ã¨ãã©ãããè¦ã¤ããããã®ããªã»ã»ã»ã¨ãã¦ããã¾ããã
(3) ç¶æ 管çã®ææããæ¹å
ãã®ãããã¾ã§ããã¨ãSSRã«é¢ä¿ãªã話ãªã®ã§ããã»ã»ã»
ãjQuery.ready()ãã®æ代ããã³ã¼ããç©ã¿è¶³ãã¦ããã®ããã£ã¦ã
ãããããå
¨ã¦ã®æ§é ãæç»ãã¦ããã¦ã
åæå¦çãä½ããã®ã¤ãã³ãã§hide/showããã»ã»ã»ã¨ããè¨è¨ãããªãæ®ã£ã¦ã¾ãã
å¾ããã®å¶å¾¡ã¯ã¨ãããã
åæå¦çï¼ï¼componentDidMountï¼ã§è¡¨ç¤ºã管çããã¨SSRã§ãããããªãã®ã§ã
å³å¯ã«props/stateã«ä¾åãã管çã«å
¨ã¦ç§»è¡ããã¾ãã
ããã¯ãããReactåããæã®ããæ®ãã¨ãããææãã®ãã©ãã¼ã«è¿ãã®ã§ããã
éã¨ã¯ããåé¡ãªãåãã¦ãããã®ã§ãã£ã¦ãã
SSRåããéã«ã¯å³å¯ã«æ¸ããªãã¨ãã¡ã£ã¦ãã¨ã§ã(´-Ï-)
çµæçã«ãcomponentDidMountçã«æ®ã£ãã³ã¼ãã¯ã
ï¼ååã®ï¼Browserã«ä¾åããã³ã¼ãã ãã«ãªãã¾ããï¼è¦ãç®ã¨ããã¤ãã³ããã³ãã©ã®ã»ããã¨ãï¼
ã¤ã¾ãããã©ã¦ã¶ã§ããåä½ããªãã¦ãåé¡ãªãã»ã»ã»ã¨ãããã¨ã§ã
export default abstract class ArcanaRenderer<T> extends React.Component<T> { protected div: HTMLDivElement | null = null public componentDidMount(): void { if (this.div) { Browser.hide(this.div) Browser.fadeIn(this.div) } } public componentWillUpdate(): void { // æ´æ°ãããæã¯ãã£ããæ¶ã if (this.div) { Browser.hide(this.div) } } public componentDidUpdate(): void { // åãã¦ã³ããããæã«ãã§ã¼ãã¤ã³ if (this.div) { Browser.fadeIn(this.div) } } // ... }
ä¸å¿ãã©ãã¼ãã¦ããã¨ãSTEP1ã®æã®å¤æã¨åãã§ã
以åã¯ãä»åã®ç®çã¯ã¨ã«ããReactã§åä½ããããã«ãããã¨ã§ã
ç´°ããè¨è¨ã®ç²ã¯æ°ã«ããªããã¨ããããªã·ã¼ã ã£ãã®ã§ã
ãå³å¯ã«ãããã£ã¦ã®ã¯ç¸å¿ã®ã³ã¹ããããã話ãªã®ã§ã
ãç®çã«åããã¦ç¾å®çãªã³ã¹ãã«è½ã¨ãè¾¼ããã£ã¦ã®ãã
ãéç¨ããã¦ããã¨ãã観ç¹ã§ã¯å¿
è¦ãªã®ããªã¨
(4) å®å ¨ãªã¬ã¹ãã³ã·ãå
ãããããæå³ææããç´ããã ããªã®ã§ããã»ã»ã»
ä»ã¾ã§ãåæå¦çã¨ãã¦windowãµã¤ãºãè¨ç®ãã
ä¸å®ã©ã¤ã³ãè¶
ããããæºå¸¯ã¢ã¼ããã§è¡¨ç¤ºãããã£ã¦ã®ããã£ã¦ã¾ãã
ï¼windowsãµã¤ãºãå
ã«ãã©ã°ã§ç®¡çï¼
å½ç¶ãããã¯windowãªãã¸ã§ã¯ãã«è§¦ããªãSSRã§ã¯éç¨ããªãã®ã§ããã
ã¨ããããPC/ã¿ãã¬ããç¨ã«æç»ãã¦ã
ãã©ã¦ã¶å´ã®åæå¦çã§ä¿®æ£ããã°ã»ã»ã»ã¨æã£ããããã¾ããããΣ(ï¾Ðï¾)カï¾ï½°ï¾
SSRã§åãåºããDOMã¨ãå¾ããèªã¿è¾¼ãã Reactï¼on Railsï¼ãå¦çããDOMã§ã
å·®åãããã¨warningãåºãã®ã§ãããæºå¸¯ãµã¤ãºã ã¨å¤§éã®warningãåºããã
ããããæåããããããªãã®ã§ã
çµå±ãæ£ããå½¢ã§BootStrapã®ã¬ã¹ãã³ã·ãæ©è½ãé©ç¨ãã¾ãã
private renderMember(): JSX.Element { const m = this.props.member // 両æ¹åºåãã¦ãbootstrapã®hiddenã¯ã©ã¹ã«å¶å¾¡ãä»»ãã if (!m) { return ( <div> <div className="none hidden-sm hidden-md hidden-lg summary-size arcana" /> <div className="none hidden-xs full-size arcana" /> </div> ) } // ... }
ãã£ã¨åæã®ã¨ãããããã¾ãããåºæ¬çãªæ¹éã¯ãããªã£ã¦ã¾ã
ç¶ã足ãããã³ã¼ãã®å¼å®³ã¨ãã£ã¦ã¿ãã°ããã¾ã§ã§ããã
ããã©ã¦ã¶ã¨ããç°å¢ãããããã«æé»çã«ãç¡æèã«ã
åæã«ç½®ãã¦ãããã»ã»ã»ã¨ãããã¨ã§ãããã¾ã(´-Ï-)
STEP3ï¼Webãµã¼ãã®ãã¥ã¼ãã³ã°
ããã¾ã§ã§ã³ã¼ãã¬ãã«ã§ã¯ã ããããªãªã¼ã¹æ°´æºã«éããã®ã§ã
åé¡ãªããã¨ã確èªãããããstagingç°å¢ã«ãããã¤ããã®ã§ããã
ãã¯ãããããåé¡ãåºã¾ããΣ(ï¾Ðï¾)カï¾ï½°ï¾
(1) Nginxã®ãã£ãã·ã¥
ä¸åç®ã®è¡¨ç¤ºã¯åé¡ãªãã®ã«ãäºåç®ä»¥éã«ã¨ã©ã¼ãåºãåé¡ãçºçãã
ã¨ã©ã¼ã¡ãã»ã¼ã¸ã§ã°ã°ã£ãã¨ããããããªè©±ã
SSRã§å·¨å¤§ãªHTMLãproxyå
ãåãåºããããã
ãã£ãã·ã¥ã使ãããããã«ãªã£ããã
ãã¼ããã·ã§ã³ã«åé¡ããã£ãã¨ãããã¨ã§ã
ã¤ã¾ããstagingç°å¢ã§ä»ã¾ã§ãã£ã¹ã¯ãã£ãã·ã¥ã¯ä½¿ã£ã¦ãªãã£ãã®ã«ã
SSRåãã¦HTMLã大ãããªã£ããããã£ãã·ã¥ã«éããå¿
è¦ãåºããã¨ãããã¨ã§ã
æ¬çªã®ãã¼ããã·ã§ã³ã¯ç¹ã«åé¡ãªãã£ãã¨ã¯ããã
ããããã¹ãã¬ã¼ã¸ã¸ã®æ¸ãè¾¼ã¿ãçºçããæç¹ã§ã¾ããã®ã§ã
ãã£ãã·ã¥ã大ããã«è¨å®ããªããã¾ãã
(2) CPUã®è² è·ï¼æªè§£æ±ºã»å éãï¼
åé
ã®åé¡ãããåºãªããã¨ã確èªããã®ã¨ã
ã¡ããã©æ¥åã§ããã©ã¼ãã³ã¹çãªåé¡ãåºããã£ã¦ã®ããã£ãã®ã§ã
ã¤ãã§ã«stagingç°å¢ã§ãã³ããã¼ã¯ãã¨ã£ã¦ã¿ã¾ãã
ããã¨ãRubyã®ããã»ã¹ã®CPU使ç¨éããããå¢ãã§ä¸ãã£ã¦ããã
ä½åº¦ãå®è¡ãã¦ããã¨ãã¬ã¹ãã³ã¹ã大å¹
ã«é
延ãããã
è©°ã¾ã£ã¦ã¨ã©ã¼ã«ãªã£ã¦ãã¾ããã¨ã(lllï¾Ðï¾)
ããªãç¡è¶ãªå©ãæ¹ããããã¨ã¯äºå®ã§ããã
æã£ããããRubyããã»ã¹ã®ä¸ã§execjsã®å¦çãå®è¡ãããã®ãéãããã§ã
ããã°ã£ããã¯ä»çµã¿ã®åé¡ã§ããã
ããããæåããRubyã§viewãä½ãã°åé¡ãªãããã§ããã
ä»åã¯SSRåèªä½ãç®çã§ãããããµã¤ãã®è¨ªåã¯çç¡ãªã®ã§ãæ°ã«ããªããã¨ã«
ããç¨åº¦ã¢ã¯ã»ã¹ãå¤ããããªãã°ã
viewã¬ãã«ã®ãã£ãã·ã¥ãå
¥ãã¦ããå¿
è¦ãããã¨æãã¾ããã
æçµçã«execjsã«HTMLåºåå¦çãæããé¢ä¿ã§ãRailsã®ãã£ãã·ã¥ãçããã¥ããæ§é ã§ã
ã¾ãã«ãä½ã£ã¦éç¨ãããã¨ãããããããåé¡ãã§ããã
ãããããã£ãã ãã§ãåç©«ãªã®ã§ããã
ãã£ã±ãSSRã¯ããããé£ããã§ããã»ã»ã»(´-Ï-)
ã¾ããç¾å®ã«ã¯ããã¾ã§å¤§ããªã¢ã¯ã»ã¹ããªããµã¤ãã§ããã
ä»åã¯ç¹ã«ä½ããã¾ããã§ãã
(3) éä¿¡éã大ãããã
åé¡ã解決ããï¼ãããã¯å
éãããï¼ã®ã§ãä»åº¦ã¯æ¬çªã«ãããã¤ãã¦ã
Googleã®ã¢ãã¤ã«ã¹ãã¼ããã¹ããµã¤ãã§ç¢ºèªããã¨ããã
ãã£ã¡ãé
ãã¨ããå¤å®ã«Î£(ï¾Ðï¾)カï¾ï½°ï¾
SSRã§éãããã¯ããªã®ã«ããªãã§ãã»ã»ã»ã¨æã£ããã
ã©ããéä¿¡éã大ããããã¨ããææã§ãã
åç´ã«Nginxãgzipå§ç¸®ãããã¨ã§è§£æ±ºãã¾ãããã
ãã£ã¨æ©ããã£ã¦ããã£ã¦è©±ã§ã¯ããã¾ãã(´・Ïï½¥)(ï½¥Ïï½¥ï½)ï¾ï½°
ãã¨ã¯ã¾ã ãpacks/ccpts.jsãminifyããã¦ãªãã£ã¦åé¡ãããã®ã§ããã
ãã¾ãã¡ãã¾ããããªãã®ã§ããã£ããä¿çãã¦ããã¾ã
ã¾ã¨ã
ã¨ãããã¨ã§ãé·ã ã¨æ¸ãã¦ãã¾ããããæå¾ã«ã¾ã¨ãã§ã...Ï(ï½¥Ïï½¥ï½)
- SSRã®å¤§åæãå¿ãã¦ã¯ãããªã
- SPAããã£ã¦ã®SSRã§ãã
- æåãããµã¼ããµã¤ãã§viewãä½ãè¨è¨ã¨ã®æ¯è¼ãå¿ è¦
- æé»çã«ããã©ã¦ã¶ãã«ä¾åãã¦ããé¨åã®æé¤ã大å¤
- JavaScriptã§æ¸ãããã³ã¼ãã§ã¯ããããããµã¼ããµã¤ãã§åãããã®ãæèããªãã¨ãã¡
- ccptsç¨åº¦ã®è¦æ¨¡ã§ãããã ã大å¤ãªã®ã§ãæ¥åã¬ãã«ã®ã¢ããªã§ã¯ããªãé¢å
- ï¼å人çã«ï¼ããã¾ãè¨è¨ããã¾ã è¦ããªã
- å ¨é¨ãµã¼ããµã¤ãã¯ãªããéåæãããã®ã§ããã¾ãã¯ã©ã¤ã¢ã³ãã¨åãé¢ããã
ä»ã¾ã§ãããã§ãã£ãããã«ãä»åã®ä¿®æ£ããããå®æã£ã¦ããã§ã¯ãªãã®ã§ã
ã¾ãä½ãæ°ããæè¡ã使ã£ã¦æ´çã§ããã¨ããããªã¨æãã¾ã