ソース:nobiki/vue-test

RailsのTurbolinksを使いたくなかったのでフロントエンドで完結出来るようにvueやvue-routerなどを使ってみた

環境

  • anyenv
  • ndenv
  • webpack
  • bulma (こちらのテンプレートを借りてます)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ndenv version
v8.1.0 (set by /workspace/vue-test/.node-version)

$ npm ls --depth=0
/workspace/vue-test
├── css-loader@0.28.9
├── extract-text-webpack-plugin@3.0.2
├── style-loader@0.20.1
├── vue@2.5.13
├── vue-loader@14.1.1
├── vue-router@3.0.1
├── vue-template-compiler@2.5.13
├── vuex@3.0.1
└── webpack@3.10.0

Webpackに関して:WebpackでcssとjsをBundleしたメモ

サイトマップ

トップページに3つリンクがあるだけの、とりあえずシンプルなやつです

1
2
3
4
トップ
├── ページ1
├── ページ2
└── ページ3

Webpack: 設定とファイルツリー

rulesに、vue-loaderの設定を追加resolve.aliasに、vue,vuex,vue-routerの設定を追加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ cat /workspace/vue-test/webpack.config.js

var ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: {
"common": path.join(__dirname, "./webpack/common/entry.js"),
"app/top": path.join(__dirname, "./webpack/app/top/entry.js"),
},
output: {
filename: "./public/assets/[name]/bundle.js"
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({fallback:'style-loader',use:'css-loader'})
},
{
test: /\.(jpg|gif|png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
},
]
},
resolve: {
alias: {
'vue': 'vue/dist/vue.esm.js',
'vuex': 'vuex/dist/vuex.esm.js',
'vue-router': 'vue-router/dist/vue-router.esm.js'
}
},
plugins: [
new ExtractTextPlugin("./public/assets/[name]/bundle.css")
]
};

webpack関係の物は「webpack」ディレクトリに入ってます

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ tree /workspace/vue-test/webpack/

/workspace/vue-test/webpack/
├── app
│   └── top
│   ├── components
│   │   ├── index.vue
│   │   ├── linkA.vue
│   │   ├── linkB.vue
│   │   └── linkC.vue
│   ├── css
│   │   └── top.css
│   ├── entry.js
│   ├── js
│   │   └── top.js
│   ├── router
│   │   └── routes.js
│   └── view
│   ├── indexView.vue
│   ├── linkAView.vue
│   ├── linkBView.vue
│   └── linkCView.vue
└── common // →「common」ディレクトリ内はbulma関係のファイルなのでVueとは無関係

Vue: Router

URLとViewを紐づけるやつ

1
2
3
4
5
6
7
8
9
10
11
12
$ cat /workspace/vue-test/webpack/app/top/router/routes.js
import indexView from './../view/indexView.vue';
import linkAView from './../view/linkAView.vue';
import linkBView from './../view/linkBView.vue';
import linkCView from './../view/linkCView.vue';

export default [
{ path: '/', component: indexView },
{ path: '/linkA', component: linkAView },
{ path: '/linkB', component: linkBView },
{ path: '/linkC', component: linkCView },
];

Vue: View

h2タグが1つあるだけのシンプルなやつです

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ cat /workspace/vue-test/webpack/app/top/view/linkAView.vue

<template>
<div class="wrap linkA">
<h2>linkA</h2>
</div>
</template>

<style scoped>
.wrap {
padding: 0 10px;
}
</style>

<script>
import linkA from './../components/linkA.vue';
export default {
components: {
linkA
},
}
</script>

Vue: Component

今回は画面遷移を確認するだけなので内容は何も無いよう

1
2
3
4
5
6
7
8
9
$ cat /workspace/vue-test/webpack/app/top/view/linkAView.vue
<template>
<div>
</div>
</template>

<script>
export default { methods: {} }
</script>

Vue: top.js

elの行で、*[data-route]を指定したら一括でrouter設定できるかなと思ってやってみたけどダメだったので3つ書いてるけどほかによい方法があるかもしれない(今回はなるべく掘り下げずシンプルに)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import Vue from 'vue';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
import routes from '../router/routes.js';

Vue.use(Vuex);
Vue.use(VueRouter);

const router = new VueRouter({
routes
});

new Vue({
el: "*[data-route='contents']",
router: router,
});

new Vue({
el: "*[data-route='topNav']",
router: router,
});

new Vue({
el: "*[data-route='footNav']",
router: router,
});

Webpack: bundle

1
$ ./node_modules/.bin/webpack -p

HTML: index.html

長いので必要な部分だけ抜粋してます

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="ja">
<head>
<link rel="stylesheet" type="text/css" href="/assets/common/bundle.css">
<link rel="stylesheet" type="text/css" href="/assets/app/top/bundle.css">
</head>
<body>
<nav class="navbar is-white topNav">
<div class="container">
<div class="navbar-menu" data-route="topNav">
<div class="navbar-start">
<router-link class="navbar-item" to="/">トップ</router-link>
<router-link class="navbar-item" to="/linkA">リンクA</router-link>
<router-link class="navbar-item" to="/linkB">リンクB</router-link>
<router-link class="navbar-item" to="/linkC">リンクC</router-link>
</div>
</div>
</div>
</nav>
<section class="container">
<div class="columns">
<div class="column is-10">
<div id="contents" class="box tile content" data-route="contents">
<router-view></router-view>
</div>
</div>
</div>
</section>
<footer class="footer">
<div class="container">
<hr>
<div class="content has-text-centered" data-route="footNav">
<p>
<router-link to="/">トップ</router-link> |
<router-link to="/linkA">リンクA</router-link> |
<router-link to="/linkB">リンクB</router-link> |
<router-link to="/linkC">リンクC</router-link>
</p>
</div>
</div>
</footer>
<script async type="text/javascript" src="/assets/common/bundle.js"></script>
<script async type="text/javascript" src="/assets/app/top/bundle.js"></script>
</body>
</html>

<router-link to="[リンク先]>は、DOMがロードされた時にはaタグになります

<router-view>に、リンク先の内容が出力されます