webpack5でJSとSassをコンパイル(CSSを別ファイルに出力)

webpack5を使ってJavaScriptとSassをコンパイルする方法を記録しておきます。

この記事では、以下の項目をコンパイル条件としています。

  • JavaScriptとCSSを別々のファイルで出力する。
  • 出力先のCSSに自動でベンダープレフィックスを追加する。
  • production(本番環境用に)出力する場合のみコードを圧縮(軽量化)する。
  • development(開発環境用に)出力する場合のみソースマップを出力する。

node.js(npm)のインストール

コンパイルするにはnpmが必要です。npmはnode.jsのパッケージ管理システムなので、まずPCにnode.jsをインストールします。すると同時にnpmもインストールされます。

node.js公式
https://nodejs.org/ja/

npmのセットアップ

node.jsをインストールしたら、npmのセットアップをしておきます。

プロジェクトフォルダ内で以下のコマンド

$ npm init -yes

-yesオプションを付けると、セットアップ項目が全てデフォルトで設定されます。(付けない場合は、項目毎にEnterを押すか入力が必要)

実行すると、プロジェクトフォルダ内に「package.json」というファイルができます。

「package.json」はnpmの設定やインストールパッケージの管理情報が書かれているファイルです。

webpack5のインストール

次にコンパイルツールのwebpackをインストールします。バージョン指定しなければ最新(現時点では5.x系)が入ります。

$ npm install --save-dev webpack

-g:グローバルインストール
–save-dev:プロジェクト単位インストール(-D でも可)

実行すると、プロジェクトフォルダ内に「package-lock.json」というファイルと「node_modules」というフォルダができます。

webpack-cliのインストール

webpack5を使うためには必須。

$ npm install --save-dev webpack-cli

必要なパッケージのインストール

ここでコンパイルに必要なパッケージのインストールをしていきます。

不要なパッケージはスキップ、追加したいパッケージがあれば追加しても良いですが、今回は、冒頭で書いた内容でのコンパイルを目指しているので、パッケージが変わると、この後の工程で出てくる「webpack.config.js」への記入内容が変わってくるのでご注意ください。

css-loader

CSSファイルをJS用モジュールにコンパイルするパッケージ。

$ npm install --save-dev css-loader

sass-loader

Sass / SCSSファイルをロードし、CSSにコンパイルするパッケージ。sassも一緒にインストール。

$ npm install --save-dev sass-loader sass

postcss-loader

「PostCSS」を使ってsassをコンパイルするためのパッケージ。なので「PostCSS」も同時にインストールする。今回は自動でベンダープレフィックスを付けるための「autoprefixer」用に使用します。

$ npm install --save-dev postcss-loader postcss

MiniCssExtractPlugin

JS内に内包されたCSSを抽出して別ファイルとして出力するプラグイン。このプラグインを使用しない場合は、通常JS内にCSS情報が書き込まれる。その場合、CSSとしてHTML上で機能させるためには、「style-loader」というパッケージが必要。今回は別出力するので「style-loader」は使用しない。

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

webpack-fix-style-only-entries

「MiniCssExtractPlugin」を使ってCSSファイルを出力する際に、一緒に出力されてしまう不要なJSファイル(MiniCssExtractPluginのバグ?)を削除してくれるプラグイン。

$ npm install --save-dev webpack-fix-style-only-entries

autoprefixer

sassをコンパイルする際にベンダープレフィックスを自動で付与してくれる。postcss-loaderのプラグイン。

$ npm install --save-dev autoprefixer

Clean plugin for webpack

出力先のフォルダ内のファイルを一旦きれいに(削除)してくれるプラグイン。開発用に書き出されたソースマップファイルを本番コンパイル時には削除したい場合などに便利。

$ npm install --save-dev clean-webpack-plugin

webpack.config.jsの確認

以上のパッケージやプラグインをインストールしたら、「webpack.config.js」を確認してみましょう。以下のようにインストールパッケージのリストが書き込まれているはずです。

{
  "name": "myapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^10.3.1",
    "clean-webpack-plugin": "^4.0.0-alpha.0",
    "css-loader": "^6.2.0",
    "mini-css-extract-plugin": "^2.1.0",
    "postcss": "^8.3.6",
    "postcss-loader": "^6.1.1",
    "sass": "^1.35.2",
    "sass-loader": "^12.1.0",
    "webpack": "^5.45.1",
    "webpack-cli": "^4.7.2",
    "webpack-fix-style-only-entries": "^0.6.1"
  }
}

エントリーポイント(コンパイル元)と出力先フォルダを作成

一般的にコンパイル元のフォルダとして「src」、出力先フォルダとして「dist」という名前にするのが一般的です。今回はその中にさらに「js」「sass」や「css」というフォルダを作成してみます。全体のファイル構成は以下の通り。「dist」フォルダは作らなくてもコンパイル時に作成されます。

[プロジェクトフォルダ]
     ├dist/
       ├ js/
       └ css/
     ├node_modules/
     ├src/
       ├ js/
       └ sass/
     ├ package.json
     ├ package-lock.json
     ├ postcss.config.js
     └ webpack.config.js

上記の図にまだないファイルが2つありますね。次に「postcss.config.js」と「webpack.config.js」を作っていきます。

webpack.config.jsの作成

「webpack.config.js」はコンパイルの仕方などを記した設定ファイルです。今回の記事と同じ条件でコンパイルする場合は、以下の内容をそのままコピペで問題ありません。

const webpack = require('webpack');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');


module.exports = {
    // コンパイルモード
    mode: 'production',
    // エントリーポイントの設定
    entry: {
         // コンパイル対象のファイルを指定
        'index': path.resolve(__dirname, "./src/js/index.js"),
        'index.css': path.resolve(__dirname, './src/sass/index.scss')
    },
    // 出力設定
    output: {
        path: path.resolve(__dirname, './dist/'), // 出力先フォルダを絶対パスで指定
        filename: 'js/[name].js' // [name]にはentry:で指定したキーが入る
    },
    module: {
        rules: [
            // sassのコンパイル設定
            {
                test: /\.(sa|sc|c)ss$/, // 対象にするファイルを指定
                use: [
                    MiniCssExtractPlugin.loader, // JSとCSSを別々に出力する
                    'css-loader',
                    'postcss-loader', // オプションはpostcss.config.jsで指定
                    'sass-loader',
                    // 下から順にコンパイル処理が実行されるので、記入順序に注意
                ]
            }
        ]
    },
    plugins: [
        // 出力先のフォルダを一旦空に
        new CleanWebpackPlugin({
            // 対象ファイル指定
            cleanOnceBeforeBuildPatterns: [ // 複数ある場合は配列で指定
                '**/*', // 出力フォルダ(output: で指定したパス)内のすべてのファイル
            ],
        }),
        new FixStyleOnlyEntriesPlugin(), // CSS別出力時の不要JSファイルを削除
        new MiniCssExtractPlugin({ // CSSの出力先
            filename: 'css/[name]'// 出力ファイル名を相対パスで指定([name]にはentry:で指定したキーが入る)
        }),
    ],
    // node_modules を監視(watch)対象から除外
    watchOptions: {
        ignored: /node_modules/
    }
};

postcss.config.jsの作成

こちらは、PostCSS用の設定ファイルです。「webpack.config.js」内にpostcss-loaderのオプションとして記入することもできますが、今回は別ファイルで作成してみます。postcss-loaderは自動的にこのファイルを読みにいってくれます。autoprefixerをプラグインとして読み込んでいます。こちらも同条件ならコピペでOK。

postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')({ // 自動でベンダープレフィックスを付与
            "overrideBrowserslist": [ // 対象ブラウザの設定
                "last 2 versions",
                "ie >= 11",
                "Android >= 4"
            ]
        })
    ]
};

コンパイル

コンパイルしたいjsファイルとsassファイルを用意します。今回「webpack.config.js」のentry:に記載した例では、以下の場所にそれぞれコンパイル用ファイルを用意する必要があります。変更する場合は、entry:を書き換えてください。

src/js/index.js
src/sass/index.scss

以上でコンパイルする準備が整いました。以下のコマンドでコンパイルしてみましょう。

$ npx webpack

「dist」フォルダにコンパイルされたjsファイルやcssファイルが出力されていれば成功です。

package.jsonのカスタマイズ

「package.json」をカスタマイズすることで、オリジナルのコマンドを作成することができます。例えば、"scripts":のところへ以下のように追記します。

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "prod": "webpack --mode production",
    "dev": "webpack --mode development --devtool=source-map",
    "watch": "webpack --mode development --watch"
  },

上記の場合、以下のようなコマンドで様々なコンパイルを実行できるようになります。

コマンド コンパイル内容
$ npm run build デフォルトの設定でコンパイル。
$ npm run prod 本番環境用に出力。
$ npm run dev 開発環境用に出力。ソースマップも出力。
$ npm run watch エントリーポイントのファイルを監視して、変更があれば自動でコンパイル。

メモ

最初に記載した今回のコンパイル条件の中に、「production(本番環境用に)出力する場合のみコードを圧縮(軽量化)する。」という項目がありますが、こちらは特にプラグインを使用せずともwebpackが対応してくれます。webpack5から追加された機能とのこと。webpack4の場合は、「Optimize CSS Assets Webpack Plugin」というプラグインで対応可能。

Optimize CSS Assets Webpack Plugin

「cssnano」を使用してCSSファイルを圧縮、最適化して出力してくれるwebpack4用プラグイン。

$ npm install --save-dev css-minimizer-webpack-plugin

webpack5の場合は、代わりに「CssMinimizerWebpackPlugin」を使う。しかしwebpack5でこれを入れるとJavaScriptの方の圧縮が解除されてしまうので、JavaScript圧縮用のプラグインも同時使用する必要がある。例えば、「TerserWebpackPlugin」など。そもそもwebpack5は標準で圧縮してくれるのでこれらのプラグインは不要ですよね。。。