0. はじめに
この資料はjavascriptの基本的な書き方を学習し終わった方向けに
vue-cli3を使った簡易なWebアプリの作り方を説明するための資料となっています。
内容としては
- vue-cli3の使い方
- 作成されるプロジェクトの概要
- Vue.jsの基本的な機能
- APIサーバーの作成方法
- UIとAPIサーバーの通信方法
を含み、またおまけとして
- ibmcloudのcloudfoundryを用いたwebへのデプロイ方法
- Watson Assistantを用いたチャットボットアプリへの拡張
を含みます。
抜け、漏れや間違いなどございましたらコメントでご指摘いただけますと幸いです。
1. 環境構築
実施環境
今回のプロジェクトは以下のような環境で作成しました。
mac : Big Sur 11.5
google chrome : 92.0
npm : 7.18.1
node : v16.4.1
@vue/cli : 4.5.13
ibmcloud cli : 1.5.1
node.jsの導入
この辺りを参考にnode.jsを導入してください。
MacにNode.jsをインストール
node.js公式サイト
vue-cli3の導入
ターミナル(windowsならPowershell)を開いて次のコマンドを実行してください。
npm install -g @vue/cli
完了したら次のコマンドを実行してインストールが正しく行えたか確認してください。
vue --version
次のようにバージョンが表示されたらインストール成功です。
@vue/cli 4.5.13
環境構築はここまで
2. アプリの作成
アプリを置いておきたいディレクトリに移動して次のコマンドを実行してください
(フォルダごと作成されるので専用のフォルダなどを作る必要はありません)
vue create <アプリ名>
以下は作成時に聞かれる項目の解説です
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 2] babel, eslint)
Default (Vue 3) ([Vue 3] babel, eslint)
Manually select features
オプションのプリセット、簡単なアプリを作るだけならDefaultでも事足りますが、
今回はよく使う機能の説明も含むので一番下のManually select featuresを選択してださい。
? Check the features needed for your project: (Press <space> to select, <a> to t
oggle all, <i> to invert selection)
❯◉ Choose Vue version
◉ Babel
◯ TypeScript
◯ Progressive Web App (PWA) Support
◉ Router
◯ Vuex
◯ CSS Pre-processors
◯ Linter / Formatter
◯ Unit Testing
◯ E2E Testing
最初から導入しておきたいパッケージを選択します
↑↓キーで選択、Spaceキーで切り替え、Enterキーで完了
今回はVue3.0, Babel, Routerのみを有効にしてください
各パッケージの簡単な説明
-
Choose Vue version
Vueのバージョンを選択する -
Babel
javascriptの新しい記法を色々なブラウザで使えるようにするパッケージ
参考:【5分でなんとなく理解!】Babel入門 -
TypeScript
javascriptを拡張した言語
型が明確、継承がサポートされているなど複数人が関わるプロジェクトで役立つ機能が多い -
Progressive Web App (PWA) Support
Webアプリからスマートフォンの一部機能を利用できるようになる機能 -
Router
ページを遷移せずに複数のコンテンツを表示するために利用する
SPA(SinglePageApplication、単一のページでコンテンツを表示するwebアプリケーション)の実装に重要 -
Vuex
異なるページの間でデータを共有するために利用する -
CSS Pre-processors
SASSなどのCSSを拡張するパッケージ -
Linter / Formatter
インデントや関数の形式などコードの書き方を管理するパッケージを導入する
複数人が関わるプロジェクトではほぼ必須 -
Unit Testing
コードの単体テストを行うパッケージを導入する
DevOpsやTDD(テスト駆動開発)で利用されるが、テストコード自体も適切な管理が必要なので注意 -
E2E Testing
コードのEndToEndテスト(結合テスト)を実施するパッケージを導入する
注意点はUnitTestと同様
? Choose a version of Vue.js that you want to start the project with (Use arrow
keys)
2.x
❯ 3.x
Vueのバージョンを選択します。
ネットにある記事は2.0のものが多いですが、
3.0では周辺モジュール(vue-routerなど)の書き方が変わっていたりUIコンポーネント(Bootstrapなど)が一部対応していなかったりするので注意してください。
今回は3.xを選択してください。
? Use history mode for router? (Requires proper server setup for index fallback
in production) (Y/n)
Routerを導入した場合のみ発生、vue-routerをhistoryモードで動かすかどうかについての質問です。
通常Vue-Routerを使用すると各コンテンツのURLは
http://localhost:8080/#/hoge
のように # が必要となるが、historyモードを用いると # を省略して
http://localhost:8080/hoge
と記述できます
ただし、こちらのモードを利用する場合以下のような仕様があるため注意してください。
- サーバへの通信が発生するため速度が低下する
- アプリをデプロイする際サーバー側で設定が必要
- History APIをサポートしていないブラウザで動作しない
詳細な説明はこちら
今回はhistoryモードを使用しないため、 n を入力してください。
? Where do you prefer placing config for Babel, ESLint, etc.?
❯ In dedicated config files
In package.json
Babel, ESLintなど各種パッケージの設定をどこで行うかを設定する質問です。
In dedicated config filesでは個別のconfig fileを作成し、
In package.jsonではpackage.jsonでまとめて管理します
今回は In dedicated config files を選択してください。
? Save this as a preset for future projects? (y/N)
今回の設定をプリセットとして保存するかどうかの質問です。
今回は保存しないため n を入力しください。
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn
Use NPM
package管理ツールの選択です。
今回はyarnを使用するので Use Yarn を選択してください。
3. 作成されたプロジェクトの確認
3.1. プロジェクト構造の確認
各ファイルの説明
-
babel.config.js
babelの設定ファイル -
node_modules
npm or yarnでインストールしたパッケージが配置されるフォルダ -
package.json
パッケージの状況やアプリの実行コマンドなどアプリのコンフィグの大部分を管理するファイル -
public
クラウドなどにデプロイするためのビルド済みファイルが配置されるフォルダ -
README.md
アプリの説明文を記入するファイルgitなどのリポジトリで自動表示される -
src
画面ファイルのソースコードが入っているフォルダ -
App.vue
Webアプリのメイン画面を記述するソースコード
全てのコンテンツに共通する内容はここで記述する -
assets
動的な変更を必要としない画像や動画などを配置するフォルダ -
components
画面部品を配置するフォルダ
複数の箇所で使い回す場合や責務の分離が必要な場合、コンポーネントとして分離する -
main.js
Webアプリ起動時に最初に動作するファイル
App.vueなどを呼び出す -
router
vue-routerの設定ファイルが入っているフォルダ -
views
各コンテンツの内容はここで記述する
webページ作成で主に編集するフォルダ -
yarn.lock
yarnにおけるパッケージの依存関係を管理するファイル
package.jsonを変更すると自動で変更される
起動して確認するためには以下のコマンドを実行する
yarn serve
次のような表示が出たら実行準備完了です。
App running at:
- Local: http://localhost:8080/
- Network: http://192.168.50.136:8080/
Note that the development build is not optimized.
To create a production build, run yarn build.
ブラウザを開いてhttp://localhost:8080/
にアクセスしてください。
このような画面が表示されれば成功です。
アプリを終了するときには
control + C
キーを同時押ししてください。
3.2. コードを編集してみる
src/views/Home.vue
をメモ帳,vim,vscodeなどのエディタで開いた後
再度 yarn serve
でアプリを起動してください。
```vuejs:src/views/Home.vue
`Welcome to Your Vue.js App`を適当な文字列に書き換えて保存してみましょう

指定した文字列に書き換わりましたね
このように`yarn serve`での起動中にソースコードを書き換えるとアプリケーションに自動で反映されます
### 3.3. routerの確認
アプリを動かしたままもう一つターミナルを開いて
`/src/router/index.js`を開いてみましょう
``` javascript:`/src/router/index.js`
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
ここで画面に表示するコンテンツの元になるファイルを指定しています
変数routesに注目してみましょう
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
}
]
ここで各コンテンツのURLと表示する内容を設定しています
それぞれ
- path: URLにおける #以降のアドレス
- name: コンテンツの名前
- component: 表示する元となるファイル
を表します、例えば2個目のaboutならば
http://localhost:8080/#/about
にアクセスすると/src/views/About.vue
ファイルを表示することになるわけです
実際にhttp://localhost:8080/#/about
にアクセスしてみます。
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
/src/views/About.vue
と見比べてみると一致しているのがわかると思います。
(上のHome|Aboutは/src/app.vue
に書かれた共通処理)
4. Vue.jsの記法
4.1. 準備
この項ではVue.jsでよく使う記法について書いていきます
まずテスト用に新しいページを作ります。
/src/router/index.js
の変数routesに
{
path: '/test',
name: 'Test',
component: () => import('../views/Test.vue')
}
を追加しましょう。
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
},
{
path: '/test',
name: 'Test',
component: () => import('../views/Test.vue')
} //これを追加
]
この時ブラウザはエラーになりますが一旦放置で大丈夫です。
続いて/src/views
フォルダにTest.vue
という名前のファイルを作りましょう。
この時点でブラウザのエラーが解消されるのでhttp://localhost:8080/#/test
にアクセスします。Home|Aboutだけが表示されている状態になったら準備完了です
まずTest.vue
に次のように書き込みます
<template>
</template>
<script>
export default {
name: 'Test',
components: {},
methods: {
},
data: () => ({
}),
}
</script>
<style>
</style>
これがvue.jsでファイルを扱う際の基本形です
<template> ~ </template>
の範囲がWebページの基本的な構造、仕組みを書く部分
<script> ~ </script>
の範囲が変数や関数などの処理を書く部分
<style> ~ </style>
の範囲が見た目の飾り付けを書く部分
となります
<style>
ブロックは通常のCSSと同じ挙動でクラスなどを用いて見え方を調整することができますが、今回の内容では扱いません。
まず
<template> ~ </template>
の中に
<div>
Hello Vue
</div>
と書き込んで保存してみます。
このように書き込んだ文字が表示されたら正しくRoutingできています
4.2. 基本機能の確認
vue.jsの基本的な機能をいくつかテストしていきます。
4.2.1.変数の表示
<script> ~ </script>
のdata: () => ({ ~~~~ })
の中に変数を定義します
<script>
export default {
name: 'Test',
components: {},
methods: {
},
data: () => ({
testData: 'Vueはじめました' //このように定義
}),
}
</script>
続いて先ほど作った<div>
ブロックの中に{{今定義した変数}}
の形で書き込んで保存します。
<template>
<div>
{{testData}}
</div>
</template>
画面には先ほど定義した変数の内容が表示されているはずです。
このようにdataで定義した変数を{{ }}
で囲うことでその値を表示することができます。
4.2.2. タグ属性の操作(v-bind)
htmlタグの属性情報を変数に紐付けて自由に変更できるようにしてみます。
まず、先ほど作った<div>
ブロックの中に
<img src="../assets/logo.png" width='100'>
を記入して保存します。
(この画像は/src/assets
の中に入っています)
<template>
<div>
<img src="../assets/logo.png" width='100'>
</div>
</template>
このように画像が表示されたと思います。
この時、src="../assets/logo.png" width='100'
の部分をタグの属性情報と言い、これを変更することで表示する画像や画像のサイズを操作することができます。
試しにwidthを200などに書き換えてみると画像のサイズが倍になることが確認できると思います。
jqueryや素のjavascriptなどを使う場合にはWebページが開かれているときに属性情報を変更するためにはタグを検索して取得、変更するような手順が必要となります。
一方vueでは、属性情報と変数を紐付けておき、変数が変更されたときに属性情報を書き換えることが可能です。
実際にテストしてみます。
まず、4.2.1.と同様変数部分にimgWidth: 100
を定義します、
その後、<img src="../assets/logo.png" width='100'>
のwidth='100'
をv-bind:width='imgWidth'
に書き換えてみましょう。
<template>
<div>
<img src="../assets/logo.png" v-bind:width='imgWidth'> //属性情報を書き換え
</div>
</template>
<script>
export default {
name: 'Test',
components: {},
methods: {
},
data: () => ({
imgWidth: 100 //imgWidthを定義
}),
}
</script>
この状態でimgWidthの値をさまざまに切り替えて保存してみましょう。
属性情報を直接書き換えた時のように画像のサイズが切り替わっているのがわかると思います。
このようにv-bind:<属性情報>='<変数名>'
という記法を使うことで
タグの属性情報に変数を紐付けできるわけです。
また、v-bindは省略可能で一般的には:<属性情報>='<変数名>'
と書くことが多いのでこちらも覚えておくと良いでしょう。
属性情報の紐付けはアプリの見た目を考える段階、特にBootstrapなどのUIコンポーネントを使うようになると使う機会が大きく増えます。
4.2.3.関数の実行(v-on)
関数を定義することでボタンのクリックなど様々なイベントに対して処理を割り当てることができるようになります。
まず実行用のボタンを作ります。
4.2.2.で挿入した<img>
タグの下に<input type='button' value='test'>
を追加しましょう。
<template>
<div>
<img src="../assets/logo.png" v-bind:width='imgWidth'>
<input type='button' value='test'>
</div>
</template>
図のように画像の下にボタンが表示されたはずです。
今はこのボタンを押しても何も起こりません。これからこのボタンに処理を追加していきます。
続いて、<script>
ブロックのmethods:{}
の中に関数を定義します。
関数は
書き方1
関数名(){
〜処理〜
}
書き方2
関数名: function(){
〜処理〜
}
のような形で定義することができます。
どちらを選んでも良いですが、コードの中で複数の書き方を混在させないようにしましょう。
今回はボタンを押したときに画像のサイズを変更する処理を実装したいと思います。
changeImgSize(){
this.imgWidth = 200
}
このとき、data
にある変数はthis.変数
の形で記入してください
(関数の中で他の関数を呼び出す場合も同様にthis.関数
の形で書きます)
では、定義した関数をボタンで呼び出せるようにします。
<input type='button' value='test'>
に
v-on:click='changeImgSize'
を追加します。
<template>
<div>
<img src="../assets/logo.png" :width='imgWidth'>
<input type='button' value='test' v-on:click='changeImgSize'>
</div>
</template>
保存してtestボタンをクリックしてみましょう。
図のように画像サイズが大きくなったはずです。
このようにv-on:<イベント>='<関数>'
という記法を使うことでクリックやテキスト入力、マウスオンなどのイベントに対して関数を紐づけることができるようになりました。
こちらのv-on
も省略記法があり@<イベント>='<関数>'
の形で書くことができます。
また、今回関数を'changeImgSize'
と( )のない形で書きましたが、'changeImgSize(変数)'
のように書くことで通常の変数ありの関数も扱うことができます。
イベントの種類はこの辺りを参考にしてください。
ここで、関数を扱う上で重要なデバッグ機能について追記しておきます。
javascriptで変数の途中の状態や関数が実行されているかどうかを確認する方法の一つとしてconsole.log
があります。これを関数内で実行することで、指定した変数や文字列をコンソールに表示することが可能です。
例)
changeImgSize(){
this.imgWidth = 200
console.log(this.imgWidth) //imgWidthの値を表示
}
この時、console.log
の結果が表示されるのはyarn serve
が動いているターミナルではなくブラウザのデバッグコンソールです。
これはブラウザを開いた状態で
mac:command + option + i
windows:Ctrl + Shift + i
を押すと開くもので、コンソールの確認の他にもスマホなどでの見え方の確認やCSSの調整など様々な機能がありますのでwebアプリを作る時には必ず確認するようにしましょう。
4.2.4. 繰り返し表示(v-for)
チャットや一覧表示のようにコンテンツを繰り返し表示する必要がある場合、
vueではv-forという記法を用いて書くことができます。
まず、data内にtestArray: ['テキスト1','テキスト2','テキスト3']
という配列を定義します。
続いてブロック内に
<div v-for="data in testArray">
{{data}}
</div>
を追加します。
<template>
<div v-for="data in testArray">
{{data}}
</div>
</template>
<script>
export default {
name: 'Test',
components: {},
methods: {},
data: () => ({
testArray: [
'テキスト1',
'テキスト2',
'テキスト3'
]
}),
}
</script>
v-for
は指定したブロックを配列内の要素分繰り返す記法です、
確認のため作成した<div>
ブロックの中に
<img src="../assets/logo.png" width='50'>
を記入してみます。
<template>
<div v-for="data in testArray">
{{data}}
<img src="../assets/logo.png" width='50'>
</div>
</template>
このようにv-for
で指定したブロックの中身が繰り返されていることがわかります。
また、次のように配列内にオブジェクトを指定するとv-for
ブロック内で表示する内容を変更することができます。
testArray: [
{
text: 'タイトル1',
width: '50'
},
{
text: 'タイトル2',
width: '100'
},
{
text: 'タイトル3',
width: '200'
},
]
例として以下のように書くと
<template>
<div v-for="data in testArray">
{{data.text}}
<img src="../assets/logo.png" :width='data.width'>
</div>
</template>
testArrayから取り出されたObjectがdata
に代入され、data.text
、data.width
の形で値を取り出すことができます。
このサンプルの結果は図のようになります。
このようにv-for='<取り出し先> in <配列>'
という記法を使うことでhtml要素を配列の要素分繰り返すことができるようになりました。
4.2.5. 変数の同期(v-model)
4.2.2.のv-bindで属性情報に変数を紐付けました。
v-bindは変数が変わった際にhtml要素を操作することができますが、html要素を変更した場合に変数を変更することはできません。
例として以下のような<input>
タグの挙動を試します
<template>
<div>
{{testData}}
</div>
<div>
<input type='text' :value='testData'>
</div>
</template>
<script>
export default {
name: 'Test',
components: {},
methods: {},
data: () => ({
testData: 'テスト'
}),
}
</script>
この時、上の表示欄と下の入力欄の両方にテスト
が表示されていますが、
入力欄を書き換えた場合、
書き換え欄と入力欄が一致しません。
このようにhtmlへの入力を変数に反映させるためにはv-model
という記法を使います。
<input>
ブロックの:value
をv-model
に書き換えて保存し、ブラウザを更新してください。
入力欄を書き換えると表示欄の内容が同時に書き変わるようになるはずです。
このように、v-model='<変数>'
という記法を使うことでhtml要素と変数を同期させることができるようになります。
なお、入力を同期させたい場合には@change='変数に入力を代入する関数'
のような方法で代用することも可能です。v-modelとchangeイベントは同時に使えないため、入力時に複数の処理を行いたい場合にはこちらを利用するのが良いと思います。
4.2.6. 要素の使い回し(コンポーネント)
vueではvueファイルの中で他のvueファイルを呼び出してコンポーネント(部品)として扱うことができます。
これによって色々なページで使い回す要素(ヘッダーやフッターなど)やv-for内で繰り返す要素を分割して管理することができます。
これを試すために
/src/components
にTestComponent.vue
というファイルを作って以下のように書き込んでください。
<template>
<div>
コンポーネント
</div>
</template>
<script>
export default {
name: 'TestComponent',
props: {
},
methods: {},
data: () => ({
}),
}
</script>
続いて、Test.vue
における<script>
ブロックにimport TestComponent from '@/components/TestComponent.vue'
を書き込んでください。
また、methodsの上にcomponents: { TestComponent },
を作成します。
完成形はこのようになります。
<script>
import TestComponent from '@/components/TestComponent.vue'
export default {
name: 'Test',
components: {
TestComponent
},
methods: {},
data: () => ({
}),
}
</script>
これで先ほどTestComponent.vue
で定義したコンポーネントを利用できるようになりました。
続いて<template>
ブロックの中に読み込んだ<TestComponent>
でブロックを作ります。
<template>
<div>
<TestComponent>
</TestComponent>
</div>
</template>
コンポーネントの内容がTest.vue
のページに反映されました。
コンポーネントは通常のhtml要素同様に属性情報を渡すことが可能です。
TestComponent.vue
のpropsオブジェクトの中にmsg: String
を追加してみましょう
この時、Stringは入力をString型で行うことを表します。
また、<template>
ブロックにmsg
を表示する記述を追加します。
完成形はこのようになります。
<template>
<div>
コンポーネント:{{msg}}
</div>
</template>
<script>
export default {
name: 'TestComponent',
props: {
msg: String
},
methods: {},
data: () => ({
}),
}
</script>
続けて、Test.vue
の<TestComponent>
ブロックにmsg='親コンポーネントからの入力'
という属性情報を追加しましょう。
<template>
<div>
<TestComponent msg='親コンポーネントからの入力'>
</TestComponent>
</div>
</template>
図のようにTest.vue
で入力した内容がTestComponent.vue
に反映されて表示されます。
このように、Componentを使うことで複数回使う要素を一回で記述したり、ページを部品ごとに分担して作成することができるようになります。
これはvueに限らずAngularなど他のフレームワークでも多用されるテクニックなので覚えておくと良いと思います。
5.APIサーバーの作成
ここからはUI側の表示ではなく、ファイル操作や認証を伴うAPIの呼び出し、DB操作などサーバー側で行う処理を作っていきます。
まず、yarn serve
が動いている場合にはCtrl + C
で停止してください。
続けて作成したプロジェクトのpackage.json
が入っているディレクトリでvue add express
を実行してください。
(プロジェクト内であればどこでも実行できますが説明を簡単にするためにこのようにします。)
このような表示が出てきた場合にはyを入力してください
WARN There are uncommitted changes in the current repository, it's recommended to commit or stash them first.
? Still proceed? (y/N)
続いてこのような表記が出るのでyを入力してください
? Should serve vue app? (Y/n)
最後にこのような表記が出るので、サーバー機能を保存したいフォルダ名を入力してください。
(今回はそのまま実行しsrvディレクトリに保存)
? Where will be located your server? (./srv)
ディレクトリを確認すると今入力した名前のフォルダができているはずなので、中に入っているindex.js
を開きましょう。
import express from 'express';
// import socketIO from "socket.io";
export default (app, http) => {
// app.use(express.json());
//
// app.get('/foo', (req, res) => {
// res.json({msg: 'foo'});
// });
//
// app.post('/bar', (req, res) => {
// res.json(req.body);
// });
//
// optional support for socket.io
//
// let io = socketIO(http);
// io.on("connection", client => {
// client.on("message", function(data) {
// // do something
// });
// client.emit("message", "Welcome");
// });
}
中にはサンプルが入っていますが、socket.ioは今回使わないため削除し、そのほかのコメントアウトされた箇所を戻します。
(socket.ioはリアルタイムの情報通信を可能にする接続形式です。
チャットなどを作る場合には非常に便利なので気になる方は調べてみてください)
import express from 'express';
export default (app, http) => {
app.use(express.json());
app.get('/foo', (req, res) => {
res.json({msg: 'foo'});
});
app.post('/bar', (req, res) => {
res.json(req.body);
});
}
これでサーバー側機能の基本形は完成です。
yarn express
でサーバーを起動し、http://localhost:3000/foo
にアクセスしてみましょう
図のように表示されたと思います。
/srv/index.js
で定義された
app.get('/foo', (req, res) => {
res.json({msg: 'foo'});
});
と比較してみると一致しているのがわかると思います。
こちらもUI同様、起動中に書き換えた内容は即座に反映されるため、
内容を書き換えて画面を更新すると書き換えた内容が表示されるようになります。
このように作成したAPIをテストする場合には主にブラウザの拡張機能が利用できます。
例)
Chlome:Talend API Tester
Firefox:RESTClient
Talend Api Testerの動作例
SCHEMAにURLを設定し、BODYに送る内容を記入してSendボタンを押すとテストできます。
結果はこのようになります。
6.UIとServerの通信
最後に、UIからServer側で作成したAPIを呼び出せるようにします。
このような通信を行うパッケージはいくつかありますが、今回はaxiosというパッケージを使います。
まず、ServerとUIの両方をCtrl + C
で停止させた上で
yarn add axios vue-axios
を実行してください。
続けて、/src/main.js
を開き、下のように書き換えてください。
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import axios from 'axios' //追加
import VueAxios from 'vue-axios' //追加
createApp(App)
.use(router)
.use(VueAxios, axios) //追加
.mount('#app')
完了したら保存して閉じ、次にvue.config.js
を開いてください。
こちらにはdevServer: { proxy: 'http://localhost:3000' }
を追加して保存します。
module.exports = {
pluginOptions: {
express: {
shouldServeApp: true,
serverDir: './srv'
}
},
devServer: {
proxy: 'http://localhost:3000',
} //追加
}
この処理は開発環境の時(yarn serveの時)このserverから外にアクセスした際に自動で
API Serverが動いているポートにアクセスできるようにするための設定です。
詳細は省きますが、このように設定しないとAPIへのアクセスができません。
興味のある方はCORSで調べてみてください。
以上が完了したら/src/Test.vue
をエディタで表示した上で、
yarn serve
及び yarn express
を二つのターミナルを使って同時に実行してください。
vue-axiosを導入するとAPIの呼び出しを下のような形で行うことができます。
this.axios.get('/<apiのURL>')
.then((res) => {
処理
}).catch((err) => {
エラー時の処理
})
この時、APIの呼び出しは非同期で行われます。
つまり、
let test = '呼び出し前の値'
this.axios.get('/<apiのURL>')
.then((res) => {
test = '呼び出し後の値'
})
console.log(test)
のように書いた場合console.log
で表示されるのは'呼び出し前の値'になります。
もし、APIを呼び出した後の処理を使って処理を続けたい場合は
this.axios.get('/<apiのURL>')
.then((res) => {
処理1
}).then((res) => {
処理2
}).then((res) => {
処理3
}).catch((err) => {
エラー時の処理
})
のように書く必要があります。
このようにthen
,catch
を使って同期処理・エラーハンドリングを行う書き方はPromiseという機能に従ったもので処理を正しい順序で行うために非常に重要な機能なので、拡張形であるasync
,await
と合わせて覚えておいてください。
また、then()
の中で利用されている
() => {
処理
}
のような記法をラムダ式と言い、名前を持たない簡易の関数を定義するための記法です。
(入力) => {
処理
return 返り値
}
あるいは
(入力) => (返り値)
の形で書くことができ、Promiseだけでなくfilterやmapといった
プロトタイプ関数を使う際にもよく利用する記法ですので覚えておいてください。
さて、これらを用いてTest.vueをAPIとの通信をテストできるよう書き換えます。
<template>
<div>
<input type='text' v-model='sendData'>
</div>
<div>
<input type='button' @click='getMessage' value='受信'>
<input type='button' @click='sendMessage' value='送信'>
</div>
<div>送るテキスト:{{sendData}}</div>
<div>受け取ったテキスト:{{getData}}</div>
</template>
<script>
export default {
name: 'Test',
methods: {
getMessage(){
this.axios.get('/foo')
.then((res) => {
this.getData = res.data.msg
})
},
sendMessage(){
this.axios.post('/bar', { msg: this.sendData })
.then((res) => {
this.getData = res.data.msg
})
}
},
data: () => ({
sendData: '送信するテキスト',
getData: '受け取ったテキスト'
}),
}
</script>
getMessage
関数ではaxiosのget methodを使い、/foo
の内容を受け取ってgetData
変数に代入しています。
sendMessage
関数ではaxiosのpost methodを使い、/bar
に対してsendData
変数を送信し、返り値をgetData
変数に代入しています。
それぞれ挙動をテストしてみてください。
受信を押した時にfooが、送信を押したときに入力と同じ内容が表示されていれば成功です。
UIとServerの通信は以上です。
yarn serve
及びyarn express
をCtrl + C
で停止してください。
7. おわりに
ここまで読んでいただきありがとうございました。
Vue.jsはAngular、Reactといった仮想DOMを扱うフレームワークの中で最も学習コストが低いため、他のフレームワークの入り口としても有効なものだと思っています。
この記事の内容が少しでも皆様のお役に立てば幸いです。
今回作成したソースコードはこちらに配置しています。
8. おまけ1:Croudfoundryへのアップロード
ここでは作成したアプリをIBMcloudにアップロードして誰でもアクセスできるようにする方法を紹介します。
AWSやGCP、Azureなどを使う場合と共通する点もありますが異なる点もあるのでその場合は各自リファレンスを読んで頑張ってください。
8.1. ソースコードのビルド
まず、本番環境にアップロードするファイルを作るため、yarn build
を実行します。
完了するとプロジェクトの中にdist
というフォルダが追加されます。
これは現時点のコードをコンパイルして、これ単体で動くようなファイルにまとめたものです。
こちらはyarn serve
で実行した場合と異なり、ソースコードを書き換えても再度yarn build
を実行するまで変更されません。
dist
が確認できたら今度はyarn express:run
を実行し、http://localhost:3000/#/test
にアクセスしてみます。
(失敗する場合はyarn express
が動きっぱなしになっている可能性があります)
yarn serve
及びyarn express
を同時に実行していたときと同じ状態になっていると思います。
これはdist
の中身とRESTapiserverを同時に動かすコマンドで、これが動作するのであれば本番環境でも動作する可能性が高いということになります。
これらの機能はvue-cliのパッケージを使って行われますが、vue-cliはデフォルトでは開発環境のみで動作するようになっています。
そこで、package.json
を開き、devDependencies
の内容を全てdependencies
に移しておきましょう
{
"name": "test-project",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"express": "vue-cli-service express:watch",
"express:run": "vue-cli-service express:run"
},
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.6.5",
"vue": "^3.0.0",
"vue-axios": "^3.2.5",
"vue-router": "^4.0.0-0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0",
"vue-cli-plugin-express": "~1.0.2"
},
"devDependencies": {}
}
8.2. ibmcloudの準備
IBM Cloud
にログイン
CloudFoundryで検索し、CloudFoundryをクリック
リソースを SDK for Node.js
を選択
アプリ名を設定
作成をクリック
(Liteアカウントで登録している場合、無料で使用することができます。リソースは30日間経つと削除されます)
以下を参考にIbmcloud cli toolをインストールしてください。
IBMCloud cli toolのインストール方法
8.3. アプリのデプロイ
プロジェクトの一番上のディレクトリに.cfignoreファイルを作成し、以下の内容を書き込みます。
node_modules
yarn.lock
このファイルはCloudFoundryにアップロードしないファイルを設定するものです。
node_modulesはCloudFoundryにアップロードした際に自動でインストールされるため、時間短縮のために除外します。
また、yarn.lockは依存関係の都合上、入っているとデプロイに失敗するため除外します。
続いて同じディレクトリにmanifest.ymlファイルを作成し、以下の内容を書き込みます
applications:
- name: <8.2.で設定したアプリ名>
routes:
- route: <アプリ名>.<ドメイン名>
memory: 256M
disk_quota: 512M
command: yarn express:run
これはCloudFoundryにアップロードする際の設定ファイルです。
ここでCommandをyarn express:run
に設定することでvue-cliを用いた起動が使えるようになります。
(設定しない場合、npm start
が利用されます)
ibmcloud login -r us-south
と打ち込んでibmcloudにログインします。
続いてibmcloud target --cf
と打ち込み、cloud foundryをアップデート先に設定します。
最後にibmcloud cf push
を入力します
9. おまけ2:Watson Assistantとの連携
9.1. インスタンスの作成
IBM Cloud
にログイン
Watson Assistantで検索し、Watson Assistantをクリック
ロケーションを適当に設定(CloudFoundryを使う場合は合わせる)
ライトアカウントを選択
9.2.チャットボットの作成
Add an actions or dialog skillをクリック
名前を設定、
LanguageをJapaneseに設定、
Skill typeをDialogに設定し
Create skillをクリック
簡単のために構築済みIntentを利用します。
Content Catalogをクリック
一般カテゴリのインテントをAdd to skillで追加します
Intentsタブで追加したIntentを確認できます。
また、Create Intentで新しいIntentを作成できます。
名前を設定し、5つ以上のサンプルを追加することで類似した入力を検知できるようになります。
Dialogタブに移動し、Add nodeでいくつかノードを追加します。
ノードを選択し、
Nameに名前
Enter conditionに認識するIntent(その他にも固有の語を認識するEntitiesや変数を認識するContextなどがある)
Assistant respondsに返答を設定する
これを作成したノード分行う。
設定が完了したら右上のTry itをクリック
テキストを入力することで動作をテストできます。
9.3.アプリの実装
UI側
<template>
<div>
<div>
<BotLog :log='log' v-for="log in logs"/>
</div>
<div>
<input type='text' v-model='sendData.text'>
<input type='button' value='送信' @click='addLog'>
</div>
</div>
</template>
v-modelで入力が連動するようにしたテキスト入力欄とログを追加する関数を実行する送信ボタン
v-forでログ用コンポーネントを繰り返し表示する表示欄を作成します。
addLog(){
this.logs.push(Object.assign({},this.sendData)) //入力したデータをログに追加
this.axios.post('/sendMsg', this.sendData) //APIにデータ送信
.then((res) => {
this.logs.push({
speaker: 'bot',
text: res.data.text
}) //APIの結果をログに追加
})
this.sendData.text = '' //入力内容を初期化
}
Server側
ターミナルでyarn add dotenv
を実行します。
これは環境変数を一時的に.env
ファイルから呼び出せるようにするパッケージです。
APIキーや接続先URLなどの資格情報はコード内に書き込むのではなく、
他のファイルに分離しておくと後で接続先が変わった時などに便利です。
特に、kubernetesなどを使ったマイクロサービス的なシステムを構築する際は、
環境変数をkubernetesのyamlで管理可能なため、資格情報などを環境変数から呼び出すように作っておくことが推奨されています。
project一番上のディレクトリ(package.jsonがあるディレクトリ)に.env
ファイルを作成します。
中身は
URL="<Watson AssistantのインスタンスURL>"
API_KEY="<作成したAssistantのAPIKEY>"
ASSISTANT_ID="<作成したAssistantのID>"
とします。
これらの情報は
①左上の一覧をクリック
②3点ボタンをクリック
③Settingを選択 の順で表示することができます。
ただし、Assistant URLはhttps://~ibm.comまでを使うようにしてください、これ以降を含めるとエラーになります。
/srv/index.js
を開き、import express from 'express';
の下に
require('dotenv').config();
を追記します。
Assistant API リファレンスを開きます。
Nodeタブを選択し、説明に従って
npm install ibm-watson@^6.1.2
を実行します
左の目次からSend user input to assistant(stateless)
を選びます。
(Statelessでは直前の会話を保存しません、会話の結果を利用して次のノードに移動する場合などはStatefulを利用してください)
/sendMsg
にPOSTメソッドを作成し、Example requestの内容を貼り付けます
その後
'{apikey}'
をprocess.env.API_KEY
'{url}'
をprocess.env.URL
'{assistant_id}'
をprocess.env.ASSISTANT_ID
に書き換え
input: {
'message_type': 'text',
'text': 'Hello',
}
の'text'
をreq.body.text
に変更し、
.then(res => {
console.log(JSON.stringify(res.result, null, 2));
})
部分を呼び出し元への返信に書き換えます。
.then(assistantResponse => {
res.json({
text: assistantResponse.result.output.generic[0].text
});
})
完成形は下のようになります。
app.post('/sendMsg', (req, res) =>{
const AssistantV2 = require('ibm-watson/assistant/v2');
const { IamAuthenticator } = require('ibm-watson/auth');
const assistant = new AssistantV2({
version: '2021-06-14',
authenticator: new IamAuthenticator({
apikey: process.env.API_KEY,
}),
serviceUrl: process.env.URL,
});
assistant
.messageStateless({
assistantId: process.env.ASSISTANT_ID,
input: {
'message_type': 'text',
'text': req.body.text,
}
})
.then(assistantResponse => {
res.json({
text: assistantResponse.result.output.generic[0].text
});
})
.catch(err => {
console.log(err);
});
})
CroudFoundryへのアップロード用
.cfignore
を開き、.env
を追加します。
manifest.yml
を開き、
env:
- URL: "<Watson AssistantのインスタンスURL>"
- API_KEY: "<作成したAssistantのAPIKEY>"
- ASSISTANT_ID: "<作成したAssistantのID>"
を追加します
設定は以上です。