Vue.jsとVuexとwebpackでTodoListを作ってみた

# はじめに

前回の「[Vue.jsとVuexでTodoListを作ってみた](http://qiita.com/tiwu_official/items/d66c5f3fe92794536d32)」にwebpackを追加してみたのでその解説を書いていきたいと思います。

[成果物](https://theimaginationwasunbroken.com/vue-sample/src/vuex-webpack-todo-sample/src/)

機能は前回と同じく「追加」と、「完了」と、「完了から戻す」3つだけ。

Vue.jsとVuexの簡単な説明は前回のQiitaに書いたので割愛。

次の記事 [Vue.jsとVuexとwebpackで単一ファイルコンポーネント化してTodoListを作ってみた](http://qiita.com/tiwu_official/items/6a877bcdf2c3022f0ff6)

## スペック

- webpackは少しだけ使ったことある
- nodeとnpmはわりと使ったことある

# webpack

[公式](https://webpack.js.org/)

いろいろなファイルを1つにまとめるモジュールバンドラ。


今回はVue.jsとVuexと自分の記述したJSを1つのファイルに纏める用途に利用しています。

# ソースコード解説

[全体](https://github.com/tiwuofficial/vue-sample/tree/master/src/vuex-webpack-todo-sample)

今回は1つのファイルではありませんのでファイルごとに解説していきます。

## package.json

npmで作られるパッケージ管理ファイル。

インストールしたのはvue.jsとvuexとwebpack。

webpackを実行するためにscriptを書いています。

```json
{
  "name": "vuex-webpack-todo-sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vue": "^2.4.2",
    "vuex": "^2.4.0"
  },
  "devDependencies": {
    "webpack": "^3.5.6"
  }
}
```

## index.html

前回と違うのは直接書いていたJSを移し、vue.jsとvuexを読み込む代わりにbundle.jsを読み込んでいます。

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Vuex Todo Sample</title>
  <link rel="stylesheet" href="">
  <style>
    main {
      display: flex;
    }
    ul {
      list-style: none;
    }
    .wrap {
      padding: 0 10px;
    }
    [v-cloak] {
      display: none;
    }
  </style>
</head>
<body>
  <main id="app">
    <div class="wrap">
      <h2>Todo Input</h2>
      <input type="text" @keyup.enter="addTodoText"/>
    </div>
    <div class="wrap">
      <h2>Todo List</h2>
      <ul v-cloak>
        <li v-for="todo in todos">
          <p>ID : {{todo.id}}</p>
          <p>Text : {{todo.text}}</p>
          <button @click="doneTodo(todo.id)">Done</button>
        </li>
      </ul>
    </div>
    <div class="wrap">
      <h2>Done</h2>
      <ul v-cloak>
        <li v-for="done in dones">
          <p>ID : {{done.id}}</p>
          <p>Text : {{done.text}}</p>
          <button @click="resetTodo(done.id)">Reset</button>
        </li>
      </ul>
    </div>
  </main>
  <script src="js/bundle.js"></script>
</body>
</html>
```

## app.js

前回直接書いていたJSを基本的に移しただけです。
変更点は最初の3行のrequireとuseです。

```javascript
var Vue = require('vue');
var Vuex = require('vuex');
Vue.use(Vuex);

var store = new Vuex.Store({
  state: {
    todos: [],
    dones: []
  },
  actions: {
    addTodo (context, todo) {
      context.commit('ADD_TODO',todo.text);
    },
    done (context, todo) {
      context.commit('DONE_TODO',todo.id);
    },
    reset (context, todo) {
      context.commit('RESET_TODO',todo.id);
    }
  },
  mutations: {
    ADD_TODO (state, text) {
      var todo = {
        id: 0,
        text: text
      }
      if (state.todos.length !== 0) {
        todo.id = state.todos[state.todos.length -1].id + 1;
      }
      state.todos.push(todo);
    },
    DONE_TODO (state, id) {
      for (var i = 0; i < state.todos.length; i++) {
        if (state.todos[i].id === id) {
          state.dones.push(state.todos[i]);
          state.todos.splice(i, 1);
          break;
        }
      }
    },
    RESET_TODO (state, id) {
      var todo = {};
      for (var i = 0; i < state.dones.length; i++) {
        if (state.dones[i].id === id) {
          todo = state.dones[i];
          state.dones.splice(i, 1);
          break;
        }
      }
      state.todos.push(todo);
      state.todos.sort(function(a,b){
        if(a.id<b.id) return -1;
        if(a.id > b.id) return 1;
        return 0;
      })
    }
  }
});

new Vue({
  el: '#app',
  store: store,
  computed: {
    todos: function() {
      return this.$store.state.todos;
    },
    dones: function() {
      return this.$store.state.dones;
    }
  },
  methods: {
    addTodoText: function(e){
      var text = e.target.value;
      this.$store.dispatch('addTodo', {
        text: text
      });
      e.target.value = '';
    },
    doneTodo: function(id) {
      this.$store.dispatch('done', {
        id: id
      })
    },
    resetTodo: function(id) {
      this.$store.dispatch('reset', {
        id: id
      })
    },
  }
});
```

## webpack.config.js

webpackの設定ファイル。

entryでメインのJSを、outputで出力先を設定。

`require('vue');`でvue.jsを読み込むためaliasを設定。

vuexも同様に設定。

```js

module.exports = {
  entry: './src/js/app.js',
  output: {
    path: __dirname,
    filename: './src/js/bundle.js'
  },
  resolve: {
    alias: {
      vue: 'vue/dist/vue.js',
      vuex: 'vuex/dist/vuex.js',
    }
  }
};
```

# ビルド

`npm run dev`でbundle.jsを生成する。

# 所感

ファイルを分割できた。

と言いたいところだけどwebpack使わなくてもファイル分割はできる・・・。

今回webpackいれたのは、Vueのコンポーネントを利用したかったので入れてみました。

次回はVueコンポーネントを作ってみる。