npm script で SCSS をコンパイルしてたのだけれど、環境変数や変数展開などを多用していたら Windows 環境でエラーになりビルド出来ない問題続出してメンテコストが高くなってしまいそうだったので、ざっくり webpack で CSS だけビルドする設定を作成下のメモ
環境
- webpack v5.60.0
install packages
# webpack $ npm i -D webpack webpack-cli css-loader # Sass $ npm i -D sass sass-loader # postCSS $ npm i -D postcss postcss-loader autoprefixer cssnano # plugin $ npm i -D mini-css-extract-plugin webpack-remove-empty-scripts
Plugins
- mini-css-extract-plugin … CSS をファイルとして出力する
- webpack-remove-empty-scripts … entrypoint に CSS を指定した場合に空の js を出力しないようにする
ターゲットブラウザを browserslist で指定する
ターゲットブラウザは browserslist.dev で確認するのが便利。
package.json に browserslist
プロパティで指定する
{ … "browserslist": [ "last 2 versions", "> 1%", "not dead" ] }
webpack.config.js
// webpack.config.js const path = require("path"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const RemoveEmptyScriptsPlugin = require("webpack-remove-empty-scripts"); const sass = require("sass"); const cssnano = require("cssnano"); const autoprefixer = require("autoprefixer"); const MODE = process.env.MODE || process.env.NODE_ENV || "development"; const ENABLED_SOURCEMAP = MODE === "development"; const TARGET_DIR = path.resolve(__dirname, '/path/to/src'); const DIST_DIR = path.resolove(__dirname, 'path/to/build'); module.exports = { mode: MODE, target: ["web", "es5"], // development の時だけ差分をビルドする cache: MODE === "development", entry: { // scss をエントリーポイントに指定できる css: `${TARGET_DIR}/scss/styles.scss`, }, output: { path: DIST_DIR, filename: "js/[name].js", }, module: { rules: [ { test: /\.s(c|a)ss$/i, use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: { // url() を require() に変換しない url: false, // development の時だけ source map を出力する sourceMap: MODE === "development", // css-loader の前に loader を 2つ (postcss, sass) 実行する importLoaders: 2, }, }, { loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ cssnano, { // コメントを削除する preset: [ "default", { discardComments: { removeAll: true } }, ], }, ], [autoprefixer, { grid: true }], ], }, }, }, { loader: "sass-loader", options: { // dart-sass を使用する implementation: sass, }, }, ], }, ], }, plugins: [ // /js/css.js を出力しない new RemoveEmptyScriptsPlugin(), new MiniCssExtractPlugin({ // `${DIST_DIR}/css/styles.css` として出力される filename: "css/styles.css", }), ], }
※ 今回はエントリーポイントの JS が無いので HTML をホットリロード (HMR) 関連の設定はしていません。
ビルドコマンドの作成
npm script から環境変数を渡す際の OS 間の差異を吸収するパッケージをインストール
$ npm i -D cross-env
package.json
{ "scripts": { "build:prod": "cross-env MODE=production webpack", "build:dev": "webpack", "dev": "webpack --watch --progress" } }
👇 ビルド
# production mode でビルド $ npm run build:prod # 変更を監視して自動ビルド $ npm run dev
所管
環境ってそう何度も作るものじゃないから毎回なんだったっけ?ってなる。webpack のドキュメントが充実しているのは本当に助かりました。
実は当初は esbuild で環境を作っていたのですが、まだ Sass をエントリーポイントに出来ないっぽかったので、 JS 以外もエントリーポイントに出来たので今回は webpack で作成しました。 esbuild 周りもまたちゃんとやって書きたいデス。(環境づくりばかりしてるな…)
[参考]
- webpack
- mini-css-extract-plugin - npm
- webpack-remove-empty-scripts - npm
- Entry Points | webpack
- Target | webpack
- Watch and WatchOptions | webpack
- Cache | webpack
- Browserslist
- 最新版で学ぶwebpack 5入門 - スタイルシート(CSS/Sass)を取り込む方法 - ICS MEDIA
- webpackでSass(SCSS)をCSSにコンパイルする最もシンプルな方法
- webpack を使って Sass をコンパイルする方法
- cross-env - npm
esbuild
CSS はエントリーポイントできるようになったけど、Sass (SCSS) はまだできないっぽい。
- https://www.npmtrends.com/@babel/core-vs-esbuild-vs-parcel-vs-rollup-vs-snowpack-vs-webpack
- [Web フロントエンド] esbuild が爆速すぎて webpack / Rollup にはもう戻れない - 株式会社カブク | 株式会社カブク
- ABEMAにesbuildを導入してWebのバンドル処理を69倍高速化した話 | CyberAgent Developers Blog
- esbuild - An extremely fast JavaScript bundler
- [MVP] Bundle CSS modules · Issue #20 · evanw/esbuild · GitHub
- Plugin onTransform API · Issue #647 · evanw/esbuild · GitHub