èæ¯

ããã«ã¡ã¯ãHabrã 2016幎ã®åå¬ãç§ã¯åã³å€ç¬ã«ãªããŸããã ãã°ããããŠãTinderã§ãããã¡ã€ã«ãååŸããããšã«ããŸããã ãã¹ãŠã¯åé¡ãããŸããããç©ççãªããŒããŒãã§ã¯éåžžå
¥åã§ããªããããåŸã
ã«ç²åŽãèç©ãå§ããŸããã ãã®åé¡ã«å¯Ÿããããã€ãã®è§£æ±ºçãèŠãŸããã
- å
¬åŒã¹ããŒããã©ã³ã¢ããªãåãå
¥ããŠåŒãç¶ã䜿çšãã
- BlueStacksãå
¬ââåŒã®Androidã¢ããªã§äœ¿çšãã
- ãã¹ã¯ãããã«æ¢åã®ã¯ã©ã€ã¢ã³ãã䜿çšããïŒ Tinder ++ ïŒ
- èªåã§æžã
æåã®ãªãã·ã§ã³ã¯ãå®éã®ããŒããŒããç»é¢äžã®ããŒããŒããããæ ¹æ¬çã«åªããŠãããããç§ã«ã¯åããŠããŸããã§ããã 2çªç®ã®ãªãã·ã§ã³ã¯ãçµå±ã®ãšããããã¹ã¯ãããçšã«æé©åãããŠããªãã¢ããªã±ãŒã·ã§ã³ã«ãªããããé©åã§ã¯ãããŸããã§ããã 3çªç®ã®ãªãã·ã§ã³ã¯ããã¶ã€ã³ããã°ããªããžããªå
ã®ã¢ã¯ãã£ããã£ãå°ãªãããšãé€ããŠããã¹ãŠã®äººã«é©ããŠããŸããã åŸã«Tinder ++ã¯Tinderã®åŒè·å£«ããæçŽãåãåãããããžã§ã¯ãã¯å®å
šã«ãã£ã³ã»ã«ãããŸããã ãããã£ãŠãå人çã«ã¯ãéžæã¯æããã§ããã
éå§ãã

ãŸã第äžã«ãTinderã«ã¯ãªãŒãã³APIããããŸãããã2014幎ã«MITMã䜿çšããŠãªãŒãã³ãããããšã¯æ³šç®ã«å€ããŸãã ããã¯ãã¯ã©ã€ã¢ã³ããäœæããã®ã«ååã§ããããšãå€æããŸããã
ããããããããžã§ã¯ãã®å°é£ãªéåœã®éã«ã»ãšãã©å€ãããªãã£ãå¯äžã®ãã®ã¯ãšã¬ã¯ããã³ã§ããã
ç§ã¯Reactãããããããšæã£ãŠããã®ã§ãæšæºãã³ãã«ã§ããreact + redux + redux-saga + immutableãéžæãããŸããã æåã®ããŒãžã§ã³ã¯5æãŸã§ã«æžãããŸãããã æ²ãã£ãæ ã¢ãŒããã¯ãã£ã reduxãé«éåããã«ã¯ãã¡ã¢åãshouldComponentUpdateãã»ã¬ã¯ã¿ãŒãã¡ã¯ããªãªã©ã®å€ãã®æäœæ¥ãå¿
èŠã§ããããšãå€æããŸããã
æ¯ãè¿ã£ãŠã¿ããšãããããããã§ã¯ãªãã£ãã§ãããããŸãããããããã¹ããŒãªãŒå
šäœãèŠæ±ããImmutable.Map.mergeDeepã䜿çšããŠæ¢åã®ã¹ãã¢ãšããŒãžããããšã¯æ¯å䟡å€ããããŸããã§ãã
ãããã«ãããreduxãšredux-sagaã®åé·æ§ã¯ç§ãéå±ããå§ããŸããã ç§ã®çµ¶ãéãªãå°è±¡ã¯ãå³æžé€šãæäŒã代ããã«ç§ãšæŠã£ãŠãããšããããšã§ããã
Reduxã«ã€ããŠreduxã¯æªãã©ã€ãã©ãªã ãšã¯èšããããããŸããã 審çŸçãªèŠ³ç¹ããã圌女ã¯éåžžã«ãšã¬ã¬ã³ãã§ãã ãããŠãè¯ãã³ãŒããæžãããšãã§ãããªãããããæãéèŠãªããšã§ãã ãã ããåçŽãªãã®ã§ãã£ãŠããå€ãã®è£å©ã³ãŒããäžç·ã«äœæããããšãéåžžå¿
èŠã§ããããšãåŠå®ããããšã¯ã§ããŸããã
ã ãããreduxã¹ã¿ã€ã«ã¯ç§ã«åãããé
ããŠç§ã¯ãããéé£ããŠåå¿ããŸããã ããšäžã€ã ãæ®ã£ãã
æžãã®ãããã

ãã¡ãããã¿ã€ãã«ã¯å°ãæçºçã§ãã å®éãåæ¥èšŒæžã®ä¿è·æéãã»ãã·ã§ã³ãæ¿åãè»äºè²»ãããã³ä»ã®åœãžã®ç§»åã®ããã®ææžã®ã³ã¬ã¯ã·ã§ã³ãç»å ŽããŸããã ãããããã¹ãŠãå°ãèœã¡çããšããã«ã次ã®ãã€ã³ãã«ç§»ããŸããã
No.1ããã¹ãŠæžãæãã
æ°ããã¹ã¿ãã¯ã«ã¯ã InfernoãšMobXãå«ãŸããŠããŸãã ã ãããã®ã©ã€ãã©ãªã¯äž¡æ¹ãšããæå°éã®æåäœæ¥ã§è¯å¥œãªããã©ãŒãã³ã¹ãçŽæããŸããïŒåŸã§å€æããŸããããå®éã«ã¯ããã§ã¯ãããŸããã§ããïŒã äžè¬ã«ãMobXã®ãããã§ã³ãŒãã¯ããç°¡æœã«ãªããŸãããã3ã€ã®åé¡ãåæã«å¢å€§ããŸããã
ã¹ããŒãªãŒãã©ãã«ä¿åããŸããïŒ

æåã®æãããªè§£æ±ºçã¯ãlocalStorageã䜿çšããããšã§ããã ãã®ããã«ãç§ã¯çŽ æŽãããlocalForageã©ã€ãã©ãªãŒã䜿çšããŸããã ãã ããå±¥æŽãä¿åããã³ååŸããããã³ã«JSON.stringifyããã³JSON.parseïŒããã³æŽæ°ããšã«å
šäœãæ°ããä¿åããããã³ã«ïŒåã³ã¯è¿œå ãããŸããã§ããã çŸåšããµãŒããŒããã®æŽæ°ã®ã¿ãèŠæ±ããããããå±¥æŽã«ããŒãžãããšããäºå®ã§ãããæãŸããããã©ãŒãã³ã¹ãéæããããšã¯ã§ããŸããã§ããã

次ã®è§£æ±ºçã¯ãIndexedDBã䜿çšããããšã§ããã Dexie.jsã©ã€ãã©ãªãæ倧ã®ããã©ãŒãã³ã¹ãåŸãããã«éžæãããŸããã å€æŽãããããŒã¿ã®ã¿ãæŽæ°ãããšé床ã倧å¹
ã«åäžããããšãããã«æããã«ãªããŸããããã€ã³ã¿ãŒãã§ã€ã¹ã®é
延ã¯äŸç¶ãšããŠé¡èã§ããã 次ã«ãWebWorkerã§IndexedDBã䜿çšããŠãã¹ãŠã®äœæ¥ãè¡ã£ããšããããã¹ãŠãããŸãããããã«èŠããŸããã
ããŒã¿ãåæããæ¹æ³ã¯ïŒ

Tinder APIããªã¯ãšã¹ãããã«ã¯ãAndroidã¯ã©ã€ã¢ã³ãã§æš¡å£çšã®ç¹å¥ãªããããŒãèšå®ããå¿
èŠããããŸãã ã»ãã¥ãªãã£äžã®çç±ããããã©ãŠã¶ããŒã¹ã®JSã¯ãã®ãããªããªãã¯ããµããŒãããŠããªãããããã¹ãŠã®ãªã¯ãšã¹ãã¯ã¡ã€ã³ã®Electronããã»ã¹ããå®è¡ãããŸããã
ãã®ãããããŒã¿ã¯æ¬¡ã®ããã«ãªããŸããã
- ã¡ã€ã³ããã»ã¹ã§ãµãŒããŒããåä¿¡ããWebWorkerã«éä¿¡ãã
- åŠçãIndexedDBãžã®æžã蟌ã¿ãã¬ã³ãã©ãŒãžã®éä¿¡
- ã€ã³ã¿ãŒãã§ã€ã¹ã®æŽæ°ãæäŸããMobXã¹ãã¬ãŒãžã«èšé²ãã
ããã«ããã蚱容å¯èœãªããã©ãŒãã³ã¹ãéæã§ããŸããããã¹ãã¢ãæ¡å€§ãããã®ãã³ã«IndexedDBã®ããŒã¿ãæ
éã«ããŒãžããŠãããMobXã§åãäœæ¥ã2åè¡ãããšã«ãªããŸããã ããã«ã3çªç®ã®åé¡ããããŸããã
Raw Infernoã€ã³ãã©ã¹ãã©ã¯ãã£

Infernoã¯ãã»ãŒãã¹ãŠã®ãã³ãããŒã¯ã§ç«¶åä»ç€ŸãããåªããŠããŸãããéçºè
ã®çç£æ§ãåæ§ã«éèŠã§ãã inferno-compatã®ååšã«ãããããããå€ãã®Reactã©ã€ãã©ãªã¯ãŸã æ©èœããŸããã§ããã material-uiãèµ·åããããšã¯å°é£ã§ããã ã react-vistualizedã¯ããŒããããŸããã§ããã
移è¡æ±ºå®
ãã¡ãããäžè¶³ããŠãããã®ã®ã»ãšãã©ã¯éåžžã«ã·ã³ãã«ã§ç°¡åã«æžãããšãã§ããŸããã ããã€ãã®å Žæã§ã¯ãããã€ãã®æ±ããããã³ã°ã§Reactã©ã€ãã©ãªãååŸããããšãå€æããŸããã ããããäžè¬ã«ãããŒã¿ããŒã¹ãšãªã¢ã¯ãã£ãã¹ãã¬ãŒãžã®æååæãšåæ§ã«ããã®ç¶æ³ã¯ç§ãéå±ããå§ããŸããã ç§ã¯Infernoãªããžããªã«è²¢ç®ããããšããŸããããé·ãéç§ã¯ååã§ã¯ãããŸããã§ããã ãã®ãããªåçŽãªã¢ããªã±ãŒã·ã§ã³ã®3ã€ã®ããã»ã¹ãå€ãããããã«æãããŸããã 宣èšçãªãã®ãå¿
èŠã§ããµããŒãããããã«å€§éã®ã³ãŒããå¿
èŠãšããŸããã
No.2ããã¹ãŠæžãæãã

ä»åã¯ã決å®ã®ãã©ã³ã¹ãåããŠããŸããã Reactãšã®äºææ§ãå¿
èŠã§ã-Reactã䜿çšããŠãã ããããã®ãããªãã³ãããŒã¯ã¯ãæ°åã®èŠçŽ ã衚瀺ããå Žåã«ã®ã¿éèŠã§ãã ç§ã¯ããŸãå€ãã®ããã»ã¹ã奜ãã§ã¯ãããŸãã-ããã¯ãããŒã¿ãã¡ã€ã³ããã»ã¹ã®å
ã®å Žæãšåãå Žæã«ä¿åãããå¿
èŠãããããšãæå³ããŸãã äžè¬çã«ãç§ã¯MobXãšãã®å©ç¹ã奜ãã§ããã倧ããªãªããžããªã§äœæ¥ããã®ã¯ããŸã䟿å©ã§ã¯ãããŸããããããã£ãŠãMobXã¯ã³ã³ããŒãã³ãã®ããŒã«ã«ç¶æ
ã®ãããŒãžã£ãŒãšããŠæ®ããä»ã®äœããã°ããŒãã«ããŒã¿ã«äœ¿çšãããŸãã
èšäºã®ã¿ã€ãã«ãèªããšã ä»ã®äœããæããã«ãªããŸãã ãã¡ãããããã¯GraphQLã§ãã ã¯ã©ã€ã¢ã³ããšããŠã Apolloã䜿çšãããŸãã æåã¯ããã®ãœãªã¥ãŒã·ã§ã³ã¯çããããã«èŠããŸãããèããŠã¿ããšå€ãã®å©ç¹ããããŸãã
- ããŒã¿ã¯ãããã¯ãŒã¯äžã§ã¯ãªãIPCãä»ããŠéä¿¡ãããŸããã€ãŸããå®éã«ã¯é
延ã¯ãããŸããã
- Apolloã¯reduxãªããžããªã®ããŒã¿ãèªåçã«ããŒãžããŸã
- ã³ã³ããŒãã³ããžã®ããŒã¿ã®å®£èšçãªæåº
- 楜芳çãªæŽæ°ã®ãããªè€éãªãã®ã®ããã®æ¢è£œã®ãœãªã¥ãŒã·ã§ã³
ãã¡ãããApolloã«ã¯ããã©ã«ãã§IPCãµããŒãããããŸããããç¬èªã®ãããã¯ãŒã¯ã€ã³ã¿ãŒãã§ã€ã¹ãäœæããããšã¯å¯èœã§ãã ããã¯éåžžã«ç°¡åã§ãïŒ
import { ipcRenderer } from 'electron' import { GRAPHQL } from 'shared/constants' import uuid from 'uuid' import { print } from 'graphql/language/printer' export class ElectronInterface { ipc listeners = new Map() constructor(ipc = ipcRenderer) { this.ipc = ipc this.ipc.on(GRAPHQL, this.listener) } listener = (event, args) => { const { id, payload } = args if (!id) { throw new Error('Listener ID is not present!') } const resolve = this.listeners.get(id) if (!resolve) { throw new Error(`Listener with id ${id} does not exist!`) } resolve(payload) this.listeners.delete(id) } printRequest(request) { return { ...request, query: print(request.query) } } generateMessage(id, request) { return { id, payload: this.printRequest(request) } } setListener(request, resolve) { const id = uuid.v1() this.listeners.set(id, resolve) const message = this.generateMessage(id, request) this.ipc.send(GRAPHQL, message) } query = request => { return new Promise(this.setListener.bind(this, request)) } }
以äžã¯ãã¡ã€ã³ããã»ã¹ã®ãªã¯ãšã¹ãåŠçã³ãŒãã§ãã ãã¹ãŠã®ãã¡ã¯ããªã¯ãServerAPIã¯ã©ã¹ã®ã¡ãœãããäœæããŸãã
GraphQLã¯ãšãªãå®è¡ããããã®ã³ãŒãïŒ
å¿çã¡ãã»ãŒãžãäœæããããã®ã³ãŒãïŒ
ãªã¯ãšã¹ããåŠçããŠããŒã¿ãè¿ãã³ãŒãïŒ
æåŸã«ãã³ã³ã¹ãã©ã¯ã¿ãŒã§ãã¡ãã»ãŒãžã®ãµãã¹ã¯ã©ã€ããŒãäœæããŸãã
import { ipcMain } from 'electron' ipcMain.on(GRAPHQL, instance.processRequest)
çŸåšãåæŽæ°ãåä¿¡ãããšã NeDBããŒã¿ããŒã¹ã«æžã蟌ãŸããIPCã䜿çšããã¡ã€ã³ããã»ã¹ã¯ãå®éã®ããŒã¿ãå確èªããå¿
èŠæ§ã«é¢ããã¡ãã»ãŒãžãã¬ã³ãã©ãŒããã»ã¹ã«éä¿¡ããŸãã
è¿œå
ããã²ãŒã·ã§ã³
éåžžã«é·ãéã åå¿ã«ãŒã¿ãŒã䜿ããããããŸããã§ããã å®éãç§ã¯åœŒããAPIã®å€§èŠæš¡ãªæžãçŽããèŠã€ããã®ã§ãåãã¬ãŒããåã³èžãããšã¯ããŸããã§ããã ãããã£ãŠããŸããMobXã®ç¶æ
ãåæããrouter5 +èªäœããã«ãŠã§ã¢ãæ¥ç¶ããŸããã Electronã«ã¯éåžžã®æå³ã§äºå®äžã®URLã¯ãããŸããããã®ãããããã²ãŒã·ã§ã³ç¶æ
ããªã¢ã¯ãã£ãã¹ãã¬ãŒãžã«ä¿åãããšããã¢ã€ãã¢ã¯çŽ æŽãããã£ãã§ãã ãã ãããã®ãããªãã³ãã«ã䜿çšãããšããã²ãŒã·ã§ã³ãå®å
šã«å¶åŸ¡ã§ãããšããäºå®ã«ãããããããäœåãªã³ãŒããå¿
èŠã«ãªãå ŽåããããŸãã
react-router @ v4ãžã®ç§»è¡ãšãFlexboxããCSS Gridãžã®éšåçãªç§»è¡ãçµã¿åãããŸããã ãããã¯ãäºãã®ããã«äœãããŠããããã§ãã ä»åã¯react-routerã³ãã³ããæ¬åœã«ããããã§ãïŒ
ãã«ãã·ã¹ãã
æåã¯webpackãšelectron-packagerã䜿çšããŸããããæåŸã®å€§ããªå€æŽã®éã«electron-forgeã«åãæ¿ããŸããã ç§ã®ç¥ãéããå°æ¥ããã®ããã±ãŒãžã¯Electronäžã§ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããã³é
åžããããã®æšæºãœãªã¥ãŒã·ã§ã³ã«ãªããŸãã ã¢ã»ã³ããªããã³electron-compileçšã®electron-packagerãå«ãŸããŠãããJS / TSã®è»¢çœ®ãä»ã®åœ¢åŒïŒã¬ã¹ãã¹ã¿ã€ã©ã¹ãSCSSïŒãªã©ã®ã³ã³ãã€ã«ããå®è³ªçã«èšå®ãªãã§å®è¡ã§ããŸãã
çµæ

GraphQLã䜿çšããŠãå€ãã®ã³ãŒããåé€ããŸããïŒã€ãŸãããã°ãããïŒã ã³ãŒãã«æ°ããæ©èœãè¿œå ããã®ããã£ãšç°¡åã«ãªããŸããã ç§ãšã¢ããªã±ãŒã·ã§ã³ã¯ããéãåãå§ããŸããã
ãã®ã¢ãããŒããé»åã¢ããªã±ãŒã·ã§ã³ã®æ§ç¯ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã GraphQL-over-IPCã®å®è£
ãå¥ã®npmããã±ãŒãžã«åå²ããŠã䟿å©ã«äœ¿çšã§ããããã«ããäºå®ã§ãã
éçºèšç»
ããŒãžã§ã³2.0ãŸã§ã«ã
- å°ãªããšãTypeScriptã®ã¡ã€ã³ããã»ã¹ãæžãæãã
- æçš¿ãšé£çµ¡å
ã«æ€çŽ¢ãè¿œå
- ãŠãŒã¶ãŒããããã¯ãããããã¡ã€ã«ãç·šéããæ©èœãè¿œå ããŸã
èå³ã®ããæ¹ãž
â GitHub
â ãŠã§ããµã€ã
ã¹ã¯ãªãŒã³ã·ã§ãã çµè«- 宣èšåã¯åœä»€åãããåªããŠããŸã
- Xäžã®ãã¹ãŠãæžãçŽããããšç¢ºä¿¡ããŠãããªãããŸãèããŠãã ããïŒ
- æžãçŽãã¹ãã§ããïŒ
- Xãæè¯ã®éžæã§ããïŒ
- 代æ¿æ¡ãæ¢ããŠäžé±éãéããããã¹ãŠã®é·æãšçæãæ¯èŒæ€èšãã
çŽ æµãªã€ã©ã¹ããããããžã¥ãªã¢ã»ã¯ã«ãã£ã«æè¬ããŸãïŒ