webpackのcss-loaderでCSS Modulesをやる

  • 99
    Like
  • 0
    Comment

はじめに

CSS Modulesの発想はよくわかったけど、具体的にどうやって導入したらいいかわかりにくく感じたので、webpackでCSS Modulesを使うための設定と、ReactでCSS Modulesを使う簡単な例を紹介します。

CSS Modulesの概要やいいところについてはこのあたりをどうぞ。

CSS Modulesを行うための方法はwebpack以外にもいくつかあるようです。
Browserify pluginのcss-modulesifyも人気そうです。(発音できない)

やってみる

まずは、必要なモジュールをインストールします。
CSS Modulesを使うために、style-loaderとcss-loaderが必要です。
React+babel+webpackの構成に必要なものも記述しています。

$ npm init -y
$ npm install --save react react-dom
$ npm install --save-dev webpack style-loader css-loader babel-loader babel-preset-es2015 babel-preset-react

次に、webpackの設定です。
loaders部分には、babel-loaderとCSS Modulesの二つが設定されています。
'css?modules'と書いてある部分が重要です。
modulesオプションを与えることで、css-loaderがCSS Modulesの振る舞いをするようになります。

webpack.config.js
module.exports = {
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015'],
          plugins: ['transform-react-jsx'],
        },
      },
      {
        test: /\.css$/,
        loaders: ['style-loader', 'css-loader?modules'],
      },
    ],
  },
  entry: './app',
  output: {
    path: __dirname,
    filename: 'bundle.js',
  },
  resolve: {
    extensions: ['', '.js', '.jsx'],
  },
};

次に、CSSをこんな感じで書きます。。
CSSのクラス名は一般的にはhyphen-caseが多いような気がしますが、CSS Modulesの場合はJS側からアクセスしやすいようにcamelCaseにしておくと良さそうです。

app.css
.hogeHoge {
  background-color: green;
}

最後に、Reactを使ったJS部分です。
app.cssをimport(またはrequire)することで、衝突しないように変換されたクラス名を読み込むことができます。
importした結果をdiv要素のclassNameに与えています。

app.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import styles from './app.css'

class App extends React.Component {
  render() {
    return <div className={styles.hogeHoge}>hello</div>;
  }
}

ReactDOM.render(<App/>, document.getElementById('content'));

一応HTMLも置いておきます。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>CSS Modules Example</title>
  </head>
  <body>
    <div id="content"></div>
    <script src="bundle.js"></script>
  </body>
</html>

以下のように適当にwebpackでビルドします。
私は普段はnpm scriptsに書いています。

$ ./node_modules/.bin/webpack

ブラウザでアクセスするとdivのクラス名が_3PdwrDVeQurTJpm2SrFLC2というように変換されていることが確認できると思います。
クラスの命名ルールはcss-loaderのlocalIdentNameオプションで変更することができます。
例えば、'css?modules&localIdentName=[path][name]---[local]---[hash:base64:5]'のように設定するとクラス名がapp---hogeHoge---3Pdwrのようになります。

おわりに

どうしてもSassを書きたくなかったので、これでBEM+Sassの代替手段として機能しそうです。