Share
Embed
Vue.js simple Chat Handson (in Hamamatsu.js 2019.11)
Hamamatsu.js #8 at 2019.11.9 (https://connpass.com/event/148554/)
jacoyutorius
November 06, 2019
Transcript
61 slides
-
Yuto Ogi @jacoyutorius Web developer, AIRS • ࠷ۙαʔόʔϨεΞʔΩςΫνϟ͕ ͖ •
AlexaͷεΩϧΛ࡞ͬͨΓWebΞϓϦ έʔγϣϯΛ࡞ͬͨΓ • ࣗ࡞ΩʔϘʔυপʹϋϚ͍ͬͯͯͦΖ ͦΖ3ػΛ࡞Δ༧ఆ Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 2 -
on docker docker-compose.yml version: "3.7" services: dev: image: node:12.13-alpine container_name:
vue-dev ports: - "8080:8080" volumes: - .:/app tty: true stdin_open: true Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 5 -
on docker $ docker-compose up -d Creating network "hmjs-chat_default" with
the default driver Pulling dev (node:12.13-alpine)... ~ Creating vue-dev ... done $ docker exec -it vue-dev sh Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 6 -
on docker # yarn global add @vue/cli Hamamatsu.js Amplify +
Vue.js Handson @jacoyutorius 7 -
Stages 1. create Vue project 2. install Bootstrap 3. Chat
mockup 4. integrate Chat API Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 8 -
before handson • Node.js • install @vue/cli • Vue.js devtools
(Chrome plugin) Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 9 -
versions $ node -v v10.14.1 $ npm -v 6.11.3 Hamamatsu.js
Amplify + Vue.js Handson @jacoyutorius 10 -
$ vue create vue-chat-app Vue CLI v3.2.1 ┌────────────────────────────┐ │ Update
available: 3.11.0 │ └────────────────────────────┘ ? Please pick a preset: default (babel, eslint) ✨ Done in 16.32s. ⚓ Running completion hooks... # Generating README.md... $ Successfully created project vue-chat-app. $ cd vue-chat-app $ subl . / atom . / code . Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 13 -
$ tree -L 1 . ├── README.md ├── babel.config.js ├──
node_modules ├── package.json ├── public ├── src └── yarn.lock 3 directories, 4 files Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 14 -
$ yarn serve $ open http://localhost:8080 Hamamatsu.js Amplify + Vue.js
Handson @jacoyutorius 15 -
1. create vue project done • VueΞϓϦέʔγϣϯͷॳظԽ Hamamatsu.js Amplify +
Vue.js Handson @jacoyutorius 17 -
eslintͷઃఆΛগ͚ͩ͠؇͘͢Δ no-conoleͷϧʔϧΛه͓ͯ͘͠ͱޙʑָɻ eslintConfig": { "rules": { "no-console": "off" // ه
}, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 18 -
$ yarn add bootstrap-vue bootstrap core-js > [email protected] postinstall /Users/yuto-ogi/Work/aws_amplify/vue-chat-app/node_modules/bootstrap-vue
> opencollective || exit 0 ;XXXXXXXXXXXX333333333XXXXXXXXXXXXX; :2XXXXXXXXXXSisssssiSXXXXXXXXXXX2: .;S3XXXXXXXXX, .,,,,..,SXXXXXXXX3S;, .:SX2222XXXXXX, :XXXXS. r3XXXX2222X2;. .riiiiii5XXXXX, .;;;;, :2XXXX5iiiiiir. ;iiiiiiSXXXX, ,rrrr;,.;XXXSiiiiii; ;iiiiiiS2XX, ;3333X; .2XSiiiiii; :siiiiii2X, .::::,..r2iiiiiis: ,siiiiii2isrrrrrsi22iiiiiis, ,riiiiii23333333X2iiiiiir, .riiiiii5XXXXXX5iiiiiir. .;iiiiiiSXXXXSiiiiii;. ;iiiiiiSXXSiiiiii; :siiiiiiiiiiiis: ,siiiiiiiiiis, ,riiiiiiiir, .riiiiiir. .;iiii;. ;ii; ;; Thanks for installing bootstrap-vue ! Please consider donating to our open collective to help us maintain this package. Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 20 -
2. install Bootstrap src/main.js import Vue from 'vue' import App
from './App.vue' import BootstrapVue from 'bootstrap-vue' import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' Vue.use(BootstrapVue) Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app') Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 21 -
2. install Bootstrap src/App.vue <div id="app"> <b-container> <b-jumbotron header="BootstrapVue" lead="Bootstrap
v4 Components for Vue.js 2"> <p>For more information visit our website</p> <b-btn variant="primary" href="https://bootstrap-vue.js.org/">More Info</b-btn> </b-jumbotron> <b-form-group horizontal :label-cols="4" description="Let us know your name." label="Enter your name" > <b-form-input v-model.trim="name"></b-form-input> </b-form-group> <b-alert variant="success" :show="showGreeting">Hello {{ name }}</b-alert> </b-container> </div> Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 22 -
2. install Bootstrap src/App.vue export default { name: "app", data()
{ return { name: "" }; }, computed: { showGreeting() { return this.name.length > 4; } } } Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 23 -
2. install Bootstrap • Vue.js devtools ͰίϯϙʔωϯτͷϓϩύςΟΛ֬ೝ͢Δ Hamamatsu.js Amplify +
Vue.js Handson @jacoyutorius 26 -
3. mockup src/App.vue <div id="app"> <header> <b-navbar variant="info" type="dark"> <b-navbar-brand
href="#">Vue Chat</b-navbar-brand> <b-navbar-nav class="ml-auto"> <b-nav-form> <b-button @click="modalShow = !modalShow" variant="light">Post</b-button> </b-nav-form> </b-navbar-nav> </b-navbar> </header> Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 28 -
3. mockup src/App.vue <b-container> <section class="form"> <section> <b-modal v-model="modalShow" size="lg"
title="Post chat message"> <b-form> <b-form-group label="User:" label-for="user"> <b-form-input id="user" v-model="form.user" required placeholder="Enter user"></b-form-input> </b-form-group> <b-form-group label="message" label-for="message"> <b-form-textarea id="message" v-model="form.message" placeholder="Enter something..." rows="3" max-rows="6" ></b-form-textarea> </b-form-group> </b-form> <template v-slot:modal-footer="{ submit, cancel, close }"> <b-button variant="success" @click="onPostMessage">Submit</b-button> <b-button variant="default" @click="onCancel">Cancel</b-button> </template> </b-modal> </section> Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 29 -
3. mockup src/App.vue <section> <b-card footer="yutoogi - 2019-09-14 23:59" footer-tag="footer">
<b-media> <template v-slot:aside> <b-img blank blank-color="#ccc" width="64" alt="placeholder"></b-img> </template> Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus. </b-media> </b-card> </section> </section> </b-container> </div> Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 30 -
3. mockup src/App.vue export default { name: "app", data() {
return { form: { user: "", message: "" }, chats: [], modalShow: false }; }, computed: {}, methods: { onPostMessage() { console.log("submit"); this.modalShow = false; }, onCancel() { console.log("cancel"); this.modalShow = false; } } }; Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 31 -
3. mockup src/App.vue .card { margin: 1em 0; } Hamamatsu.js
Amplify + Vue.js Handson @jacoyutorius 32 -
3. mockup point • ϞʔμϧμΠΞϩάͷ "Submit" ΛΫϦοΫ͢Δͱ console.log ͕ग़ྗ͞ΕΔ •
ϞʔμϧμΠΞϩάͷ "Cancel" ·ͨ ӈ্ͷ "x" ·ͨμΠΞ ϩά֎ͷΤϦΞΛΫϦοΫ͢ΔͱϞʔμϧμΠΞϩά͕ด͡Δ Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 35 -
3 - 1. click event "Submit" ϘλϯΛΫϦοΫ͢Δͱνϟοτϝοηʔδ͕ొ͞Ε Δɻ Hamamatsu.js Amplify
+ Vue.js Handson @jacoyutorius 36 -
3 - 1. click event <b-card>λά෦ΛҎԼͷΑ͏ʹॻ͖͑Δɻ src/App.vue <b-card v-for="(chat, i)
in chats" v-bind:key="i" v-bind:footer="chat.user + ' - ' + chat.created_at" footer-tag="footer" > <b-media> <template v-slot:aside> <b-img blank blank-color="#ccc" width="64" alt="placeholder"></b-img> </template> {{ chat.message }} </b-media> </b-card> Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 37 -
3 - 1. click event onPostMessageϝιουΛҎԼͷΑ͏ʹॻ͖͑Δɻ src/App.vue methods: { onPostMessage()
{ this.chats.push({ user: this.form.user, message: this.form.message, created_at: new Date().toLocaleString() }); this.modalShow = false; this.form.user = ""; this.form.message = ""; }, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 38 -
3 - 2. valida+on src/App.vue <b-modal>λάͷԼʹΤϥʔϝοηʔδΛදࣔ͢ΔྖҬΛઃஔ <b-modal v-model="modalShow" size="lg" title="Post
chat message"> <section v-if="errors.length > 0" class="alerts"> <div v-for="(error, j) in errors" v-bind:key="j" class="alert alert-danger" role="alert" >{{ error }}</div> </section> <b-form> Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 40 -
3 - 2. valida+on src/App.vue data() { return { ~
(ུ) ~ errors: [] // Ճ͢Δ }; }, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 41 -
3 - 2. valida+on src/App.vue computed: { formIsInValid() { return
this.errors.length > 0; } } Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 42 -
3 - 2. valida+on src/App.vue methods: { onPostMessage() { this.checkMessageParams();
if (this.formIsInValid) { return; } ~ (ུ) ~ }, checkMessageParams() { this.errors = []; if (this.form.user === "") { this.errors.push('"User" is required.'); } if (this.form.message === "") { this.errors.push('"Message" is required.'); } } Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 43 -
4 - 1. copy AWS se/ng AWSͷઃఆϑΝΠϧΛΈࠐΉ Hamamatsu.js Amplify +
Vue.js Handson @jacoyutorius 45 -
4 - 1. copy AWS se/ng src/aws-exports.js const awsmobile =
{ "aws_project_region": "ap-northeast-1", "aws_appsync_graphqlEndpoint": "https://izjtvc7nijhrrihcnxu2umyuzy.appsync-api.ap-northeast-1.amazonaws.com/graphql", "aws_appsync_region": "ap-northeast-1", "aws_appsync_authenticationType": "API_KEY", "aws_appsync_apiKey": "" //͓͑͠·͢ }; export default awsmobile; Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 46 -
4 - 1. create AWS se/ng src/graphql ͱͦͷԼͷϑΝΠϧΛ࡞Δ Hamamatsu.js Amplify
+ Vue.js Handson @jacoyutorius 47 -
create amplify AWS files $ tree src src ├── App.vue
├── assets │ └── logo.png ├── aws-exports.js ├── components │ └── HelloWorld.vue ├── graphql │ ├── mutations.js │ ├── queries.js │ ├── schema.json │ └── subscriptions.js └── main.js 3 directories, 9 files Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 48 -
4 - 2. install aws-amplify aws-amplify ΛΠϯετʔϧ͢Δ Hamamatsu.js Amplify +
Vue.js Handson @jacoyutorius 49 -
4 - 2. install aws-amplify $ yarn add aws-amplify aws-amplify-vue
Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 50 -
4 - 2. install aws-amplify src/main.js import Amplify, * as
AmplifyModules from 'aws-amplify' import { AmplifyPlugin } from 'aws-amplify-vue' import awsconfig from './aws-exports' Amplify.configure(awsconfig) Vue.use(AmplifyPlugin, AmplifyModules) Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 51 -
4 - 3. Query src/App.vue import { API, graphqlOperation }
from "aws-amplify"; import { listHmjsChats } from "@/graphql/queries"; ~ ུ ~ async created() { const listChats = await API.graphql(graphqlOperation(listHmjsChats)); this.chats = listChats.data.listHmjsChats.items; } Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 53 -
4 - 4. Post ϝοηʔδΛAPIʹPOST͢Δɻ Hamamatsu.js Amplify + Vue.js Handson
@jacoyutorius 54 -
4 - 4. Post src/App.vue import { createHmjsChat } from
"@/graphql/mutations"; computed: { ~ ུ ~ chatParams() { return { ...this.form, created_at: new Date().toLocaleString() }; } }, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 55 -
4 - 4. Post src/App.vue onPostMessage() { this.checkMessageParams(); if (this.formIsInValid)
{ return; } this.postMessage(); this.modalShow = false; }, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 56 -
4 - 4. Post src/App.vue async postMessage() { await API.graphql(
graphqlOperation(createHmjsChat, { input: this.chatParams }) ).catch(error => { console.error(error); }); }, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 57 -
4 - 5. Subscribe src/App.vue import { onCreateHmjsChat } from
"@/graphql/subscriptions"; created() { API.graphql( graphqlOperation(onCreateHmjsChat) ).subscribe({ next: chat => { this.chats.push(chat.value.data.onCreateHmjsChat); } }); }, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 59