はじめに
Webpack を使ったフロントエンド開発では、Webpack dev server を使うと、ファイルの変更をチェックして自動的にビルド・ブラウザのリロードをやってくれます。このとき、サーバ側に REST API の機能を持たせたい…ということがあります。
それを Vue-CLI3 ベースのプロジェクトでやる方法について紹介します。
使う道具
Ubuntu 18.04 でやっています。
hagiwara@dev01:~/tmp$ nodejs --version
v8.10.0
hagiwara@dev01:~/tmp$ npm --version
6.6.0
hagiwara@dev01:~/tmp$ vue --version
3.3.0
hagiwara@dev01:~/tmp$
Vue-CLI3 ベースのプロジェクトを用意する
とりあえずサンプルのプロジェクトをサクッと立てます。
hagiwara@dev01:~/tmp$ vue create foobar
Vue CLI v3.3.0
? Please pick a preset: default (babel, eslint)
Vue CLI v3.3.0
✨ Creating project in /home/hagiwara/tmp/foobar.
🗃 Initializing git repository...
⚙ Installing CLI plugins. This might take a while...
(省略)
🎉 Successfully created project foobar.
👉 Get started with the following commands:
$ cd foobar
$ npm run serve
hagiwara@dev01:~/tmp$
ひとまず dev server 起動してみましょう。
hagiwara@dev01:~/tmp/foobar$ npm run serve
> foobar@0.1.0 serve /home/hagiwara/tmp/foobar
> vue-cli-service serve
DONE Compiled successfully in 4841ms
App running at:
- Local: http://localhost:8080/
- Network: http://10.0.2.15:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
localhost:8080
にアクセスするとこんな感じで動きます。
vue-cli-plugin-express で API Server を作る
vue-cli-plugin-express - npm を使います。
インストール
hagiwara@dev01:~/tmp$ cd foobar/
hagiwara@dev01:~/tmp/foobar$ vue add express
📦 Installing vue-cli-plugin-express...
(省略)
✔ Successfully installed plugin: vue-cli-plugin-express
? Should serve vue app? Yes
? Where will be located your server? ./srv
🚀 Invoking generator for vue-cli-plugin-express...
✔ Successfully invoked generator for plugin: vue-cli-plugin-express
The following files have been updated / added:
srv/index.js
vue.config.js
package.json
You should review these changes with git diff and commit them.
hagiwara@dev01:~/tmp/foobar$
途中の質問についてはデフォルト回答ですが、"Should serve vue app?" は yes にしてください。この後出てくる "Fallback" 動作に関する設定です。インストールすると、表示があるとおり、いくつかファイルが変更・追加されてます。
設定
デフォルト設定で動かしましょう。追加された srv/index.js
に express server のコードがコメントアウトされた状態で貼っているので、とりあえず GET api のみ使えるようにします。
import express from 'express';
export default app => {
app.use(express.json());
app.get('/foo', (req, res) => {
res.json({msg: 'foo'});
});
}
API Server を動かす
hagiwara@dev01:~/tmp/foobar$ npm run express
DONE Mon Jan 28 2019 17:37:14 GMT+0900 (JST)
♻️ Server running at:
- Local: http://localhost:3000/
- Network: http://10.0.2.15:3000/
⚙ You're in development mode. to start the application, run yarn serve.
🎉 Fallback to this server enabled: you can use relative routes in your code!
🔀 api routes found:
- /foo: GET
localhost:3000/foo
をたたいてみましょう。
ちゃんと JSON データが返ってきてますね。
アプリ (Frontend) からAPIを使う
ここまでだとだからどうしたって話なんですよね。まだアプリはアプリ、API Server は API Server で個別に動いているだけです。
アプリ側サーバ起動
npm run express
して API Server を起動している状態で、npm run serve
してアプリ用の dev server も起動しましょう。このとき dev server 側で
INFO Starting development server...
DONE Express server Fallback will be done on your server. You can use relative calls to it in your code.
というメッセージが出ているのを確認しておいてください。このあと "Fallback" ってなんのこっちゃ、という話をします。
アプリから REST API をたたく
API /foo
をたたいたとき返っている msg
の値をサンプルアプリ側で表示してみます。
まず API Server 側で適当なメッセージを返すように変更。
import express from 'express';
export default app => {
app.use(express.json());
app.get('/foo', (req, res) => {
res.json({msg: 'Welcome to Your Vue.js App FROM API SERVER'});
});
}
アプリ側は /foo
をたたいて取得した JSON を元にメッセージを設定します。
hagiwara@dev01:~/tmp/foobar$ git diff src/App.vue
diff --git a/src/App.vue b/src/App.vue
index fcc5662..2d6dac4 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,7 +1,7 @@
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
- <HelloWorld msg="Welcome to Your Vue.js App"/>
+ <HelloWorld v-bind:msg="message"/>
</div>
</template>
@@ -12,6 +12,18 @@ export default {
name: 'app',
components: {
HelloWorld
+ },
+ computed: {
+ message () {
+ const req = new XMLHttpRequest
+ let message = ''
+ req.open('GET', '/foo', false)
+ req.onload = function () {
+ message = JSON.parse(req.responseText).msg
+ }
+ req.send(null)
+ return message
+ }
}
}
</script>
hagiwara@dev01:~/tmp/foobar$
HelloWorld
というコンポーネントに msg
で渡した文字列が表示されるので、そこを computed (算出プロパティ) の message
で置き換えます。で、message
の中身は単純に /foo
をたたく→ JSON をパース → msg
の値を取り出し、というだけ。(エラーチェックも何もない雑な処理ですがまあサンプルなので。)
アプリはこうなります。ちゃんと /foo
を GET して取得してきた値で更新できています。
これをやってみると、以下の点気づくかと思います。
- App.vue を編集するとアプリが自動的にリビルドされてブラウザ上でリロードされる。
- これはもともと使ってる dev server の動作
- index.js を編集すると API サーバ側がリロードされる。
- express plugin もサーバ側ソースコードの更新を watch してリロードしてくれます。
- アプリ側 dev server は tcp/8080, API server は tcp/3000 で起動しているのに、アプリ側コードではそれらの違いを気にしなくても動いている。
- ここが "Fallback" といってる動作ですね。
express-plugin の中身の動作まで細かく追いかけてるわけではないのですが、簡単な動作確認ができます。API server, Dev server の両方が動いている状態で、API サーバだけ落としてみましょう。その上でアプリ側を更新 (ブラウザ F5) すると、こういうエラーが出ます。
Proxy error: Could not proxy request /foo from localhost:8080 to http://0.0.0.0:3000/.
……ということで、内部的に Proxy してくれてるみたいですね。
Mode (develop/production) の設定
上記の話は development mode での利用方法でした。Production では下記のようにします。
まず npm run build
してパッケージングする (dist
ディレクトリができます)。
hagiwara@dev01:~/tmp/foobar$ npm run build
(省略)
hagiwara@dev01:~/tmp/foobar$ ls dist
css favicon.ico img index.html js
hagiwara@dev01:~/tmp/foobar$
この状態で npm run express:run
を実行する。
hagiwara@dev01:~/tmp/foobar$ npm run express:run
> foobar@0.1.0 express:run /home/hagiwara/tmp/foobar
> vue-cli-service express:run
DONE Mon Jan 28 2019 18:42:00 GMT+0900 (JST)
♻️ Server running at:
- Local: http://localhost:3000/
- Network: http://10.0.2.15:3000/
📦 You're in production mode. To build the application, run yarn build.
🎉 Fallback to the app enabled: your application is served!
🔀 api routes found:
- /foo: GET
これで localhost:3000
にアクセスするとアプリが動きます。(express plugin でアプリケーションを含めて起動している)
まとめ
vue-cli-plugin-express を使うと API サーバを含むフロントエンド開発がお手軽にやれるようになります。
- アプリ側は API Server の URL をいちいち気にしなくてよい
- サーバ側は API の定義だけ書けばよい
- development の場合
- API, App (dev server) をそれぞれ起動する
-
npm run express
: API server (default, tcp/3000) -
npm run serve
: App dev server (default, tcp/8080)
- production の場合
-
npm run build
でビルド (packing) -
npm run serve
で App/API server を起動 (default, tcp/3000)
-
おまけ
for Heroku
ここまでできていればあとは Node/Express なアプリをデプロイするのと同じなのでそれほど困らないはず。
- デフォルトでは vue-cli が生成した .gitignore に dist ディレクトリが入っているので注意
- サーバのポート番号設定を Heroku にあわせる
const port = process.env.PORT || 3000
app.set('port', port)
-
heroku config:set NPM_CONFIG_PRODUCTION=false
しておく。- Node.js now installs
devDependencies
by default ということなので特にいじってなければ問題ないです。package.json 見ればわかるんですが、npm run express
は中でvue-cli-server
を呼んでいます。で、このパッケージ類がdevDependencies
になってるんですよね。この辺いじると後々面倒だろうから素直にdevDependencies
含めて全部パッケージ入れましょう。
- Node.js now installs
vue-cli-plugin-express 以外の方法
vue-cli-plugin-express を使わない場合どうするか、というと…… Dev server 自体が express middleware になっているので、ソレを組み込んだサーバスクリプトを書き始めることになると思います。下記参照…。見ればわかるんですが、まあそれなりに面倒なので。express 周りに詳しい人はいろいろやれて良いのかもしれないけど。