Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
破綻しない Vue.js アプリケーション開発のために大切なこと / How to make ...
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
potato4d(Takuma HANATANI)
October 15, 2018
Programming
10k
30
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
破綻しない Vue.js アプリケーション開発のために大切なこと / How to make a robust Vue.js application
2018/10/15 に JSLounge の活動として UUUM株式会社様で行った発表のスライドです。
potato4d(Takuma HANATANI)
October 15, 2018
More Decks by potato4d(Takuma HANATANI)
See All by potato4d(Takuma HANATANI)
どうせキレイに書けない処理は逆にAIに書いてもらうほうが良い説 / #kyotojs 22
potato4d
3
470
TSX First な Zero-Runtime SSG potato4d/dodai とその仕組み / owned static site generator #kyotojs
potato4d
1
2.6k
Vue.js with TSX - From Vue 2.x to Vue 3 #v_tokyo11
potato4d
9
5.1k
終わりゆく Vue 2.x 時代の状態設計のアンサー - Vue 3 の Provider への期待 / The Last Architecture of the Vue 2.x
potato4d
25
7.2k
Web Worker を使ってブラウザ上でポケモンの画像を解析したい! / Pokemon recognition from screenshots in browser using web worker
potato4d
0
1.4k
Firebase & Google Cloud によるサーバーレス帳票管理 #FJUG / Serverless Architecture in Candy
potato4d
8
3.8k
NestJS meetup Tokyo Opening Talk / What is NestJS? #nestjs_meetup
potato4d
11
4.4k
私たちはなぜ SPA で開発するのか / Why you choose SPA
potato4d
38
29k
Amplify Console 誕生以来本番運用しつづけてわかったこと #awswakaran_tokyo
potato4d
6
3.7k
Other Decks in Programming
See All in Programming
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
9.5k
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.2k
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
4
410
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
760
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
260
ハーネス設計入門 〜 基礎知識の整理から実務へのステップアップ 〜
kinopeee
20
20k
APNsからLive Activityを開始する話
yumnumm
0
150
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
2
590
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2.3k
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
220
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
8
5.4k
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
310
Featured
See All Featured
First, design no harm
axbom
PRO
2
1.3k
Discover your Explorer Soul
emna__ayadi
2
1.3k
Utilizing Notion as your number one productivity tool
mfonobong
4
610
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
76k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.6k
The Curse of the Amulet
leimatthew05
3
15k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
380
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
GraphQLとの向き合い方2022年版
quramy
50
15k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.8k
Transcript
ഁ͠ͳ͍ Vue.js ΞϓϦέʔγϣϯ։ൃͷͨΊʹ େͳ͜ͱ 2018.09.15 HANATANI Takuma
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ׂఔҠ২Մೳ) ˕ ϓϩδΣΫτʹ͋Θ͍ͤͨΘΏΔʮϢʔςΟϦςΟʯ ˕ ൚༻తͳ(Ξφϯε௨ͳͲͷ)ίϯϙʔωϯτͷϩδοΫ
࠷ऴతʹΔͷ……ʁ ͍͚ͬͯΔͷࣝͱܦݧ มΘΔ͜ͱΛલఏʹʮࣺ͍ͯ͢ʯίʔυΛ࡞Δ = ϑϩϯτΤϯυϩʔάϥΠΫ
ࠓ͢͜ͱ • ݱࡏͷϑϩϯτΤϯυΞϓϦέʔγϣϯͷ༻ʹ͍ͭͯ • Vue.js ͰඞཁΓΔͨΊʹඞཁͳجຊతͳߟ͑ํ • ࣮ྫ͔ΒֶͿϝϯςφϏϦςΟΛԼ͛Δίʔυͱઃܭ • Vue
CLI / Nuxt.js ʹΑΔഁͮ͠Β͍։ൃڥͷߏங…
جຊతͳߟ͑ํ ʮࣺ͍ͯ͢ʯίʔυͷͨΊʹ…… 1. ʮ࠶ར༻ੑʯͷແؔ৺ͱݻࣥಟ 2. VuexԿͷͨΊʹ͋Δ͔Λߟ͑Δ 3. Vue.js ͓Αͼ SFC
ʹͩ͜ΘΓ͗͢ͳ͍ ͜͜Ͱ֓೦ͷΈɺ࣮ྫ࣍ͷηΫγϣϯͰɹ⾣
ʮ࠶ར༻ੑʯͷແؔ৺ͱݻࣥಟ • ͷଟ͍ίʔυ·ͱΊͯഁغ͢Δඞཁ͕ग़ͯ͘Δ • ͔ͱݴͬͯ Vuex ͳͲͷάϩʔόϧͳσʔλʹ҆қʹґଘ͢Δ ͱࠜຊతͳվमʹ͑ΒΕͳ͍ • ϓϨθϯςʔγϣϯͷͨΊ͚ͩͷσʔλ൚༻ੑΛٻΊΔ
• ϩδοΫ୯ମͰՄೳͳݶΓബ͘ॻ͘ • ͳͲͳͲ……
Vuex ͳΜͷͨΊʹ͋Δ͔Λߟ͑Δ • શͯͷσʔλΛೖΕͯ͠·͏ͱͦΕͨͩͷάϩʔόϧม • ϩʔΧϧεςʔτͱ͏·͍͚͘Δ • Vuex Λͨͩͷശͱͯ͠ஔ͘ͷ͔ɺϦΞΫςΟϒͳυϝΠϯϨ ΠϠʔΛߏங͢Δج൫ͱ͢Δͷ͔Λ͖ͬΓͤ͞Δ
• ͳͲͳͲ……
Vue.js / SFC ʹͩ͜ΘΓ͗͢ͳ͍ • Vue.js ͔ͩΒͱ͍ͬͯશͯΛ .vue Ͱ݁ͤ͞Δඞཁͳ͍ •
SFC Vue Test Utils Λར༻ͨ͠είʔϓͷେ͖͍ςετͳͲ ͕ඞཁʹͳΔͷͰඞવੑͷ͋Δ͚ͩΛͨͤΔ • ͋ͱ VanillaJS ʹΑΔهड़Λ৺͕͚Δ • ৄ࣍͘͠ͷηΫγϣϯͰ
ࠓ͢͜ͱ • ݱࡏͷϑϩϯτΤϯυΞϓϦέʔγϣϯͷ༻ʹ͍ͭͯ • Vue.js ͰඞཁΓΔͨΊʹඞཁͳجຊతͳߟ͑ํ • ࣮ྫ͔ΒֶͿϝϯςφϏϦςΟΛԼ͛Δίʔυͱઃܭ • Vue
CLI / Nuxt.js ʹΑΔഁͮ͠Β͍։ൃڥͷߏங
࠶ར༻ੑͷײ֮ͷζϨ
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁ <template> <button @click=“like”>Like</button> </template> <script> import { mapActions }
from ‘vuex’ export default { props: { id: Number }, methods: { click() { this.like({ id }) }, .. .mapActions(‘entries’, [‘like’]) } } </script> -JLF#VUUPOWVF
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁ <template> <button @click=“like”>Like</button> </template> <script> import { mapActions }
from ‘vuex’ export default { props: { id: Number }, methods: { click() { this.like({ id }) }, .. .mapActions(‘entries’, [‘like’]) } } </script> Atoms ૬ͷϞϊ͕ Vuex ʹґଘ͍ͯ͠Δ -JLF#VUUPOWVF
վળྫ <template> <button @click="like">Like</button> </template> <script> export default { methods:
{ click(event) { this.$emit('click', event) } } } </script> Vue.js ͷΠϕϯτγεςϜΛͬͯΛബ͘ -JLF#VUUPOWVF
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁ <template> <div class=“some-form”> <template v-if=“mode === ‘new’”> <div></div> </template>
<template v-if=“mode === ‘edit’”> <div></div> </template> <!-— code --> </div> </template> <script> export default { props: { mode: String } } </script> 6TFS'PSNWVF
͜Μͳίϯϙʔωϯτ࡞ͬͯ·ͤΜ͔ʁ <template> <div class=“some-form”> <template v-if=“mode === ‘new’”> <div></div> </template>
<template v-if=“mode === ‘edit’”> <div></div> </template> <!-— code --> </div> </template> <script> export default { props: { mode: String } } </script> ίϯϙʔωϯτʹೋͭҎ্ͷׂ͕͋Δ 6TFS'PSNWVF
վળྫ <template> <div class=“some-form”> <template> <div> <!-— code --> </div>
</template> </div> </template> <script> export default { } </script> 6TFS$SFBUF'PSNWVF ʹͳͬͯͦΕͧΕผͷίʔυʹ͢Δ
վળྫ <template> <div class=“some-form”> <template> <div> <!-— code --> </div>
</template> </div> </template> <script> export default { } </script> 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'PSNWVF 1. ίϯϙʔωϯτ͚͕͍ͩͬͯΕྑ͍தؒঢ়ଶʹVuexΛ͍ͬͯΔ 2. Vuex ͷ mapXXX ͷΤΠϦΞεػೳͷ͍ͤͰ grep ͮ͠Β͘ͳ͍ͬͯΔ
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁ /* ... state code ... */ const getters =
{ entries: [], editEntry: null } /* ... mutation code ... */ const actions = { // ... other actions updateEditEntry({ 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'PSNWVF 1. தؒঢ়ଶϩʔΧϧεςʔτʹด͡ࠐΊͯ Vuex ʹΰϛσʔλ͕Βͳ͍Α͏ʹ 2. ೖྗ͕Ωϟϯηϧ͞Εͨ߹ίϯϙʔωϯτͷϥΠϑαΠΫϧʹΑͬͯదʹഁغ
मਖ਼ྫ /* ... state code ... */ const getters =
{ entries: [] } /* ... mutation code ... */ const actions = { updateEntry() {} // ࣮ࡍͷσʔλͷߋ৽͚ͩΛߦ͏ } export default { namespaced: true, state, mutations, getters, actions } FOUSJFTKT Vuex ࣮σʔλʹͷΈઐ೦Ͱ͖ɺ͔ͭԼखʹϦηοτॲཧΛॻ͔ͳ͍Ͱྑ͍Α͏ʹ
Single File Component vs VanillaJS
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁ <script> export default { data() { return { formData:
{ val1: '', val2: '' }, status: '' } // దͳঢ়ଶ } methods: { handleAction() { const foo = this.covert({…this.formData}) this.$store.dispatch('namespace/someAction', foo) }, convert(args) { return {...args} // Կ͔͠ΒͷॲཧΛߦͬͨޙʹฦ٫ } } } .Z$PNQPOFOUWVF
͜ΜͳίʔυΛॻ͍ͯ·ͤΜ͔ʁ <script> export default { data() { return { formData:
{ val1: '', val2: '' }, status: '' } // దͳঢ়ଶ } methods: { handleAction() { const foo = this.covert({…this.formData}) this.$store.dispatch('namespace/someAction', foo) }, convert(args) { return {...args} // Կ͔͠ΒͷॲཧΛߦͬͨޙʹฦ٫ } } } ୯ҰϑΝΠϧίϯϙʔωϯτͰͭඞཁͷͳ͍ॲཧ͕ଘࡏ͢Δ (ಛʹෳͷίϯϙʔωϯτͰग़ݱ͢Δ߹) .Z$PNQPOFOUWVF
मਖ਼ྫ function convert(args) { return {...args} } export default convert
VUJMTDPOWFSUFSKT JavaScript ͚ͩͰ݁͢Δ෦ JavaScriptͰΓग़͢
मਖ਼ྫ import convert from './converter' describe('converter.js', () => { test('test
code', () => { const input = { val1: '', val2: '' } expect(convert(input)).toMatchObject(input) }) }) TQFDVUJMTDPOWFSUFSTQFDKT JavaScript Ͱॻ͘͜ͱͰςετίʔυهड़͘͢͠
ࠓ͢͜ͱ • ݱࡏͷϑϩϯτΤϯυΞϓϦέʔγϣϯͷ༻ʹ͍ͭͯ • Vue.js ͰඞཁΓΔͨΊʹඞཁͳجຊతͳߟ͑ํ • ࣮ྫ͔ΒֶͿϝϯςφϏϦςΟΛԼ͛Δίʔυͱઃܭ • Vue
CLI / Nuxt.js ʹΑΔഁͮ͠Β͍։ൃڥͷߏங…
Vue CLI v3 • Vue.js ۘͷ CLI πʔϧ • طଘͷڥ(ࣗྗͰ
webpack Λ৮Δڥ)͔ΒҠߦ͍͢͠ • CLIπʔϧͷԆΒ͍͠ػೳ͕๛ • ϓϥάΠϯʹΑΔڥͷڧԽ͕༰қ • ϓϥάΠϯʹΑΔڥͷߏங͕༰қ • ίϚϯυҰൃͰςετڥͳͲΛ࡞Մೳ • ։ൃମݧͱͯ͠ڥճΓΛڧԽ͢Δཁૉ͕ڧ͍
7VFKT1SPKFDU 5FTUJOH Nuxt.jsΛ༗ޮ׆༻͢Δ 7VFKT 7VF3PVUFS 7VFY 7VF5FTU6UJMT 1VSF+BWB4DSJQU &YUFSOBM4FSWJDF )551
6UJMJUZ CVJMEFOWJSPONFOU CVJMEFOWJSPONFOU CVJMEFOWJSPONFOU
7VF$-*W1SPKFDU 7VF$-*4FSWJDF 5FTUJOH Vue CLI v3 ༗ޮ׆༻͢Δ 7VFKT 7VF3PVUFS 7VFY
7VF5FTU6UJMT 1VSF+BWB4DSJQU &YUFSOBM4FSWJDF )551 6UJMJUZ
Nuxt.js • Vue.js ͔ΒݟΔ߹ඇެࣜͷϑϨʔϜϫʔΫ • Vue.js ͷίϛϡχςΟύʔτφʔͱͳͬͨͷͰڠྗؔͰ͋Δ • ϑϨʔϜϫʔΫΒ͍͠ػೳΛఏڙ͢Δ •
ಠࣗͷϞδϡʔϧϓϥάΠϯγεςϜ • ΦʔτϩʔσΟϯάܥͷػೳ SSR ͷσϑΥϧταϙʔτ • ϓϩδΣΫτͷجຊઃܭΛ Nuxt.js ʹͤΔ͜ͱ͕Ͱ͖Δ • ։ൃମݧͱͯ͠ϓϩδΣΫτઃܭΛڧԽ͢Δཁૉ͕ڧ͍
7VFKT1SPKFDU 5FTUJOH Nuxt.jsΛ༗ޮ׆༻͢Δ 7VFKT 7VF3PVUFS 7VFY 7VF5FTU6UJMT 1VSF+BWB4DSJQU &YUFSOBM4FSWJDF )551
6UJMJUZ CVJMEFOWJSPONFOU CVJMEFOWJSPONFOU CVJMEFOWJSPONFOU
/VYUKT1SPKFDU 5FTUJOH /VYUKT Nuxt.jsΛ༗ޮ׆༻͢Δ 7VFKT 7VF3PVUFS 7VFY 7VF5FTU6UJMT 1VSF+BWB4DSJQU &YUFSOBM4FSWJDF
)551 6UJMJUZ webpack vue-meta vue-server-renderer Project structure
Vue CLI v3 or Nuxt.js • ར༻Ϟνϕʔγϣϯ͔Βͯ͠ҧ͏ͷͰҰ֓ʹൺֱతͰ͖ͳ͍ • ݸਓతʹ Vue.js
ͷϏΪφʔ͕গͳ͍߹ Nuxt.js Λਪ • ͍͖ͳΓ Nuxt.js Λ৮Δͷϋʔυϧ͕ߴ͍ͷͰඇਪ • ͋Δఔ׳Εͨਓ͕ Nuxt.js ͰҰ௨ΓΜͰ͠·͑ϏΪφʔ͕͋ ͱ͔ΒೖͬͯյΕͳ͍Α͏ͳઃܭ͕Ͱ͖Δ • ͲͷΈͪ 2 ఔͷεύϯͰߟ͑ΔͳΒϨʔϧʹͬͯߴ͍ੜ࢈ ੑΛಘͨ΄͏͕ϓϩδΣΫτΛυϥΠϒͰ͖Δ
thanks!