Help us understand the problem. What is going on with this article?

ゼロからVue向けのウェブパック設定

More than 1 year has passed since last update.

この記事でゼロからVueに使えるwebpack環境を立ち上げます。フィーチャー:

  • webpack-dev-server
  • ホットリロード
  • ローダーの使い方(vue-loader)
  • プラグインの使い方(HtmlWebpackPlugin)
  • Vueのビルドの違いの説明。(umd, common, esm)

ソースはここです

設定

package.jsonをつくります。

echo {} >> package.json

webpackcliwebpack-dev-serverをインストールします。

npm install webpack webpack-cli webpack-dev-server --save-dev

動いているか確認します。npx webpack. npxはNode.jsのバイナリーを実行するツールです。インストールしたバイナリーはnode_modules/.binにあります。

ls node_modules/.bin | grep web

webpack
webpack-cli
webpack-dev-server

npx webpackを実行すると、2つのエラーが出て来ます。

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

2.

ERROR in Entry module not found: Error: Can't resolve './src' in '/Users/lachlanmiller/javascript/vue/webpack-simple'

1個目はmodeと関係があります。modeを設定しないと、デフォルトはproduction。設定しましょう。package.jsonの中でscriptsdevコマンドを追加します:

"scripts": {
  "dev": "npx webpack --mode development"
}

これからnpm webpackではなくnpm run devで実行します。

次のエラーは:

Can't resolve './src' in ...

ウェブパックのデフォルトエントリーポイントはsrc.index.js。まだwebpack.config.jsを作っていないのでそこで探しています。作りましょう。

mkdir src && touch src/index.js

npm run devを実行すると:

Hash: 52bc792a675c1ee221f2
Version: webpack 4.10.2
Time: 71ms
Built at: 2018-05-30 23:58:42
  Asset      Size  Chunks             Chunk Names
main.js  3.77 KiB    main  [emitted]  main
Entrypoint main = main.js
[./src/index.js] 0 bytes {main} [built]

バンドルしたコードをdist/main.jsにあります。

Hello Webpack

上のアウトプットを見ると3.77 KiBが書いてあります。なぜ?まだコードを1行もを書いていません!

確認してみてください。cat dist/main.jsを実行すると、100行くらいのコードがあって、最後に

/***/ "./src/index.js":
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("\n\n//# sourceURL=webpack:///./src/index.js?");

/***/ })

/******/ });

これはバンドルしたsrc/index.js。まだ何も書いていないので何もないです。src/index.jsを更新します:

const HELLO = "WORLD"

そしてnpm run dev && cat dist/main.js

/***/ "./src/index.js":
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("const HELLO = \"WORLD\"\n\n\n//# sourceURL=webpack:///./src/index.js?");

/***/ })

入りました!バンドルのサイズを見てみると:

Built at: 2018-06-01 20:08:21
     Asset       Size  Chunks             Chunk Names
   main.js   3.79 KiB    main  [emitted]  main
index.html  191 bytes          [emitted]

3.77 KiB -> 3.79 KiBに増えました。

mode

npx webpack --mode production

を実行して見ます。

Built at: 2018-06-01 20:09:43
     Asset       Size  Chunks             Chunk Names
   main.js  930 bytes       0  [emitted]  main
index.html  191 bytes          [emitted]

930 bytesになりました! cat dist/main.jsを実行すると:

!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t){}]);%

長い1行だけです。ミニファイしてくれました。

cat dist/main.js | grep WORLD

すると、何も出てこないです。dist/main.jsを目で確認したら、びっくりします。const HELLO = "WORLD"がなくなりました。なぜ?変数を定義したが、使っていないのでウェブパックを無視して削除してくれました。productionモードなので、できるだけバンドルを小さくしてくれました。src/index.jsを更新します:

export const HELLO = "WORLD"

npx webpack --mode productionを実行して、そして

cat dist/main.js | grep WORLD

ちゃんと出て来ました!目で確認すると、

("use strict";r.r(t),r.d(t,"HELLO",function(){return n});const n="WORLD"}]);

のようなコードがあります。

webpack.config.js

configファイルを作りましょう。touch webpack.config.js。その中で、

module.exports = {
  entry: "./src/index.js"
}

HtmlWebpackPlugin

最初のプラグインを入れます。簡単なindex.htmlを作るプラグインをインストールします:

npm install html-webpack-plugin --save-dev

Vueを入れたいので、<div id="app"></div>が必要です。欲しいテンプレートを作ります。touch template.htmlを実行して、このコードを入れます:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

webpack.config.jsを更新します:

const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")

module.exports = {
  entry: "./src/index.js",

  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "template.html")
    })
  ]
}

pluginsは配列です。使いたいプラグインを入れて、そしてoptionsオブジェクトを渡します。ここでtemplateオプションでHtmlWebpackPluginに使いたいtemplateを渡します。

またnpm run devを実行して、cat dist/index.htmlをすると:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <div id="app"></div>
<script type="text/javascript" src="main.js"></script></body>
</html>

HtmlWebpackPlugin

<script type="text/javascript" src="main.js"></script></body>

入りました。

Vueを追加

ようやくVueを入れます。

npm install vue --save

普段はbabelなどでコンパイルしないとimport, exportを使えないですが、webpackでバンドルしているのでimportexportが使えます!src/index.jsを更新:

import Vue from "vue"

document.addEventListener("DOMContentLoaded", () => {
  new Vue({
    el: "#app",

    data() {
      return {
        msg: "Hello"
      }
    },

    template: "<div>{{ msg }}</div>"
  })
})

npm run dev。そして:

Hash: 9c0afed8a7477e9712d1
Version: webpack 4.10.2
Time: 645ms
Built at: 2018-05-31 00:23:36
     Asset       Size  Chunks             Chunk Names
   main.js    317 KiB    main  [emitted]  main
index.html  191 bytes          [emitted]

317 KiBになりました。Vueをミニファイしていないビルドを使っているので大きいです。とりあえず大丈夫です。あとで直します。

サーバーを立ち上げると、ブラウザでバンドルしたmain.jsが動けるはずです。パイソンでサーバーを実行します:

cd dist && python -m SimpleHTTPServer

そしてlocalhost:8000にアクセスと・・・何もないです。ブラウザのコンソールを見ると:

[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.

理由は、templateオプションでヴVueのマークアップで作っていることです。

template: "<div>{{ msg }}</div>"

vue-template-compilerはこのビルドに入っていないので、上のコードをコンパイルできません。Node.jsimportするとこれはデフォルトとなります。src/index.jsを更新します:

import Vue from "vue/dist/vue.esm.js"

エラーが消えたはずです。Helloが見えるはずです。

vue-loader (.vueファイル)

.vueファイルを使って見ましょう。

touch src/Hello.vue

そしてこのコードを入れます:

<template>
  <div>{{ msg }}</div>
</template>

<script>
export default {
  name: "Hello",

  data() {
    return {
      msg: "Hello"
    }
  }
}
</script>

src/index.jsを更新してコンポーネントを使って見ます:

import Vue from "vue/dist/vue.esm.js"
import Hello from "./Hello.vue"

document.addEventListener("DOMContentLoaded", () => {
  new Vue({
    el: "#app",

    components: {
      Hello
    },

    template: "<Hello />"
  })
})

npm run devを実行したら:

ERROR in ./src/Hello.vue
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <template>
|   <div>{{ msg }}</div>
| </template>
 @ ./src/index.js 2:0-31 9:6-11

webpack.vueファイルの読み込み方がわからないので。You may need an appropriate loaderというエラーが出て来ました。デフォルトの設定で、.jsしか読み込めないです。インストールしましょう:

npm install vue-loader --save-dev

そしてwebpack.config.jsを更新する:

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

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: "vue-loader"
      }
    ]
  },

  plugins: [
    // ...
    new VueLoaderPlugin()
  ]
}

vue-loaderの細かいはここ。日本語がありません。

またnpm run devを実行すると、うまくいくはずなのに・・・

ERROR in ./src/Hello.vue
Module build failed: Error: 
Cannot find module 'vue-template-compiler'

なぜかというと、vue-loadervue-template-compilerpeerDependencyとして使っています。そうなると、npm installを実行しても、インストールされません。

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

で対応できます。

そしてnpm run devを実行して、動いているはずです。(まだpythonサーバーを立ち上げていたなら。)

Built at: 2018-05-31 21:17:47
     Asset       Size  Chunks             Chunk Names
   main.js    327 KiB    main  [emitted]  main
index.html  191 bytes          [emitted]

327 KiBを覚えてください。もうすぐ軽くなります。

render関数でバンドルを軽く

vue/dist/vue.esm.jsを使う前のエラーメッセージをレビューします:

Either pre-compile the templates into render functions, 
or use the compiler-included build.

前は、vue/dist/vue.esm.jsを使うことで、compilerを入れました。その代わりに、render関数を使ってみましょう。src/index.jsを更新します:

import Vue from "vue"
import Hello from "./Hello.vue"

document.addEventListener("DOMContentLoaded", () => {
  new Vue({
    el: "#app",

    render: h => h(Hello)
  })
})

render関数を使うことで、もう少しシンプルになりました。npm run devを実行して:

Built at: 2018-05-31 21:18:35
     Asset       Size  Chunks             Chunk Names
   main.js    245 KiB    main  [emitted]  main
index.html  191 bytes          [emitted]

245 KiBになりました!327 KiBより全然軽くなりました。--mode productionなら:

     Asset       Size  Chunks             Chunk Names
   main.js   66.2 KiB       0  [emitted]  main
index.html  191 bytes          [emitted]

66.2 KiBとなります。

dev-serverとホットリロード

webpack-dev-serverを簡単に使えます。

npx webpack-dev-server

だけで実行できます。

ℹ 「wds」: Project is running at http://localhost:8080/
ℹ 「wds」: webpack output is served from /
⚠ 「wdm」: Hash: 55f5a357f2dc60279c3f
Version: webpack 4.10.2
Time: 1210ms
Built at: 2018-05-31 21:26:08
     Asset       Size  Chunks             Chunk Names
   main.js    204 KiB       0  [emitted]  main
index.html  191 bytes          [emitted]

http://localhost:8080/にアクセスすると、見れるはずです。pythonのサーバーがいらなくなりますた。Hello.vueを更新して、保存すると自動に更新されるはずです。

webpack.config.jsをもう一回更新します:

module.exports = {
  // ...
  devServer: {
    overlay: true
  }
}

すると、JSのコンパイルエラーがあれば、ブラウザのオーバーレイで表示されます。

まとめ

この記事で:

  • ゼロからwebpack.config.jsを作りました
  • webpackの設定が理解しました
  • プラグインの使い方を学びました
    • VueLoaderPlugin
    • HtmlWebpackPlugin
  • modulerulesを追加ました
    • test: /\.vue$/

30行だけのwebpack.config.jsだけでモダーン開発環境を作りました。

改善

  • babel-loaderを追加して、古いブラウズをサポートする(泣)
  • babel-loaderを追加して、新しいES7などをサポートする(嬉)

ソースはここです

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away