vuejsプロジェクト雛形を楽に作りたい
2日経つと前に何作ってたか忘れてまた最初からやりたくなる病。
そのために作り始めを早めるメモ
主に組み込むものとバージョン
- node(v5.4.0)
- npm(3.5.3)
- vue(^1.0.14)
- vuex(^0.2.0)
- es6
- mocha(2.3.4)
- power-assert(1.2.0)
手順概要
- ディレクトリ用意
- いろいろインストール
- 環境に必要なもの用意
- 小さいvuexサンプル
- 最小テスト
手順詳細
ディレクトリ用意
# ディレクトリ作成
mkdir プロジェクトのフォルダ
cd プロジェクトのフォルダ
mkdir -p {build,test/{unit,e2e},src/{components,views/app,filters,directives,assets/{js,style,images}}}
いろいろインストール
npm init --y
npm i -g webpack webpack-dev-server mocha babel-core babel-loader power-assert
npm i -S vue vuex
npm i -D babel-core babel-loader webpack style-loader css-loader sass-loader html-loader mocha mocha-loader babel-plugin-add-module-exports babel-plugin-transform-runtime babel-polyfill babel-preset-es2015 babel-preset-stage-2 babel-runtime file-loader url-loader espower-babel power-assert
環境に必要なもの用意
.babelrc
{
"presets": ["es2015", "stage-2"]
}
webpack.config.js
module.exports = {
entry: {
app: "./src/assets/js/app.js"
},
output: {
path: './build/js',
publicPath: '/js/',
filename: "[name].js"
},
resolve: {
alias: {
vue: "vue/dist/vue"
},
modulesDirectories: ['node_modules', 'src/', 'src/assets/js/**', 'src/assets/style/**', 'src/views/**', 'src/directives/**', 'src/filters/**', 'src/components/**'],
// require()するときに拡張子を省略可能にします
extensions: ['', '.webpack.js', '.web.js', '.js']
},
devServer: {
contentBase: "./build",
},
module: {
preloaders: [],
loaders: [
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "url-loader?limit=10000&minetype=application/font-woff"
},
{
test: /\.png$/,
loader: "url-loader?limit=100000"
},
{
test: /\.jpg$/,
loader: "file-loader"
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader"
},
{
test: /\.scss$/,
loader: "style!css!sass"
},
{
test: /\.html$/,
loader: "html"
},
{
test: /\.js(x?)$/,
loader: 'babel-loader?sourceMaps=true'
}
]
}
};
package.jsonのscriptsの中身を書き換え
"scripts": {
"hot": "webpack-dev-server -d --inline",
"test": "mocha --compilers js:espower-babel/guess test/unit",
"e2e": "mocha --compilers js:espower-babel/guess test/e2e"
},
上から、
npm run hot
でデバッグ用のサーバ起動するためのもの
npm test
でtest/unit配下に格納したテストを実行するもの
npm run e2e
でe2eテストに格納したテストが動くはず(今回はやらない)
小さいvuexサンプル
前段その1サーバ起動確認
build/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>sample</title>
</head>
<body>
<div id="app">this is app</div>
<script type="text/javascript" src="js/app.js" charset="utf-8"></script>
</body>
</html>
src/assets/js/app.js
console.log('hoge');
ここでコンソール上でnpm run hot
を実行して下記URLで"this is app"、デバッグコンソールに"hoge"と表示されればここまでOK
前段その2小さいvueコンポーネント
build/index.html書き換え
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>sample</title>
</head>
<body>
<app></app>
<script type="text/javascript" src="js/app.js" charset="utf-8"></script>
</body>
</html>
src/assets/js/app.js書き換え
import Vue from 'vue'
import App from '../../views/app'
new Vue({
el: 'body',
components: { App }
});
src/views/app/index.js
export default {
template: require('./template.html')
}
src/views/app/template.html
<div>this is app view</div>
http://localhost:8080/
にthis is app viewと表示されていればOK
小さいvuexサンプル(vuexさん公式のcounterサンプルを丸パクリします)
src/views/app/index.js書き換え
import Counter from '../../components/counter'
export default {
template: require('./template.html'),
components: {
"counter": Counter
}
}
src/views/app/template.html書き換え
<counter></counter>
src/components/counter/index.js
import store from '../../assets/js/store'
export default {
template: require('./template.html'),
computed: {
count () {
return store.state.count
}
},
methods: store.actions
}
src/components/counter/template.html
<div>
Clicked: {{ count }} times
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">Increment if odd</button>
<button @click="incrementAsync">Increment async</button>
</div>
src/assets/js/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
// mutation types
// optional if you don't like constants.
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
// root state object.
// each Vuex instance is just a single state tree.
const state = {
count: 0
};
// actions are what components will be able to
// call as store.actions.xxx
// note these are not the final functions the
// components will be calling.
const actions = {
// for simple actions that just dispatches a single mutation,
// we can just provide the mutation type.
increment: INCREMENT,
decrement: DECREMENT,
// for a normal action function, it always recieves the store
// instance as the first argument, from which we can get the
// dispatch function and the state object. Any additional
// arguments will follow the store argument.
incrementIfOdd: ({ dispatch, state }) => {
if ((state.count + 1) % 2 === 0) {
dispatch(INCREMENT)
}
},
// Same thing for async actions.
incrementAsync: ({ dispatch }) => {
setTimeout(() => {
dispatch(INCREMENT)
}, 1000)
}
};
// mutations are operations that actually mutates the state.
// each mutation handler gets the entire state tree as the
// first argument, followed by additional payload arguments.
// mutations must be synchronous and can be recorded by middlewares
// for debugging purposes.
const mutations = {
[INCREMENT] (state) {
state.count++
},
[DECREMENT] (state) {
state.count--
}
};
// A Vuex instance is created by combining the state, the actions,
// and the mutations. Because the actions and mutations are just
// functions that do not depend on the instance itself, they can
// be easily tested or even hot-reloaded (see counter-hot example).
//
// You can also provide middlewares, which is just an array of
// objects containing some hooks to be called at initialization
// and after each mutation.
export default new Vuex.Store({
state,
actions,
mutations
})
http://localhost:8080/
にカウンターが表示されていればOK
最小テスト
test/unit/store-test.js
import assert from 'power-assert';
import store from '../../src/assets/js/store'
describe('storeのテスト', () => {
it('mutationsのincrement処理を実行するとstateのcountが増える', () => {
let before = store.state.count;
store.actions.increment();
let after = store.state.count;
assert(before < after);
});
it('mutationsのdecrement処理を実行するとstateのcountが減る', () => {
let before = store.state.count;
store.actions.decrement();
let after = store.state.count;
assert(before > after);
});
});
npm test
で実行して結果が表示されればOK
assert(before === after)
などに書き換えてエラーを出してみるのもよいかも