Last updated at
info
この記事は最終更新から1年以上経っています。情報が古くなっている可能性があります。
この記事は Webpack を使って単一ファイルコンポーネント(Single File Component)の Vue アプリケーションを作るチュートリアルです。
公式の日本語ドキュメントはかなりしっかりしています。 しかし、vue-cli を使わない通常の開発フローに沿ったチュートリアルや、単一ファイルコンポーネントの使い方等、実際に使うにあたって必要な情報がかなり少ないです。 本記事ではその部分のカバーをすることを目的とします。
対象読者は
くらいの人を想定しています。
このチュートリアルでは、Vue.js を使ったカウンターアプリを作ります。
JS ファイルのビルドには Webpack を、各コンポーネントは単一ファイルコンポーネント(.vue
ファイル)を使います。
チュートリアルを通して出来上がる最終的な完成物のリポジトリを作成しているので、わからなくなったりうまく動かない場合は参照してください。
まずはじめにプロジェクトのディレクトリを作り、package.json
を作成します。(既存のディレクトリを使う場合は省略)
mkdir vue-counter-app
cd vue-counter-app
npm init # いくつか質問されるので適当に答える
次に、アプリケーションをビルドするために Webpack をインストールします。
一緒に超ベンリな開発サーバを立ててくれる webpack-dev-server もインストールします。
webpack-cli はwebpack
コマンドを使うために必要なパッケージです。
npm install --save-dev webpack webpack-cli webpack-dev-server
# 以降は下記の省略形式で記載します
# npm i -D webpack
インストールできたら Webpack の設定ファイルを作成します。
// webpack.config.js
const path = require("path");
module.exports = {
// エントリポイントのファイル
entry: "./src/index.js",
output: {
// 出力先のディレクトリ
path: path.resolve(__dirname, "./dest"),
// 出力ファイル名
filename: "bundle.js",
},
devServer: {
// webpackの扱わないファイル(HTMLや画像など)が入っているディレクトリ
contentBase: path.resolve(__dirname, "public"),
},
};
この時点で JS ファイルをコンパイルする準備ができたので、試しに簡単な JS ファイルをビルドしてみましょう。 まず適当にソースファイルを作成します。
// src/index.js
console.log("Hello, World!");
次に開発環境の起動コマンドをpackage.json
に書きます。
// package.json
{
// ...省略
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --hot" // <-- 追加
}
// ...省略
}
最後に表示する HTML ファイルを作成します。
<!-- public/index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue app</title>
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
以下のコマンドを実行してからブラウザでhttp://localhost:8080を開き、開発者ツールを開いてみましょう。
Hello, World!
という文字列が表示されていれば成功です。
npm start
確認できたら一旦Ctrl + C
で開発サーバを終了しときます。
では本題である Vue をセットアップしていきます。
まず以下のコマンドで Vue をインストールします。
npm i --save vue
また、Vue の単一ファイルコンポーネント(SFC)を扱うための Webpack のローダーをインストールします。
# 基本ローダー
npm i -D vue-loader vue-template-compiler css-loader style-loader
# JS系ローダー
npm i -D babel-loader @babel/core @babel/preset-env
インストールしたローダーを組み込んでいきます。
// webpack.config.js
// vue-loader@15から必要
const VueLoaderPlugin = require("vue-loader/lib/plugin");
module.exports = {
// ...
module: {
rules: [
{
test: /\.vue$/, // ファイルが.vueで終われば...
loader: "vue-loader", // vue-loaderを使う
},
{
test: /\.js$/,
loader: "babel-loader",
},
{
test: /\.css$/,
use: ["vue-style-loader", "css-loader"], // css-loader -> vue-style-loaderの順で通していく
},
],
},
resolve: {
// import './foo.vue' の代わりに import './foo' と書けるようになる(拡張子省略)
extensions: [".js", ".vue"],
alias: {
// vue-template-compilerに読ませてコンパイルするために必要
vue$: "vue/dist/vue.esm.js",
},
},
plugins: [VueLoaderPlugin()],
// ...
};
最後に Babel の変換設定を追加して終了です。
// package.json
{
// ...
"babel": {
"presets": ["@babel/preset-env"]
},
// メジャーな最新2バージョンで、まともに使われており、IE以外のブラウザをターゲットにする
// ここはプロジェクトに応じて適当に決めてください
// 詳細は以下を参照
// https://github.com/browserslist/browserslist
"browserslist": "last 2 versions, not dead, not ie > 0",
// ...
}
お疲れ様です、これで Vue アプリを開発する環境は整いました!
ではアプリを書いていきましょう。 まず、適当なコンポーネントを作ってみましょう。
<!-- src/components/App.vue -->
<template>
<div>
<p>Hello, World!</p>
</div>
</template>
次にsrc/index.js
を編集します。
// src/index.js
import Vue from "vue";
import App from "./components/App"; // 作ったやつ
new Vue({
el: "#app", // アプリをマウントする要素(セレクタで指定)
components: { App }, // Appというコンポーネントを使うよ、という宣言
template: "<app/>", // el(今回は#app)の中に表示する内容
});
npm start
で開発サーバを立ててhttp://localhost:8080を確認してみるといつもの文字列が表示されているはずです。
先ほどのコンポーネントにひと手間加えてみましょう。
<!-- src/components/App.vue -->
<template>
<div>
<p>Hello, World!</p>
</div>
</template>
<style>
* {
border: 1px solid red;
}
</style>
ブラウザを確認すると、沢山のボーダーが増えているかと思います。 ではこのコンポーネントで定義したスタイルをこのコンポーネントの要素のみに適用してみましょう。
- <style>
+ <style scoped>
罫線が減っていますね。これは Scoped CSS というものです。基本的にはこれを使ってスタイルを適用していくのが良いと思います。
ではカウンタの実装をしていきましょう。
<!-- src/components/Counter.vue -->
<template>
<div>
<button>-</button>
<span>0</span>
<button>+</button>
</div>
</template>
作ったらそれをアプリに追加します。今回はメインコンポーネントであるsrc/components/App.vue
に追加します。
+ <script>
+ import Counter from './Counter'
+
+ export default {
+ components: {Counter},
+ }
+ </script>
<template>
<div>
<p>Hello, World!</p>
+ <counter/>
</div>
</template>
<style lang="scss">
* {
border: 1px solid #f00;
}
</style>
追加したcomponents: {Counter}
の部分でカウンターコンポーネントを登録し、テンプレート内の<counter/>
の部分で使用しています。
この状態でブラウザを確認すると追加したコンポーネントが表示されているはずです。
それではカウンターを動くようにしましょう。
+ <script>
+ export default {
+ data() {
+ return {
+ count: 0,
+ }
+ }
+ }
+ </script>
<template>
<div>
<button>-</button>
- <span>0</span>
+ <span>{{count}}</span>
<button>+</button>
</div>
</template>
これでコンポーネントにデータを追加することができました。
Vue では HTML テンプレート内に{{value}}
で値を埋め込むことができます。
ここには Component の各プロパティをキーだけで指定することができます。
count: 0
の部分の値を変えて保存し、ブラウザを見ると表示も変わっているかと思います。
では、次にボタンを押すと値を増減できるようにしましょう。
<script>
export default {
data() {
return {
count: 0,
}
},
+ methods: {
+ increment() {
+ this.count += 1
+ },
+ decrement() {
+ this.count -= 1
+ },
+ }
}
</script>
<template>
<div>
- <button>-</button>
+ <button v-on:click="decrement">-</button>
<span>{{count}}</span>
- <button>+</button>
+ <button v-on:click="increment">+</button>
</div>
</template>
これを保存しブラウザに戻ると、ボタンを押すと値が増減するようになっているはずです。
Vue のコンポーネントのmethods
にメソッドを定義すると、<template>
内で使うことができるようになります。
<template>
側で使うにはv-on:event
属性でメソッドを指定します。onclick="increment"
みたいなものなのでわかりやすいですね。
また、イベントのバインディングには@event
という略記法があり、基本的にそちらを使うことが推奨されています。
<button @click="decrement">-</button>
<span>{{count}}</span>
<button @click="increment">+</button>
これでカウンターアプリはほぼ完成したので、あとはお好きにスタイル調整をしたりマークアップを変えてみていろいろ試してみてください。
アプリが完成して実際にデプロイしたい、と思ってもこのままだとバンドルが生成されないのでプロダクションビルド用の設定を追加していきます。
// package.json
{
// ...
"scripts": {
// ...
"build": "webpack -p"
}
// ...
}
public
ディレクトリ以下のファイルをdest
にコピーするための用意をします。
JS ファイルの分割等を行う際に便利なので、dest
に HTML や Web フォントを置かずにこちらの方法をとることをおすすめします。
npm i -D copy-webpack-plugin
// webpack.config.js
// ...
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
// ...
plugins: [
// ...
new CopyPlugin([{ from: "./public" }]),
],
// ...
};
以下のコマンドを叩くと、dest/bundle.js
が生成されます。
npm run build
webpack の-p
オプションはNODE_ENV=production
の指定とwebpack.optimize.UglifyJsPlugin
の指定をしてくれるので、基本的にこの設定だけでファイルは最小化されて出力されます。
デプロイ時にはこのdest
ディレクトリを公開します。
だいぶ長くなってしまいましたが、以上が Webpack+Vue を使ったシンプルな SPA の構築方法です。vue-cli は確かに便利ですが、こういうものを理解するのは手で書いていくのが一番なので是非公式でちゃんとチュートリアルを書いてほしいものです。