LoginSignup
53
50

More than 3 years have passed since last update.

【2019年05月現在】Webpack4でVue.js単一ファイルコンポーネントの作り方

Last updated at Posted at 2019-05-19

間違ってたらご指摘お願いします:bow:

参考

サンプル

サンプルとして簡単なカウンターを作ってみました

コードはこちら

MuXJvH6i4r.gif

bash
yarn init -y
yarn add -D webpack webpack-cli vue vue-loader vue-template-compiler vue-style-loader css-loader babel-loader @babel/core @babel/preset-env

# または、

npm init -y
npm i -D webpack webpack-cli vue vue-loader vue-template-compiler vue-style-loader css-loader babel-loader @babel/core @babel/preset-env
フォルダ構成
.
├ src/
│  ├ components
│  │  └ Btn.vue
│  ├ App.vue
│  └ index.js
├ .babelrc
├ index.html
├ package.json
└ webpack.config.js
webpack.config.js
const VueLoaderPlugin = require("vue-loader/lib/plugin")

module.exports = {
    mode: "development",
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: "vue-loader",
            },
            {
                test: /\.js$/,
                loader: "babel-loader",
            },
            {
                test: /\.css$/,
                use: [
                    "vue-style-loader",
                    "css-loader",
                ],
            },
        ]
    },
    plugins: [
        new VueLoaderPlugin()
    ],
    resolve: {
        extensions: [".vue", ".js"],
        alias: {
            "vue$": "vue/dist/vue.esm.js"
        }
    },
}
.babelrc
{ "presets": ["@babel/preset-env"] }
src/index.js
import Vue from "vue"
import App from "./App"

new Vue({
    el: "#app",
    template: "<App/>",
    components: { App }
})
src/App.vue
<template>
    <div id="app" class="container">
        <h1>My Counter</h1>
        <hr>
        <p class="count">{{ count }}</p>
        <Btn class="blue" @handleCount="doCount('up')">Up</Btn>
        <Btn class="green" @handleCount="doCount('down')">Down</Btn>
    </div>
</template>

<script>
import Btn from "./components/Btn"

export default {
    components: {
        Btn
    },
    data () {
        return {
            count: 0,
        }
    },
    methods: {
        doCount(countType) {
            this.count += (countType === "up" ? 1 : -1)
        },
    },
}
</script>

<style scope>
.container {
    text-align: center;
    width: 500px;
}

.count {
    font-size: 35px;
    margin: 10px;
}
</style>
src/components/Btn.vue
<template>
    <button @click="_handleCount">
        Count <slot></slot>!
    </button>
</template>

<script>
export default {
    methods: {
        _handleCount() {
            this.$emit("handleCount");
        }
    }
}
</script>

<style scope>
button {
    border-radius: 5px;
    cursor: pointer;
    font-size: 15px;
    height: 35px;
    width: 40%;
    color: #fff;
    transition: opacity .15s;
}
button:hover {
    opacity: .8;
}
button.blue {
    background-color: #007bff;
    border-color: #007bff;
}
button.green {
    background-color: #28a745;
    border-color: #28a745;
}
</style>
index.html
<!DOCTYPE html>
<meta charset=utf-8>
<title>sample</title>
<script src=dist/main.js defer></script>
<div id=app></div>
bash
yarn webpack

#または、

npx webpack

index.htmlをブラウザで開くと動きが確認できます

Sassを使う

sass-loadernode-sassを追加します

# 全部installする場合
yarn add webpack webpack-cli vue vue-loader vue-template-compiler vue-style-loader css-loader babel-loader @babel/core @babel/preset-env sass-loader node-sass
webpack.config.js
  const VueLoaderPlugin = require("vue-loader/lib/plugin")
  module.exports = {
      mode: "development",
      module: {
          rules: [
              {
                  test: /\.vue$/,
                  loader: "vue-loader",
              },
              {
                  test: /\.js$/,
                  loader: "babel-loader",
              },
              {
-                 test: /\.css$/,
+                 test: /\.scss$/,
                  use: [
                      "vue-style-loader",
                      "css-loader",
+                     "sass-loader",
                  ],
              },
          ]
      },
      plugins: [
          new VueLoaderPlugin()
      ],
      resolve: {
          extensions: [".vue", ".js"],
          alias: {
              "vue$": "vue/dist/vue.esm.js"
          }
      },
  }
vue
<style lang="scss" scope>
body {
    .container {
        text-align: center;
        width: 500px;
    }
}

/* ... */
</style>

  • ソースマップを有効にする
webpack.config.js
  const VueLoaderPlugin = require("vue-loader/lib/plugin")
  module.exports = {
      mode: "development",
      module: {
          rules: [
              {
                  test: /\.vue$/,
                  loader: "vue-loader",
              },
              {
                  test: /\.js$/,
                  loader: "babel-loader",
              },
              {
+                 test: /\.scss$/,
                  use: [
                      "vue-style-loader",
+                     {
+                         loader: "css-loader",
+                         options: { sourceMap: true },
+                     },
+                     {
+                         loader: "sass-loader",
+                         options: { sourceMap: true },
+                     },
                  ],
              },
          ]
      },
      plugins: [
          new VueLoaderPlugin()
      ],
      resolve: {
          extensions: [".vue", ".js"],
          alias: {
              "vue$": "vue/dist/vue.esm.js"
          }
      },
  }

Screen Shot 2019-05-19 at 20.35.22.png

source mapが確認できました

PostCSSを使う

postcss-loaderを追加します。今回は例としてpostcss-nestedで試してみます

# 全部installする場合
yarn add webpack webpack-cli vue vue-loader vue-template-compiler vue-style-loader css-loader babel-loader @babel/core @babel/preset-env postcss-loader postcss-nested
webpack.config.js
// ...
{
    test: /\.css$/,
    use: [
        "vue-style-loader",
        {
            loader: "css-loader",
            options: { importLoaders: 1 }
        },
        {
            loader: "postcss-loader",
            options: { plugins: [ require("postcss-nested") ] },
        },
    ],
},
// ...
vue
<style scope>
body {
    h1 {
        color: blue;
    }
}
</style>

↑の設定でPostCSSを用いたネスト記法を使ってcssを書けるようになりました、わかりやすくsource mapもつけてみます

webpack.config.js
// ...
{
    test: /\.css$/,
    use: [
        "vue-style-loader",
        {
            loader: "css-loader",
            options: {
                sourceMap: true,
                importLoaders: 1
            },
        },
        {
            loader: "postcss-loader",
            options: { 
                sourceMap: true, 
                plugins: [ require("postcss-nested") ],
            },
        },
    ],
},
// ...

Screen Shot 2019-05-19 at 20.51.21.png

Pugを使う

pugpug-plain-loaderを追加します

# 全部installする場合
yarn add webpack webpack-cli vue vue-loader vue-template-compiler vue-style-loader css-loader babel-loader @babel/core @babel/preset-env pug pug-plain-loader
webpack.config.js
// ...
{
    test: /\.pug$/,
    loader: 'pug-plain-loader'
},
// ...
vue
<template lang="pug">
div
  h1 Hello world!
</template>

Screen Shot 2019-05-19 at 21.13.29.png

Hot Reload する

参考:https://vue-loader.vuejs.org/guide/hot-reload.html

webpack-dev-server --hotとするとうまくいくようです

# 全部installする場合
yarn add webpack webpack-cli webpack-dev-server vue vue-loader vue-template-compiler vue-style-loader css-loader babel-loader @babel/core @babel/preset-env
index.html
<!DOCTYPE html>
<meta charset=utf-8>
<title>sample</title>
<script src=main.js defer></script>
<div id=app></div>
webpack.config.js
const VueLoaderPlugin = require("vue-loader/lib/plugin")

module.exports = {
    mode: "development",
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: "vue-loader",
            },
            {
                test: /\.js$/,
                loader: "babel-loader",
            },
            {
                test: /\.css$/,
                use: [
                    "vue-style-loader",
                    "css-loader",
                ],
            },
        ]
    },
    plugins: [
        new VueLoaderPlugin()
    ],
    resolve: {
        extensions: [".vue", ".js"],
        alias: {
            "vue$": "vue/dist/vue.esm.js"
        }
    },
    devServer: {
        compress: true,
        port: 9000,
        open: true
    },
}
yarn webpack-dev-server --hot

B9G3batcIB.gif

ページがリロードされることなく、ファイル保存すると、コンポーネントも更新されていることが確認できました。

--hotをつけないと、ファイル保存するとページがリロードされるという動きでした。


最後まで読んでいただいてありがとうございました。m(_ _)m

53
50
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
53
50