Webpack 入門 その2 : SCSS のトランスパイル・Autoprefixer による Browserslist 参照
前回に引き続き、Webpack を利用して色々トランスパイルしつつ、Browserslist の効果を確認していく企画。前回の記事の続きなので未見の方はソチラを先にドウゾ。
また、最終成果物のコードは以下の GitHub リポジトリで公開しているのでコチラもドウゾ。
今回は SCSS ファイルを CSS ファイルとしてトランスパイルして出力しつつ、そこに Browserslist を参照しての Autoprefixer を効かせてみる。
目次
- 仕組みを理解する
- ビルド手順と使用ツール
- Webpack ちからの養い方
- 必要な Loader・Plugin をインストールする
- 素の CSS を扱ってみる
- SCSS を変換してみる
- CSS ファイルを別に出力する
- PostCSS + Autoprefixer + Browserslist によるベンダプレフィックス付与を試す
- 次回に続く
仕組みを理解する
最初は手前の一文を理解するのが難しいと思う (自分も理解が追いつかなかった) ので、仕組みを整理する。
SCSS ファイルはそのままではブラウザで認識されない。生の CSS にトランスパイルする必要がある。ココまでは良いだろう。
今回、Browserslist の設定を利用して、新しめのコードにはベンダプレフィックス等のフォールバックを追加させたいと考えている (Browserslist の効果を知るのが当初の目的だったので…)。
SCSS コードに Browserslist を適用させるには、まず SCSS から CSS へトランスパイルを済ませてしまい、その CSS に対して、Autoprefixer がベンダプレフィックスをブチ込む流れになる。Autoprefixer が Browserslist の設定ファイルを参照して、どの程度ベンダプレフィックスを追加するか決めるというワケ。
CSS コードに Autoprefixer を効かせるためには、PostCSS というパーサが間に入ることになる。
ココまでで SCSS ファイルを CSS コードに変換できたワケだが、その CSS コードを Webpack で処理できるようにするため、css-loader
という Loader が必要になる。
css-loader
をかませると、CSS コードを ./dist/js/main.js
内にバンドル出来るようになるのだが、今回は JS ファイル内にバンドルするのではなく、.css
ファイルとして別に書き出したい。そこでさらに mini-css-extract-plugin
という Webpack プラグインをかませる。
ビルド手順と使用ツール
ということで、手順と関連しそうなツールを並べると、次のとおり。
- 元の SCSS コードを CSS にトランスパイルする
sass-loader
という Loader でファイルを読み込む- トランスパイル自体は sass パッケージが行う
- CSS コードにベンダプレフィックスを追加する
- PostCSS が間に入り、Autoprefixer が対応する
- Autoprefixer は Browserslist 設定ファイルを参照する
- 生成された CSS コードを Webpack が操作できるようにする
css-loader
- JS ファイル内にバンドルするのではなく、CSS ファイルとして書き出させる
mini-css-extract-plugin
うーむ。何やら色々出てきたな…。Gulp プラグインが大量に必要になるのと同じことが Webpack でも起きている…。
ちなみに、style-loader
という似たような名前の Loader もあるのだが、コチラは JS 内に取り込んだ CSS コードを、HTML 中に style
要素で直接流し込むための Loader。SPA でコンポーネント単位にカプセル化する仕組みに利用したりだとか、用途が異なる。
- 参考 : PostCSS まとめ - Qiita
- 参考 : 入門者/初心者にもわかるwebpackの基礎(Loader編) | アールエフェクト
- 参考 : autoprefixer 基本 - Qiita
Webpack ちからの養い方
何度か出てきている Loader って何やねん、というと、雑に言えば Loader はファイルを扱うプラグイン的なモノ。英語ながら公式サイトに解説がある。
- 参考 : Loaders | webpack
どうやったらそういう Loader があるの分かんねん、というと、公式サイトに各 Loader の解説があるので、コレを読みながら何となく触る。
- 参考 : sass-loader | webpack
- 参考 : css-loader | webpack
- 参考 : style-loader | webpack
必要な Loader・Plugin をインストールする
それでは必要なツール類をインストールしよう。ベースとなるのは前回の記事までで、webpack
と webpack-cli
がインストール済のプロジェクトとする。
$ npm install -D sass sass-loader autoprefixer postcss-loader css-loader mini-css-extract-plugin
package.json
: インストールされたバージョン
"devDependencies": {
"autoprefixer": "9.8.5",
"css-loader": "4.0.0",
"mini-css-extract-plugin": "0.9.0",
"postcss-loader": "3.0.0",
"sass": "1.26.10",
"sass-loader": "9.0.2",
"webpack": "4.44.0",
"webpack-cli": "3.3.12"
}
あぁー多いなぁー。依存パッケージが多くて嫌だなぁー。w
素の CSS を扱ってみる
いきなり全ての Loader や Plugin を使うと混乱するので、順に行こう。
まずは最も基礎となる css-loader
だけを使って、CSS ファイルを JS ファイル内にバンドルしてみる。
次の2ファイルを書いていく。
src/js/main.js
- このファイルがエントリポイントとなるので、このファイルから CSS ファイルに辿り着けるよう、CSS ファイルを
import
してやる - 今回は JS はこの1行だけ
- このファイルがエントリポイントとなるので、このファイルから CSS ファイルに辿り着けるよう、CSS ファイルを
import '../css/main.css';
src/css/main.css
- 中身は適当に
body {
color: red;
}
ソースコードができたら、ビルド設定を次のように記述する。
webpack.config.js
.css
ファイルを見つけたらcss-loader
で処理する、というルールを記述
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/js/main.ts',
output: {
path : path.resolve(__dirname, 'dist/'),
filename: 'js/[name].js'
},
// ↓ 以下を追加
module: {
rules: [
{
test: (/\.css$/u),
use: [
'css-loader'
]
}
]
}
};
コレでビルドしてみると、./dist/js/main.js
の中に、次のような CSS コードが含まれていることが分かるだろう。
o.push([t.i, "body {\n color: red;\n}", ""])
なるほど、css-loader
を使うと、CSS ファイルを読み込んで JS にバンドルできた。
SCSS を変換してみる
次は CSS ではなく SCSS ファイルを変換してみる。
src/js/main.js
import
するファイルを SCSS に変更した
import '../scss/main.scss';
src/scss/main.scss
- 先程とはディレクトリと拡張子が違う
body {
color: red;
p {
color: blue;
}
}
webpack.config.js
- ルール部分を次のように変更する
// .sass・.scss・.css ファイルを対象にする
{
test: (/\.(sa|sc|c)ss$/u),
use: [
'css-loader',
'sass-loader'
]
}
ココで重要なのは、use
配列の順番。Webpack のルールは配列の最後に書いた Loader・Plugin から順に適用される。よって、配列の並びとしては css-loader
が先に来ているが、実際に適用されるのは sass-loder
が最初で、次に css-loader
となる。
このように設定してビルドすると、./dist/js/main.js
の中に、次のような文字列を確認できると思う。
o.push([t.i, "body{color:red}body p{color:blue}", ""])
body p {}
の指定などを見ると、sass-loader
によって SCSS をトランスパイルできていることが分かる。
CSS ファイルを別に出力する
トランスパイルができたので、CSS ファイルを別に書き出すところをやってみる。
ソースコードはそのままに、ビルド設定を書き換える。
webpack.config.js
const path = require('path');
// ↓ 追加
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'production',
entry: './src/js/main.ts',
output: {
path : path.resolve(__dirname, 'dist/'),
filename: 'js/[name].js'
},
// ↓ plugins セクションを追加
plugins: [
new MiniCssExtractPlugin({
filename: '/css/[name].css'
})
],
module: {
rules: [
{
test: (/\.(sa|sc|c)ss$/u),
use: [
MiniCssExtractPlugin.loader, // ← ココに追加
'css-loader',
'sass-loader'
]
}
]
}
};
use
配列の最初に mini-css-extract-plugin
を配置したので、処理順としては最後に適用されることになる。つまり、SCSS を sass-loader
がトランスパイル、それを JS で扱えるよう css-loader
が加工するが、その結果を別ファイルに書き出すということで mini-css-extract-plugin
が働く、という順番だ。
mini-css-extract-plugin
は plugins
セクションで、出力ファイルのパスを設定している。
コレでビルドしてみると、./dist/js/main.js
の中から CSS コードの記述が消え、代わりに ./dist/css/main.css
が出力されていることが分かるだろう。この中身は ./src/scss/main.scss
がトランスパイルされたモノとなる。
PostCSS + Autoprefixer + Browserslist によるベンダプレフィックス付与を試す
ココまでで SCSS のトランスパイルは完璧に出来るようになった。最後に、Autoprefixer をかませてベンダプレフィックスを付与させてみよう。
Autoprefixer をかませるためのツールとして PostCSS (postcss-loader
) が登場し、Autoprefixer がどのベンダプレフィックスを適用すべきかを判断するために、内部で Browserslist を使用する、という関係だ。
src/scss/main.scss
- 古いブラウザではベンダプレフィックスが必要になりそうなコードを書いていく
.container {
box-sizing: border-box;
display: grid;
grid-gap: 1rem;
grid-template: "header header" 1fr
"nav main " minmax(100px, 2fr)
"nav footer" 1fr /
300px 1fr;
header { grid-area: header; }
nav { grid-area: nav ; }
main { grid-area: main ; }
footer { grid-area: footer; }
}
.browserslistrc
- 新規で設定ファイルを作る
- ベンダプレフィックスを適用させるため、今回は古めの IE を対象に入れてみる
> 5%
last 2 versions
Firefox ESR
dead
# IE に対応させる
ie >= 6
postcss.config.js
- コチラも新規で設定ファイルを作る
- ココで Autoprefix を読み込んでおり、さらに CSS Grid 用のベンダプレフィックスを付与させる設定を書いている
// PostCSS 実行時に Autoprefixer を読み込み、Browserslist の指定を利用させる
module.exports = {
plugins: [
require('autoprefixer')({
// CSS Grid に関する対応を入れる (IE 向け)
grid: true
})
]
};
webpack.config.js
{
test: (/\.(sa|sc|c)ss$/u),
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader', // ← 追加。Autoprefixer の指定は postcss.config.js で行う
'sass-loader'
]
}
こんな感じ。いざビルドしてみると、./dist/css/main.css
にベンダプレフィックスが追加されているのが確認できるはずだ。
dist/css/main.css
- 実際は1行にまとめられているが、Beautify をかけて一部抜粋
.container {
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: -ms-grid;
display: grid;
grid-gap: 1rem;
-ms-grid-rows: 1fr 1rem minmax(100px, 2fr) 1rem 1fr;
-ms-grid-columns: 300px 1rem 1fr;
grid-template: "header header"1fr "nav main "minmax(100px, 2fr) "nav footer"1fr/300px 1fr
}
スバラシイ。
.browserslistrc
の内容をいじくったりすると、ベンダプレフィックスの付き方が変わることが確認できるはずだ。
次回に続く
SCSS のトランスパイルと、Autoprefixer による Browserslist の利用はココまで。
次回は ECMAScript や TypeScript を Babel でトランスパイルしてみる。