webpack で CSS を import すると「You may need an appropriate loader」で失敗する
webpack が既定で解釈できるのは JavaScript と JSON だけで、CSS はローダーを通さないと構文エラーになる。css-loader と style-loader を module.rules に登録し、適用順が右から左であることを踏まえて並べれば解決する。
公開:
要約
Module parse failed: Unexpected token と You may need an appropriate loader to handle this file type は、webpack が CSS ファイルを JavaScript として読もうとして失敗したという意味です。
webpack が追加設定なしで解釈できるのは JavaScript と JSON だけです。
それ以外の形式は、ローダーを経由して JavaScript が扱える形へ変換する必要があります。
CSS の場合は css-loader がその役目を担います。
エラーメッセージに出ているファイル名が CSS なら、原因はほぼ設定漏れです。
よくある原因
- ローダー自体を設定していない。
パッケージをインストールしただけでは何も起きません。module.rulesに書いて初めて適用されます。 useの並びが逆になっている。
webpack はローダーを配列の後ろから前へ適用するため、["css-loader", "style-loader"]と書くとstyle-loaderが生の CSS を受け取って失敗します。testの正規表現が実ファイルに一致していない。/\.css$/だけを書いて.scssを import している場合などです。- 設定ファイルが読まれていない。
webpack.prod.jsのような別名にしているのに--configを付け忘れると、webpack は既定の設定で動きます。
解決策
1. ローダーを入れて rules に登録する
npm install --save-dev style-loader css-loader// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
};css-loader が @import や url() を解決して JavaScript のモジュールに変換し、style-loader がそれを実行時に <style> として DOM へ挿入します。
役割が分かれているので、両方が要ります。
2. 適用順を間違えない
use の配列は 後ろから前へ 適用されます。
読む順ではなく、通す順が逆になる点が混乱の元です。
// 正しい: css-loader → style-loader の順に通る
use: ["style-loader", "css-loader"]
// 誤り: style-loader が CSS 原文を受け取り、同じエラーが続く
use: ["css-loader", "style-loader"]Sass を使う場合も同じ考え方で、変換の起点になるローダーを配列の末尾に置きます。
use: ["style-loader", "css-loader", "sass-loader"]3. 本番ビルドは別ファイルに切り出す
style-loader は CSS を JavaScript バンドルに埋め込むため、本番では初回描画までスタイルが当たりません。
ファイルとして出したい場合は mini-css-extract-plugin に差し替えます。
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module: {
rules: [
{ test: /\.css$/i, use: [MiniCssExtractPlugin.loader, "css-loader"] },
],
},
plugins: [new MiniCssExtractPlugin()],
};4. どのファイルで落ちたかを読む
エラー本文には対象ファイルのパスが必ず出ます。
それが CSS ではなく画像やフォントなら、必要なのは css-loader ではなく Asset Modules の設定です。
同じメッセージでも足りていないローダーは違うので、まずパスを確認してください。