botãã¡ã®å®¶ãä½ã£ã¦ãã
仿¥ãå ¥ç¤¾æ¥ã§ãã
ãã®è¨äºã¯ç¬¬2ã®ãã¯ã³ã´ Advent Calendar 2017ã®18æ¥ç®ã§ãã
12/11ã«æ è¡è¡ã£ã¦ã¦ãªãã¨ãªãç¾å°ã§ä½ãããã¨æã£ã¦ããããæ¸ãã¦ãã¾ãã®ã§ãã¾ã ä¸å°ã®æ®µéã§ããä»å¾ã«æå¾ ãã¦ãã ãã:)
ã¨ããããæä½éã®ãã¼ã¹ã®æ©è½å®è£ ãè¡ãã¾ããã
ããã¯ãªã«ï¼
Slack Appã§ãï¼
ååã®éããbotãã¡ãå容ããæ½è¨ã§ãã
åBotãJSã®ã³ã¼ããæã£ã¦ãã¦ã親ããããåããã¾ãã
以ä¸ãè¦ã¦ããããã¨ããããããããã
æå¾ ãããã®ã¯è¦ªbotã§å®è¡ãããã®ã¯åä¾botã¨ãªãã¾ãã
å®å ¨ã«PCç¨ã§ä½ã£ã¦ããã®ã§ãã¬ã¹ãã³ã·ããã¶ã¤ã³ã¨ããªãã§ãã
ç®ç
botãæ¸ã -> ã©ããã«ãããã¤ãã -> slackã§botã®è¨å®ããã
ãã®ããã¼ãæ¯åããã®è¾ãããï¼(ããã©ããã)
ãã©ã¦ã¶ä¸ã§JSã®å®è¡ããããã³ã¼ããæ¸ãã ãã§å¾ã¯ãã£ã¦ãããæãã«ãã¦ã»ããã®ã§ãããç®çã§ãã
ç¾å¨ã®é²æ
ä»å¾ãããããã¨
æ©è½é¢
- ä»ç¾å¨ãbotã«å¯¾ããå¼ã³åºãã®åèªãä¸ã¤ãªã®ã§æ£è¦è¡¨ç¾ã使ããããã«ãã
- ä¸ã¤ã®botã«å¯¾ãã¦è¤æ°ã®ãã£ã³ãã«ãç»é²ã§ããããã«ãã
- ã¹ãã¬ã¼ã¸æ©è½ã®å®è£ (ä¾: TODOã¢ããª)
- privateæ©è½ã¨æ¨©éå¨ã
- Slackã®RTMã使ã£ã¦ããããæ§ã ãªã¤ãã³ãããã¯ãã§ããã®ã§ãããã«ãåå¿ã§ãã
- ã¢ã¤ã³ã³ã®ç»å対å¿
- 表示ã¯ã§ãããã¢ãããã¼ãç»é¢ä½ãã®ããã©ãããã¦ã¾ã ãã£ã¦ãªã
ã³ã¼ãé¢
- botã®evalå®è¡(
Function
ã§ãå¯)ã«å¯¾ãã¦ããã£ã³ã»ãªã³ã°ãå®è£ ãã - ã»ãã¥ãªãã£ãã°ã
- ä»ã¯slackãã¼ã ã¨ãã身å ã§ä½¿ãã®ã§åªå 度ãä½ã
- ä¾å¤å¦çãéé
- ãã¶ã¤ã³ã®å¤æ´
- ãã¹ããæ¸ã
- Nodeã®ã³ã¼ããBabelãéããè¿·ã
- ããã³ãã¨ã³ãã®ã³ã¼ããFlowã§åå®ç¾©ããã¦ãããããAPIã®åã使ããã
- dockerãçé¢ç®ãªè¨å®ã«æ¸ãæãã
- 飿ã¨ããã¼ãã£ã³ã°ã¨ã
ä»çµã¿
親ã®bot(Slack app)ããã¦ããããåä¾ã®scriptãå®è¡ãããã¨ãããæ¬ä¼¼çã«åä¾ã®botãããããã«è¦ããã
ç°¡åã«ããã¨ãpostMessage
ã¨ãã颿°ã«iconãnameãä»ãããã®ã§ããã夿´ãã¦å¥botãåãã¦ããä»çµã¿ã§ãã
ãªã®ã§ãwebä¸ã§JSã®ã³ã¼ããæ¸ããããããå¿çã§åãbotã«ãªãã¾ãã
ãã¯ã³ã´ç¤¾å
slackã§ãåãã¦ããAlfaããã®bot天å½ã®JSçå®è£
ã§ãã
github.com
ä»ç¾å¨ãåä¾botãã§ãããã¨
fetch, domæä½, ã¡ãã»ã¼ã¸ãéããã§ãã¾ãã(attachmentã¯ã¾ã )
async/awaitã«å¯¾å¿ãã¦ããã®ã§ãããç¨åº¦ã®ãã¨ã¯ã§ãã¾ãããã¾ã ãã£ã³ã»ãªã³ã°ã®å®è£
ãã¦ãªãã®ã§ãããè½ã¡çããããããã¨æã£ã¦ãã¾ãã
Cancel Promise pattern (no cancellable promises)
æè¡ã¹ã¿ãã¯
æ¸ãéãå¤ããªãã®ã§ãããã¯ã¢ãããã¦ããã¾ãã
ãã©ã³ã¹ãã¤ã©ãBabelã§ãã³ãã©ã¼ãwebpackã§ãã
- react
- react-loadable
- JSãã£ã³ã¯ãèªã¿è¾¼ãã«ã¼ãã£ã³ã°æã«ãã¼ãã£ã³ã°ãã
- react-alert
- react-ace
- JSã®ã¨ãã£ã¿ã§è£å®ã¨ããã§ãã
- redux
- redux-saga
- express
- sequelize
- ä»åã¯postgresqlã¨sequelize-cliã§migrateçãè¡ã
- ä»å¾ãbookshelfã«æ»ããã
- emoji-mart
- çµµæåã®ãã¬ããã³ã³ãã¼ãã³ãã¨çµµæå夿ã³ã³ãã¼ãã³ã
- brace
- riek
- inlineãã©ã¼ã ã®å®è£
- classnames
- workbox
- googleã®Service Workerã©ã¤ãã©ãª
- postcss-cssnext
- node-slack-sdk
ãã¨ã¯package.jsonãè¦ã¦ãã ããã
DB
ORMã¯sequelizeã§DBã¯postgresqlã使ãã¾ããã
æ¸ãã¾ã§ã«å®è£ ããæéããã¾ãç¡ãã£ããããbookshelfãããæ £ãã¦ããsequelize, sequelize-cli, postgresqlã使ãã¾ãã
åºæ¬çã«ã¯ãsequelize-cliçµç±ã§ãã¤ã°ã¬ã¼ã·ã§ã³ãè¡ã£ãããã·ã¼ããå·®ãè¾¼ãã ããã¾ãã
docker-compose
å½åãdocker-composeå
ã§éçºãè¡ã£ã¦ããã®ã§ãããã©ããnodemonã䏿ãåããªãã£ãã®ã§ä¸æ¦ãã¼ã«ã«ã§ã®éçºã«æ»ãã¾ããã
ãã¡ããããããã¯ã·ã§ã³ã§ã¯docker-composeã§åãã¾ãã
ã¡ãªã¿ã«dockerã§ã®webpack-dev-serverã®HMR
.env
ã使ã£ã¦ç°å¢å¤æ°ãæä½ãã¦ããã®ã§ããããããã¯ã·ã§ã³ããã£ããããã¡ã³ãã¨ãã®.env
ãã¡ã¤ã«ãèªã¿è¾¼ã¾ããã®ã¯ã©ãããã®ãæé©è§£ãªã®ã ãããæ°ã«ãªãã¾ãããã
ã¾ãherokuã¸ã®ãããã¤ãæ¬å½ã«æ¥½ã§ããã
$ heroku container:push web --app bot-house
ããã§buildãã¦pushãã¦ããã¦åãã®ã§æé«ã§ãã
node-slack-sdk
slack社å
¬å¼ã®Node.jsã¯ã©ã¤ã¢ã³ãã
åºæ¬ããã¥ã¡ã³ããç¡ãã®ã§ãã³ã¼ãèªãã ã»ããæããã«éãã§ãã
ã³ã¼ãã«æ¸ãããã³ã¡ã³ããdocã¯ã¹ã´ã¤ä¸å¯§ãªã®ã§ãããä¸çªæåã«è¦ãã¹ãã ã¨æãã¾ããã
RTMã¯ã¾ã æªå®è£
ãªé¨å(ä¾ãã°RTMã§attachmentã®ã¡ãã»ã¼ã¸ãéããªãç)ãå¤ãã®ã§ããããã¨ãã¯WEBã¨ããnode-slack-sdkã®ã¡ã½ããã使ãã¨ããã§ãã
ã¾ããSlackã®èªè¨¼ãã®ãã®ãããããããªãã£ãã®ã§ä»¥ä¸ã®è¨äºããã¿ã¾ããã
fastify
éããã¨ã§æåãªwebãã¬ã¼ã ã¯ã¼ã¯ã
åãã¦ä»å使ã£ã¦ã¿ã¾ããã使ããããã£ãã§ãã
ãã ããã¯ãexpressã¨æ¯ã¹ãã¨ã¨ã³ã·ã¹ãã ãå
å®ãã¦ããªãã¦ãã¢ããªã±ã¼ã·ã§ã³ãä½ã£ã¦ããã¨å¤§å¤ã§ããã
viewå¨ããèªè¨¼(passport対å¿)ãå¼±ãã¨ããå°è±¡ãããã¾ãã
ä¾ãã°ãwebpack-hot-middlewareã使ããªãã£ãããã¾ãã
github.com
ã¾ã ã¾ã å§ã¾ã£ãã°ããã®ããã¸ã§ã¯ããªã®ã§ã使ã£ã¦ã¿ã¦ä½¿ããããã¨ããå°è±¡ãå¼·ãã£ãã®ã§ãã³ããããã¦ããããã¨æã£ãåé¢ãæ§ç¯ã§ãããæéãããã£ãã®ã§ãã¯ããããã¯ã·ã§ã³ã®ã³ã¢ãªé¨åã¯ã¨ã³ã·ã¹ãã ãå
å®ãã¦ããã©ã¤ãã©ãªã使ãã¹ãã ã¨æãã¾ãã
ä»å¾å¨ãã®ã¨ã³ã·ã¹ãã ã®ä½æãã³ã¢ã«ã³ããããã¦ã¿ããã¨æã£ã¦ãã¾ãã
ã°ã°ã£ã¦ãæ
å ±ã¯åºæ¬ãªãã®ã§ãæåã«issueã¨ã³ã¼ããèªãã ã»ããéãã§ãã
ä»åã¯2æ¥éãããããã£ãé¨åããããçµå±expressã¸ä¹ãæãã¾ããã
ã¡ãªã¿ã«ãã¼ãã·ã¼ã
ã¯ã©ã¤ã¢ã³ãå´ã«ã¼ãã£ã³ã°åã³ãã£ã³ã¯
react-routerã使ã£ã¦ãã¾ãã
ã¾ããä»åã¯dynamic importã®ããreact-loadableã使ã£ã¦ãã¾ãã
react-loadableã¯ãã£ã³ã¯ã§åããããã¼ããèªã¿è¾¼ãã¾ã§ã«è¡¨ç¤ºããããã¼ãã¼ã®è¨ç½®ãªã©ãã§ãã¾ãã
ãã¡ãããPreloadingãã§ãã¾ããä»åã¯ã¾ã ãã£ã¦ã¾ããã
Asset Size Chunks Chunk Names StratumNo1 Medium-06a6ac1709970857f419dc78aca05353.ttf 62.3 kB [emitted] BotsShow.bundle.54f65aa8.js 304 kB 0 [emitted] [big] BotsShow Index.bundle.54f65aa8.js 10.3 kB 1 [emitted] Index ChannelsShow.bundle.54f65aa8.js 8.3 kB 2 [emitted] ChannelsShow UsersIndex.bundle.54f65aa8.js 4.39 kB 3 [emitted] UsersIndex bundle.54f65aa8.js 31.2 kB 4 [emitted] bundle vendor.54f65aa8.js 1.46 MB 5 [emitted] [big] vendor 1f42da94f3ff91d479713521dee90778.css 1.5 kB 4 [emitted] bundle index.html 326 bytes [emitted]
import Loadable from 'react-loadable'; export const BotsShow = Loadable({ loader : () => import(/* webpackChunkName: 'BotsShow' */ '../containers/pages/Bots/Show'), loading: () => (<div>Loading...</div>) }); const Router = () => ( <App> <Switch> <Route path="/bots/:id" component={() => (<BotsShow />)} /> </Switch> </App> );
ããã³ãã¨ã³ãç¨ã®ã©ã¤ãã©ãªã¯vendor.jsã¸ãã¹ã¦ã¾ã¨ããã«ã¼ãã£ã³ã°ãã¨ã«ãã¡ã¤ã«ãåãã¾ãã
react-universal-componentã¨ã©ã¡ãã使ããè¿·ãã¾ããããreact-loadableã«ãã¾ããã
history
ä»åã¯ãbrowserHistoryã§ã¯ãªã䏿¦hashHistoryã«ãã¦ãã¾ãã
çç±ã¨ãã¦ã¯ãwatchæã«html-webpack-pluginã¨expressãã«ã¼ãã£ã³ã°å¨ãã§ç«¶åããããéçºå¹çãè½ã¡ãããã§ãã
æ®æ®µãSSRã®æã«html-webpack-pluginã使ã£ã¦ããªãã£ãããæ°ä»ããããã£ã¦ãã¾ã£ã¦ã¾ãããã
SSR
ä»åã¯ãã¨ãã«ããå¿
è¦ããªãã®ã§ãã¾ããã
SSRãããã¡ãªããã¨ãã¦ã¯ãSEO対çã¨First Viewã«é¢ããé度ãããã¾ãã2ã¤ã¨ãä»åã¯å¿
è¦ã®ç¡ããã¨ã ããã§ãã
ãã®ãããã«è¡¨ç¤ºããã©ã¼ãã³ã¹ã®é¢ã§ã¯ãdynamic importã¨Service Workerã§è£ãã¾ãã
PWAã®ããã®ã©ã¤ãã©ãªã§ããWorkboxã使ããä»åã¯Service Workerãæ±ãã¾ãã
ä»ã¯html-webpack-pluginã§htmlãã¡ã¤ã«ãåãåºãã¦ã¾ãããä»å¾SSRåæ§ã«inlineã¸ã¨å¤ãããã¨æãã¾ãã
ææ³
æå¤ã¨å¤§è¦æ¨¡ãªãã®ãä½ã£ã¦ãã¦æéãããã¾ããã§ããã
ç¹ã«Slackã®ãããã°ãæ¬å½ã«å¤§å¤ãªã®ã¨Slack Appã¨ããã®ããªããªã®ãã¿ãããªé¨åããç¥ããªãã¨ãããªãã¦å°ãSlackã«è©³ãããªã£ãæ°ãããã
ã¾ã ã¾ã ãããã¨ãå¤ãã®ã§ããå°ããã®éçºã«æ¥½ãããã¨æã£ã¦ãã¾ãã
ç°¡åã«å°å ¥ã§ããã®ã§æ¯é使ã£ã¦ã¿ã¦ãã ããï¼ï¼