はじめに
必要があってWebアプリ開発の領域を少し調べてみたのだが、またしばらくWebアプリを作ることはなさそうなので、備忘録的に開発方法をまとめてみた。
ここではデモ用のアプリとして、unsplashの写真を一覧表示するWebアプリを作成する。また、フロントエンドCSSライブラリ(UIのデザイン)としてBootstrapを用いる。
WebアプリやWebのフロントエンド開発者にはHTML5+CSS+Javascriptで開発が一般的である。最近のフロントエンド開発においては次のような3つのメジャーフレームワークとモバイルアプリ開発環境があり、それぞれWebアプリと同様の開発方法でスマホアプリを作ることが可能となっている。
| フレームワーク | モバイル開発環境 |
|---|---|
| React (by Facebook) | React Native |
| Angular (by Google) | NativeScript or Ionic + Cordova |
| Vue.js | Weex or Cordova |
ここではVue.jsをつかったWebアプリ開発についてまとめる。
1. 開発環境
- macOS High Sierra ver.10.13.6
- node.js: ver.10.15.1
- npm: ver.6.8.0
- vue.js (vue cli): ver.3.4.0
- bootstrap-vue: @2.0.0-rc.14
- Visual Studio Code: ver.1.32.2
- Google Chrome: ver.72.0.3626.121
2. 環境構築
2-1. node.js (npm) のインストール
- Homebrewをセットアップ
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"- brewでnodeをインストール
brew install nodebrewnodebrew install-binary latestnodebrew use v10.15.1- npmはnode.jsをインストールすると同時にセットアップされる。
2-2. yarnのインストール
- npmからyarnに徐々にトレンドが移っている様子
brew install yarn
2-3. vueのインストール
-
npm install -g @vue/cliもしくはyarn global add @vue/cli
3. プロジェクト("my-project")作成
3-1. vue create
-
vue create my-projectもしくはvue uiでGUI付きセットアップ - Preset選択では
default (babel, eslint)を選ぶ(そのままリターンすれば良い) cd my-project- 特に断りがないときはこのルートフォルダでnpmやyarnなどのコマンドを叩く。
3-2. フォルダ構成
初期化直後の状態。
Webアプリ開発では主にsrcフォルダとpublicフォルダの中身を変更する。
.
├── .gitignore
├── README.md
├── babel.config.js
├── node_modules
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├─- App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ └── main.js
└── yarn.lock
4. デバッグ方法
4-1. ビルド
-
yarn serveでWebサーバが起動してブラウザで表示できるようになる。 - 表示されているURL(例えば、http://localhost:8080/ )にChromeでアクセスする
こんな画面が表示されていたらひとまず、OK
4-2. デバッグ
ChromeとVS Codeを使ったデバッグについては公式ページ(VS Code によるデバッグ)をみると良い。ブレークポイントを張りながらデバッグできるので便利。
4-2-1. Chromeを用いたデバッグ
- Chromeのデベロッパツールを開く(Windows: F12キー、macOS: option+command+"i")
- Vue.js devtoolsというChrome機能拡張をインストールすると、デベロッパツールの上にあるタブに"vue"という項目が追加され、vue毎のプロパティをライブ編集できるようになる。
- Vue.js devtoolsを使うときは、以下の設定ファイル(vue.config.js)をルートフォルダに追加する。
- デバッグ時は
yarn serveしてから、VS Codeでブレークポイントを張るなどしてデバッグを開始、URLを入れてChromeで表示する。
module.exports = {
configureWebpack: {
devtool: 'source-map'
}
}
4-2-2. vueの設定
vue cli ver.3からvueの設定ファイルは自動生成されなくなった。設定する場合は自分でルートフォルダにvue.config.jsファイルを作成し、定義を参考に設定を記載する。webpack関連はvue.config.jsファイル内にconfigureWebpackオプションを記載して設定できるが、outputDirなどvueの設定として定義されているものがある場合は、configureWebpackオプションを使わず、vueの設定を利用しなければならない。
5. 開発
ここではunsplashの写真を一覧表示するページを作る。APIとしてはpicsumのものを用いる。
5-1. bootstrap-vueとaxiosのセットアップ
UIデザインにはbootstrap-vueを利用する。また、HTTPの通信にはaxiosを利用する。(昔はvue-resourceが使われていたらしい。)
以下のようにしてプロジェクトのnode_modulesにインストールする
npm install --save bootstrap
npm install --save bootstrap-vue
npm install --save axios
yarnでやる場合には、yarn add ~ という形式で進めること
5-2. コード変更
- ここで利用したソースコードはgithub にある。
- 変更はmain.jsとHelloWorld.vueの2ファイルのみ。
- (1) main.js
- Bootstrap Vueを使うため、src/main.jsを以下のように書き換えた
- ※↑BootStrap-Wikipedia → 公式ドキュメント
import Vue from 'vue'
import App from './App.vue'
import BootstrapVue from "bootstrap-vue"
Vue.use( BootstrapVue )
import 'bootstrap/dist/css/bootstrap.css'
import "bootstrap-vue/dist/bootstrap-vue.css"
Vue.config.productionTip = false
new Vue( {
render: h => h( App ),
} ).$mount( '#app' )
- (2) HelloWorld.vue
- src/components/HelloWorld.vueを以下のように書き換えた。
<template>
<div class="hello">
<!-- (a) -->
<h1>{{ msg }}</h1>
<div class="row">
<!-- (b) -->
<div
class="col-sm-6 col-md-3 col-xl-2"
v-for="(result, idx) in processedResults"
:key="result.id"
>
<!-- (c) -->
<a class="card" :href="result.post_url">
<!-- (d) -->
<h5 class="card-title">{{idx}}:{{result.author}}</h5>
<!-- (e) -->
<img class="card-img" :src="result.url" :alt="result.post_url">
<p class="card-text">{{result.filename}}.</p>
</a>
</div>
</div>
</div>
</template>
<script>
const axios = require("axios");
export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
info: null,
results: []
};
},
// (f)
mounted: function() {
{
axios
.get("https://api.coindesk.com/v1/bpi/currentprice.json")
.then(response => (this.info = response.data.bpi));
axios
.get("https://picsum.photos/list")
.then(response => (this.results = response.data));
}
},
computed: {
// (g)
processedResults: function() {
let results = this.results;
for (let i = 0; i < results.length; i++) {
results[i].url = "https://picsum.photos/300/200?image=" + results[i].id;
}
return results;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
a {
color: #42b983;
}
</style>
-
(a)
{{ msg }}部分はpropsのパラメータとなっており、親側(/src/App.vue)から設定される。App.vueをみると、<HelloWorld msg="Welcome to Your Vue.js App"/>のようにしてmsgに文字列が設定されている。 -
(b-1)
class="col-sm-6 col-md-3 col-xl-2"部分はbootstrap-vueのLayout and Grid Systemを利用し、画面の横幅を12等分したうち、どのような割合でグリッドに分割するかを示している。col-sm-6は画面の幅がSmall(≥576px)の時、6/12=1/2のところでグリッド分割することを示している。つまり、一行には横並びに2つの画像が表示されるようになる。ここでは、"col-sm-6 col-md-3 col-xl-2"のように3つの指定がある。これは画面幅がSmall(sm≥576px)の時に2つ(6/12ずつ)、Medium(md≥576px)の時に4つ(3/12ずつ)、Extra large(xl≥576px)の時に6つ(2/12ずつ)、画像が表示されることを示している。Smallより小さいとき(<576px)は1つ(12/12)の画像が表示される。bootstrap-vueのグリッドオプションによれば、 -
Extra small (xs) <576px
-
Small (sm) ≥576px
-
Medium (md) ≥768px
-
Large (lg) ≥992px
-
Extra large (xl) ≥1200px
のように定義されている。 -
(b-2)
v-for="(result, idx) in processedResults"部分は、v-forによってprocessedResultsという配列(実際には算出プロパティ(g))を一つ一つ処理することを示している。個々の要素は第一引数であるresultで受け取れる。第二引数(idx)は配列のインデックス。:key="result.id"とすることで、第一引数resultにあるidをv-forで必要となるkeyとして設定している。keyではなく:keyとすることで"result.id"が文字列ではなくパラメータとして扱われる。ここでresultは以下のようなデータを持つ。このことは、実際に通信を行うことで確認できる。上述のVue.js devtoolsを使ってChromeの開発者モードを使っても見ることができる。
{
"format":"jpeg",
"width":5616,
"height":3744,
"filename":"0000_xxxx.jpeg",
"id":0,
"author":"xxxxxxxx",
"author_url":"https://unsplash.com/@xxxxx",
"post_url":"https://unsplash.com/photos/xxxxx",
"url":"https://picsum.photos/300/200?image=0"
}
- (c)
<a class="card" :href="result.post_url">部分ではbootstrap-vueのcardを利用した。カードをクリックした際のURLを:hrefとして設定した。hrefでなく:hrefなのは上述の通り、"result.post_url"をパラメータとして利用するため。 - (d)
<h5 class="card-title">{{idx}}:{{result.author}}</h5>部分では、カードのタイトルとして"0:xxxxxxxx"のような物を設定している。{{と}}で囲むことでパラメータを展開して利用する。 - (e)
<img class="card-img" :src="result.url" :alt="result.post_url">部分では"result.url"のURLにある画像を表示する。` - (f)
mounted: function()はvueのライフサイクルでページが表示される直前に呼び出される関数である。ここでは、mountedの中で、https://picsum.photos/listにアクセスし、resultsパラメータに応答を記録している。.thenで繋げているのは非同期で結果が返ることを示唆している。 - (g) 前述の(b)で配列として説明した
processedResultsはcomputed:で定義された算出プロパティとなっている。内部でthis.resultsを利用しているため、(f)の結果が返り、this.resultsが更新されると、processedResultsが呼び出される。そして、(b)のv-for部分が更新され、画像のリストが表示される。
5-3. 動作結果
ブラウザで見ると以下のように表示される。左側にVueの表示、右側がChromeのディベロッパツールを表示させている。

5-4. gitでcloneした場合のセットアップ
-
npm installもしくはyarn installでnode_modulesをセットアップする。
6. デプロイ方法
-
yarn buildすると、デプロイ用のdistフォルダが生成される。
7. まとめ
vue cli3 を使った例として、セットアップからデバッグまでを説明し、画像をリスト表示させるWebアプリを作成した。
