pixiv SketchのSSRの話

019c906aa98e907cc7951cab7d4850ea?s=47 geta6
April 11, 2017

pixiv SketchのSSRの話

pixiv SketchでSSRしている感じの話です

019c906aa98e907cc7951cab7d4850ea?s=128

geta6

April 11, 2017
Tweet

Transcript

  1. None
  2. ೥௮͚͜Μͩ443ͷ࿩ αʔόʔαΠυϨϯμϦϯά

  3. w ໊લɿ͛ͨ w ৬ۀɿҰൠϊʔϚϧΤϯδχΞ w QJYJW4LFUDIͰ8FCଆͷ࣮૷શൠͨ͠Γϔϧϓͯ͠ ͘ΕΔਓͷհޢΛͨ͠Γ͍ͯ͠·͢ HFUB

  4. 443ͬͯͳʹΑ w αʔόʔαΠυϨϯμϦϯάͷ͜ͱ w ͬ͘͟Γݴ͏ͱ w 41"ͷॳճϩʔυ଎͍ͨ͘͠ w KTͰίϯςϯπߏங͠ऴΘͬͨঢ়ଶΛαʔόʔ αΠυͰ࡞ͬͯग़ͪ͠Ό͑͹଎͘ͳΔ͡ΌΜʂͦ

    ͷ··ಉ͡ίʔυ࢖͍ճͤΔ͠ఱ࠽ʂ w ͱ͍͏ײ͡ͷΞϨ
  5. ࿩͢͜ͱϦετ w TLFUDIͷΞʔΩςΫνϟʢ֓આʣ w 443ͬͯ۩ମతʹͲ͏΍Δͷ w DTTͲ͏ͯ͠Δͷ w ͳΜͰ443ʹͳͬͨͷ w

    σϝϦοτͱϝϦοτ w ͦͷͨ
  6. ΞʔΩςΫνϟ

  7. ΞʔΩςΫνϟ Web Browser pixiv Sketch API rails iOS Android iOS

    app Android app node.js javascript ࠷ۙͨ·ʹݟ͔͚Δߏ੒͚ͩͲɺ೥΍ͬͯΔͱ͜͸গͳͦ͏
  8. ΞʔΩςΫνϟ Web Browser pixiv Sketch API rails iOS Android iOS

    app Android app node.js javascript ΅͘ͷ୲౰
  9. Web Browser pixiv Sketch API rails node.js javascript ΞʔΩςΫνϟ express

    React + Fluxible
  10. Web Browser pixiv Sketch API rails node.js javascript ΞʔΩςΫνϟ SSR

    React SharedCode XHR HTTP viewͳ͠ɺjson͚ͩ
  11. Web Browser pixiv Sketch API rails node.js javascript ΞʔΩςΫνϟ MCͷೄுΓ

    VͷೄுΓ αʔόʔ෇͖ͷڊେͳSPA
  12. 3FOEFSFS w OPEFαʔόʔ SFOEFSFS ͸ϏδωεϩδοΫ΍ηο γϣϯػߏΛҰ੾͍࣋ͬͯͳ͍ w "1*͔Β౉͞ΕͨσʔλΛݩʹɺϒϥ΢βͱಉ͡ ίʔυͰ)5.-Λߏஙͯ͠ϨϯμϦϯά w

    αʔόʔαΠυͰ΋"1*ϦΫΤετ͸)551 w $PPLJFϔομΛαʔόʔͷ)551ϦΫΤελʔʹ ηοτͯ͠ೝূঢ়ଶΛදݱ
  13. 3FOEFSFS w ؆୯ʹݴ͏ͱ.7$ͷ.$͕SBJMTͰ7͕OPEF w .$ͱ7ͷؒʹΞʔΩςΫνϟͷน͕ଘࡏ͢Δʢݴ ޠɾ'8ɾΠϯελϯε͕ҧ͏ʣͷͰɺޓ͍Λ৵ ൜Ͱ͖ͳ͍

  14. 3FOEFSFS w 6*ͷ͜ͱ͚ͩΛߟ͍͑ͯΕ͹͍͍ɺϩδοΫʹབྷΉ ෳࡶͳॲཧ͸"1*ʹͿΜ౤͛ͯɺ͓͔͔ͬͨ͠ΒYY ͔YY͕ฦͬͯ͘ΔͷͰΑ͠ͳʹमਖ਼ w ಺෦৘ใ΁ಛݖతʹΞΫηε͢Δखஈ͕ଘࡏ͠ͳ͍ ͷͰɺOPEF࣮૷ͷΤϯόά͕ηΩϡϦςΟϦεΫ ʹܨ͕ΔՄೳੑ͕௿͍ "1*͕ਖ਼͍͠ͱԾఆͯ͠

  15. 3FOEFSFS Web Browser pixiv Sketch API rails node.js javascript ӽ͑ΒΕͳ͍น

    SSR͢ΔͱMCͱV͸ ෼͚͟ΔΛಘ͘ͳΔ
  16. 3FOEFSFS w .7$ڲਖ਼Ϊϒε w ͲΕ͚ͩٸ͍Ͱ͍ͯ΋಄ͷ͓͔͍͠7JFXίʔυ ͕ॻ͚ͳ͍ɺෛ࠴ઈର࡞Βͳ͍Ϛϯ w 443͸͍͍ͧ

  17. ۩ମతʹͲ͏΍Μͷʁ

  18. 443ग़ྗͷΠϝʔδ w %0$5:1&Ҏ֎ͷ)5.-Λશͯ3FBDUͰߏங w BDUJPOΛୟ͍ͯίϯςϯπදࣔʹඞཁͳTUPSF σʔλΛऩू w 3FBDU%0.SFOEFS5P4UBUJD.BSLVQΛར༻ͯ͠ %0.ΛTUSJOHʹ͢Δɺ͍ͭ͜ʹ%0$5:1&Λͬ͘ ͚ͭͯFYQSFTT͔ΒSFTTFOE͢Δ͚ͩ

    w ͔ΜͨΜʂʂ
  19. 443ग़ྗͷΠϝʔδ const app = new Fluxible({ /* shared app root

    component, stores */ }); const srv = express(); srv.use((req, res) => { req.context = app.createContext(); /* ͍Ζ͍Ζ४උ͢Δ (APIΛfetchͨ͠Γͯ͠ɺfluxΛճ͢) */ const react = React.createElement(Html, { context: req.context }); const html = ReactDOM.renderToStaticMarkup(react); res.send(`<!doctype html>${html}`); }); ͜͜Ͱڞ௨ίʔυ Λ౉͢ html͕ϧʔτͷ component ͔ΜͨΜʂʂ
  20. express (1 request) 443ग़ྗͷΠϝʔδ req Flux Context res React Flux

    Context ReactDOM store store css React (html)
  21. express (1 request) 443ग़ྗͷΠϝʔδ req Flux Context res React Flux

    Context ReactDOM store store css React (html) shared shared server code
  22. JTPNPSQIJDTUPSF w TUPSFͷσʔλ͸TFSWFS͔ΒDMJFOU΁ҙࣝతʹ౉ͯ͠ ͋͛ͳ͍ͱ͍͚ͳ͍ w TUPSFͷঢ়ଶ͸TFSJBMJ[Fͨ͠KTσʔλͱͯ͠ςϯϓ Ϩʔτ )UNM$PNQPOFOU ͔ΒϖʔδʹຒΊࠐΉ w

    DMJFOUͷॳظԽ࣌ʹ͜ΕΛೖखͯ͠TUPSFͷঢ়ଶΛ ෮چͤ͞Δ
  23. JTPNPSQIJDTUPSF const app = new Fluxible({ /* shared app root

    component, stores */ }); const srv = express(); srv.use((req, res) => { req.context = app.createContext(); /* ͍Ζ͍Ζ४උ͢Δ (APIΛfetchͨ͠Γͯ͠ɺfluxΛճ͢) */ const dehydrated = `window.dehydrated=${serialize(app.dehydrate(req.context))}`; const react = React.createElement(Html, { context, dehydrated }); const html = ReactDOM.renderToStaticMarkup(react); res.send(`<!doctype html>${html}`); }); serializeͯ͠౉͢
  24. JTPNPSQIJDDTT w XFCQBDLΛ࢖༻ͯ͠DTTΛఏڙ͢ΔGVODUJPOͱͯ͠ USBOTQJMF͓ͯ͘͠ʢLSJBTPGUJTPNPSQIJDTUZMF MPBEFSʣ w $PNQPOFOU͸Ϛ΢ϯτ࣌ʹ͜ͷϝιουΛݺΜͰɺ ࣗ਎͕ඞཁͱ͢ΔTUZMFΛϒϥ΢βʹఏڙ͢Δ

  25. JTPNPSQIJDDTT w DMJFOUͱTFSWFSͰDTTͷॲཧํ๏Λม͑Δ w TFSWFSͰ͸DTTΛTUSJOHͱͯ͠ಘΔGVODUJPOΛ࣮ߦɺ BSSBZʹTUSJOHΛQVTI͓͍ͯͯ͠ϨϯμϦϯά࣌ʹ TUZMFλάʹల։͢Δ w DMJFOUͰ͸TUZMFΛIFBEʹJOTFSU͢Δ%0.ૢ ࡞෇͖GVODUJPOΛ࣮ߦ

  26. JTPNPSQIJDDTT const app = new Fluxible({ /* shared app root

    component, stores */ }); const srv = express(); srv.use((req, res) => { req.context = app.createContext(); /* ͍Ζ͍Ζ४උ͢Δ (APIΛfetchͨ͠Γͯ͠ɺfluxΛճ͢) */ const context = req.context.getComponentContext(); const styles = []; context.insertCss = (s) => styles.push(s._getCss()); const dehydrated = `window.dehydrated=${serialize(app.dehydrate(req.context))}`; const react = React.createElement(Html, { context, dehydrated, styles }); res.send(`<!doctype html>${html}`); }); ReactContextͰpush
 ͢ΔϝιουΛ౉͢
  27. )UNM$PNQPOFOU w EBOHFSPVTMZ4FU*OOFS)5.-Λ࢖ͬͯ౉͞ΕͨTUZMF ΍TFSJBMJ[F͞ΕͨTUPSFσʔλΛΨϯΨϯຒΊࠐΉ w DMJFOU༻ͷॳظԽTDSJQUͰςϯϓϨʔτͱͯ͠ຒΊࠐ ·Εͨ͜ΕΒΛೖख͠ɺDMJFOUଆͷΞϓϦέʔγϣ ϯΛαʔόʔͱಉ͡ঢ়ଶʹ෮چ͢Δ

  28. express (1 request) 443ग़ྗͷΠϝʔδ req Flux Context res React Flux

    Context ReactDOM store store css React (html) serialize ArrayPush render toStaticMarkup res.send
  29. DTTͷ͜ͱৄ͘͠

  30. ˺8FC$PNQPOFOUT w 4LFUDI8FC൛ͷ$PNQPOFOUઓུ w 3FBDU$PNQPOFOUͷKT࣮૷ɾDTTείʔϓ͕ࣗ਎ ͷ֎΁ӨڹΛٴ΅͞ͳ͍Α͏ʹ࣮૷ɾઃܭ͢Δ w DTT͸XFCQBDLΛ࢖༻ͯ͠KTʹ಺แɺίϯϙʔωϯ τ୯ҐͰهड़͠ίϯϙʔωϯτࣗ਎ʹ؅ཧͤ͞Δ w

    LSJBTPGUJTPNPSQIJDTUZMFMPBEFSࢀর
  31. ˺8FC$PNQPOFOUT w DPNQPOFOU8JMM.PVOUͰDTTΛϚ΢ϯτ͠ɺ DPNQPOFOU8JMM6ONPVOUͰDTTΛΞϯϚ΢ϯτ͢Δ w Ϛ΢ϯλʔɾΞϯϚ΢ϯλʔ͸಺෦ʹΧ΢ϯλʔ Λ͍࣋ͬͯΔ w Ϛ΢ϯλʔ͸ʮطʹࣗ਎ͱಉ͡$PNQPOFOU͕ଘ ࡏ͍ͯ͠Ε͹ʯϚ΢ϯτ͠ͳ͍

    w ΞϯϚ΢ϯλʔ͸ʮ·ͩࣗ਎ͱಉ͡$PNQPOFOU ͕ଘࡏ͍ͯ͠Ε͹ʯΞϯϚ΢ϯτ͠ͳ͍
  32. ίϯϙʔωϯτߏ੒ - Component/ `- package.json // { "main": "Component.jsx" }

    `- Component.jsx // component `- Component.styl // stylesheet for component σΟϨΫτϦΛimportͨ࣌͠ʹ mainͷ஋Λࢀরͯ͘͠ΕΔ
  33. $PNQPOFOUKTY import React, { Component } from 'react'; import {

    withStyle } from '../../utils/Decorator'; @withStyle(require('./Component.styl')) export default class Component extends Component { static displayName = 'Component'; componentDidMount = () => { console.log('mounted'); }; render = () => ( <div id='Component'> <div id='ComponentBody'> <span>component content</span> </div> </div> ); } ޙड़ ίϯϙʔωϯτ໊ͱಉ͡ id͔classΛRootʹऔΔ ※ transform-decorators-legacy
  34. $PNQPOFOUTUZM #Component &Body box-sizing border-box margin 0 auto padding 0

    20px max-width 600px width 100% ϑΝΠϧ͋ͨΓ Root͸1ݸͷϧʔϧ
  35. 4UZMF%FDPSBUPS import noop from 'lodash/noop'; import React, { Component, PropTypes

    } from 'react'; export const withStyleDecorator = (style) => (ComposedComponent) => ( class WithStyle extends Component { static displayName = `withStyle(${ComposedComponent.displayName})`; static contextTypes = { insertCss: PropTypes.func.isRequired, }; constructor(props, context) { super(props, context); this.removeCss = style ? this.context.insertCss(style) : noop; } componentWillUnmount = () => { this.removeCss && setTimeout(this.removeCss, 0); }; render = () => ( <ComposedComponent {...this.props} /> ); } ); isomorphic-style-loader ͔Βఏڙ͞ΕΔϚ΢ϯλʔ
  36. 4UZMFTIFFU3VMF w ίϯϙʔωϯτ໊ͱϧʔτͷJEDMBTT໊ΛҰகͤ͞ ΔͱɺϑΝΠϧγεςϜͷ੍໿্͓ͳ໊͡લͷ 3PPU&MFNFOU͸࡞੒Ͱ͖ͳ͘ͳΔ w ໊લ෇͚ͷϧʔϧΛ౷Ұ͢Δ͚ͩͳͷͰDTTNPEVMF Λಋೖ͢ΔΑΓखܰ

  37. 443Λબ୒ͨ͠ཧ༝

  38. 8FCͷେ·͔ͳมભ w  ։ൃ։࢝ νʔϜϝϯόʔਓ  w  ϦϦʔε w

     υϩʔػೳWϦϦʔε 4NPPUI-JOF  w  8FCϦϑΝΫλϦϯά w  υϩʔػೳWϦϦʔε 8FC(-൛
  39. w ϦϦʔε͔Βݱࡏ·ͰΞʔΩςΫνϟʹมߋͳ͠ w αʔϏεϦϦʔε͔ΒҰ؏ͯ͠αʔόछߏ੒ɺ ʮػೳ௥Ճʯͱʮ࠷దԽʯͷΈΛ࣮ࢪ w ϦϑΝΫλ͸3FBDUWରԠʹ෇ਵ͢Δ$PNQPOFOU ࠷దԽɾTUPSFपΓͷϝϞϦར༻࠷దԽɾ&4΁ ͷ௥ै͕ओͳλʔήοτ w

    αʔϏεϦϦʔε࣌ʹཁ݅ʹ߹க͢Δʮਖ਼ղʯͷΞʔ ΩςΫνϟΛબ୒͢Δ͜ͱ͕Ͱ͖ͨ
  40. 443ΛܾΊͨϑϩʔ

  41. 443ΛܾΊͨϑϩʔ w Ұ൪࠷ॳ͸OPEFͰϓϩτλΠϐϯάͨ͠ w ౰࣌3FBDU W ͕ྲྀߦΓΈΛਂΊ͍ͯͯɺϑϩ ϯτ࿦૪͕ա౉ظΛܴ͍͑ͯͨ w ৽ن։ൃͷબ୒ࢶ͔Β#BDLCPOFͷྶѹ͕ফ͑ɺ

    "OHVMBS͔3FBDU͔ͱ͍͏ײ͡ʹͳΓͦ͏ͳࠒ
  42. 443ΛܾΊͨϑϩʔ w ΋ͱ΋ͱɺ3FOES BJSCOC੡ͷ#BDLCPOFΛαʔόʔ Ͱ࢖͑Δ΍ͭ ͬΆ͍࣮૷ͰKTʹ·ͭΘΔೋॏςϯ ϓϨʔτ࣮૷Λഁ໓͍ͤͨ͞ئ๬͕͋ͬͨ w #PPUIͰKTςϯϓϨʔτͷೋॏ࣮૷ʹർΕ͖͍ͬͯͨ

  43. 443ΛܾΊͨϑϩʔ w ϓϩτλΠϓதʹ'MVYJCMFͱ͍͏443ରԠͷ'8Λݟ ͚ͭͨͷͰɺ͍ܰϊϦͰ443Λࢼͨ͠ w ΅͘ʮOPEFͰ΍͍͍ͬͯʁʯ w 1.ʮ͍͍ͧʯ w ΅͘ʮ3FBDUͬͯͷͱ'MVYJCMFͬͯͷͰ443͕ʔʯ

    w 1.ʮ͡ΌΜ͡ΌΜߦ͜͏ʯ
  44. 443ΛܾΊͨϑϩʔ w όοΫΤϯυ΁ͷෆ͔҆ΒSBJMTΤϯδχΞΛௐୡ w SBJMT͔ΒWJFXΛग़͢ͷ͸ઈରʹݏͩͬͨ ޙड़  w 1.ʮJ04൛͸ઈରಉ࣌ʹϦϦʔε͢Δͧʯ w

    αʔϏεϦϦʔε౰ॳ͔Β"1*͕ඞཁ w SBJMTαʔόʔ͔ΒWJFXΛग़ྗ͢Δͱɺ"1*ͱWJFX Ͱೋॏʹ࣮૷͕ඞཁʹͳͬͯ͠·͏
  45. 443ΛܾΊͨϑϩʔ w αʔϏε͸UVNCMS΍JOTUBHSBNͷΑ͏ͳʮλΠϜϥ Πϯʯ͕جຊϏϡʔɺϖʔδϯά࣮૷͕ඞਢ w SVCZͷJUFNUFNQMBUFʹKTͷJUFNUFNQMBUFΛ ॻ͍ͯ9)3ͰKTPOΛೖखͯ͠ΰϦΰϦϖʔδϯ άɺΈ͍ͨͳ஍ࠈ͸ಘͨ͘ͳ͍ w ΋͔ͯ͠͠8FC΋ҰͭͷΫϥΠΞϯτͱݟͳͤ͹Α

    ͍ͷͰ͸ɺOPEFαʔόʔΛʮ8FC#SPXTFS޲͚ͷ ΞϓϦʯͬͯݴ͍ுΕͳ͍ͩΖ͏͔
  46. 443ΛܾΊͨϑϩʔ w ʮ8FCϒϥ΢β޲͚ͷΞϓϦʯͱ͍͏ঢ়ଶʹͳΔͱ ωΠςΟϒΞϓϦͱίϯςΩετ͕ڞ༗Ͱ͖Δ w "1*ͷར༻ํ๏ʹؔͯ͠஌ݟڞ༗͕Մೳɺ࣮૷ί ετΛݮΒͤΔ w SBJMTͷ࣮૷΋KTPO͚ͩΛ஻Ε͹Α͘ͳΔɺUFNQMBUF ࣮૷͕ඞཁͳ͍ͷͰ࣮૷ίετΛݮΒͤΔ

  47. 443ΛܾΊͨϑϩʔ w .$ͱ7ͷؒʹΞʔΩςΫνϟͷน͕͋Δ͜ͱͰ ʮUFNQMBUFʹ͔͠ଘࡏ͠ͳ͍ม਺ʯ͕ੜଘͰ͖ͳ ͍ɺϝϯςφϯείετ͕ݮΒͤΔ w ΫϥΠΞϯτ޲͚࣮૷͕ޓ͍ʹґଘੑΛ࣋ͨͳ͍ w ͋ΔϓϥοτϑΥʔϜ͕ಛఆͷػೳΛαϙʔτ͢Δ ͔Ͳ͏͔͸ɺ७ਮʹ༏ઌ౓ͷ໰୊ʹू໿͞ΕΔ

  48. 443ΛܾΊͨϑϩʔ w KTͰੜ੒͢Δίϯςϯπ͕4&0తʹΞϨ͕ΞϨ͔ͩ ΒΞϨɺΈ͍ͨͳ࿩Λ͠ͳͯ͘Α͘ͳΔ ౰࣌  w OPEFKTαʔόʔΛSBJMTαʔόʔͱ͸ผʹཱͯͯ443 ͠Α͏ͥɺͱ͍͏ྲྀΕʹઆಘྗ͕༩͑ΒΕͨ

  49. 443ΛܾΊͨϑϩʔ w 443͕໾ཱͪͦ͏ͳγʔϯ w ΠςϨʔτ͢ΔϦονίϯςϯπΛఏڙ͍ͨ͠ w ςϯϓϨʔτͷೋॏ࣮૷Λආ͚͍ͨ w ϞόΠϧͱಉ࣌ϦϦʔε "1*͕࠷ॳ͔Βඞཁ

  50. σϝϦοτ

  51. σϝϦοτ w ॏ͍ɺ͍͍ͩͨͷ΋ͷ͕ॏ͍ɺͱʹ͔͘ॏ͍

  52. σϝϦοτ w αʔόʔαΠυͰ΋"1*ϦΫΤετ͸)551 w Φʔόʔϔου͕େ͖͍ɺϨεϙϯεʹ͔͔Δ͕࣌ؒ Ұ൪ॏ͍ͱ͜ΖͰT͘Β͍͔͔ͬͯ͠·͏ w 3FOEFSFS͸Ұ੾ͷಛݖΛ࣋ͨͳ͍ͨΊɺϢʔβʔ͕ϩά Πϯ͍ͯ͠Δ͔Ͳ͏͔Λ"1*ͷGFUDIແ͠ʹ஌Γಘͳ͍ɺ ϧʔςΟϯάޙͷTUPSFͷঢ়ଶΛݟͯ൑ఆ͢Δ͔͠ͳ͍

    w ͦͷͨΊʮ1SPNJTFBMMͰϦΫΤετΛશฒྻʹͯ͠ζ υϯʯͷΑ͏ʹ୯७ʹ͸͍͔ͳ͍ɺ4LFUDIͰ͸443࣌ ʹฒྻϦΫΤετΛճʹ෼͚ͯૹ͍ͬͯΔ
  53. σϝϦοτ w ഑৴͢ΔKT͕ංେԽ͕ͪ͠ w XFCQBDLͰશͯΛUSBOTQJMF͢ΔͱKTίʔυʹDTT΋ ؚ·ΕΔ͜ͱʹͳΔ w ݱ࣌఺ͰϑΝΠϧαΠζ͸.#ɺϞόΠϧΞϓ Ϧ͕ແ͍αʔϏεͰ͋Ε͹ݱ࣮తͳαΠζͰ͸ͳ͍ w

    XFCQBDLͷMPBEFSઃఆʹґଘ͢ΔͷͰະѹॖՕॴΛ૞ ࡧ͢Δͷ͕ࠔ೉ ͜ͳ͍ͩDTTͷॏෳͱະѹॖͷͱ͜ ݟ͚ͭͯ.#͘Β͍ݮΒͨ͠
  54. σϝϦοτ w ಄ͷ͓͔͍͠ίʔυ͕ॻ͚ͳ͍ w σʔλ͸"1*͔Β͔͠औͬͯ͜Εͳ͍͠ɺ͍ͬͺ ͍औΔͱͦΕ͚ͩϨεϙϯε͕஗͘ͳΔ w ͓·͚ʹKT͕མͪΔͱαʔόʔ͕ΤϥʔΛు͘ w ख਺ΑΓ΋ઃܭʹଟ͘ͷ࣌ؒΛׂ͘͜ͱʹͳΔ

    w ʮԿ೔·Ͱʹ͜Ε࣮૷͠ͱ͍ͯʂϤϩγΫʂʯͬ ͯͳͬͨ࣌ʹͭΒ͍ɺ֬อ͠ͳ͚Ε͹͍͚ͳ͍࣌ ͕ؒগ͠ଟ͘ͳΔ
  55. ϝϦοτ

  56. ϝϦοτ w ಄ͷ͓͔͍͠ίʔυ͕ॻ͚ͳ͍ w KTࣗ਎͕σʔλΛೖखͯ͠දݱ͢ΔͷͰɺ༝དྷͷ ෆ໌ͳσʔλ͕ଘࡏ͠ͳ͍ʢςϯϓϨʔτʹྲྀ͠ ࠐ·Ε͍ͯΔม਺ͳͲʣ w ࣮૷͸େม͚ͩͲɺશମ૾Λ೺Ѳͨ͠ਓ͕ॻ͘ͱ ͍͍ͩͨಉ͡Α͏ͳίʔυʹͳΔ

  57. ϝϦοτ w ϓϥοτϑΥʔϜͷ֦ுੑ͕ߴ͍ w શͯͷϓϥοτϑΥʔϜ͕ʮ"1*ͱΫϥΠΞϯτ ΞϓϦʯͱ͍͏ಉҰͷϞσϧʹͳΔ w ޻਺͑֬͞อͰ͖Ε͹ϦϦʔε͔࣌Βશͯͷϓϥο τϑΥʔϜ޲͚ʹΞϓϦ͕࡞੒Ͱ͖Δ

  58. ϝϦοτ w ϓϥοτϑΥʔϜؒͷґଘੑ͕௿͍ w "1*ΛؚΉϓϥοτϑΥʔϜؒͷґଘੑ͕௿͍ͷͰɺ ೚ҙͷλΠϛϯάͰΞϓϦ΍ػೳͷ։ൃΛ։࢝͠ɺ೚ ҙͷλΠϛϯάͰఀࢭͰ͖Δ w 4LFUDIͰ͸"1*ʹSBJMTΛ࠾༻͍ͯ͠Δ͕ɺࣾ಺ͷ஌ݟɾ ϦϦʔε࣌ظɾઃܭϑϩʔͳͲͷ౎߹Ͱͨ·ͨ·࠾༻

    ͞Ε͍ͯΔ͚ͩ w ྫ͑͹ʮKTPO͔͠஻Βͳ͍͠(Pʹஔ͖׵͑Α͏ͥʯ ͱ͍͏࿩΋Ͱ͖Δ
  59. ϝϦοτ w ೋॏ࣮૷ͷօࡴ͠ w ϒϥ΢βଆͰϖʔδϯάͨ͠ΓQVTI4UBUFΛαϙʔτ ͨ͠Γ͢Δࡍɺॳճग़ྗͱܧ͗଍͢༻ͷςϯϓϨʔτ Λೋॏʹߟྀ͢Δඞཁ͕ͳ͍ w ίʔυϕʔε͕ಉ͡+BWB4DSJQUͳͷͰͦͷ··࢖͍ ճͤ͹͍͍

    w ܧ͗଍͞ΕΔՕॴͷΈΞʔΩςΫνϟΛ·͍ͨͩڞ༗ ͷςϯϓϨʔτʹ͢Δͱ͔ɺ)5.-Λ"1*3FTQPOTFʹ ຒΊࠐΉͱ͔ɺͦ͏͍͏͜ͱΛ͠ͳ͍͍ͯ͘
  60. w ϝϦοτͱσϝϦοτ͕͋ΔɺશͯͷΞϓϦέʔγϣ ϯͷύλʔϯʹద߹͢ΔສೳༀͰ͸ͳ͍ w ԼهͷΑ͏ͳϞνϕʔγϣϯʹରͯ͠༗༻ w ೋॏ࣮૷Λආ͚͍ͨ w αʔϏεΛϦονͳ41"ͱͯ͠ߏங͍ͨ͠ w

    ෳ਺ͷϓϥοτϑΥʔϜΛಉ࣌ʹαϙʔτ͍ͨ͠ w ͱʹ͔͘ԿͰ΋͍͍͔Β443͕͍ͨ͠
  61. ͦͷଞ

  62. SFTQPOTF w )551ϦΫΤετ͕ϘτϧωοΫʹͳΔ w ͳΔ΂͘଎͘͢ΔͨΊ1SPNJTFBMMΛ࢖ͬͯฒྻԽ w BTZODBXBJUͰ1SPNJTFBMMͨ͠΍ͭΛBXBJU͢Δ w ͜͜͸֎෦ґଘʹͳΔͨΊɺඞͣλΠϜΞ΢τΛઃ ఆ͢Δ

  63. SFTQPOTF srv.use(async (req, res, next) => { try { await

    Promise.all([ request1, request2, request3, ]); next(); } catch (error) { next(error); } }); ͜͏͍͏ײ͡
  64. 6OIBOEMFE3FKFDUJPO w ඞͣVOIBOEMFE3FKFDUJPOΛ؂ࢹ͢Δ w ์ஔ͢ΔͱɺΤϥʔʹૺ۰ͨ͠ϢʔβʔͷϨεϙ ϯεΛλΠϜΞ΢τͷݶք·Ͱ଴ػͯ͠͠·͏ w ௚͙ͯ͢͠σϓϩΠͰ͖ΔΑ͏ʹ؂ࢹ͓ͯ͘͠ w TFSWFS

    QSPDFTTPO VOIBOEMFE3FKFDUJPO 'VOD  w DMJFOU XJOEPXPOVOIBOEMFESFKFDUJPO'VOD
  65. FYQSFTTFSSPSIBOEMF w FYQSFTTͰ͸BSJUZ͕ͷGVODUJPOΛVTF͓ͯ͘͠ͱΤ ϥʔ࣌ͷGBMMCBDLʹͳΔ w ͍ͭ͜ͰIUNMͳͲΛฦ٫͢ΔΑ͏ʹ͓ͯ͘͠ w ࠷ۙ·Ͱ๨ΕͯͯੜΤϥʔϖʔδ͕ग़͍ͯͨʢ໓ଟʹΤϯόά͠ͳ͔ͬͨͷ Ͱؾ෇͔ͳ͔ͬͨʣ

  66. CBCFMMPBEFS w TFSWFSͱDMJFOUͰXFCQBDLͷCBCFMMPBEFSઃఆΛม ͑Δ w OPEFWҎ্Λ࢖༻͍ͯ͠Ε͹ɺBTZODBXBJUΛ αϙʔτ͍ͯ͠ΔͷͰCBCFMͷSFHFOFSBUPSͰ QPMZpMM͢Δඞཁ͕ͳ͍ w CBCFMQSFTFUFOWΛ࢖͍TFSWFSଆΛOPEF

    DVSSFOUͱ͢Ε͹Α͍ɺQSPDFTTWFSTJPO͔Βద ੾ͳQSFTFUΛબ୒ͯ͘͠ΕΔ
  67. $PNQPOFOU࠶ར༻ w ͳΔ΂͘$PNQPOFOUΛ࠶ར༻͢Δ w ϨϯμϦϯά΋KTͷ഑৴αΠζ΋ίʔυΛॻ࣌͘ ؒ΋όάͷಛఆ΋ɺ଎͘খ͘͞Ͱ͖Δ w DTTͷϚ΢ϯτɾΞϯϚ΢ϯτ΋Χ΢ϯλʔॲཧ ͰऴΘΔͷͰΫϥΠΞϯτͷύϑΥʔϚϯε΋☝

  68. $PNQPOFOU࠶ར༻ Button FollowButton ݟͨ໨ͷ੍ޚ Click ϑΥϩʔঢ়ଶͷ੍ޚ Button ݟͨ໨ͷ͜ͱ͚ͩ ঢ়ଶͷ؅ཧ͚ͩ

  69. QBDLBHFKTPO w XFCQBDLͰ͸QBDLBHFKTPOͰNBJOΩʔͷଞʹ΋ɺ CSPXTFSͱ͍͏Ωʔ͕ೝࣝͰ͖Δ w ϑΥϧμʹQBDLBHFKTPOΛஔ͍ͱ͍ͯɺͦͷ QBDLBHFKTPOʹCSPXTFSͱ͍͏ΩʔΛઃఆ͢Δ w ϒϥ΢βଆͷϏϧυͰ͸CSPXTFSͷϑΝΠϧΛ࢖ ͍ɺαʔόʔଆͷϏϧυͰ͸NBJOΛ࢖͏ɺͱ͍

    ͏࢖͍෼͚͕Ͱ͖Δ w )551ͷϦΫΤελʔ͸͜ΕΛ࢖ͬͯ෼͚͍ͯΔ
  70. QBDLBHFKTPO

  71. MPDBM4UPSBHF w MPDBM4UPSBHFΛར༻͢ΔͷΛ΍Ίɺ$PPLJFΛ4UPSBHF ͱͯ͠ར༻͢Δ w ͨͱ͑͹ϞόΠϧ޲͚ͷΞϓϦ༠ಋϔομʔͷද ࣔɾඇද੍ࣔޚ w 443࣌ʹϨϯμϦϯάͰ͖͍ͯͨํ͕SFQBJOU͕ ൃੜ͠ͳ͍ɺ$PPLJFʹ͍࣋ͬͯͨํ͕ॳظϩʔ

    υύϑΥʔϚϯεͷ޲্ΛݟࠐΊΔ
  72. ΤϯυϙΠϯτ w ͠͹Β͘ͷؒɺαʔόʔଆͷ಺෦ϦΫΤετͷΤϯ υϙΠϯτʹ΋IUUQTTLFUDIQJYJWOFUͱ͍͏ϑ ϧͷ63-Λ࢖͍ͬͯͨ w ໊લղܾͰ͍ͬͨΜ֎ʹग़Δ෼ͱɺIUUQTͰड͚Δ DQVফඅ෼Λճආ͢ΔͨΊɺαʔόʔϦΫΤετͰ ͸ϑϩϯταʔόʔ΁ͷ*1Λ࢖͏Α͏ઃఆͨ͠

  73. w ςετ͸KFTUͩͱ͔σϓϩΠ͸TIJQJUͩͱ ͔ SFBDU@QFSGͩͱ͔αʔϏεॳظͰ͸γʔυσʔ λͷूΊํ͕Ұ൪େࣄͩͱ͔&4-JOUͩͱ͔BTZOD BXBJUͩͱ͔%0.ͷྔΛ཈੍͢Δख๏ͩͱ͔).3 ͩͱ͔47(ΞΠίϯͩͱ͔ը૾ͷϋογϡϏϧυͩ ͱ͔Ϧϩʔυͳ͠Ͱݴޠ੾Γସ͑ΒΕΔͩͱ͔Ұ൪ ϝϞϦফඅͷগͳ͍TUPSFͷઃܭख๏ͩͱ͔σΟϨ ΫτϦอकํ਑ͱ͔Կ͔͍Ζ͍Ζ͋Γ͗ͯ͢࿩͖͠

    Εͳ͍ w ͕࣌ؒ଍Γͳ͍ɺؾʹͳͬͨΒฉ͍͍ͯͩ͘͞
  74. ·ͱΊ w 443͸͍͍ͧ

  75. Ҏ্