Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Micro Frontends の理論と実践
 -価値提供を高速化する真のマイクロサービスのあ...

Micro Frontends の理論と実践
 -価値提供を高速化する真のマイクロサービスのあり方- / The Theory and Practice of Micro Frontends

AWS Dev Day Tokyo 2018でMicro Frontendsについて話したスライドです。

#MicroFrontends #マイクロフロントエンド

nobuhikosawai

November 02, 2018
Tweet

More Decks by nobuhikosawai

Other Decks in Technology

Transcript

  1. "HFOEB !5 • ୈᶗ෦.JDSP'SPOUFOETͷཧ࿦ • ୈᶘ෦.JDSP'SPOUFOETͷ࣮ફ • ߟ࡯ • ·ͱΊ

    ࣮ફ্ͨ͠Ͱͷ஌ݟ΍՝୊Λڞ༗͠·͢ ຊ൪౤ೖͷࢀߟʹͳΕ͹ʂ
  2. ϚΠΫϩαʔϏεͷϝϦοτ !33 • σϓϩΠͷಠཱ • αʔϏε͕෼͔Ε͍ͯΔͷͰσϓϩΠ͕ࣗ༝ʹͰ͖Δ • ٕज़ҟ࣭ੑ • αʔϏεಛੑ͝ͱʹ࠷దͳٕज़બ୒͕Մೳ

    • ٕज़తෛ࠴ΛҾ͖ͣΓʹ͍͘ • ߹੒Մೳੑ • αʔϏε͝ͱʹద੾ͳཻ౓ͷ"1*͕ެ։͞Ε͍ͯΔͨΊɺ࠶ར༻ੑ͕ߴ·Δ • ૊৫ͷࣗ཯ੑ • ίϛϡχέʔγϣϯύεΛݮΒ͠ɺҙࢥܾఆΛ͢͹΍͘͢Δ
  3. औΓ૊Έͷࣄྫ !53 • औΓ૊ΜͰ͍Δاۀ •*,&" •4QPUJGZ •ͳͲ IKEA Spotify https://www.youtube.com/watch?v=4KVOuQDIfmw

    https://www.slideshare.net/kevingoldsmith/how-spotify-builds-products-organization-architecture-autonomy-accountability
  4. • ߪങϘλϯΛग़͢ྫ $VTUPN&MFNFOUTͷྫ !59 class BlueBuy extends HTMLElement { constructor()

    { super(); this.innerHTML = 
 ɹɹɹ`<button type="button">buy for 66,00 €</button>`; } disconnectedCallback() { ... } } window.customElements.define('blue-buy', BlueBuy); <blue-buy></blue-buy>
  5. .JDSP'SPOUFOETͷ࣮ݱํ๏ !60 { "id": 1, "name": "foobar", "title": “hooray!” }

    JSON { "id": 1, "name": "foobar", "title": “hooray!” } JSON { "id": 1, "name": "foobar", "title": “hooray!” } JSON { "id": 1, "name": "foobar", "title": “hooray!” } JSON • ैདྷόοΫΤϯυ ͸֤.JDSPTFSWJDFT ͕σʔλΛฦ͢
  6. .JDSP'SPOUFOETͷ࣮ݱํ๏ !61 <div> <h1>hooray!</h1> <p>foobar</p> </div> <div> <h1>hooray!</h1> <p>foobar</p> </div>

    <div> <h1>hooray!</h1> <p>foobar</p> </div> <div> <h1>hooray!</h1> <p>foobar</p> </div> HTML • ϑϩϯτΤϯυ͸
 ͭͷ6*ʹม׵ͯ͠ ͍ͨ
  7. .JDSP'SPOUFOETͷ࣮ݱํ๏ !62 class BlueBuy extends HTMLElement { constructor() { super();

    this.innerHTML = `<button ></button>`; } disconnectedCallback() { ... } } window.customElements.define('b lue-buy', BlueBuy); JavaScript <blue-buy></blue-buy> HTML • 8FC$PNQPOFOUTͷఆٛʢ+4 Λฦ͢ • ౷߹ϨΠϠʔ͸ͦΕΛ഑ஔ͢Δ͚ͩ
  8. .JDSP'SPOUFOETͷཧ࿦·ͱΊ !66 • ٕज़తʹ͸JGSBNF΍8FC$PNQPOFOUTΛ࢖࣮ͬͯݱ class BlueBuy extends HTMLElement { constructor()

    { super(); this.innerHTML = `<button ></button>`; } disconnectedCallback() { ... } } window.customElements.define('b lue-buy', BlueBuy); JavaScript <blue-buy></blue-buy> HTML
  9. ίʔυΠϝʔδ !79 • ϐΞɾϘʔφεଆ class TimelineComponents extends HTMLElement { async

    connectedCallback() { const mountPoint = document.createElement('span'); const shadow = this.attachShadow({ mode: 'open' }); shadow.appendChild(mountPoint); const currentUser = await UserRepository.fetch(); render( <React.Fragment> <link rel="stylesheet" type="text/css" href="http://localhost:3020/main.css"/> <Timeline currentUser={currentUser}/> </React.Fragment>, mountPoint, ); retargetEvents(shadow); } } customElements.define(‘peerbonus—timeline’, TimelineComponents);
  10. ίʔυΠϝʔδ !80 • GJODBQQXFCଆ import React from 'react'; class PeerBonus

    extends React.Component { render() { return ( <div className="l-main_contents_area"> <peerbonus-timeline></peerbonus-timeline> </div> ); } } export default PeerBonus;
  11. ࣮ફʹ͓͍ͯ௚໘ͨ͠՝୊ !81 • ࣮ࡍʹͲͷΑ͏ͳ໰୊ʹ͍ͭͯऔΓ૊Μͩͷ͔Λ঺հ͠·͢ • Ϗϧυͷ໰୊ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝୊

    • άϩʔόϧͳঢ়ଶͷڞ༗ • ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ໰୊ • ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM  • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍໰୊
  12. DBDIFCVTUJOHͷ໰୊ !82 • Ϗϧυͷ໰୊ •DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝୊ • άϩʔόϧͳঢ়ଶͷڞ༗ •

    ը໘ભҠ • ঢ়ଶ؅ཧ • ϥΠϒϥϦͷ໰୊ • ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM  • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍໰୊
  13. άϩʔόϧͳঢ়ଶͷڞ༗ !90 • Ϗϧυͷ໰୊ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝୊ •άϩʔόϧͳঢ়ଶͷڞ༗ •

    ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ໰୊ • ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM  • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍໰୊
  14. ՝୊ !92 • αʔϏεͷૄ݁߹Λอͬͨ··Ͳ͏ڞ༗͢Δ͔ • Ξϯνύλʔϯڞ༗σʔλετΞ • ڊେͳڞ༗"1*ʹͳΔ • มߋ͕ࠔ೉

    ೝূ Micro Frontends Micro Frontends localStorage Write Read Ξϯνύλʔϯ: ڞ༗σʔλετΞ
  15. ରԠ.JDSP'SPOUFOETͷ৔߹ !94 ೝূ Micro Frontends Micro Frontends Store Dispatcher change

    state ౷߹ϨΠϠʔ Micro Frontends Custom Events (globalStateChanged) Custom Events (loggedIn)
  16. ରԠ.JDSP'SPOUFOETͷ৔߹ !95 ೝূ Micro Frontends Micro Frontends Store Dispatcher change

    state ౷߹ϨΠϠʔ Micro Frontends Custom Events (globalStateChanged) Custom Events (loggedIn) 'MVYͷΞφϩδʔͰղܾͰ͖Δʂ
  17. ը໘ભҠ !96 • Ϗϧυͷ໰୊ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝୊ • άϩʔόϧͳঢ়ଶͷڞ༗

    •ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ໰୊ • ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM  • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍໰୊
  18. ରԠ !102 • ࣮૷ΠϝʔδϦϯΫ༻ͷίϯϙʔωϯτ class FawLink extends Component { handleClick

    = (e) => { const { to } = this.props; e.preventDefault(); const event = new CustomEvent('transition', { detail: { to, }, }); window.dispatchEvent(event); }; render() { const { to, children } = this.props; return ( <a href={to} onClick={this.handleClick}> {children} </a> ); } } export default FawLink;
  19. ରԠ !103 • ࣮૷ΠϝʔδϦϯΫ༻ͷίϯϙʔωϯτ class FawLink extends Component { handleClick

    = (e) => { const { to } = this.props; e.preventDefault(); const event = new CustomEvent('transition', { detail: { to, }, }); window.dispatchEvent(event); }; render() { const { to, children } = this.props; return ( <a href={to} onClick={this.handleClick}> {children} </a> ); } } export default FawLink; BλάͰఆٛ
  20. ରԠ !104 • ࣮૷ΠϝʔδϦϯΫ༻ͷίϯϙʔωϯτ class FawLink extends Component { handleClick

    = (e) => { const { to } = this.props; e.preventDefault(); const event = new CustomEvent('transition', { detail: { to, }, }); window.dispatchEvent(event); }; render() { const { to, children } = this.props; return ( <a href={to} onClick={this.handleClick}> {children} </a> ); } } export default FawLink; $VTUPN&WFOUΛఆٛ͠ ͯ౤͛Δ
  21. ରԠ !105 • ࣮૷Πϝʔδ౷߹ϨΠϠʔଆ import React from 'react'; import {

    browserHistory } from 'react-router'; class Peerbonus extends React.Component{ componentDidMount() { window.addEventListener('transition', (e) => { browserHistory.push(e.detail.to); }); } render() { return ( <div className="l-main_contents_area"> <peerbonus-timeline></peerbonus-timeline> </div> ); } } export default Peerbonus; &WFOU͔ΒભҠઌΛ
 ड͚औͬͯભҠ
  22. ঢ়ଶ؅ཧ !106 • Ϗϧυͷ໰୊ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝୊ • άϩʔόϧͳঢ়ଶͷڞ༗

    • ը໘ભҠ •ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ໰୊ • ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM  • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍໰୊
  23. ରԠ !113 • ಉҰαʔϏεͳͷͰͭͷHMPCBM4UBUFʹͭͳ͕ͬͨܗͰఏڙ͢Δ const store = configureStore(); class XCountButton

    extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); const shadow = this.attachShadow({ mode: 'open' }) shadow.appendChild(mountPoint); render( <Provider store={store}> <CountButton /> </Provider>, mountPoint ); retargetEvents(shadow) } } customElements.define('x-count-button', XCountButton); class XCountDisplay extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); this.attachShadow({ mode: 'open' }).appendChild(mountPoint); render( <Provider store={store}> <CountDisplay /> </Provider>, mountPoint ); } } customElements.define('x-count-display', XCountDisplay);
  24. ରԠ !114 • ڞ௨ͷTUPSFΛఆٛ͠QSPWJEFSʹ౉͢ const store = configureStore(); class XCountButton

    extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); const shadow = this.attachShadow({ mode: 'open' }) shadow.appendChild(mountPoint); render( <Provider store={store}> <CountButton /> </Provider>, mountPoint ); retargetEvents(shadow) } } customElements.define('x-count-button', XCountButton); class XCountDisplay extends HTMLElement { connectedCallback() { const mountPoint = document.createElement('span'); this.attachShadow({ mode: 'open' }).appendChild(mountPoint); render( <Provider store={store}> <CountDisplay /> </Provider>, mountPoint ); } } customElements.define('x-count-display', XCountDisplay);
  25. ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM !115 • Ϗϧυͷ໰୊ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝୊ •

    άϩʔόϧͳঢ়ଶͷڞ༗ • ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ໰୊ •ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM  • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍໰୊
  26. 3FBDUͰTIBEPX%0.Λ͔ͭ͏໰୊ !119 • Ϗϧυͷ໰୊ • DBDIFCVTUJOH • Ϣʔβʔମݧ౷߹ͷ՝୊ • άϩʔόϧͳঢ়ଶͷڞ༗

    • ը໘ભҠ • ίϯϙʔωϯτؒͷ࿈ܞ • ϥΠϒϥϦͷ໰୊ • ϒϥ΢βؒͷࠩ෼ͷղফ QPMZGJMM  • 3FBDUͷFWFOU͕TIBEPX%0.Ͱ͏·͘ಈ͔ͳ͍໰୊
  27. ࣗݾ঺հ !135 • ໊લ: ᖒҪ એ඙
 ʢ͞Θ͍ ͷͿͻ͜ʣ • twitter/github:

    nobuhikosawai • αʔόʔαΠυ(Rails) • ϑϩϯτΤϯυ(React.js)
  28. ࢀߟจݙ !138 • ϚΠΫϩαʔϏεΞʔΩςΫνϟʢ 4BN/FXNBOஶɺࠤ౻௚ੜ؂मɺ໦Լ఩໵༁ʣ • NJDSPGSPOFOETPSH • $PQZSJHIU $

    OFVMBOE#ÛSPGÛS*OGPSNBUJL #SFNFO (FSNBOZ
 IUUQTHJUIVCDPNOFVMBOENJDSPGSPOUFOETMJDFOTF • 3FBDUJTTVFT • IUUQTHJUIVCDPNGBDFCPPLSFBDUJTTVFT • IUUQTHJUIVCDPNGBDFCPPLSFBDUJTTVFT • IUUQTHJUIVCDPNGBDFCPPLSFBDUJTTVFT