Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

.vueファイルの中にscssを書けるようにする | webpack4.x+babel7+vue.js 2.x 環境構築 2019年3月版 ステップ0003

参考にさせていただいたページ

TextField.vueを編集する

src/javascripts/vue_applications/common/components/TextField.vueのtemplate に以下の通り追記します。

    <div class="mod-error-messages">
      <ul class="mod-error-messages__list">
        <li class="mod-error-messages__item">
          sample message
        </li>
      </ul>
    </div>

ファイル末尾に以下の通り追記します。

<style lang="scss" scoped>
  .mod-error-messages {
    .mod-error-messages__list {
      box-sizing: border-box;
    }
    .mod-error-messages__item {
      color: #ff0000;
    }
  }
</style>

TextField.vueは以下のようになりました。

<template>
  <section>
    <label>TextField: </label>
    <input
      :value="value"
      type="text"
      @input="onInput"
    >
    <div class="mod-error-messages">
      <ul class="mod-error-messages__list">
        <li class="mod-error-messages__item">
          sample message
        </li>
      </ul>
    </div>
    <div class="test-synced-text">
      value: {{ value }}
    </div>
  </section>
</template>

<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex';

export default {
  name: 'TextField',
  computed: {
    ...mapState('textFieldUnit/textField', [
      'value',
    ]),
  },
  methods: {
    ...mapMutations('textFieldUnit/textField', [
      'setState',
    ]),
    onInput(e) {
      this.setState({
        key: 'value',
        value: e.target.value,
      });
    },
  },
}
</script>

<style lang="scss" scoped>
  .mod-error-messages {
    .mod-error-messages__list {
      box-sizing: border-box;
      border-radius: 4px;
    }
    .mod-error-messages__item {
      color: #ff0000;
    }
  }
</style>

一度ビルドを実行してみる

以下のコマンドでビルドを実行してみます。

webpack -d

以下のようなエラーが出ました。

ERROR in ./src/vue_applications/components/TextField.vue?vue&type=style&index=0&id=273a995e&lang=scss&scoped=true& (./node_modules/vue-loader/lib??vue-loader-options!./src/vue_applications/components/TextField.vue?vue&type=style&index=0&id=273a995e&lang=scss&scoped=true&) 40:0
Module parse failed: Unexpected token (40:0)
You may need an appropriate loader to handle this file type.
|
|
> .mod-error-message {
|   color: red;
| }
 @ ./src/vue_applications/components/TextField.vue?vue&type=style&index=0&id=273a995e&lang=scss&scoped=true& 1:0-160 1:176-179 1:181-338 1:181-338
 @ ./src/vue_applications/components/TextField.vue
 @ ./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options!./src/vue_applications/components/TextFieldUnit.vue?vue&type=script&lang=js&
 @ ./src/vue_applications/components/TextFieldUnit.vue?vue&type=script&lang=js&
 @ ./src/vue_applications/components/TextFieldUnit.vue
 @ ./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options!./src/vue_applications/App.vue?vue&type=script&lang=js&
 @ ./src/vue_applications/App.vue?vue&type=script&lang=js&
 @ ./src/vue_applications/App.vue
 @ ./src/index.js

node_modulesを追加する

.vueにscssを記述できるように以下の4つのモジュールを追加します。

npm install --save-dev style-loader css-loader sass-loader node-sass

ここまでやった段階でのpackage.json

{
  "name": "webpack_4_vue_introduction",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "watch": "webpack -d --watch",
    "test": "jest"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.4.0",
    "@babel/preset-env": "^7.4.2",
    "@vue/test-utils": "^1.0.0-beta.29",
    "babel-core": "^7.0.0-bridge.0",
    "babel-jest": "^24.5.0",
    "babel-loader": "^8.0.5",
    "css-loader": "^2.1.1",
    "jest": "^24.5.0",
    "jest-serializer-vue": "^2.0.2",
    "node-sass": "^4.11.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "vue-jest": "^3.0.4",
    "vue-loader": "^15.7.0",
    "vue-template-compiler": "^2.6.10",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0"
  },
  "dependencies": {
    "vue": "^2.6.10",
    "vuex": "^3.1.0"
  }
}

webpack.config.jsを編集する

rulesに渡している配列に以下の行を追加します。

.vueの中にscssを書くのですが、test: /\.scss$/,のルールを追加することになります。

      // 拡張子.scssのファイルに対する設定(.vueの中にscssを書きたい場合もここに設定します。)
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
          },
          {
            loader: 'sass-loader',
          },
        ]
      },

ここまでやった段階でのwebpack.config.js

以下のようになっています。

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

module.exports = {
  // entry point
  entry: {
    'javascripts/first_page': './src/javascripts/entry_points/first_page.js',
  },
  // 出力するパスは絶対パスで書きます
  output: {
    path: `${__dirname}/webroot/packed`,
    filename: (arg) => {
      return '[name].bundle.js'
    },
  },
  // webpack4はlordersではなくなりました
  module: {
    rules: [
      // 拡張子.vueのファイルに対する設定
      {
        test: /\.vue$/,
        use: [
          {
            loader: "vue-loader",
            options: {
              loaders: {
                js: 'babel-loader',
              },
            },
          },
        ]
      },
      // 拡張子.jsのファイルに対する設定
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
          },
        ]
      },
      // 拡張子.scssのファイルに対する設定(.vueの中にscssを書きたい場合もここに設定します。)
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'style-loader',
          },
          {
            loader: 'css-loader',
          },
          {
            loader: 'sass-loader',
          },
        ]
      },
    ]
  },
  // デフォルトの設定値だけでは足りないことについて解決します
  resolve: {
    // モジュールを読み込むときに検索するディレクトリの設定
    modules: [path.join(__dirname, 'src'), 'node_modules'],
    // importするときに省略できる拡張子の設定
    extensions: ['.js', '.vue'],
    alias: {
      // importのファイルパスを相対パスで書かないようにsrcのrootを設定
      '@': path.join(__dirname, 'src'),
      // 例えばmain.js内で `import Vue from 'vue';` と記述したときの`vue`が表すファイルパスを指定
      'vue$': 'vue/dist/vue.esm.js'
    },
  },
  // プラグインを列挙
  plugins: [
    new VueLoaderPlugin()
  ],
}

もう一度ビルドを実行してみる

以下のコマンドでビルドを実行してみます。

webpack -d

今度はビルド成功したと思います。

first_page.htmlをブラウザで開いてみる

スタイルが適用されて赤い文字になっているのがわかります。

また、開発者ツールなどで確認してみると、セレクタが追加されてscopedな状態になっていることがわかります。

.scssファイルをコンパイルしたい場合

  • サーバーサイドのフレームワークに任せる
  • scss用のwbpack.config.jsを作成してwebpackでやる
  • webpackを使わずnode-sass + postcssでやる

サーバーサイドのフレームワークでできそうなら、vendor prefixもお任せしたい。

おわりに

今回のポイントは.vueにstyleを書くために、.scssのルールを追加するところだと思います。

変数やmixinなど複数のコンポーネントで共通して使用する部分をsass-resources-loaderで読み込むことができるのでそのうちこの記事に追記するかもしれません。

プリプロセッサの使用 · vue-loader

次回はeslintで.vueと.jsの構文チェックをしようと思います。

続きはこちら

motomichi-works.hatenablog.com