webpackのloaderであるvue-loaderでPostCSSを使ってみる。

webpackの設定

webpack.config.js

const webpack = require('webpack')
const path = require('path')

module.exports = {
  entry: [
    path.resolve(__dirname, 'src/index.js')
  ],

  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  module: {
    rules: [
      // 他のloaderの設定

      // vue
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  }
}

src/index.jsをバンドルしてdist/bundle.jsとして出力する。拡張子が.vueのファイルは全てvue-loaderで処理する。

PostCSSの設定

vue-loaderはバージョン11以降、PostCSSの設定ファイルがあるとそれを自動で読み込んでくれる(参照)。外部ファイルにする場合はpostcss.config.js.postcssrcのどちらかを設置することになる。今回はpostcss.config.jsでいきます。

postcss.config.js

const path = require('path')
const filePath = require('./file-path')

const options = {
  postcssImport: {
    path: path.resolve(__dirname, 'src/assets/styles')
  },
  cssnext: {
    browsers: [
      'last 2 versions',
      'ie > 11',
      'iOS >= 10',
      'Android >= 5.0'
    ],
    cascade: false
  },
  cssnano: {
    preset: 'default',
    autoprefixer: false,
    discardUnused: {
      fontFace: false
    }
  }
}

module.exports = ({env}) => ({
  plugins: {
    'postcss-import': options.postcssImport,
    'postcss-cssnext': options.cssnext,
    'cssnano': env === 'production' ? options.cssnano : false
  }
})

PostCSSのプラグインであるpostcss-importpostcss-cssnextcssnanoを使う。 postcss.config.jsにすると良いことがあって、ctxという引数を受け取った状態で設定をexportできる(参照)。ctxにはenvfileoptionsの3つのオブジェクトが格納されていて、ここではenvを読んで、プロダクション環境でだけcssnanoを実行するようにしている。 余談だけど、cssnanoは(たぶん)デフォルトで使用してない@font-faceを消してしまう。オプションでdiscardUnused: {fontFace: false}と指定することで回避できる。もしかしたらcssnano-preset-defaultの機能かもしれない。

.vueにCSS書く

あとは、.vueファイルのstyleガードの中でCSSをimportしたりCSS書いたりする。

App.vue

<template>
  <div :class="$style.page">
</template>

<script>
...
</script>

<style>
@import "reset-css";
@import "font-face.css";
@import "properties.css";
@import "property-sets.css";
@import "media.css";
@import "base.css";

.page {
  max-width: var(--width_index);
  margin: var(--margin_top) auto 0;
}
</style>

こんな感じ。@importのパスは、postcss.config.jsで設定したファイルパス以下を記述する。webpack.config.jsresolveでエイリアスの設定をしても関係ないので注意。


最近は自分のサイトはだいたいVue.jsで作ってて、CSSはPostCSSで書いている。vue-loaderでは、module属性をstyleタグに追加するとCSS Modulesが使えるんだけど、それがとても便利。CSSの命名規則のつらさから解放されて、コンポーネントのスタイリングにだけ集中できる。 人によるだろうけど、.vueファイルの書き方を僕はとても気に入っていて、今までHTML/CSS/JSとファイルが全部分かれていたのをひとまとめに書けるのが気持ちいい。いざコード量が増えて1ファイルでは見通しが悪くなる場合は、外部ファイル化も可能だし、そういう痒い所に手が届く感じも素敵だと思う。