GulpではじめるVue.js（最小構成）

いろいろと話しを聞いてVue.jsも触ってみようかなと思って試して見ました。`vue-cli`からプロジェクト生成して触ってみましたがもう少しやってみたいなと思い今回はGulpでのコンパイルをやってみました。

## 準備

### インストール

まずは必要なパッケージをインストールしていきます。

```bash
# Yarnの初期化
$ yarn init -y
# Gulpのインストール
$ yarn add -D gulp
# jsのトランスパイル環境
$ yarn add -D browserify vueify babelify babel-preset-es2015 babel-plugin-transform-runtime vinyl-source-stream vinyl-buffer
# Vue.js
$ yarn add vue
```

`browserify``babelify``babel-preset-es2015``vinyl-source-stream``vinyl-buffer`はReactやES6を書くときと同じです。
Vue.jsを使うにあたって必要となるライブラリは`vueify``babel-plugin-transform-runtime`です。
`vuefity`はGulpでトランスパイルするときに必要なものでWebpackでいくと`vue-loader`がそれに該当するようになると思います。
`babel-plugin-transform-runtime`はpolyfill対象にES6を変換します。
この`vueify`と`babel-plugin-transform-runtime`を使用することでvueファイルを作成してそのなかでコードを書くことができるようになります。

### Gulp

Reactで使用しているものを流用して下のような形にしてみました。

```js:gulpfile.js
const gulp = require('gulp');
const path = require('path');

const browserify = require('browserify');
const vueify = require('vueify');
const babelify = require('babelify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');

const jsEntities = {
	src: './js/',
	dest: '../js/',
	files: [
		'app.js'
	]
};

gulp.task('vue', () => {
	jsEntities.files.forEach(entry => {
		browserify(path.join(jsEntities.src, entry), {
			debug: true,
			extensions: ['.js', '.vue'],
			transform: [
				vueify,
				babelify.configure({ 'presets': ['es2015'] })
			]
		})
		.bundle()
		.on('error', err => {
			console.log(err.message);
			console.log(err.stack);
		})
		.pipe(source(entry))
		.pipe(buffer())
		.pipe(gulp.dest(jsEntities.dest));
	});
});

gulp.task('default', () => {
	gulp.watch(path.join(jsEntities.src, '**/*.*'), ['vue']);
});
```

それほど大きく変わってる箇所はありませんが`transform`に`vueify`を追加しています。
`.babelrc`を作るか`package.json`に記述する方法が多くみられましたが個人的に分散させるのが苦手なのでgulpfileの中に記述しています。

## プロジェクトの作成

フォルダ構成は好きなかんじで良いと思いますが今回試したのはこんなかんじです。

```bash
── asset
│   ├── gulpfile.js
│   ├── js
│   │   ├── app.js
│   │   └── components
│   │       └── App.vue
│   ├── node_modules
│   ├── package.json
│   └── yarn.lock
├── index.html
└── js
```

assetフォルダ内にgulpfile.jsやvueファイルをまとめています。

まずはコンポーネントを作成します。

```html:asset/js/components/App.vue
<template>
	<div class="container">
		<h1>{{ message }}</h1>
	</div>
</template>

<script>
export default {
	data() {
		return {
			message: 'Hello, World!'
		}
	}
}
</script>
```

Riot.jsを使ったことがある方はすんなり受け入れることができるのではないかと思います。
このあたりは`vueify`を入れているのでテンプレートファイルを別で管理することができるようになります。

```js:asset/js/app.js
import Vue from 'vue';
import App from './components/App';

new Vue({
	el: '#app',
	render: h => h(App)
});
```

最初に作成した`App.vue`を読み込んでVueのインスタンスを生成しています。
まだまだVue.js自体がよくわかっていないせいもあり最初は下のように書いて実行時エラーが発生しました。

```js
import Vue from 'vue';
import App from './components/App';

new Vue({
	el: '#app',
	components: { App }
});
```

gulpではエラーが出ず一見いけた？と思いましたがいざブラウザでみるとエラーが表示されてしまいました。

>[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build. 
(found in <Root>)

Vue.jsのビルドではランタイム+コンパイラとコンパイラ限定があるようでコンパイラ限定で記述する場合は`components`ではなく`render`を使うようになります。
（まだまだ理解ができておらず間違っているといやなので詳しくはマニュアルを参照してください）
[インストール - Vue.js](https://jp.vuejs.org/v2/guide/installation.html#ランタイム-コンパイラとランタイム限定の違い)

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Vue Sample</title>
</head>
<body>
	<div id="app"></div>
	<script src="./js/app.js"></script>
</body>
</html>
```

HTMLはこんなかんじで出力用のdivなりを用意してビルド後のjsを参照するにします。

## ビルド

Gulpでやっているので`yarn gulp vue`としてやるとビルドが完了します。
あとは環境に合わせてURLを叩いてやると無事にHello, World!が表示されます。

## 感想

まだまだVue.jsをつかめていませんので深くは語ることはできませんがここまではわりとすんなりいけた感はあります。
ぼちぼちとこれにajaxや[Vuex](http://vuex.vuejs.org/ja/)、[element](http://element.eleme.io/)を使っていろいろとやってみようかなと。