
圌女ããã®èšäºãèªãã ãšãã®åŠ»ã®é¡
ç§ã¯6ã¶æåã«ã©ããã§èŠã€ããããšæãäžé£ã®èšäºãæžãããšã«ããŸããã äž»ã«React.jsã§ã¯ãŒã«ãªã¢ããªã±ãŒã·ã§ã³ã®éçºãéå§ãããããæè¿ã®å®å
šãªããã³ããšã³ãéçºã®ããã«ç¥ã£ãŠããå¿
èŠã®ããããŸããŸãªãã¯ãããžãŒãããŒã«ã®åç©åãžã®ã¢ãããŒãæ¹æ³ãããããªã人ã«èå³ããããŸãã
ããããæåãããããããæã人æ°ã®ããã·ããªãªãå®è£
ããããšæããŸããRESTAPIãæäŸãããµãŒããŒéšåããããŸã ã äžéšã®ã¡ãœããã§ã¯ãWebã¢ããªã±ãŒã·ã§ã³ã®ãŠãŒã¶ãŒããã°ã€ã³ããå¿
èŠããããŸãã
ç®æ¬¡
1ïŒååã¢ããªã±ãŒã·ã§ã³ã®åºæ¬ã¹ã¿ãã¯ãæ§ç¯ãã
2ïŒ ã«ãŒãã£ã³ã°ãšããŒãã¹ãã©ããã䜿çšããç°¡åãªã¢ããªã±ãŒã·ã§ã³ãäœæããŸã
3ïŒ APIãšèªèšŒãšã®çžäºäœçšãå®è£
ããŸã
åœéåããã¹ãã®äœæãå±éã CSSãªãã·ã§ã³ãªã©ã®åé¡ã¯æ¬åŒ§ã®å€ã«æ®ããŸãããããã®è³ªåã¯ã¯ããã«å€æ§ã§ããããããåå¥ã®èšäºã®ãããã¯ã«æç»ãããããã§ãã ãããããéèŠãããã°ãåŸã§ãããã«æ»ãã§ãããã
æ³šïŒ githubã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã®åºç€ãšããŠäœ¿çšã§ããå€ãã®ãã°ããããã€ã©ãŒãã¬ãŒããŸãã¯æ¢ã«ãã«ããããã¹ã¿ãã¯ããããŸãããåããã±ãŒãžãšã³ãŒãã®åè¡ãäœãããã®ããçè§£ããŠãç¬èªã®ã¹ã¿ãã¯ãçµã¿ç«ãŠãæ¹ãã¯ããã«æ£ããããã§ãã ããã1åè¡ãããšãåŠç¿ãããšã次åã¯ã¹ã¿ãã¯ãåéããã®ã«5å以äžãããããšã¯ã»ãšãã©ãããŸããã
泚2ïŒèªè
ã«ãã£ãŠæºåã®ã¬ãã«ãç°ãªããšæ³å®ããŠãããããã«ãã¿ãŒã®äžã«ããŒã«ã®é·ã説æãé ããŠãèšäºãç¡éã«é·ãèŠããªãããã«ããŸãã
ãããè¡ããïŒ
1.å圢Webã¢ããªã±ãŒã·ã§ã³ãéçºããŸãã
å圢ãŸãã¯æ±çšã¢ããªã±ãŒã·ã§ã³ãšã¯ãã¢ããªã±ãŒã·ã§ã³ã®JavaScriptã³ãŒãããµãŒããŒãšã¯ã©ã€ã¢ã³ãã®äž¡æ¹ã§å®è¡ã§ããããšãæå³ããŸãã ãã®ã¡ã«ããºã ã¯Reactã®åŒ·ã¿ã®1ã€ã§ããããŠãŒã¶ãŒãã³ã³ãã³ãã«ã¯ããã«é«éã«ã¢ã¯ã»ã¹ã§ããããã«ããŸãã 以äžã§ã¯ãå圢ããšããçšèªã䜿çšããŸãããããã¯ããã«äžè¬çã§ããããå圢ããšãæ®éçãã¯åäžã§ãããšçè§£ããããšãéèŠã§ãã
ååã¢ããªã±ãŒã·ã§ã³ã®è©³çްãã芧ãã ããã
ãŠãŒã¶ãŒã®èгç¹ããèŠããšãWebã¢ããªã±ãŒã·ã§ã³ãšã®çžäºäœçšã¯æ¬¡ã®ãšããã§ãã
1ïŒãã©ãŠã¶ãWebã¢ããªã±ãŒã·ã§ã³ã«ãªã¯ãšã¹ããéä¿¡ããŸãã
2ïŒ Node.jsã®ãµãŒããŒåŽã¯JavaScriptãå®è¡ããŸã ã å¿
èŠã«å¿ããŠãããã»ã¹ã¯APIèŠæ±ãå®è¡ããŸã ã ãã®çµæã宿ããHTMLããŒãžãã¯ã©ã€ã¢ã³ãã«éä¿¡ãããŸãã
3ïŒãŠãŒã¶ãŒã¯ã»ãšãã©ç¬æã«ããŒãžã³ã³ãã³ããåãåããŸãã ãã®æç¹ã§ãã¯ã©ã€ã¢ã³ãåŽã®JavaScriptãããã¯ã°ã©ãŠã³ãã§ããŠã³ããŒãããã³åæåãããã¢ããªã±ãŒã·ã§ã³ãèµ·åããŸãã æãéèŠãªããšã¯ããŠãŒã¶ãŒã¯åŸæ¥ã®ã¯ã©ã€ã¢ã³ããµã€ã JavaScript ã¢ããªã±ãŒã·ã§ã³ã®å Žåã®ããã«ã2ç§ä»¥äžãã£ãŠããã§ã¯ãªããã»ãŒå³åº§ã«ã³ã³ãã³ãã«ã¢ã¯ã»ã¹ã§ããããšã§ãã
4aïŒ JavaScript ãã¯ã©ã€ã¢ã³ãã§ããŒãã«å€±æããããšã©ãŒã§å®è¡ãããå Žåããªã³ã¯ãã¯ãªãã¯ãããšããµãŒããŒãžã®éåžžã®ãªã¯ãšã¹ããå®è¡ãããããã»ã¹ã®æåã®ã¹ãããã«æ»ããŸãã
4bïŒãã¹ãŠãæ£åžžã§ããå Žåããªã³ã¯ã¯ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠã€ã³ã¿ãŒã»ãããããŸãã å¿
èŠã«å¿ããŠã API ãªã¯ãšã¹ããå®è¡ãã ãã¯ã©ã€ã¢ã³ãåŽã® JavaScript *ããªã¯ãšã¹ããããããŒãžãçæããŠã¬ã³ããªã³ã°ããŸãã ãã®ã¢ãããŒãã«ããããã©ãã£ãã¯ãæžå°ããã¢ããªã±ãŒã·ã§ã³ã®çç£æ§ãåäžããŸãã
ãªããããã¯ãŒã«ãªã®ã§ããïŒ
1ïŒãŠãŒã¶ãŒã¯2ç§ä»¥äžã³ã³ãã³ããããéãåä¿¡ããŸãã ããã¯ãã¢ãã€ã«ã€ã³ã¿ãŒããããããŸããªãå ŽåããŸãã¯æ¡ä»¶ä»ãäžåœã«ããå Žåã«ç¹ã«åœãŠã¯ãŸããŸãã å©çã¯ãã¯ã©ã€ã¢ã³ãã®JavaScriptãããŠã³ããŒããããã®ãåŸ
ã€å¿
èŠããªããšããäºå®ã«ãããã®ã§ãããããã¯200kb以äžã§ãããçž®å°ãšå§çž®ãèæ
®ããŠããŸãã ãŸãã JavaScriptã®åæåã«ã¯æéããããå ŽåããããŸãã åæååŸã«ã¯ã©ã€ã¢ã³ãAPIãªã¯ãšã¹ããè¡ãå¿
èŠæ§ã远å ããã¢ãã€ã«ã€ã³ã¿ãŒãããäžã§éåžžã«é¡èãªé
å»¶ãçºçããããšãå€ãããšãæãåºããšãå圢ã¢ãããŒããã¢ããªã±ãŒã·ã§ã³ããŠãŒã¶ãŒã«ãšã£ãŠããå¿«é©ã«ããããšãæããã«ãªããŸãã
2ïŒãšã©ãŒã®ããã«ã¯ã©ã€ã¢ã³ãã®JavaScriptã¢ããªã±ãŒã·ã§ã³ãåäœã忢ããå Žåããµã€ãã¯ãŠãŒã¶ãŒã«ãšã£ãŠåœ¹ã«ç«ããªããªãå¯èœæ§ãé«ããªããŸãã ååã®å ŽåããŠãŒã¶ãŒãæãã§ããããšãå®è¡ã§ããå¯èœæ§ã¯ååã«ãããŸãã
å®è£
ã«é¢ããŠ
server.jsãšclient.jsã® 2ã€ã®ãšã³ããªãã€ã³ãããããŸã ã
Server.jsã¯ããŒããµãŒããŒã«ãã£ãŠäœ¿çšãããŸãã ãã®äžã§ã ãšã¯ã¹ãã¬ã¹ãŸãã¯å¥ã®WebãµãŒããŒãå®è¡ãããªã¯ãšã¹ãåŠçãšä»ã®ãµãŒããŒåºæã®ããžãã¹ããžãã¯ããã®äžã«é
眮ããŸãã
Client.js-ãã©ãŠã¶ãŒã®ãšã³ããªãã€ã³ãã ããã«é¡§å®¢åºæã®ããžãã¹ããžãã¯ãé
眮ããŸãã
Reactã¢ããªã±ãŒã·ã§ã³ã¯ãã¯ã©ã€ã¢ã³ããšãµãŒããŒã®äž¡æ¹ã§å
±æãããŸãã ããã¯ãã¢ããªã±ãŒã·ã§ã³å
šäœã®ãœãŒã¹ã³ãŒãã®90ã95ïŒ
以äžãå ããŠããŸããããã¯ãåå/æ®éçãªã¢ãããŒãã®æ¬è³ªã§ãã å®è£
ããã»ã¹ã§ã¯ããããå®éã«ã©ã®ããã«æ©èœãããã確èªããŸãã
æ°ãããããžã§ã¯ããäœæãã
Node.jsãšnpmããã±ãŒãžãããŒãžã£ãŒãã€ã³ã¹ããŒã«ããäžèŠãããŒãã®ããŒãžã§ã³ä»ãããŒãžã§ã³ã¯å°ãå¥åŠã«èŠãããããããŸããã æ··ä¹±ããªãããã«ãv4.xãLTSãã©ã³ãã§ãããv5.xãå®éšçãã©ã³ãã§ãããv6.xã2016幎10æ1æ¥ä»¥éã®å°æ¥ã®LTSã§ããããšãç¥ãã ãã§ååã§ãã ææ°ã®LTSããŒãžã§ã³ãã€ã³ã¹ããŒã«ããããšããå§ãããŸããã€ãŸããèšäºã®å
¬éæ¥ã¯4åç®ã§ããããã«ããããã©ãããã©ãŒã èªäœã®ãã°ãšã®éåžžã«äžå¿«ãªè¡çªãé²ãããšãã§ããŸãã ç§ãã¡ã®ç®çã§ã¯ã2ã€ã®éã«ç¹å¥ãªéãã¯ãããŸããã
ãªã³ã¯https://nodejs.org/en/download/ã«åŸãããšã«ããã node.jsããã³ãã©ãããã©ãŒã çšã®npmããã±ãŒãžãããŒãžã£ãŒãããŠã³ããŒãããŠã€ã³ã¹ããŒã«ã§ããŸãã
mkdir habr-app && cd habr-app npm init
ãã¹ãŠã®npmã®è³ªåã«ã€ããŠã Enterãã¿ã³ãå®å
šã«æŒããŠããã©ã«ãå€ãéžæã§ããŸãã ãã®çµæã package.jsonãã¡ã€ã«ããããžã§ã¯ãã®ã«ãŒããã£ã¬ã¯ããªã«è¡šç€ºãããŸãã
2.éçºããã»ã¹
è¿å¹Žã®JavaScriptã¯é£èºçã«çºå±ããŠããããŠãŒã¶ãŒã«ã€ããŠã¯èšããŸããã æ®å¿µãªããããã¯ãŒã«ãªæè¡çæ©èœãã®ããã«èŠèŽè
ã®å€§éšåãç ç²ã«ãã顧客ã¯ã»ãšãã©ããªãããããã©ãŠã¶ã®ææ°ããŒãžã§ã³ã®ã¿ããµããŒãããããšã¯ã§ããŸããã 幞ããªããšã«ãããã°ã©ããŒãææ°ã®èšèªæ§æã䜿çšããŠèªåã«åã£ãæ¹æ³ã§èšè¿°ã§ããããŒã«ãçºæããããããéåžžã«å€ããã©ãŠã¶ãŒã§ãæ£ããåäœããã³ãŒããååŸã§ããŸãã
ããã«
Babelã¯ã CoffeeScript ã TypeScriptãããã³ãã®ä»ã®èšèªã¢ããªã³ãå«ãJavaScriptã®æ¹èšãJavaScript ES5ã«å€æããã³ã³ãã€ã©ãŒã§ããããã¯ã babel-polyfillã远å ãããšã IE8ãå«ãã»ãšãã©ãã¹ãŠã®ãã©ãŠã¶ãŒã§ãµããŒããããŸãã Babelã®åŒ·ã¿ã¯ããã©ã°ã€ã³ã«ããã¢ãžã¥ãŒã«æ§ãšæ¡åŒµæ§ã§ãã ããšãã°ãå€ããã©ãŠã¶ã§ã¯åäœããªãããšãå¿é
ããããšãªããææ°ã®JavaScriptãããã䜿çšã§ããããã«ãªããŸããã
åå¿ã®ã³ã³ããŒãã³ãã倿ããã«ã¯ã babel-preset-reactããªã»ããã䜿çšããŸãã JavaScriptãã³ã¬ãŒã¿ã倧奜ããªã®ã§ã babel-plugin-transform-decorators-legacyããã±ãŒãžãå¿
èŠã«ãªããŸãã ã³ãŒããå€ããã©ãŠã¶ãŒã§æ£åžžã«åäœãããã«ã¯ã babel-polyfillããã±ãŒãžãã€ã³ã¹ããŒã«ããŸã ãES6 / ES7æ¹èšã§æžã蟌ãã«ã¯ãããããbabel- preset-es2015ãšbabel- preset -stage-0ãå¿
èŠã§ãã
npm i --save babel-core babel-plugin-transform-decorators-legacy babel-polyfill babel-preset-es2015 babel-preset-react babel-preset-stage-0
ã¢ããªã±ãŒã·ã§ã³ã®ãµãŒããŒåŽã«ãbabelãå¿
èŠãªããããããã®äŸåé¢ä¿ã¯ãããžã§ã¯ãã®äŸåé¢ä¿ãšããŠã€ã³ã¹ããŒã«ããå¿
èŠããããŸãã
ã¯ã©ã€ã¢ã³ãåŽã®JavaScriptãæ§ç¯ããããã«å¿
èŠãªããã±ãŒãžãã€ã³ã¹ããŒã«ããŸãã æ¬çªç°å¢ã§ã¯å¿
èŠãªããããéçºã®äŸåé¢ä¿ãšããŠã€ã³ã¹ããŒã«ããŸãã
.babelrc
babelãèµ·åãããšããããžã§ã¯ãã®ã«ãŒãã«ãã.babelrcãã¡ã€ã«ã«ã¢ã¯ã»ã¹ããŸãã ãã®ãã¡ã€ã«ã«ã¯ã䜿çšãããŠããããªã»ãããšãã©ã°ã€ã³ã®æ§æãšãªã¹ããä¿åãããŠããŸãã
ãã®ãã¡ã€ã«ãäœæãã
{ "presets": [ "es2015", "react", "stage-0" ], "plugins": [ "transform-decorators-legacy" ] }
3.çµã¿ç«ãŠ
Babelã«å¿
èŠãªãã©ã°ã€ã³ãã€ã³ã¹ããŒã«ããŸããããã ãããã€ãããèµ·åããå¿
èŠããããŸããïŒ ãã®åé¡ã«é²ãæãæ¥ãŸããã
æ³šïŒæè¿ã®Webã¢ããªã±ãŒã·ã§ã³ãããžã§ã¯ãã¯ããã¹ã¯ããããŸãã¯ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ãããžã§ã¯ããšå€§å·®ãããŸãããå€éšã©ã€ãã©ãªã MVCãã©ãã€ã ã«æãäžèŽããå¯èœæ§ãé«ããã¡ã€ã«ããªãœãŒã¹ãã¹ã¿ã€ã«ãã¡ã€ã«ãªã©ãå«ãŸããŸãã ãã®ãããªãã¬ãŒã³ããŒã·ã§ã³ã¯ããã°ã©ãã«ãšã£ãŠéåžžã«äŸ¿å©ã§ããããŠãŒã¶ãŒã«ãšã£ãŠã¯äŸ¿å©ã§ã¯ãããŸããã JavaScriptãããžã§ã¯ãã®ãã¹ãŠã®ãœãŒã¹ã³ãŒããšäœ¿çšããã©ã€ãã©ãªãååŸããäžèŠãªãã®ããã¹ãŠç Žæ£ãã1ã€ã®å€§ããªãã¡ã€ã«ã«çµåããŠçž®å°åãé©çšãããšãåºåãã¡ã€ã«ã¯å
ã®ã»ããããã10å以äžå°ãªããªããŸãã ãŸããã¢ããªã±ãŒã·ã§ã³ã®ãã¹ãŠã®ããžãã¯ãããŠã³ããŒãããããã«å¿
èŠãªãã©ãŠã¶ãªã¯ãšã¹ãã¯æ°çŸã§ã¯ãªãã1ã€ã ãã§ãã ã©ã¡ããããã©ãŒãã³ã¹ã«ãšã£ãŠéåžžã«éèŠã§ãã ãšããã§ãããŸããŸãªæ¹èšïŒ LESS ã SASSãªã©ïŒãå«ãCSSãªãœãŒã¹ã«åãããžãã¯ãé©çšãããŸãã
ãã®äŸ¿å©ãªäœæ¥ã¯webpackã«ãã£ãŠè¡ãããŸã ã
泚ïŒåãç®çã§ãã³ã¬ã¯ã¿ãŒã䜿çšã§ããŸãïŒgruntãgulpãbowerãbrowserifyãªã©ããã ããReactã®æŽå²çã«ã¯ãwebpackãæãé »ç¹ã«äœ¿çšãããŸããã
webpackããã³webpack-dev-serverã®è©³çްãŠã§ãããã¯

Webpackæäœã¢ã«ãŽãªãºã
webpackããã€ãã©ã€ã³ãšèããæãç°¡åãªæ¹æ³ã Webpackã¯ãæäŸããããšã³ããªãã€ã³ããååŸããéäžã§ééãããã¹ãŠã®äŸåé¢ä¿ãé çªã«åŠçããŸãã JavaScriptãŸãã¯ãã®æ¹èšã§èšè¿°ããããã¹ãŠã®ã³ãŒãã¯ã ããã«ãééããŠ1ã€ã®å€§ããªJavaScript ES5ãã¡ã€ã«ã«ãã©ã€ã³ããããŸãã ããã§ã¯ããããã©ã®ããã«æ©èœãããã«ã€ããŠè©³ãã説æãã䟡å€ããããŸãã ã³ãŒããšnode_modules webpackã§äœ¿çšãããã³ãŒãã®ãããããå¿
èŠãŸãã¯ã€ã³ããŒããããæçµã¢ã»ã³ããªã®ç¬èªã®å°ããªã¢ãžã¥ãŒã«ã«å²ãåœãŠãããŸãã èªåã®ã³ãŒããŸãã¯äœ¿çšããã©ã€ãã©ãªã®ã³ãŒããåã颿°ã«äŸåããå Žåã Webpackã¢ãžã¥ãŒã«ãšããŠäžåºŠã ãæçµã¢ã»ã³ããªã«å°éããããã«äŸåãããã¹ãŠã®ã³ãŒãã¯åããã®ãåç
§ããŸãæçµã¢ã»ã³ããªã®ã¢ãžã¥ãŒã«ã webpackãã«ãããã»ã¹ã®ãã1ã€ã®ã¯ãŒã«ãªæ©èœã¯ã lodashã®ãããªå·šå€§ãªã©ã€ãã©ãªã䜿çšããŠããããæ¬¡ã®ãããªç¹å®ã®é¢æ°ã®ã¿ãå¿
èŠã§ãããšæç€ºçã«è¿°ã¹ãŠããããšã§ãã
import assign from 'lodash/assign';
ã©ã€ãã©ãªå
šäœã§ã¯ãªããã©ã€ãã©ãªã®äœ¿çšæžã¿éšåã®ã¿ãæçµã¢ã»ã³ããªã«å
¥ããŸããããã«ãããã¢ã»ã³ãã«ããããã¡ã€ã«ã®ãµã€ãºã倧å¹
ã«åæžãããŸãã
泚ïŒããã¯ã䜿çšããã©ã€ãã©ãªãã¢ãžã¥ãŒã«æ§ããµããŒãããŠããå Žåã«ã®ã¿æ©èœããŸãã ãã®ãããäœè
ã¯èªåã®ãããžã§ã¯ãã§ã©ã€ãã©ãªMoment.jsãXRegExpãªã©ã䜿çšããããšãæåŠããŸããã
webpackæ§æã®ãããžã§ã¯ãã®ããŸããŸãªã¿ã€ãã®ãã¡ã€ã«ã«ã€ããŠããããåŠçããããŒããŒãŸãã¯ããŒããŒã®ãã§ãŒã³ãå®çŸ©ããŸãã
webpack-dev-server
æ¯åããããžã§ã¯ãå
šäœãåçµã¿ç«ãŠããã®ã¯éåžžã«è²»çšããããå¯èœæ§ããããŸããäžèŠæš¡ã®ãããžã§ã¯ãã®å Žåãã¢ã»ã³ããªã¯30ç§ä»¥äžã«ç°¡åã«éããããšãã§ããŸãã ãã®åé¡ã解決ããã«ã¯ãéçºäžã«webpack-dev-serverã䜿çšãããšéåžžã«äŸ¿å©ã§ãã ããã¯ãµãŒãããŒãã£ã®ãµãŒããŒã¢ããªã±ãŒã·ã§ã³ã§ãèµ·åãããšãªãœãŒã¹ã®å®å
šãªã¢ã»ã³ããªãäœæããã¢ã¯ã»ã¹ãããšRAMãããªãœãŒã¹ã®ææ°ããŒãžã§ã³ãæäŸããŸãã éçºäžã«åã
ã®webpack-dev-serverãã¡ã€ã«ã倿Žãããšããã®å Žã§å€æŽããããã¡ã€ã«ã®ã¿ãåã³ã³ãã€ã«ãããæçµã¢ã»ã³ããªã®å€ãã¢ãžã¥ãŒã«ãæ°ããã¢ãžã¥ãŒã«ã«çœ®ãæããããŸãã åæ§ç¯ãå¿
èŠãªã®ã¯ãããžã§ã¯ãå
šäœã§ã¯ãªãã1ã€ã®ãã¡ã€ã«ã®ã¿ã§ããããã1ç§ä»¥äžãããããšã¯ãã£ãã«ãããŸããã
ãã¡ãã ã æ¬çªç°å¢ã§ã¯æ§ç¯ããªãããã Webpackãšwebpack-dev-serverãéçºã®äŸåé¢ä¿ãšããŠã€ã³ã¹ããŒã«ããŸã ã
npm i --save-dev webpack@1.13.2 webpack-dev-server
泚 ïŒãã®èšäºã®å·çæããã³å
¬éæã«ã¯ãwebpack 1ã®ããŒãžã§ã³ãé¢é£ããŠããŸãããã2016幎9æ22æ¥ä»¥éãwebpack 2ããŒã¿ãããã©ã«ãã§ã€ã³ã¹ããŒã«ãããŸãã
ããŠãã¢ã»ã³ããªã®æ§æãã¡ã€ã«ãäœæããå¿
èŠããããŸãã ãããžã§ã¯ãã®ã«ãŒãã«ãã¡ã€ã«ãäœæããŸã
webpack.config.js
global.Promise = require('bluebird'); var webpack = require('webpack'); var path = require('path'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var CleanWebpackPlugin = require('clean-webpack-plugin'); var publicPath = 'http://localhost:8050/public/assets'; var cssName = process.env.NODE_ENV === 'production' ? 'styles-[hash].css' : 'styles.css'; var jsName = process.env.NODE_ENV === 'production' ? 'bundle-[hash].js' : 'bundle.js'; var plugins = [ new webpack.DefinePlugin({ 'process.env': { BROWSER: JSON.stringify(true), NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development') } }), new ExtractTextPlugin(cssName) ]; if (process.env.NODE_ENV === 'production') { plugins.push( new CleanWebpackPlugin([ 'public/assets/' ], { root: __dirname, verbose: true, dry: false }) ); plugins.push(new webpack.optimize.DedupePlugin()); plugins.push(new webpack.optimize.OccurenceOrderPlugin()); } module.exports = { entry: ['babel-polyfill', './src/client.js'], debug: process.env.NODE_ENV !== 'production', resolve: { root: path.join(__dirname, 'src'), modulesDirectories: ['node_modules'], extensions: ['', '.js', '.jsx'] }, plugins, output: { path: `${__dirname}/public/assets/`, filename: jsName, publicPath }, module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader') }, { test: /\.less$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!less-loader') }, { test: /\.gif$/, loader: 'url-loader?limit=10000&mimetype=image/gif' }, { test: /\.jpg$/, loader: 'url-loader?limit=10000&mimetype=image/jpg' }, { test: /\.png$/, loader: 'url-loader?limit=10000&mimetype=image/png' }, { test: /\.svg/, loader: 'url-loader?limit=26000&mimetype=image/svg+xml' }, { test: /\.(woff|woff2|ttf|eot)/, loader: 'url-loader?limit=1' }, { test: /\.jsx?$/, loader: 'babel', exclude: [/node_modules/, /public/] }, { test: /\.json$/, loader: 'json-loader' }, ] }, devtool: process.env.NODE_ENV !== 'production' ? 'source-map' : null, devServer: { headers: { 'Access-Control-Allow-Origin': '*' } } };
泚ïŒããã¯çç£çãªãããžã§ã¯ãã®èšå®äŸã§ãããããèŠãç®ãããå°ãè€éã«èŠããŸãã
æ§æã®èª¬æã ãã
1ïŒ bluebirdãããžã§ã¯ãã®promiseã®å®è£
ã䜿çšããããšãçºè¡šããŸãã äºå®äžã®æšæºã
2ïŒæ¬çªç°å¢ã§ã¯ããªãœãŒã¹ãã£ãã·ã³ã°ã广çã«ç®¡çããããã«ãåãã¡ã€ã«ã«ã¢ã»ã³ããªã®ããã·ã¥ãæãããå¿
èŠããããŸãã åéããããªãœãŒã¹ã®å€ãããŒãžã§ã³ãæ°ã«ãªããªãããã«ã次ã®ãã«ãã®åã«å¯Ÿå¿ãããã£ã¬ã¯ããªãã¯ãªã¢ããclean-webpack-pluginã䜿çšããŸãã
3ïŒãã«ãããã»ã¹äžã«extract-text-webpack-pluginã¯ããã¹ãŠã®css / less / sass /ä»»æã®äŸåé¢ä¿ãæ¢ããæåŸã«ããããåäžã®CSSãã¡ã€ã«ã«æç»ããŸãã
4ïŒ DefinePluginã䜿çšããŠãã°ããŒãã«ã¢ã»ã³ããªå€æ°ã DedupePluginããã³OccurenceOrderPlugin-æé©åãã©ã°ã€ã³ãèšå®ããŸãã ãããã®ãã©ã°ã€ã³ã®è©³çްã«ã€ããŠã¯ãããã¥ã¡ã³ããã芧ãã ããã
5ïŒ babel-polyfillãšclient.jsããšã³ããªãã€ã³ããšããŠæå®ããŸãã 1ã€ç®ã¯JavaScriptã³ãŒããå€ããã©ãŠã¶ãŒã§å®è¡ã§ããããã«ãã2ã€ç®ã¯ã¯ã©ã€ã¢ã³ãWebã¢ããªã±ãŒã·ã§ã³ã®ãšã³ããªãã€ã³ãã§ãããåŸã§èšè¿°ããŸãã
6ïŒ è§£æ±ºãšã¯ãã¢ããªã±ãŒã·ã§ã³ã®ã³ãŒããèšè¿°ãããšã
import SomeClass from './SomeClass';
webpackã¯ãæå®ããããã¡ã€ã«ãèŠã€ãããªããšå ±åããåã«ã SomeClass.jsãŸãã¯SomeClass.jsxãã¡ã€ã«ã§SomeClassãæ¢ããŸãã
7ïŒæ¬¡ã«ããã©ã°ã€ã³ã®ãªã¹ããæž¡ãã åºåïŒ webpackãã¢ã»ã³ããªåŸã«ãã¡ã€ã«ãé
眮ãããã£ã¬ã¯ããªïŒãæå®ããŸãã
8ïŒæãè峿·±ãã®ã¯ã ããŒããŒã®ãªã¹ãã§ãã ããã§ãäžèšã®ã³ã³ãã€ãå®çŸ©ããŸãã é©åãªæ¡åŒµåãæã€ãã¡ã€ã«ã«é©çšãããŸãã ãã®åé¡ã¯å¥ã®èšäºã«ãŸãšããããŠãããããããã¥ã¡ã³ãå
ã®ããŒããŒãšãã®ãã©ã¡ãŒã¿ãŒã決å®ãã圢åŒãããçè§£ããããšããå§ãããŸãã å®å
šã«æ ¹æ ããªãããã«ãããŒããŒã®èšèšã«çŠç¹ãåœãŠãŸãã
test: /\.less$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!less-loader')
ããã§ãæ¡åŒµåã®å°ãããã¡ã€ã«ãèŠã€ãã£ãå Žåã css-loaderïŒPostcss-loaderïŒLess-loaderãã§ãŒã³ã䜿çšããExtractTextPluginã«æž¡ãå¿
èŠããããŸãã å³ããå·Šã«èªã¿ãŸããã€ãŸããæåã®less-loader㯠.lessãã¡ã€ã«ãåŠçããçµæã¯postcss-loaderã«ãªããåŠçãããcss-loaderã®ã³ã³ãã³ããæž¡ããŸãã
9ïŒwebpackããã¥ã¡ã³ãã®devtoolã«ã€ããŠèªãããšããå§ãããŸãã
10ïŒæåŸã«ããã©ã¡ãŒã¿ãŒwebpack-dev-serverã远å ã§æå®ããŸã ã ãã®å Žåã webpack-dev-serverãšã¢ããªã±ãŒã·ã§ã³ãç°ãªãããŒãã§åäœãããããAccess-Control-Allow-Originãæå®ããããšãéèŠã§ããããã¯ã CORSåé¡ã解決ããå¿
èŠãããããšãæå³ããŸãã
æ§æã§åç
§ããã©ã€ãã©ãªã¯ã€ã³ã¹ããŒã«ãããŸããã ãããžã§ã¯ãã«ãã£ãŠã¯ã bluebirdã®ã¿ã䜿çšã§ããŸããä»ã®ãã¹ãŠã¯ã¢ã»ã³ããªå°çšã§ãã
npm i --save bluebird npm i --save-dev babel-loader clean-webpack-plugin css-loader extract-text-webpack-plugin file-loader html-loader json-loader less less-loader postcss-loader style-loader url-loader
ãŸããããã€ãã®æ°ããpackage.jsonã¹ã¯ãªããã远å ããŸãããã«ãããã³webpack devãµãŒããŒãå®è¡ããŸãã
"scripts": { "build": "NODE_ENV='production' webpack -p", "webpack-devserver": "webpack-dev-server --debug --hot --devtool eval-source-map --output-pathinfo --watch --colors --inline --content-base public --port 8050 --host 0.0.0.0" }
æŽæ°ïŒPMã®wrewolfãšNeropã®ãŠãŒã¶ãŒã¯ãããããWindowsã¹ã¯ãªããã§ã¯ç°ãªãããã«èŠããã¹ãã§ãããšå ±åããŸããã
"scripts": { "build": "set NODE_ENV='production' && webpack -p", "webpack-devserver": "webpack-dev-server --debug --hot --devtool eval-source-map --output-pathinfo --watch --colors --inline --content-base public --port 8050 --host 0.0.0.0" }
ãããžã§ã¯ãã«ãŒãã«srcãã©ã«ããŒãäœæãããã®äžã«ç©ºã®client.jsãã¡ã€ã«ãäœæããŸãã
ã¹ã¯ãªããããã¹ãããŸããã³ã³ãœãŒã«ã§npm run buildãšå
¥åããä»ã®ã³ã³ãœãŒã«ãŠã£ã³ããŠã§npm run webpack-devserverãšå
¥åããŸãã ééãããªããã°ã次ã«é²ã¿ãŸãã
4. ESLint
ããã¯ãªãã·ã§ã³ã®é
ç®ã§ãããéåžžã«äŸ¿å©ã§ãã ESLintã¯ããœãŒã¹ã³ãŒãã«æç€ºãããã«ãŒã«ã®ã³ã¬ã¯ã·ã§ã³ã§ãã ã³ãŒãã®äœæããã»ã¹äžã«ããã°ã©ãããããã®ã«ãŒã«ã®1ã€ä»¥äžã«éåãããšã webpackã®ãã«ãäžã«ãšã©ãŒãçºçããŸãã ãããã£ãŠããã¹ãŠã®Webã¢ããªã±ãŒã·ã§ã³ã³ãŒãã¯ã倿°ã®åœåãã€ã³ãã³ããç¹å®ã®æ§æèŠçŽ ã®äœ¿çšã®çŠæ¢ãªã©ãå«ãåäžã®ã¹ã¿ã€ã«ã§èšè¿°ãããŸãã
ãããžã§ã¯ãã«ãŒãã®.eslintrcãã¡ã€ã«ã«ã«ãŒã«ã®ãªã¹ããé
眮ããŸãã ESLintããã³ã«ãŒã«ã®è©³çްã«ã€ããŠã¯ããããžã§ã¯ãã®Webãµã€ããã芧ãã ããã
.eslintrc { "parser": "babel-eslint", "plugins": [ "react" ], "env": { "browser": true, "node": true, "mocha": true, "es6": true }, "ecmaFeatures": { "arrowFunctions": true, "blockBindings": true, "classes": true, "defaultParams": true, "destructuring": true, "forOf": true, "generators": false, "modules": true, "objectLiteralComputedProperties": true, "objectLiteralDuplicateProperties": false, "objectLiteralShorthandMethods": true, "objectLiteralShorthandProperties": true, "restParams": true, "spread": true, "superInFunctions": true, "templateStrings": true, "jsx": true }, "rules":{ // Possible errors "comma-dangle": [2, "never"], "no-cond-assign": [2, "always"], "no-constant-condition": 2, "no-control-regex": 2, "no-dupe-args": 2, "no-dupe-keys": 2, "no-duplicate-case": 2, "no-empty-character-class": 2, "no-empty": 2, "no-extra-boolean-cast": 0, "no-extra-parens": [2, "functions"], "no-extra-semi": 2, "no-func-assign": 2, "no-inner-declarations": 2, "no-invalid-regexp": 2, "no-irregular-whitespace": 2, "no-negated-in-lhs": 2, "no-obj-calls": 2, "no-regex-spaces": 2, "no-sparse-arrays": 2, "no-unreachable": 2, "use-isnan": 2, "valid-typeof": 2, "no-unexpected-multiline": 0, // Best Practices "block-scoped-var": 2, "complexity": [2, 40], "curly": [2, "multi-line"], "default-case": 2, "dot-notation": [2, { "allowKeywords": true }], "eqeqeq": 2, "guard-for-in": 2, "no-alert": 1, "no-caller": 2, "no-case-declarations": 2, "no-div-regex": 0, "no-else-return": 2, "no-eq-null": 2, "no-eval": 2, "no-extend-native": 2, "no-extra-bind": 2, "no-fallthrough": 2, "no-floating-decimal": 2, "no-implied-eval": 2, "no-iterator": 2, "no-labels": 2, "no-lone-blocks": 2, "no-loop-func": 2, "no-multi-str": 2, "no-native-reassign": 2, "no-new": 2, "no-new-func": 2, "no-new-wrappers": 2, "no-octal": 2, "no-octal-escape": 2, "no-param-reassign": [2, { "props": true }], "no-proto": 2, "no-redeclare": 2, "no-script-url": 2, "no-self-compare": 2, "no-sequences": 2, "no-unused-expressions": 2, "no-useless-call": 2, "no-with": 2, "radix": 2, "wrap-iife": [2, "outside"], "yoda": 2, // ES2015 "arrow-parens": 0, "arrow-spacing": [2, { "before": true, "after": true }], "constructor-super": 2, "no-class-assign": 2, "no-const-assign": 2, "no-this-before-super": 0, "no-var": 2, "object-shorthand": [2, "always"], "prefer-arrow-callback": 2, "prefer-const": 2, "prefer-spread": 2, "prefer-template": 2, // Strict Mode "strict": [2, "never"], // Variables "no-catch-shadow": 2, "no-delete-var": 2, "no-label-var": 2, "no-shadow-restricted-names": 2, "no-shadow": 2, "no-undef-init": 2, "no-undef": 2, "no-unused-vars": 2, // Node.js "callback-return": 2, "no-mixed-requires": 2, "no-path-concat": 2, "no-sync": 2, "handle-callback-err": 1, "no-new-require": 2, // Stylistic "array-bracket-spacing": [2, "never", { "singleValue": true, "objectsInArrays": true, "arraysInArrays": true }], "newline-after-var": [1, "always"], "brace-style": [2, "1tbs"], "camelcase": [2, { "properties": "always" }], "comma-spacing": [2, { "before": false, "after": true }], "comma-style": [2, "last"], "computed-property-spacing": [2, "never"], "eol-last": 2, "func-names": 1, "func-style": [2, "declaration"], "indent": [2, 2, { "SwitchCase": 1 }], "jsx-quotes": [2, "prefer-single"], "linebreak-style": [2, "unix"], "max-len": [2, 128, 4, { "ignoreUrls": true, "ignoreComments": false, "ignorePattern": "^\\s*(const|let|var)\\s+\\w+\\s+\\=\\s+\\/.*\\/(|i|g|m|ig|im|gm|igm);?$" }], "max-nested-callbacks": [2, 4], "new-parens": 2, "no-array-constructor": 2, "no-lonely-if": 2, "no-mixed-spaces-and-tabs": 2, "no-multiple-empty-lines": [2, { "max": 2, "maxEOF": 1 }], "no-nested-ternary": 2, "no-new-object": 2, "no-spaced-func": 2, "no-trailing-spaces": 2, "no-unneeded-ternary": 2, "object-curly-spacing": [2, "always"], "one-var": [2, "never"], "padded-blocks": [2, "never"], "quotes": [1, "single", "avoid-escape"], "semi-spacing": [2, { "before": false, "after": true }], "semi": [2, "always"], "keyword-spacing": 2, "space-before-blocks": 2, "space-before-function-paren": [2, { "anonymous": "always", "named": "never" }], "space-in-parens": [2, "never"], "space-infix-ops": 2, "space-unary-ops": [2, { "words": true, "nonwords": false }], "spaced-comment": [2, "always", { "exceptions": ["-", "+"], "markers": ["=", "!"] }], // React "react/jsx-boolean-value": 2, "react/jsx-closing-bracket-location": 2, "react/jsx-curly-spacing": [2, "never"], "react/jsx-handler-names": 2, "react/jsx-indent-props": [2, 2], "react/jsx-indent": [2, 2], "react/jsx-key": 2, "react/jsx-max-props-per-line": [2, {maximum: 3}], "react/jsx-no-bind": [2, { "ignoreRefs": true, "allowBind": true, "allowArrowFunctions": true }], "react/jsx-no-duplicate-props": 2, "react/jsx-no-undef": 2, "react/jsx-pascal-case": 2, "react/jsx-uses-react": 2, "react/jsx-uses-vars": 2, "react/no-danger": 2, "react/no-deprecated": 2, "react/no-did-mount-set-state": 0, "react/no-did-update-set-state": 0, "react/no-direct-mutation-state": 2, "react/no-is-mounted": 2, "react/no-multi-comp": 2, "react/no-string-refs": 2, "react/no-unknown-property": 2, "react/prefer-es6-class": 2, "react/prop-types": 2, "react/react-in-jsx-scope": 2, "react/self-closing-comp": 2, "react/sort-comp": [2, { "order": [ "lifecycle", "/^handle.+$/", "/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/", "everything-else", "/^render.+$/", "render" ] }], "react/jsx-wrap-multilines": 2, // Legacy "max-depth": [0, 4], "max-params": [2, 4], "no-bitwise": 2 }, "globals":{ "$": true, "ga": true } }
æ³šïŒ Windowsã§ã¯ãã«ãŒã«
"linebreak-style": [2, "unix"],
ã«çœ®ãæããå¿
èŠããããŸã
"linebreak-style": [2, "windows"],
npm i --save-dev babel-eslint eslint eslint-loader eslint-plugin-react
eslint-loaderãwebpackæ§æã«è¿œå ããããã babelãã³ãŒããES5ã«å€æããåã«ãæå®ãããã«ãŒã«ã«æºæ ããŠãããã©ãããã¹ãŠã®ã³ãŒãããã§ãã¯ãããŸãã
webpack.config.js
module.exports.module.loadersã§ïŒ
--- { test: /\.jsx?$/, loader: 'babel', exclude: [/node_modules/, /public/] }, +++ { test: /\.jsx?$/, loader: 'babel!eslint-loader', exclude: [/node_modules/, /public/] },
module.exportsã§ïŒ
+++ eslint: { configFile: '.eslintrc' },
5. Expressããã³Server.js
çŸåšã®ãšããããããžã§ã¯ãã¢ã»ã³ããªã JS ES5ã§ã®ã³ãŒãå€æãæ§æãããã·ã©ãçšãã®ãœãŒã¹ã³ãŒãã®æ€èšŒã«ã€ããŠèª¬æããå®è£
ããŠããŸãã ä»åºŠã¯ãã¢ããªã±ãŒã·ã§ã³èªäœãã€ãŸããµãŒããŒåŽã®èšè¿°ãéå§ããŸãã
泚ïŒç§ã¯Expressã䜿çšããŠãããå®å
šã«ç§ã«é©ããŠããŸããããã¡ãããä»ã«ãå€ãã®åæ§ã®ããã±ãŒãžããããŸãïŒããã¯Node.jsã§ãïŒã
ãšã¯ã¹ãã¬ã¹ãã€ã³ã¹ããŒã«
npm i --save express
次ã®å
容ã§server.jsãã¡ã€ã«ãã«ãŒãã«äœæããŸã
server.js
require('babel-core/register'); ['.css', '.less', '.sass', '.ttf', '.woff', '.woff2'].forEach((ext) => require.extensions[ext] = () => {}); require('babel-polyfill'); require('server.js');
ããã§ã¯ã ES6 / ES7ããµããŒãããããã«babelãå¿
èŠã§ããããšãããã³ããŒãããã©ãŒã ã®æ§é ã«ééããå Žå
import 'awesome.css';
ãã®è¡ã¯JavaScriptãŸãã¯ãã®æ¹èšã®1ã€ã§ã¯ãªããããç¡èŠããå¿
èŠããããŸã ã
ãµãŒããŒåŽã®ã³ãŒãèªäœã¯src / server.jsãã¡ã€ã«ã«ããã ES6 / ES7æ§æãèªç±ã«äœ¿çšã§ããŸãã
src / server.js
import express from 'express'; const app = express(); app.use((req, res) => { res.end('<p>Hello World!</p>'); }); const PORT = process.env.PORT || 3001; app.listen(PORT, () => { console.log(`Server listening on: ${PORT}`); });
ããã§ã¯ãã¹ãŠãéåžžã«ç°¡åã§ãïŒ ãšã¯ã¹ãã¬ã¹ WebãµãŒããŒãã€ã³ããŒããã PORTãŸãã¯3001ç°å¢å€æ°ã§è»¢éãããããŒãã§å®è¡ããŸãããµãŒããŒèªäœã¯ãã¹ãŠã®èŠæ±ã«å¿çããŸãïŒ "Hello World"
ãµãŒããŒãµã€ãJavaScriptã³ãŒããå®è¡ããèšèšã«å¿ããŠã nodemonããã±ãŒãžãã€ã³ã¹ããŒã«ããŸãã ãšã©ãŒãçºçãããšããã«ã³ã³ãœãŒã«ã«è©³çްãªã¹ã¿ãã¯ãã¬ãŒã¹ãšãšãã«ãšã©ãŒã衚瀺ããã®ã§äŸ¿å©ã§ãã
npm i --save-dev nodemon
package.jsonã«å¥ã®ã¹ã¯ãªããã远å ããŸã
+++ "nodemon": "NODE_PATH=./src nodemon server.js",
Windowsã®å ŽåïŒ
+++ "nodemon": "set NODE_PATH=./src; && nodemon server.js",
ãããŠãã³ã³ãœãŒã«ã§å®è¡ããŸã
npm run nodemon
ãã©ãŠã¶ãŒãéããããŒãžhttpïŒ// localhostïŒ3001ãéããŸãã ãã¹ãŠãé 調ã§ããã°ã Hello Worldã衚瀺ãããŸãã
6. Reactããã³ReactDOM
ããã§ãšãããããŸãïŒ ã»ãŒãã¹ãŠã®æºåãå®äºããæçµçã«åå¿ã«ç§»ãããšãã§ããŸãã
é©åãªã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŸãã
npm i --save react react-dom
ãŸãã react-hot-loaderãã€ã³ã¹ããŒã«ããŸããéçºããã»ã¹äžã«ã³ã³ããŒãã³ãã®ãœãŒã¹ã³ãŒãã倿Žãããšããã©ãŠã¶ãŒã¯ããŒãžãèªåçã«ãªããŒãããŸãã ããã¯ãç¹ã«è€æ°ã®ã¢ãã¿ãŒãããå Žåã«éåžžã«äŸ¿å©ãªæ©èœã§ãã
npm i --save-dev react-hot-loader@1.3.0
æ³šïŒ npmã®ãµã³ãããã¯ã¹ã«èšäºãæ®ã£ãŠããéã react-hot-loaderããã±ãŒãžã®ããŒãžã§ã³ã¯1.3.xãã3.xx-betaã«å€æŽãããŸããã çŸåšã3çªç®ã®ããŒãžã§ã³ã¯ããŸãææžåãããŠããªãããã以äžã§ã¯æåã®ããŒãžã§ã³ã䜿çšããŸãã
webpack.config.js
--- { test: /\.jsx?$/, loader: 'babel!eslint-loader', exclude: [/node_modules/, /public/] }, +++ { test: /\.jsx?$/, loader: process.env.NODE_ENV !== 'production' ? 'react-hot!babel!eslint-loader' : 'babel', exclude: [/node_modules/, /public/] },
次ã«ãWebã¢ããªã±ãŒã·ã§ã³ã®å圢éšåãžã®ãšã³ããªãã€ã³ãã§ããApp.jsxã®æåã®ã³ã³ããŒãã³ãã®ã³ãŒãã®èšè¿°ã«ç§»ããŸãããã
src / components / App.jsx
import React, { PropTypes, Component } from 'react'; import './App.css'; const propTypes = { initialName: PropTypes.string }; const defaultProps = { initialName: '' }; class App extends Component { constructor(props) { super(props); this.handleNameChange = this.handleNameChange.bind(this); this.renderGreetingWidget = this.renderGreetingWidget.bind(this); this.state = { name: this.props.initialName, touched: false, greetingWidget: () => null }; } handleNameChange(val) { const name = val.target.value; this.setState({ touched: true }); if (name.length === 0) { this.setState({ name: this.props.initialName }); } else { this.setState({ name }); } } renderGreetingWidget() { if (!this.state.touched) { return null; } return ( <div> <hr /> <p>, {this.state.name}!</p> </div> ); } render() { return ( <div className='App'> <h1>Hello World!</h1> <div> <p> :</p> <div><input onChange={this.handleNameChange} /></div> {this.renderGreetingWidget()} </div> </div> ); } } App.propTypes = propTypes; App.defaultProps = defaultProps; export default App;
src / components / App.css
.App { padding: 20px; } .App h1 { font-size: 26px; } .App input { padding: 10px; } .App hr { margin-top: 20px; }
ããã§ã¯ãã¹ãŠãéåžžã«ç°¡åã§ãããŠãŒã¶ãŒã«ååãå
¥åããŠæšæ¶ããããã«æ±ããŠããŸãã
ã¢ããªã±ãŒã·ã§ã³ããã®ã³ã³ããŒãã³ãã衚瀺ããããã«ããµãŒããŒãšã¯ã©ã€ã¢ã³ãã®ã³ãŒãã«æ¬¡ã®å€æŽãå ããŸãã
src / client.js
import React from 'react'; import ReactDOM from 'react-dom'; import App from 'components/App'; ReactDOM.render(<App />, document.getElementById('react-view'));
JavaScriptã®åæååŸãreactã¯react-viewã¢ããªã±ãŒã·ã§ã³ã®ã¡ã€ã³ã³ã³ãããŒãèŠã€ããŠåã¢ã¯ãã£ãåããŸãã
src / server.js
import express from 'express'; import React from 'react'; import ReactDom from 'react-dom/server'; import App from 'components/App'; const app = express(); app.use((req, res) => { const componentHTML = ReactDom.renderToString(<App />); return res.end(renderHTML(componentHTML)); }); const assetUrl = process.env.NODE_ENV !== 'production' ? 'http://localhost:8050' : '/'; function renderHTML(componentHTML) { return ` <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello React</title> <link rel="stylesheet" href="${assetUrl}/public/assets/styles.css"> </head> <body> <div id="react-view">${componentHTML}</div> <script type="application/javascript" src="${assetUrl}/public/assets/bundle.js"></script> </body> </html> `; } const PORT = process.env.PORT || 3001; app.listen(PORT, () => { console.log(`Server listening on: ${PORT}`); });
: JavaScript RenderDom.renderToString(<App />) HTML-, , renderHTML . assetUrl : , webpack-dev-server .
, :
npm run nodemon npm run webpack-devserver
: http://localhost:3001 ⊠- !
, .
1) server-side rendering . webpack-dev-server . , , .
2) client-side rendering . src/server.js , , .
--- <div id="react-view">${componentHTML}</div> +++ <div id="react-view"></div>
. , . !
: , , npm run webpack-devserver, .
Github
: https://github.com/yury-dymov/habr-app
https://github.com/yury-dymov/habr-app/tree/v1 â v1
https://github.com/yury-dymov/habr-app/tree/v2 â v2
v3 [To be done]
次ã¯ïŒ
Hello World ? , , !
react-bootstrap , , , , flux redux .
7.
- JavaScript ES2015 â https://learn.javascript.ru/es-modern
- webpack â http://webpack.imtqy.com/docs/
- webpack â https://learn.javascript.ru/screencast/webpack
- Babel â https://babeljs.io/
- ESLint â http://eslint.org/
- Express â https://expressjs.com/
- Express â http://jsman.ru/express/
- React â https://facebook.imtqy.com/react/
Ps , , . äºåã«æè¬ããŸãïŒ