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

Vue.js simple Chat Handson (in Hamamatsu.js 2019.11)

jacoyutorius
November 06, 2019

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
Tweet

More Decks by jacoyutorius

Other Decks in Technology

Transcript

  1. Yuto Ogi @jacoyutorius Web developer, AIRS • ࠷ۙ͸αʔόʔϨεΞʔΩςΫνϟ͕ ޷͖ •

    AlexaͷεΩϧΛ࡞ͬͨΓWebΞϓϦ έʔγϣϯΛ࡞ͬͨΓ • ࣗ࡞ΩʔϘʔυপʹϋϚ͍ͬͯͯͦΖ ͦΖ3ػ໨Λ࡞Δ༧ఆ Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 2
  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
  3. 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
  4. Stages 1. create Vue project 2. install Bootstrap 3. Chat

    mockup 4. integrate Chat API Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 8
  5. before handson • Node.js • install @vue/cli • Vue.js devtools

    (Chrome plugin) Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 9
  6. versions $ node -v v10.14.1 $ npm -v 6.11.3 Hamamatsu.js

    Amplify + Vue.js Handson @jacoyutorius 10
  7. $ 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
  8. $ 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
  9. $ 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 3. mockup src/App.vue .card { margin: 1em 0; } Hamamatsu.js

    Amplify + Vue.js Handson @jacoyutorius 32
  18. 3. mockup point • ϞʔμϧμΠΞϩάͷ "Submit" ΛΫϦοΫ͢Δͱ console.log ͕ग़ྗ͞ΕΔ •

    ϞʔμϧμΠΞϩάͷ "Cancel" ·ͨ͸ ӈ্ͷ "x" ·ͨ͸μΠΞ ϩά֎ͷΤϦΞΛΫϦοΫ͢ΔͱϞʔμϧμΠΞϩά͕ด͡Δ Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 35
  19. 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
  20. 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
  21. 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
  22. 3 - 2. valida+on src/App.vue data() { return { ~

    (ུ) ~ errors: [] // ௥Ճ͢Δ }; }, Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 41
  23. 3 - 2. valida+on src/App.vue computed: { formIsInValid() { return

    this.errors.length > 0; } } Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 42
  24. 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
  25. 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
  26. 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
  27. 4 - 2. install aws-amplify $ yarn add aws-amplify aws-amplify-vue

    Hamamatsu.js Amplify + Vue.js Handson @jacoyutorius 50
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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