Vue.js を初めてプロダクトに導入して直面した課題と得られた幸せ

0aa238a274c2397214b20d6eed58939b?s=47 moomoo-ya
February 19, 2019

Vue.js を初めてプロダクトに導入して直面した課題と得られた幸せ

RAKUS Meetup Tokyo #2
2019.2.19

0aa238a274c2397214b20d6eed58939b?s=128

moomoo-ya

February 19, 2019
Tweet

Transcript

  1. Vue.js ΛॳΊͯϓϩμΫτʹಋ ೖͯ͠௚໘ͨ͠՝୊ͱಘΒΕͨ ޾ͤ @moomooya Isamu Suzuki, Rakus 2019.2.19

  2. ླ໦ ༐ʢ͖ͣ͢ ͍͞Ήʣ • ๺ւಓग़਎ 35ࡀ • QiitaͰษڧձϨϙ࠷଎ΦδαϯΛ໨ࢦ͍ͯ͠·͢ • ओʹMicroservicesͱ͔JavaScriptؔ࿈த৺

    • झຯ • ITωλͷΞφϩάήʔϜ੍࡞ • ࣾ಺Ψϯϓϥ෦෦௕ • ITۀքଟΊͷαόήओ࠵ @moomooya @moomoo-ya
  3. ུྺ • ߴߍʙେֶʙ৽ଔ • ߴߍͰ͸ϓϩάϥϜίϯςετք۾Λ͏Ζ͏Ζ • IPAʢ౰࣌͸௨࢈লʣͷࢿ֨औΓ͋͞Γ • େखSIer ࣌୅

    • ূ݊/֎ࠃҝସγεςϜͷ্ྲྀ͔ΒԼྲྀ·Ͱ • อݥਃࠐΈγεςϜͷ৽ن։ൃɺͳͲ • খن໛ϕϯνϟʔΛܦ༝ͯ͠ϥΫε΁ • ɹɹɹɹɹɹͷαʔϏε։࢝ • ΤϯδχΞจԽͷ೐΍͔͠ɺͳͲ • ৽نαʔϏε։ൃ ←ࠓ೔͸͜Εͷ͜ͱΛ࿩͠·͢
  4. ຊ୊

  5. ϓϩμΫτʹ Vue.js ಋೖͯ͠ Ϳ͔ͭͬͨ՝୊Λڞ༗͠·͢ ະղܾ՝୊΋͋Γ·͢

  6. 1. Ξϩʔԋࢉࢠ࢖͑ͳ͍෦෼͕͋Δ

  7. ࠓ͔ΒJavaScriptॻ͘ͳΒ ES2015+ ͔ TypeScript

  8. ؔ਺ఆٛ΋Ξϩʔԋࢉࢠ () => {}

  9. VueίϯϙʔωϯτͰ͸ جຊతʹΞϩʔԋࢉࢠ͸࢖͑ͳ͍

  10. ͜Ε͕NG <template> <!-- ... --> </template> <script> export default {

    // ... methods: { changeText: () => { this.text = "foobar"; } } } </script> VueΠϯελϯεΛࢦ͢ ͕ࢀরͰ͖ͳ͍ this
  11. ͜ΕͳΒOK <template> <!-- ... --> </template> <script> export default {

    // ... methods: { changeText() { this.text = "foobar"; } } } </script> ࣍ظv3ͰͷରԠʹ ظ଴͠·͠ΐ͏
  12. 2. ΦϒδΣΫτͷߋ৽ํ๏

  13. Vue.js ͱ͍͑͹ ϦΞΫςΟϒγεςϜ

  14. JavaScriptΦϒδΣΫτͷߋ৽Ͱ Ϗϡʔ͕ࣗಈߋ৽͞ΕΔ

  15. ͱͯ΋ศརɺ͘͢͝

  16. ੍ͨͩ͠໿΋͋Δ • VueΠϯελϯε͕ॳظԽ͞ΕΔͱ͖ʹ
 ౉͞ΕͨJSΦϒδΣΫτʹରͯ͠ Object.definePropertyؔ਺Ͱgetter/setterΛͭ͘Δ • ͜ΕΒͷΞΫηοαΛར༻ͯ͠มߋݕ஌Λ͢Δ

  17. ͜Ε͸OK <template> <!-- ༩͑ΒΕͨΦϒδΣΫτ͔Β จࣈྻग़ྗ͢Δίϯϙʔωϯτ --> <text-output v-bind:data="textObject" /> <button

    v-on:click=“changeText()"> จࣈྻΛม͑Δ </button> </template> <script> export default { data() { return { textObject: { value: "ग़ྗ͢Δจࣈྻ", size: 16 } }; }, methods: { changeText() { this.textObject.value = "มߋͨ͠จࣈྻ"; } } }; </script> ॳظ஋ʹ͋Δ஋Λૢ࡞
  18. ͜Ε͸OK <template> <!-- ༩͑ΒΕͨΦϒδΣΫτ͔Β จࣈྻग़ྗ͢Δίϯϙʔωϯτ --> <text-output v-bind:data="textObject" /> <button

    v-on:click=“changeText()"> จࣈྻΛม͑Δ </button> </template> <script> export default { data() { return { textObject: { value: "ग़ྗ͢Δจࣈྻ", size: 16 } }; }, methods: { changeText() { this.textObject.value = "มߋͨ͠จࣈྻ"; } } }; </script> ॳظ஋ʹ͋Δ஋͸ ॻ͖׵͑Ε͹ը໘ʹ൓ө͞ΕΔ ॳظ஋ʹ͋Δ஋Λૢ࡞
  19. ͜Ε͸NG <template> <!-- ༩͑ΒΕͨΦϒδΣΫτ͔Β จࣈྻग़ྗ͢Δίϯϙʔωϯτ --> <text-output v-bind:data="textObject" /> <button

    v-on:click=“setSize()”> αΠζΛઃఆ͢Δ </button> </template> <script> export default { data() { return { textObject: { value: "ग़ྗ͢Δจࣈྻ" } }; }, methods: { setSize() { this.textObject.size = 16; } } }; </script> ॳظ஋ʹͳ͍஋Λૢ࡞
  20. ͜Ε͸NG <template> <!-- ༩͑ΒΕͨΦϒδΣΫτ͔Β จࣈྻग़ྗ͢Δίϯϙʔωϯτ --> <text-output v-bind:data="textObject" /> <button

    v-on:click=“setSize()”> αΠζΛઃఆ͢Δ </button> </template> <script> export default { data() { return { textObject: { value: "ग़ྗ͢Δจࣈྻ" } }; }, methods: { setSize() { this.textObject.size = 16; } } }; </script> ॳظ஋ʹͳ͍஋͸ ௥Ճͯ͠΋มߋ͕ݕ஌͞Εͳ͍ ໌ࣔతʹ this.$set(this.textObject, “size”, 16); ॳظ஋ʹͳ͍஋Λૢ࡞
  21. 3. ཁૉ໊ͷিಥ

  22. vue΋ϥΠϒϥϦ͕ ͲΜͲΜ੔උ͞Ε͍ͯΔ

  23. ϥΠϒϥϦͷཁૉ໊ॏෳ • ϚςϦΞϧσβΠϯͳUIϥΠϒϥϦͷVuetify • <v-image>ͱ͔<v-select>ͱ͔ͰΦγϟϨUI࡞ΕΔ • Canvasૢ࡞ϥΠϒϥϦͷKonvaΛϥοϓͨ͠vue-konva • ը૾ΦϒδΣΫτΛ<v-image>Ͱࢦఆ͢Δ

  24. ϥΠϒϥϦͷཁૉ໊ॏෳ • ϚςϦΞϧσβΠϯͳUIϥΠϒϥϦͷVuetify • <v-image>ͱ͔<v-select>ͱ͔ͰΦγϟϨUI࡞ΕΔ • Canvasૢ࡞ϥΠϒϥϦͷKonvaΛϥοϓͨ͠vue-konva • ը૾ΦϒδΣΫτΛ<v-image>Ͱࢦఆ͢Δ

  25. <v-image> ॏෳ

  26. ಈ࡞͠·ͤΜͰͨ͠

  27. ཁૉ໊ͷϧʔϧ • Vue.js ελΠϧΨΠυ https://jp.vuejs.org/v2/style-guide/index.html

  28. ͍͓ͪ͏ճආͰ͖ΔͬΆ͍ॻ͖ํ΋ ౰࣌͸ʮผ໊Λ͚ͭΔʯ΍Γํ͕෼͔Βͣ٧ΜͰ͍ͨ <script> import ComponentA from "@/components/hoge/ComponentA"; import ComponentA2 from

    "@/components/fuga/ComponentA"; export default { components: { "hoge-comp-a": ComponentA, "fuga-comp-a": ComponentA2 } } </script> ಛʹ͜ͷॻ͖ํ }
  29. 4. ηΦϦʔΘ͔Βͳ͍

  30. ϓϩμΫτͰ࡞Δͱ େྔͷ໋໊΍ɺϞδϡʔϧ෼ׂΛ ରॲ͠ͳ͚Ε͹ͳΒͳ͍

  31. camelCaseͳͷ͔ PascalCaseͳͷ͔ kebab-caseͳͷ͔

  32. ϞδϡʔϧڥքΛ Ͳ͜ʹҾ͚͹͍͍ͷ͔

  33. Vue.js ͸υΩϡϝϯτ͕ ॆ࣮͍ͯ͠Δ

  34. ελΠϧΨΠυ͕͋ΔͷͰ·ͣ͸ख़ಡ • Vue.js ελΠϧΨΠυʢެࣜʣ • https://jp.vuejs.org/v2/style-guide/ • Vue.js ίϯϙʔωϯτ ελΠϧΨΠυ

    • https://pablohpsilva.github.io/vuejs-component- style-guide/#/japanese • ౰ॳͪ͜ΒͷଘࡏΛ஌Βͳ͔ͬͨͷͰۤ͠ΜͰ͍Δ
  35. 5. Vuex ࢖͍͗͢໰୊

  36. ηΦϦʔ͕Θ͔Βͳ͔ͬͨ݁Ռ

  37. Vuex ʹա৒࣮૷

  38. Vuex(Flux)ͷΞʔΩςΫνϟ https://vuex.vuejs.org/ja/

  39. Vuexͷ࣮૷ηΦϦʔ • State • ঢ়ଶΛอଘ͢ΔʢάϩʔόϧͬΆ͍ม਺ྖҬʣ • ໌Β͔ʹଟ༻ͨ͠Βμϝͳงғؾ • Mutation ؔ਺܈

    • State Λߋ৽͢Δ།Ұͷॲཧ܈ • ಉظॲཧతʹ࣮૷͢Δ • Action ؔ਺܈ • ඇಉظॲཧΛ࣮૷ͯ͠Α͍ • State ͷߋ৽͸ Mutation ܦ༝
  40. Vuexͷ࣮૷ηΦϦʔ • State • ঢ়ଶΛอଘ͢ΔʢάϩʔόϧͬΆ͍ม਺ྖҬʣ • ໌Β͔ʹଟ༻ͨ͠Βμϝͳงғؾ • Mutation ؔ਺܈

    • State Λߋ৽͢Δ།Ұͷॲཧ܈ • ಉظॲཧతʹ࣮૷͢Δ • Action ؔ਺܈ • ඇಉظॲཧΛ࣮૷ͯ͠Α͍ • State ͷߋ৽͸ Mutation ܦ༝ ←͜ΕΛ֦େղऍͯ͠͠·ͬͨ
  41. ඇಉظσʔλऔಘॲཧΛ ͢΂ͯVuexͰ࣮૷

  42. ઈࢍҾ͖ฦ͠த

  43. ίϯϙʔωϯτʹด͡Δ΋ͷ͸ ඇಉظॲཧͰ΋ίϯϙʔωϯτ಺ʹ هड़͢Ε͹Α͍

  44. 6. ෆద੾ͳmixins

  45. Vueίϯϙʔωϯτʹ͸ v-model ଐੑͱ͍͏ ศརͳଐੑ͕͋Γ·͢

  46. Vue.jsͷίϯϙʔωϯτؒ௨৴ • ਌ίϯϙʔωϯτ͔Β • v-bind:ϓϩύςΟ໊ Ͱ౉͢ • v-on:Πϕϯτ໊ Ͱड͚औΔ <blog-post

    v-for="post in posts" v-bind:key="post.id" v-on:on-change="onChange" > </blog-post>
  47. Vue.jsͷίϯϙʔωϯτؒ௨৴ • ࢠίϯϙʔωϯτ • props ϓϩύςΟ಺ʹఆٛͯ͠ड͚औΔ • this.$emit ͰΠϕϯτૹ৴ͯ͠ฦ͢ props:

    { key: { type: Number, default: 0 } }, methods: { onChange(value) { this.$emit("on-change", value); } }
  48. v-modelͱ͸ • ϓϩύςΟ໊ͱΠϕϯτ໊Λݻఆͨ͠౶ҥߏจ • ड͚౉͢ϓϩύςΟ໊Λ value • ฦ͢ΠϕϯτΛ input <blog-post

    v-bind:value="post.id" v-on:input="post.id = $event.target.value" > </blog-post> <blog-post v-model="post.id"> </blog-post>
  49. v-modelͱ͸ • ϓϩύςΟ໊ͱΠϕϯτ໊Λݻఆͨ͠౶ҥߏจ • ड͚౉͢ϓϩύςΟ໊Λ value • ฦ͢ΠϕϯτΛ input <blog-post

    v-bind:value="post.id" v-on:input="post.id = $event.target.value" > </blog-post> <blog-post v-model="post.id"> </blog-post> ͨͩ͜͠Ε͸ ਌ίϯϙʔωϯτͷ͸ͳ͠
  50. v-modelରԠͳࢠίϯϙʔωϯτ • ຖճ͜ΕΛॻ͔ͳ͍ͱ͍͚ͳ͍ export default { props: { value: {

    type: String, default: undefined } }, methods: { onInput(value) { this.$emit("input", value); } } }
  51. v-modelରԠͳࢠίϯϙʔωϯτ • ຖճ͜ΕΛॻ͔ͳ͍ͱ͍͚ͳ͍ export default { props: { value: {

    type: String, default: undefined } }, methods: { onInput(value) { this.$emit("input", value); } } } ϛοΫεΠϯͰ ·ͱΊͨΖ
  52. ͜͜͸·ͩݕূதͰ͢

  53. propsΛmixins͢Δͷ͸μϝͦ͏ • mixinsΛղܾ͢Δ·ͰͷҰॠvalue͕undefinedʹͳΔ • template಺Ͱ࢖͍ͬͯΔͱίϯιʔϧΤϥʔ͕ग़Δ • slotͱ͔͏·͘࢖ͬͨΒڞ௨Խ͸Ͱ͖Δ͔΋͠Εͳ͍ • ↑ࢼ͍ͤͯ·ͤΜ •

    ੈؒͷUIϥΠϒϥϦͷιʔεΛݟͨײͩ͡ͱ
 ͜͜͸ڞ௨Խ͠ͳ͍ͷ͕ηΦϦʔͳؾ͕͍ͯ͠Δ
  54. Ͱ΋τʔλϧͰ͸ ಋೖͯ͠޾ͤʹͳ͍ͬͯ·͢

  55. ྑ͍ͱ͜Ζ΋αϥοͱ

  56. 1. ୯ҰϑΝΠϧίϯϙʔωϯτ

  57. DOMͱॲཧͱελΠϧΛ·ͱΊΒΕͯૉఢ • ҙຯͷ͋Δ୯ҐͰѻ͑Δ • CSS͕ scoped Ͱ1ϑΝΠϧʹ ดͯ͡ద༻Ͱ͖Δ • ίʔυ͕ංେԽ͠ʹ͍͘

    <template> <blog-post class="title" v-model="title" /> </template> <script> export default { data() { title: "λΠτϧ"; } }; </script> <style scoped> .title { font-size: large; } </style>
  58. 2. υΩϡϝϯτ͕ૉ੖Β͍͠

  59. ͜͜·Ͱࢀর͍ͯ͠Δ υΩϡϝϯτ͸ ͢΂ͯ೔ຊޠԽࡁΈ

  60. ೔தؖͳͲΞδΞݍͰྲྀߦ͍ͬͯΔΒ͍͠

  61. ΞδΞݍͰྲྀߦ͍ͬͯΔ ϑϨʔϜϫʔΫ……͏ͬɺ಄͕ Seasar2

  62. 3. React + Flux ͷܦݧ΋ϜμʹͳΒͳ͍

  63. Vue.js ͷঢ়ଶ؅ཧ Vuex ͸ FluxΞʔΩςΫνϟ

  64. ʮ͔ͬͨ͜͡ͱ͕͋Δʯఔ౓Ͱ΋ ཧղͷॿ͚ʹͳΓ·ͨ͠

  65. ·ͱΊ

  66. ελΠϧΨΠυ͕͋ΔͷͰ·ͣ͸ख़ಡ • Vue.js ελΠϧΨΠυʢެࣜʣ • https://jp.vuejs.org/v2/style-guide/ • Vue.js ίϯϙʔωϯτ ελΠϧΨΠυ

    • https://pablohpsilva.github.io/vuejs-component- style-guide/#/japanese • ౰ॳͪ͜ΒͷଘࡏΛ஌Βͳ͔ͬͨͷͰۤ͠ΜͰ͍Δ
  67. ͋Γ͕ͱ͏͍͟͝·ͨ͠