vue-cliすればvue.jsの開発をすぐに始めることができますが、webpackを使ってvue.jsの拡張子がvueのSingle File Component(シングルファイルコンポーネント)を使ってアプリケーションを作成したいといった場合どういう手順かわからない人も多いかと思います。本文書ではwebpackのインストールからSFCを使えるまでの手順をStep By Stepで丁寧に説明しています。

Single File Componentとは

Single File Componentはtemplate, script, styleの3つのセクションから構成されるvueファイルです。一つファイル内でHTML, CSS, JavaScriptを記述することができるのでコードを効率的に記述することができます。


<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello Vue Component'
    }
  }
}
</script>

<style scoped>
.example{
  font-weight: bold;
}
</style>

webpackのインストール

webpackのインストールを行うために任意の名前のディレクトリを作成します。ここではwebpack-vueという名前にしています。


 $ mkdir webpack-vue

webpackのインストールを行う前にnpm init -yコマンドでpackage.jsonファイルを作成します。


 $ npm init -y

webpackとwebpackのコマンドラインインターフェイスであるwebpack-cliの2つパッケージをインストールします。


 $ npm install --save-dev webpack webpack-cli

これでwebpackのインストールは完了です。

初めてのwebpackコマンド

srcディレクトリを作成しその中にindex.jsファイルを作成します。


 $ mkdir src
 $ cd src
 $ touch index.js

npx webpackコマンドを実行します。WARNINGが出ますがwebpackによるビルドは完了しdistディレクトリの下にmain.jsファイルが作成されます。


$ npx webpack
Hash: 26d14b3e107fab3aeed3
Version: webpack 4.42.1
Time: 327ms
Built at: 2020-04-16 16:01:27
  Asset       Size  Chunks             Chunk Names
main.js  930 bytes       0  [emitted]  main
Entrypoint main = main.js
[0] ./src/index.js 0 bytes {0} [built]
WARNING in configuration
The 'mode' option has not been set, webpa....
webpackコマンドのみを実行するとパスが通っていないためエラーになります。npxをつけることでnode_modules/.bin/ディレクトリの中から指定したコマンドを自動的に探し出して実行します。

webpackのデフォルトではsrc/index.jsファイルを自動で見つけ、ビルドを行いdistディレクトリの下にmain.jsファイルを作成します。

またコマンド実行時に表示されたWARNINGはmodeを設定することで消えます。


 $ npx webpack --mode development
or 
 $ npx webpack --mode production
developmentは開発用でproductionは本番用で使用するコマンドです。

vue.jsのインストール

vue.jsのみ追加でインストールを行います。


 $ npm install vue

vue.jsの動作確認

プロジェクトフォルダの下にindex.htmlファイルを作成します。


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Webpack Vue.js</title>
</head>
<body>
	<div id="app">
		{{ message }}
	</div>
	<script src="./dist/main.js"></script>
</body>
</html>

srcディレクトリのindex.jsにvue.jsのコードを記述します。vueは先頭でimortしています。


import Vue from 'vue'

const app = new Vue({
	el: "#app",
	data: {
		message: 'Hello World'
	}
})

index.htmlファイルとindex.jsファイルを作成後にwebpackコマンドでビルドします。


 $ npx webpack --mode development

ブラウザで確認すると画面上には{{ messsage}}が表示され、vue.jsが動作していないのでデベロッパーツールのコンソールを見ると以下のメッセージが表示されます。


vue.runtime.esm.js:620 [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.

vue.jsのマニュアルに記載されているwebpackの設定をwebpack.config.jsを作成して記述します。


module.exports = {
  // ...
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' webpack 1 用
    }
  }
}

これで先ほどのwarningが消えてブラウザ上にHello Worldが表示されます。webpakckの環境下でvue.jsを動作することができました。

[Vue warn]: Cannot find element: #appが表示された場合はdist/main.jsを読み込む場所をindex.htmlの上部ではなく#appのタグよりも下に移動してください。

SFC(Single File Components)の動作確認

vue.jsが動作することが確認できたのでシングルファイルコンポーネントの動作確認を行うためにcomponentsディレクトリを作成しその下にexample.vueファイルを作成します。


<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello Vue Component'
    }
  }
}
</script>

index.jsファイルからimportを使った作成したexample.vueファイルを読み込みます。


import Vue from 'vue'
import Example from './components/example.vue'

const app = new Vue({
	el: "#app",
	components:{
		Example,
	},
	data: {
		message: 'Hello World'
	}
})

更新が完了したらwebpackでビルドを行います。


 $ npx webpack --mode development
ERROR in ./src/index.js
Module not found: Error: Can't resolve './components/example.vue' in ...

ビルドに失敗しましたがコンポーネントへのパスに誤りがありました。Modul not found: Errorが出力された場合はパスの確認も行ってみてください。

example.vueファイルへのパスを../components/example.vueに修正し再度実行します。


 $ npx webpack --mode development
 ・
 ・
ERROR in ./components/example.vue 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

エラーにはLoaderが必要だと表示されているので、vue-loaderのインストールを行います。

vue-loaderのインストール

vue-loaderは、vueファイルに記述したtemplate, script, styleタグの中身を解析し、ブラウザに認識できる形に変換するために必要となるLoaderです。

npm installコマンドでインストールを行います。


 $ npm install --save-dev vue-loader

vue-loaderのインストールが完了したら、webpack.config.jsにloader設定を追加します。設定により.vueの拡張子が付いたファイルにvue-loaderが適用されます。


module.exports = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' webpack 1 cӬ
    },
  }
}

Loaderについては下記の文書も参考になります。

webpack.config.jsの設定が完了したらビルドを行います。さらに3件の別のエラーが発生しました。


 $ npx webpack --mode development
 ・
 ・
ERROR in ./components/example.vue
Module Error (from ./node_modules/vue-loader/lib/index.js):
[vue-loader] vue-template-compiler must be installed as a peer dependency, or a compatible compiler implementation must be passed via options.
 @ ./src/index.js 2:0-47 7:2-9

ERROR in ./components/example.vue
Module Error (from ./node_modules/vue-loader/lib/index.js):
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
 @ ./src/index.js 2:0-47 7:2-9

ERROR in ./components/example.vue
Module build failed (from ./node_modules/vue-loader/lib/index.js):
TypeError: Cannot read property 'parseComponent' of undefined

vue-template-comilerのインストール

1件目のエラーはvue-template-comilerが必要とのことなのでインストールを行います。


 $ npm install --save-dev vue-template-compiler

再度ビルドを行うと一つ目のvue-template-compilerに関するエラーは消えますが、残り2件のエラーは残ったままです。

VueLoderPluginに関する設定

1つはVueLoderPluginをwebpack.config.jsに含めないといけないということなのでwebpack.config.jsへの追加を行います。設定方法についてはVue Loaderのドキュメントのマニュアルセットアップに記述されています。


const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    // make sure to include the plugin!
    new VueLoaderPlugin()
  ],
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' webpack 1 cӬ
    },
  }
}

再度ビルドを実行するとエラーが表示されなくなりました。


 $ npm install --save-dev vue-template-compiler

ブラウザで確認するとHello Worldの下にExampleコンポーネントに記述したHello Vue Componentが表示されました。

styleタグの追加

template, scriptタグは処理できましたが、styleタグについては設定をおこなっていなかったので追加を行います。

追加

<style scoped>
.example{
  font-weight: bold;
}
</style>

scriptタグを追加後にビルドを行うとエラーが発生します。


 $ npm install --save-dev vue-template-compiler
  ・
You may need an additional loader to handle the result of these loaders.

追加のLoaderが必要なのでcssに関連するvue-style-loaderとcss-loaderの2つをインストールします。


 $ npm install --save-dev vue-style-loader css-loader

インストール後はwebpack.config.jsファイルに設定を追加する必要があります。vue-style-loaderとcss-loaderの順番も関係あるので注意してください。


const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader',
        ]
      }
    ]
  },
  plugins: [
    // make sure to include the plugin!
    new VueLoaderPlugin()
  ],
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' webpack 1 cӬ
    },
  }
}

ビルド後にブラウザで見るとHello Vue Componentの文字列にCSSが適用され太文字で表示されることが確認できます。

追加ライブラリをインストールする度にエラーが発生しましたがエラーの内容と公式ドキュメントを確認することで無事webpackの環境下でvue.jsのシングルファイルコンポーネントを使うことができました。