【コーダー向け】webpackでSassをコンパイルする方法

目次
  1. webpackの導入手順
  2. CSSを読み込む基本の考え方
  3. Sassをインラインで読み込む方法
    1. ローダーのインストール
    2. webpackの設定
    3. CSSのimport
    4. webpackでビルド
  4. CSSを別ファイルに出力
    1. 「MiniCssExtractPlugin」プラグインの導入
    2. webpackの設定
    3. HTMLからCSSを読み込む
    4. webpackでビルド
  5. CSSの構文チェックして自動修正する
    1. stylelintの拡張プラグイン「StylelintWebpackPlugin」の導入
    2. webpackの設定
    3. stylelintの定義ファイルを作成
    4. ビルドして実行結果を確認する
    5. stylelintに自動修正してもらう
  6. ベンダープレフィックスを自動付与
    1. webpackの設定
    2. ベンダープレフィックス付きそうなCSSを追加してビルド
  7. CSS内のURLが解決できない問題を解消する
    1. webpackの設定
  8. プロパティをソートしたい
    1. webpackの設定
    2. プロパティ順を混ぜてビルド
  9. メディアクエリを1つにまとめる
    1. webpackの設定
    2. ビルドを試してみる
  10. importをまとめる
  11. おわり

※この記事は2020年4月時点の内容です。

webpackでSassをコンパイルする方法です。webpackはHTMLコーダーにあまり優しくない印象(偏見)がありましたが、結論から言うとやりたいことは十分にやらせてくれます。

具体的に実際にやっているのは、以下の5つです。

  • CSSファイルの出力
  • 構文チェック & 自動修正
  • ベンダープレフィックスの自動付与
  • プロパティのソート
  • メディアクエリの統合

webpackでSassをコンパイルしたい方はぜひ参考にしていただければと思います。

webpackの導入手順

「my-webpack」というプロジェクトフォルダを作成します。作成場所はどこでもOKです。

mkdir my-webpack

「my-webpack」に移動。

cd my-webpack

npmの初期化を行います。

npm init -y

最初の構成ファイルとしては、以下のように配置していますので、同様に進めたい方は作成しておいてください。

  • dist・・・ビルド後の出力先フォルダ
  • src・・・ビルド前の出力元フォルダ
  • index.html・・・静的HTMLファイル
  • webpack.config.js・・・webpackの設定ファイル

index.htmlは以下のように配置しています。

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>webpack Test</title>
	<link rel="stylesheet" href="dist/css/style.css">
</head>
<body>
	<div id="main">
		<p>テスト</p>
	</div>
	<script src="dist/my-bundle.js"></script>
</body>
</html>

CSSを読み込む基本の考え方

まずはwebpackにおけるCSSの読み込み方についておさらいしておきます。webpackの基本的な用途としては、JavaScriptやJSONを依存関係を考慮していい感じにまとめるといったビルドツールです。要するにJavaScript用ということです。

そんなwebpackですが、JavaScript開発と付随して使われがちなCSSやHTMLに関する拡張要素も豊富にあり、ローダーやプラグインで拡張していくことによって、フロントエンドの開発が効率的に行えるようになっていたりします。

ポイントとしては、

  • Sassをコンパイルするには拡張して足していくこと
  • webpackのローダー、プラグインという機能を活用すること

の2点を押さえておいてもらえたらと思います。
※ ローダーとプラグインという聞き慣れない単語かもしれませんが、両方ともwebpackの「拡張機能」という認識をしておけばなんとなくの理解はできるかと。

Sassをインラインで読み込む方法

それでは早速ローダーを使ってSassファイルをインラインで読み込んでいきましょう。インラインとは<head>内に直接記載されるCSSのことですね。

必要なローダーとしては以下のとおりです。インラインとして記載するために必要なのはstyle-loaderになります。なのでインライン記述にしない場合はこちらは不要ですが、css-loaderとsass-loaderはSassを使うならお決まりレベルで活用するローダーになります。

ローダーのインストール

  • style-loader・・・<head>内にインラインCSSで出力するためのローダー
  • css-loader・・・CSS記述を解釈するためのローダー
  • sass-loader・・・Sass記述を解釈するためのローダー

style-loaderのインストール。

npm install --save-dev style-loader

css-loaderのインストール。

npm install --save-dev css-loader

sass-loaderとsassのインストール。

npm install --save-dev sass-loader sass

webpackの設定

ローダーの指定は、webpack.config.jsのmoduleに書いていきます。

const PATH = require('path');

module.exports = {
	mode: 'production',
	entry: './src/my-main.js',
	output: {
		path: PATH.resolve(__dirname, 'dist'),
		filename: 'my-bundle.js'
	},
	module: {
		rules: [
			{
				test: /\.scss$/i,
				use: [
					{
						loader: 'style-loader',
					},
					{
						loader: 'css-loader',
					},
					{
						loader: 'sass-loader',
						options: {
							sassOptions: {
								outputStyle: 'expanded',
							},
						},
					},
				]
			},
		]
	}
};

testに対象ファイルを指定して、useにローダーを指定します。

ローダーは定義した下から順番に読み込んでいくイメージです。この設定の場合は、sass-loaderが読み込まれ、次にcss-loader、最後にstyle-loaderという流れです。

Sassを解析して、CSSを解析して、インラインへ反映、みたいなイメージです。

その他の設定については、以下のwebpackの最小構成の記事を参考にしてください。

webpackの基本的な使い方!最小構成で動作を試してみよう

CSSのimport

エントリーポイントとなる、src/my-main.jsを作成し、style.scssを読み込ませます。

import './css/style.scss';

そして、同じ階層にcss/style.scssを作成して以下のように記述してあげます。

body {
	background: #eee;
}

#main {
	p {
		color: #666;
	}
}

これで準備はOKです。

webpackでビルド

ローダーの導入、ローダーの設定と必要ファイルの準備ができました。それではwebpackでビルドしてみましょう。

npx webpack

index.htmlを開いてみると、head内にコンパイルされたCSSが挿入されていることが分かるかと思います。

CSSを別ファイルに出力

インラインの流れでおおよそのSassからCSSにする方法が分かったかと思います。これでもサイトとしては表現可能ですが、CSSは別ファイルにした方が管理しやすいです。

次は、CSSを別ファイルとして出力する方法について見ていきましょう!

「MiniCssExtractPlugin」プラグインの導入

CSSを別ファイルに出力するためには、「MiniCssExtractPlugin」プラグインによって拡張する必要があります。
(公式) → MiniCssExtractPlugin | webpackMiniCssExtractPlugin | webpack

それでは早速インストールしていきましょう。

npm install --save-dev mini-css-extract-plugin

webpackの設定

webpack.config.jsへの設定は、インラインの指定から主にはstyle-loaderの部分を「MiniCssExtractPlugin」に変えるようなイメージです。

以下の追加を行います。

  • requireでMiniCssExtractPluginの読み込み
  • pluginsでMiniCssExtractPluginを追加
  • MiniCssExtractPluginをローダーに追加

全体のコードがこちらです。

const PATH = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
	mode: 'production',
	entry: './src/my-main.js',
	output: {
		path: PATH.resolve(__dirname, 'dist'),
		filename: 'my-bundle.js'
	},
	module: {
		rules: [
			{
				test: /\.scss$/i,
				use: [
					{
						loader: MiniCssExtractPlugin.loader,
					},
					{
						loader: 'css-loader',
					},
					{
						loader: 'sass-loader',
						options: {
							sassOptions: {
								outputStyle: 'expanded',
							},
						},
					},
				]
			},
		]
	},
	plugins: [
		new MiniCssExtractPlugin({
			filename: 'css/style.css',
			ignoreOrder: true,
		})
	]
};

意識的に指定するのは、pluginsで指定しているfilenameですね。ここに出力先のファイル名(+パス)を記載することができます。

このケースだと、cssフォルダ内のstyle.cssになります。ちなみに、この親フォルダは、outputで指定しているpathのフォルダです。

HTMLからCSSを読み込む

インラインではなく外部ファイルとなるので、HTMLからstyle.cssを読み込む必要があります。head内にdist/css/style.cssを読み込む記述を追加してあげましょう。

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>webpack Test</title>
	<link rel="stylesheet" href="dist/css/style.css">
</head>

webpackでビルド

それでは、webpackでビルドして出力されるか見てみましょう!

npx webpack

distフォルダの中にcss/style.cssが出来上がっていれば成功です。

CSSの構文チェックして自動修正する

CSSの構文チェックツールとしてstylelintがあります。webpackでstylelintを使って構文チェックからの自動修正まで行ってもらおうと思います。

stylelintの拡張プラグイン「StylelintWebpackPlugin」の導入

StylelintWebpackPluginによってwebpackにstylelintを導入することができます。
(公式) → https://webpack.js.org/plugins/stylelint-webpack-plugin/StylelintWebpackPlugin | webpack

webpackにStylelintWebpackPluginをインストールします。

npm install --save-dev stylelint-webpack-plugin

stylelint自体も必要なのでインストールしてください。

npm install --save-dev stylelint

webpackの設定

追加することは2つだけです。

  • 「StylelintWebpackPlugin」プラグインをrequire
  • pluginsにStylelintPluginを読み込み

コードの全体はこちら。

const PATH = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const StylelintPlugin = require('stylelint-webpack-plugin');

module.exports = {
	mode: 'production',
	entry: './src/my-main.js',
	output: {
		path: PATH.resolve(__dirname, 'dist'),
		filename: 'my-bundle.js'
	},
	module: {
		rules: [
			{
				test: /\.scss$/i,
				use: [
					{
						loader: MiniCssExtractPlugin.loader,
					},
					{
						loader: 'css-loader',
					},
					{
						loader: 'sass-loader',
						options: {
							sassOptions: {
								outputStyle: 'expanded',
							},
						},
					},
				]
			},
		]
	},
	plugins: [
		new MiniCssExtractPlugin({
			filename: 'css/style.css',
			ignoreOrder: true,
		}),
		new StylelintPlugin(),
	]
};

stylelintの定義ファイルを作成

.stylelintrcを作成して、以下のようにルールを定義してみました。

{
	"rules": {
		"no-extra-semicolons": true,
		"color-hex-length": "short",
	}
}

「セミコロンは1個だけにしましょう」と、「16進数の値はできるだけ短く」という指定です。そしてあえてミスとなるようにstyle.scssを書き換えました。

body {
	background: #eee;;
}

#main {
	p {
		color: #666666;
	}
}

ビルドして実行結果を確認する

それでは、ビルドして結果を確認してみましょう!

npx webpack

しっかりエラーとして出力され、stylelintが機能していることが分かります。

stylelintに自動修正してもらう

stylelintには自動修正の機能も備わっています。そちらを利用して自動修正までやってもらいましょう。webpackの設定からオプションを指定するだけなのでめちゃくちゃ簡単です。

webpack.config.jsのnew StylelintPlugin()にオプションを追加します。該当部分だけ抜粋すると以下のとおりです。

plugins: [
	new StylelintPlugin({
		fix: true,
	}),
]

これで実行してみると、出力されるCSSが自動的に修正されていることが分かるはずです!

body {
  background: #eee;
}

#main p {
  color: #666;
}

ベンダープレフィックスを自動付与

webpackでのSassのコンパイル時に自動でベンダープレフィックスを付与してあげましょう。ベンダープレフィックスの付与といえば、Autoprefixerですね。

PostCSSのプラグインであるAutoprefixerを、postcss-loaderを通して適応させるようなイメージです。

その2つをインストールします。

npm install --save-dev postcss-loader autoprefixer

webpackの設定

css-loaderとsass-loaderの間にpostcss-loaderを追加してあげます。PostCSSのプラグインとしてautoprefixerを読み込みオプションで条件を指定します。
(この例ではIE11以上、各ブラウザの過去2バージョンまでサポート)

module: {
	rules: [
		{
			test: /\.scss$/i,
			use: [
				{
					loader: MiniCssExtractPlugin.loader,
				},
				{
					loader: 'css-loader',
				},
				{
					loader: 'postcss-loader',
					options: {
						plugins: [
							require('autoprefixer')({
								browsers: [
									"last 2 versions",
									"ie >= 11",
								],
							}),
						]
					}
				},
				{
					loader: 'sass-loader',
					options: {
						sassOptions: {
							outputStyle: 'expanded',
						},
					},
				},
			]
		},
	]
},

ちなみに"browserslist": [ "defaults" ]でデフォルトの指定となります(オプションを指定しない場合も同じ)

ベンダープレフィックス付きそうなCSSを追加してビルド

background-image: linear-gradient()を追加してみました。

body {
	background: linear-gradient(to right, #ff6f00 50%, #009688 50%);
}

#main {
	p {
		color: #666;
	}
}

webpackでビルドしてみましょう。

npx webpack

-webkit-がついてかつ謎の記載が追加されていますね。

body {
  background: -webkit-gradient(linear, left top, right top, color-stop(50%, #ff6f00), color-stop(50%, #009688));
  background: linear-gradient(to right, #ff6f00 50%, #009688 50%);
}

#main p {
  color: #666;
}

これでAutoprefixerの導入もできました!

CSS内のURLが解決できない問題を解消する

実は今のままだと、CSS内のbackground: url(../img/hoge.png);のように記載された時のURLの部分でエラーが起きます。これを解消するためにfile-loaderを導入してあげます。

npm install --save-dev file-loader

webpackの設定

jpg等の拡張子に対して、file-loaderを読み込んであげてください。
※ module部分の一部を抜粋しています。

module: {
	rules: [
		{
			test: /.(jpg|png|gif|svg)$/,
			use: {
				loader: 'file-loader',
				options: {
					name: '../img/[name].[ext]',
				}
			}
		},
		{
			test: /\.scss$/i,
			use: [
				{
					loader: MiniCssExtractPlugin.loader,
				},
				{
					loader: 'css-loader',
					options: {
						url: true,
					},
				},
				{
					loader: 'sass-loader',
					options: {
						sassOptions: {
							outputStyle: 'expanded',
						},
					},
				},
			]
		},
	]
},

プロパティをソートしたい

PostCSSのプラグインであるcss-declaration-sorterによってwebpackでCSSプロパティをソートすることができます。

npm install --save-dev css-declaration-sorter

webpackの設定

postcss-loaderのプラグインとして拡張してあげます。
※ postcss-loaderのサンプル部分だけを提示しています。

{
	loader: 'postcss-loader',
	options: {
		plugins: [
			require('autoprefixer')({
				browsers: [
					"last 2 versions",
					"ie >= 11",
				],
			}),
			require('css-declaration-sorter')({
				order: 'alphabetical'
			}),
		]
	}
},

指定できる値は以下の3つです。今回はアルファベット順で指定してみました。

  • alphabetical・・・アルファベット順
  • smacss・・・重要なプロパティ順
  • concentric-css・・・ボックスモデルの外から内

プロパティ順を混ぜてビルド

あえてアルファベット順ではないSassファイルをビルドしてみます。

body {
	z-index: 1;
	text-align: center;
	background: #eee;
}

#main {
	p {
		color: #666;
		border: 1px solid #666;
	}
}
npx webpack

ちゃんとアルファベット順にソートされました!

body {
  background: #eee;
  text-align: center;
  z-index: 1;
}

#main p {
  border: 1px solid #666;
  color: #666;
}

メディアクエリを1つにまとめる

Sassでメディアクエリを入れ子で記載した場合、通常通りのコンパイルすると、いたるところにメディアクエリが出てきてしまいます。これをまとめるための拡張を行っていきます。

npm install --save-dev postcss-sort-media-queries

webpackの設定

PostCSSのプラグインとして追加してあげてください。
※ postcss-loaderのサンプル部分だけを提示しています。

{
	loader: 'postcss-loader',
	options: {
		plugins: [
			require('autoprefixer')({
				browsers: [
					"last 2 versions",
					"ie >= 11",
				],
			}),
			require('css-declaration-sorter')({
				order: 'alphabetical',
			}),
			require('postcss-sort-media-queries')({
				sort: 'desktop-first',
			}),
		]
	}
},

指定できるsortのオプションは以下の2つです。

  • mobile-first・・・スマホファースト
  • desktop-first・・・PCファースト

ビルドを試してみる

以下のような入れ子でメディアクエリを入れたSassを用意してみました。PCファーストです。

body {
	background: #eee;

	@media (max-width: 1079px) {
		background: #999;
	}

	@media (max-width: 767px) {
		background: #111;
	}
}

#main {
	p {
		color: #666;

		@media (max-width: 1079px) {
			background: #333;
		}

		@media (max-width: 767px) {
			background: #fff;
		}
	}
}

webpackでビルドしてみます。

npx webpak

メディアクエリごとに正しくまとまって出力してくれるようになりました!

body {
  background: #eee;
}

#main p {
  color: #666;
}

@media (max-width: 1079px) {
  body {
    background: #999;
  }
  #main p {
    background: #333;
  }
}

@media (max-width: 767px) {
  body {
    background: #111;
  }
  #main p {
    background: #fff;
  }
}

importをまとめる

通常Sassでimportする場合は以下のようにファイル名まで指定して書きます。

@import "page/index";
@import "page/about";
@import "page/contact";

ただ、これだとSassのファイルが増えるたびにimportの記述を増やす必要があり手間です。globというツールを使えば@import "page/**";という**の記述によってそのフォルダ配下のSassをすべて読み込めるという書き方ができて便利なので、こちらもwebpackに導入していきましょう!

Sassの前にimport-glob-loaderローダーを通すことで、importをファイル名まで指定しなくても読みこんでくれるようになります。

npm install --save-dev import-glob-loader

そしてwebpackの設定でローダーとして指定してあげてください。ポイントはsass-loaderより前(コード上は下)に配置してあげればOKです!

※ moduleのサンプル部分だけを提示しています。

{
	loader: 'sass-loader',
	options: {
		sassOptions: {
			outputStyle: 'expanded',
		},
	},
},
{
	loader: 'import-glob-loader',
},

おわり

webpackでSassをコンパイルする方法でした。もともとGulpを主体でSassをコンパイルして作業していましたがwebpackでも同様のコンパイルが問題なく行えることが分かりました。

ちなみにGulpの記述は以下の記事で紹介しています。

Sassから完璧なCSSファイルを出力するために通したいGulpのタスク【WordPress編】

webpackでSassをコンパイルしたい人の助けになれば幸いです。

WordPressでお悩みの方はお気軽にご相談ください。

ちょっとしたお困り事からサイト全体のリニューアルのようなご依頼まで、お悩みに応じて柔軟に対応いたします。

この記事を書いた人

はにわまん

HPcode代表。300件以上のWordPress案件を対応してきました。ちょっとしたWordPressのカスタマイズからブロックテーマでのリニューアルまで。更新できるWordPressサイトが好きです。