2018/10/15 に JSLounge の活動として UUUM株式会社様で行った発表のスライドです。
ഁ͠ͳ͍Vue.js ΞϓϦέʔγϣϯ։ൃͷͨΊʹେͳ͜ͱ2018.09.15 HANATANI Takuma
View Slide
Profile• Ֆ୩ ຏ as known as potato4d• Vue.js / Nuxt.js Japanese Document• Translator / maintainer• Vue.js Japan user group• Staff / Vue Fes Japan 2018 staff• Nuxt.js beginners guide author
What's JSLounge produced by ElevenBack ?ΦϑϥΠϯΠϕϯτ ΦϯϥΠϯڭࡐఏڙ اۀ͚ߨशhttps://jslounge.connpass.com https://jslounge-archives.elevenback.jp/ https://blog.elevenback.jp
ࠓͷΰʔϧ
ࠓͷΰʔϧ• طଘίʔυͷෛ࠴• ͍ͭ࡞Γม͑Δ͔ͷΈ• Vue.js ͷΞϯνύλʔϯͷ՝ײ
ࠓͷΰʔϧ• طଘίʔυͷෛ࠴• ͍ͭ࡞Γม͑Δ͔ͷΈ• Vue.js ͷΞϯνύλʔϯͷ՝ײ• ίʔυͷʮࣺͯͲ͜Ζʯͷཧղ• ϑϩϯτΤϯυͷ༻ͷѲ• ഁغ͍ͯ͘͜͠ͱΛલఏͱͨ͠ઃܭ
ࠓ͢͜ͱ• ݱࡏͷϑϩϯτΤϯυΞϓϦέʔγϣϯͷ༻ʹ͍ͭͯ• Vue.js ͰඞཁΓΔͨΊʹඞཁͳجຊతͳߟ͑ํ• ࣮ྫ͔ΒֶͿϝϯςφϏϦςΟΛԼ͛Δίʔυͱઃܭ• Vue CLI / Nuxt.js ʹΑΔഁͮ͠Β͍։ൃڥͷߏங…
ࠓ͢͜ͱ• ݱࡏͷϑϩϯτΤϯυΞϓϦέʔγϣϯͷ༻ʹ͍ͭͯ• Vue.js ͰඞཁΓΔͨΊʹඞཁͳجຊతͳߟ͑ํ• ࣮ྫ͔ΒֶͿϝϯςφϏϦςΟΛԼ͛Δίʔυͱઃܭ• Vue CLI / Nuxt.js ʹΑΔഁͮ͠Β͍։ൃڥͷߏங
༻ʹ͍ͭͯ• ࣮ࡍͷ։ൃͷγʔϯͰͳ͘ϝϯςφϯεͰ͖Δͷ2,3͕ݶ• ΞʔΩςΫνϟϓϩάϥϜͷࢹ͚ͩࡁΉͰͳ͍• ྫ͑υϝΠϯ֓೦ͷݟ͠ͷै• ྫ͑σβΠϯϦχϡʔΞϧͷै• ٕज़τϨϯυʹ߹Θͤͨભٶ
υϝΠϯ֓೦ͷݟ͠• ʮ͜ͷػೳॳ͚͋ͬͨΕͲผػೳʹ౷߹͠Α͏ʯ• ʮҙຯ͢Δͱ͜Ζ͕มΘͬͨͷͰશମΛϦωʔϜ͠Α͏ʯ• ʮআ͠Α͏ʯ
σβΠϯϦχϡʔΞϧͷै• ʮϦϒϥϯσΟϯάͷͨΊʹશମΛϦχϡʔΞϧ͍ͨ͠ʯ• ʮ(ϚςϦΞϧͷΑ͏ͳ)ۀքͷτϨϯυ͕ҠͬͨͷͰ߹Θ͍ͤͨʯ• ʮUIϑϨʔϜϫʔΫϕʔε͚ͩͬͨͲಠࣗʹ͍ͨ͠ʯ
ٕज़τϨϯυʹ߹Θͤͨมભ• Vue.js 1.0 3 લɺ Vue.js 2.0 2 લɺ࣍ͷ v3 ……• ʮݹ͘ͳΔͱใ૿͑ͣศརͳͷ͑ͳ͍ʯ• ʮՄೳͰ͋Ε࣌ؒΛͱͬͯ࠷ݶϝδϟʔ͍͋͛ͨʯ
ٕज़τϨϯυʹ߹Θͤͨมભ• খ͞ͳτϨϯυ୯ҐͰτϨϯυมΘΔ• ࣌ࠁૢ࡞ day.js ͕ moment ͷΘΓʹͳ͍ͬͯΔ͔• HTTP ௨৴ XHR ͳ axios Ͱͳ͘ fetch ϕʔεͷͷ͔
࠷ऴతʹΔͷ……ʁ✘ Vue.js UI ʹܹ͘͠ґଘͨ͠෦✘ Build environment✘ ྲྀߦΓͷϥΠϒϥϦʹΑ࣮ͬͯ͞Εͨ෦✘ υϝΠϯશҬ(ഽײίʔυϕʔεͷ6ׂఔҠ২Մೳ)˕ ϓϩδΣΫτʹ͋Θ͍ͤͨΘΏΔʮϢʔςΟϦςΟʯ˕ ൚༻తͳ(Ξφϯε௨ͳͲͷ)ίϯϙʔωϯτͷϩδοΫ
࠷ऴతʹΔͷ……ʁ͍͚ͬͯΔͷࣝͱܦݧมΘΔ͜ͱΛલఏʹʮࣺ͍ͯ͢ʯίʔυΛ࡞Δ= ϑϩϯτΤϯυϩʔάϥΠΫ
جຊతͳߟ͑ํʮࣺ͍ͯ͢ʯίʔυͷͨΊʹ……1. ʮ࠶ར༻ੑʯͷແؔ৺ͱݻࣥಟ2. VuexԿͷͨΊʹ͋Δ͔Λߟ͑Δ3. Vue.js ͓Αͼ SFC ʹͩ͜ΘΓ͗͢ͳ͍͜͜Ͱ֓೦ͷΈɺ࣮ྫ࣍ͷηΫγϣϯͰɹ⾣
ʮ࠶ར༻ੑʯͷແؔ৺ͱݻࣥಟ• ͷଟ͍ίʔυ·ͱΊͯഁغ͢Δඞཁ͕ग़ͯ͘Δ• ͔ͱݴͬͯ Vuex ͳͲͷάϩʔόϧͳσʔλʹ҆қʹґଘ͢Δͱࠜຊతͳվमʹ͑ΒΕͳ͍• ϓϨθϯςʔγϣϯͷͨΊ͚ͩͷσʔλ൚༻ੑΛٻΊΔ• ϩδοΫ୯ମͰՄೳͳݶΓബ͘ॻ͘• ͳͲͳͲ……
Vuex ͳΜͷͨΊʹ͋Δ͔Λߟ͑Δ• શͯͷσʔλΛೖΕͯ͠·͏ͱͦΕͨͩͷάϩʔόϧม• ϩʔΧϧεςʔτͱ͏·͍͚͘Δ• Vuex Λͨͩͷശͱͯ͠ஔ͘ͷ͔ɺϦΞΫςΟϒͳυϝΠϯϨΠϠʔΛߏங͢Δج൫ͱ͢Δͷ͔Λ͖ͬΓͤ͞Δ• ͳͲͳͲ……
Vue.js / SFC ʹͩ͜ΘΓ͗͢ͳ͍• Vue.js ͔ͩΒͱ͍ͬͯશͯΛ .vue Ͱ݁ͤ͞Δඞཁͳ͍• SFC Vue Test Utils Λར༻ͨ͠είʔϓͷେ͖͍ςετͳͲ͕ඞཁʹͳΔͷͰඞવੑͷ͋Δ͚ͩΛͨͤΔ• ͋ͱ VanillaJS ʹΑΔهड़Λ৺͕͚Δ• ৄ࣍͘͠ͷηΫγϣϯͰ
࠶ར༻ੑͷײ֮ͷζϨ
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁLike<br/>import { mapActions } from ‘vuex’<br/>export default {<br/>props: { id: Number },<br/>methods: {<br/>click() {<br/>this.like({ id })<br/>},<br/>.. .mapActions(‘entries’, [‘like’]) <br/>} <br/>}<br/>-JLF#VUUPOWVF
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁLike<br/>import { mapActions } from ‘vuex’<br/>export default {<br/>props: { id: Number },<br/>methods: {<br/>click() {<br/>this.like({ id })<br/>},<br/>.. .mapActions(‘entries’, [‘like’]) <br/>} <br/>}<br/>Atoms ૬ͷϞϊ͕ Vuex ʹґଘ͍ͯ͠Δ-JLF#VUUPOWVF
վળྫLike<br/>export default {<br/>methods: {<br/>click(event) {<br/>this.$emit('click', event)<br/>}<br/>} <br/>}<br/>Vue.js ͷΠϕϯτγεςϜΛͬͯΛബ͘-JLF#VUUPOWVF
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁ<br/>export default {<br/>props: { mode: String }<br/>}<br/>6TFS'PSNWVF
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁ<br/>export default {<br/>props: { mode: String }<br/>}<br/>ίϯϙʔωϯτʹೋͭҎ্ͷׂ͕͋Δ6TFS'PSNWVF
վળྫ<br/>export default {<br/>}<br/>6TFS$SFBUF'PSNWVFʹͳͬͯͦΕͧΕผͷίʔυʹ͢Δ
վળྫ<br/>export default {<br/>}<br/>6TFS&EJU'PSNWVFผͷίʔυʹ͓ͯ͘͠ͱʮߋ৽ෆՄʯͷ߲ͷ࣮༰қ
VuexʹدͤΔ͖ίʔυͱدͤΔ͖Ͱͳ͍ίʔυ
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁimport { mapGetters, mapActions } from 'vuex'export default {computed: {...mapGetters('entries', { form: 'editEntry' }) },methods: {...mapActions('entries', ['updateEditEntry', 'updateEntry'])}}&OUSZ&EJU'PSNWVF
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁimport { mapGetters, mapActions } from 'vuex'export default {computed: {...mapGetters('entries', { form: 'editEntry' }) },methods: {...mapActions('entries', ['updateEditEntry', 'updateEntry'])}}&OUSZ&EJU'PSNWVF1. ίϯϙʔωϯτ͚͕͍ͩͬͯΕྑ͍தؒঢ়ଶʹVuexΛ͍ͬͯΔ2. Vuex ͷ mapXXX ͷΤΠϦΞεػೳͷ͍ͤͰ grep ͮ͠Β͘ͳ͍ͬͯΔ
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁ/* ... state code ... */const getters = {entries: [],editEntry: null}/* ... mutation code ... */const actions = {// ... other actionsupdateEditEntry({ commit }, { formData }) {commit('updateEditEntry',formData)}}export default { namespaced: true, state, mutations, getters, actions }FOUSJFTKTυϝΠϯ֓೦͕ೖ͍ͬͯΔͣͷ entries ʹԿނ͔ϑΥʔϜͷঢ়ଶ͕
मਖ਼ྫimport { mapGetters, mapActions } from 'vuex'export default {data() {const form = this.entries.find((e) => e.id == this.$route.params.id))return {form }},computed: {...mapGetters('entries', ['entries']) },methods: {...mapActions('entries', ['updateEntry'])}}&OUSZ&EJU'PSNWVF1. தؒঢ়ଶϩʔΧϧεςʔτʹด͡ࠐΊͯ Vuex ʹΰϛσʔλ͕Βͳ͍Α͏ʹ2. ೖྗ͕Ωϟϯηϧ͞Εͨ߹ίϯϙʔωϯτͷϥΠϑαΠΫϧʹΑͬͯదʹഁغ
मਖ਼ྫ/* ... state code ... */const getters = {entries: []}/* ... mutation code ... */const actions = {updateEntry() {} // ࣮ࡍͷσʔλͷߋ৽͚ͩΛߦ͏}export default { namespaced: true, state, mutations, getters, actions }FOUSJFTKTVuex ࣮σʔλʹͷΈઐ೦Ͱ͖ɺ͔ͭԼखʹϦηοτॲཧΛॻ͔ͳ͍Ͱྑ͍Α͏ʹ
Single File Component vs VanillaJS
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁ<br/>export default {<br/>data() {<br/>return { formData: { val1: '', val2: '' }, status: '' } // దͳঢ়ଶ <br/>}<br/>methods: {<br/>handleAction() { <br/>const foo = this.covert({…this.formData})<br/>this.$store.dispatch('namespace/someAction', foo) <br/>},<br/>convert(args) {<br/>return {...args} // Կ͔͠ΒͷॲཧΛߦͬͨޙʹฦ٫<br/>}<br/>}<br/>}<br/>.Z$PNQPOFOUWVF<br/>
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁ<br/>export default {<br/>data() {<br/>return { formData: { val1: '', val2: '' }, status: '' } // దͳঢ়ଶ <br/>}<br/>methods: {<br/>handleAction() { <br/>const foo = this.covert({…this.formData})<br/>this.$store.dispatch('namespace/someAction', foo) <br/>},<br/>convert(args) {<br/>return {...args} // Կ͔͠ΒͷॲཧΛߦͬͨޙʹฦ٫<br/>}<br/>}<br/>}<br/>୯ҰϑΝΠϧίϯϙʔωϯτͰͭඞཁͷͳ͍ॲཧ͕ଘࡏ͢Δ<br/>(ಛʹෳͷίϯϙʔωϯτͰग़ݱ͢Δ߹)<br/>.Z$PNQPOFOUWVF<br/>
मਖ਼ྫfunction convert(args) {return {...args} }export default convertVUJMTDPOWFSUFSKTJavaScript ͚ͩͰ݁͢Δ෦ JavaScriptͰΓग़͢
मਖ਼ྫimport convert from './converter'describe('converter.js', () => {test('test code', () => {const input = { val1: '', val2: '' }expect(convert(input)).toMatchObject(input)})})TQFDVUJMTDPOWFSUFSTQFDKTJavaScript Ͱॻ͘͜ͱͰςετίʔυهड़͘͢͠
Vue CLI v3• Vue.js ۘͷ CLI πʔϧ• طଘͷڥ(ࣗྗͰ webpack Λ৮Δڥ)͔ΒҠߦ͍͢͠• CLIπʔϧͷԆΒ͍͠ػೳ͕๛• ϓϥάΠϯʹΑΔڥͷڧԽ͕༰қ• ϓϥάΠϯʹΑΔڥͷߏங͕༰қ• ίϚϯυҰൃͰςετڥͳͲΛ࡞Մೳ• ։ൃମݧͱͯ͠ڥճΓΛڧԽ͢Δཁૉ͕ڧ͍
7VFKT1SPKFDU5FTUJOHNuxt.jsΛ༗ޮ׆༻͢Δ7VFKT7VF3PVUFS7VFY7VF5FTU6UJMT1VSF+BWB4DSJQU&YUFSOBM4FSWJDF)5516UJMJUZCVJMEFOWJSPONFOUCVJMEFOWJSPONFOUCVJMEFOWJSPONFOU
7VF$-*W1SPKFDU7VF$-*4FSWJDF5FTUJOHVue CLI v3 ༗ޮ׆༻͢Δ7VFKT7VF3PVUFS7VFY7VF5FTU6UJMT1VSF+BWB4DSJQU&YUFSOBM4FSWJDF)5516UJMJUZ
Nuxt.js• Vue.js ͔ΒݟΔ߹ඇެࣜͷϑϨʔϜϫʔΫ• Vue.js ͷίϛϡχςΟύʔτφʔͱͳͬͨͷͰڠྗؔͰ͋Δ• ϑϨʔϜϫʔΫΒ͍͠ػೳΛఏڙ͢Δ• ಠࣗͷϞδϡʔϧϓϥάΠϯγεςϜ• ΦʔτϩʔσΟϯάܥͷػೳ SSR ͷσϑΥϧταϙʔτ• ϓϩδΣΫτͷجຊઃܭΛ Nuxt.js ʹͤΔ͜ͱ͕Ͱ͖Δ• ։ൃମݧͱͯ͠ϓϩδΣΫτઃܭΛڧԽ͢Δཁૉ͕ڧ͍
/VYUKT1SPKFDU5FTUJOH/VYUKTNuxt.jsΛ༗ޮ׆༻͢Δ7VFKT7VF3PVUFS7VFY7VF5FTU6UJMT1VSF+BWB4DSJQU&YUFSOBM4FSWJDF)5516UJMJUZwebpackvue-metavue-server-rendererProject structure
Vue CLI v3 or Nuxt.js• ར༻Ϟνϕʔγϣϯ͔Βͯ͠ҧ͏ͷͰҰ֓ʹൺֱతͰ͖ͳ͍• ݸਓతʹ Vue.js ͷϏΪφʔ͕গͳ͍߹ Nuxt.js Λਪ• ͍͖ͳΓ Nuxt.js Λ৮Δͷϋʔυϧ͕ߴ͍ͷͰඇਪ• ͋Δఔ׳Εͨਓ͕ Nuxt.js ͰҰ௨ΓΜͰ͠·͑ϏΪφʔ͕͋ͱ͔ΒೖͬͯյΕͳ͍Α͏ͳઃܭ͕Ͱ͖Δ• ͲͷΈͪ 2 ఔͷεύϯͰߟ͑ΔͳΒϨʔϧʹͬͯߴ͍ੜ࢈ੑΛಘͨ΄͏͕ϓϩδΣΫτΛυϥΠϒͰ͖Δ
thanks!