webpack を使って Sass をコンパイルする方法
Sass を webpack を使ってコンパイルする方法の覚書です。webpack は JavaScript だけではなく、CSS や Sass をバンドルすることができます。
webpack 5 で新しく導入された Asset Modules など内容を version 5 に合わせて書き換えました。また、PostCSS Preset Env の使い方も追加しました(2022年1月5日)。
以下は Node.js がインストールされていることを前提にしています。また、主なパッケージのバージョンは以下になります(環境は Mac での例になります)。
- sass(dart-sass):1.45.2
- webpack:5.65.0
- webpack-cli:4.9.1
- webpack-dev-server:4.7.2
- node: 16.13.2
- npm: 8.1.2
作成日:2020年11月9日
関連ページ:
webpack のインストール
webpack は Node.js のパッケージマネージャ npm を使ってインストールすることができます。
この例では作業ディレクトリ(myProject)を作成し、そこへローカルインストールを行います。
作業用フォルダーを任意の場所に作成しそこに cd で移動します。
以下では mkdir でフォルダを作成していますが、右クリックから「新規作成」などでも OK です。
$ mkdir myProject return //フォルダーを任意の場所に作成 $ cd myProject return //作成したフォルダー(ディレクトリ)に移動
npm を使ってインストールする場合、まず npm init コマンドで package.json を生成します。デフォルトのオプションで package.json を生成すれば良いので -y オプションを指定します。
$ npm init -y return //package.json をデフォルトで生成 //生成された package.json のパスと内容が表示される Wrote to /Applications/MAMP/htdocs/myProject/package.json: { "name": "myProject", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
続いて npm install コマンドで webpack をインストールします。
webpack 4.0以降では、コマンドライン操作用のパッケージは webpack-cli という別パッケージで提供されているので併せてインストールします。
オプションの -D(または --save-dev)は開発環境で使うパッケージ(バンドルにのみ使用し、本番ビルドに含めない場合)に指定するオプションです。
以下のようにバージョンを指定しないでパッケージをインストールすると最新版がインストールされます。
$ npm install -D webpack webpack-cli return //webpack と webpack-cli をインストール added 119 packages, and audited 120 packages in 5s
インストールが完了すると、インストールされたパッケージは node_modules というフォルダに保存され、package.json 及び package-lock.json という npm の設定ファイルが更新されます。
以下は tree コマンドで myProject 内のディレクトリやファイルを表示する例です。
$ tree -L 2 return //ツリー表示 . ├── node_modules //npm でインストールされるパッケージのディレクトリ │ ├── @discoveryjs │ ├── @types │ ├── @webassemblyjs │ ├── @webpack-cli │ │ ・・・中略・・・ │ │ ├── webpack │ ├── webpack-cli │ ├── webpack-merge │ ├── webpack-sources │ ├── which │ └── wildcard ├── package-lock.json //npm の設定ファイル └── package.json //npm の設定ファイル
インストールされた webpack と webpack-cli のバージョンは npx コマンドに -v(または --version )オプションを指定して webpack を実行して確認できます。
$ npx webpack -v webpack: 5.65.0 webpack-cli: 4.9.1 webpack-dev-server not installed
webpack guides: installation
関連ページ:
初期構成の作成
初期構成として以下のようなフォルダとファイルを作成します。
ビルドを実行するとデフォルトでは src フォルダのファイルがコンパイルされて dist フォルダに出力されます(dist フォルダは作成しなくても自動的に生成されます)。
myProject ├── dist //ビルド時に自動的に生成されるフォルダ ├── index.html //追加した HTML ファイル(表示用) ├── node_modules ├── package-lock.json ├── package.json └── src //追加したフォルダ ├── index.js //追加した Javascript ファイル(エントリーポイント) └── style.scss //追加した Sass ファイル
エントリーポイントの index.js では import を使って同じ src フォルダの Sass ファイル(style.scss)を読み込みます。
// スタイルシート(Sass)を読み込む import './style.scss';
Sass ファイルには確認用に Sass 変数を使った設定を記述しています。
$p_color: green; $p_bg_color: yellow; p { color: $p_color; background-color: $p_bg_color; }
index.html では Sass がコンパイルされて出力される dist フォルダの CSS(style.css まだこの時点では存在しない)を読み込みます。
MiniCssExtractPlugin というプラグインを使うと CSS をバンドルせずに(CSS を抽出して別ファイルとして) dist フォルダに出力することができます。この例では style.css という名前で CSS ファイルを出力します。
この例では Javascript ファイルはバンドルしませんが、Javascript もバンドルする場合は dist フォルダに main.js というファイルが出力されるのでそれを読み込みます。以下ではコメントアウトしています。
<!doctype html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="dist/style.css"> <title>Sass 読み込みサンプル</title> </head> <body> <div class="sass_sample"> <h1>Sass</h1> <p>sample text.</p> </div> <!--<script src="dist/main.js"></script>--> </body> </html>
ローダーとプラグインのインストール
- css-loader:CSSの @import や url() を JavaScript の import や require() に変換するモジュール
- sass-loader:Sass を CSS へ変換するためのモジュール
- sass:Sass をコンパイルするためのモジュール(Dart Sass)
- MiniCssExtractPlugin:CSS を別ファイルとして出力するためのプラグイン
Sass のモジュールは sass(Dart Sass)を使用しています。LibSass(Node Sass)は将来的には非推奨になるようです(LibSass is Deprecated)。
この例では MiniCssExtractPlugin.loader を使って CSS を別ファイルとして出力していますが、MiniCssExtractPlugin.loader を使わずに、style-loader をインストールして JavaScript から style 要素を生成して CSS を head 要素に挿入することもできます。
npm install コマンドに -D(または --save-dev) オプションを指定してモジュールとプラグインをインストールします。
$ npm install -D css-loader sass-loader sass mini-css-extract-plugin return added 44 packages, and audited 164 packages in 3s
上記インストールを実行後、package.json を確認すると devDependencies にインストールしたモジュールとプラグインがリストされています。
{ "name": "myproject", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1" } }
main の指定はパッケージを NPM で公開しない場合は不要なので、main の行(5行目)を削除し、プロジェクトを誤って公開しないようにするため "private": true を追加します。
description にはプロジェクトの説明などを記述しても良いですし、削除して問題ありません。keywords や author、license も削除しても問題ありません。
{ "name": "myproject", "version": "1.0.0", "description": "", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1" } }
fibers
オプションで fibers というパッケージをインストールすることができます。
fibres を使用することでコンパイルの速度を速くすることができるようです(※注)。以下は sass-loader からの抜粋です(webpack の sass-laoder にも同じことが記述されています)。
sass(Dart Sass)を使用する場合、非同期コールバックのオーバーヘッドのため、同期コンパイルはデフォルトで非同期コンパイルの2倍の速度であることに注意してください。 このオーバーヘッドを回避するために、fibres パッケージを使用して、同期コードパスから非同期インポーターを呼び出すことができます。
※注
但し fibres のページには「廃止の注意-このプロジェクトの作者は、可能であればその使用を避けることをお勧めします」とあり、また、「node.js の v16.0.0 以降と互換性がありません」とも書かれています。
そのため、node.js の v16.0.0 以降を使う場合は sassOptions で fiber: false を指定して使用しないようにする必要があります。このサンプルの場合、node.js のバージョンは 16.12.0 なので fibers はインストールしていません。
webpack.config.js
webpack の設定ファイル webpack.config.js を作成します。
myProject ├── dist ├── index.html ├── node_modules ├── package-lock.json ├── package.json ├── src │ ├── index.js │ └── style.scss └── webpack.config.js // webpack 設定ファイルを追加
以下が大まかなローダーの処理の流れです。
- sass-loader を使って Sass を CSS へ変換
- css-loader で CSS を JavaScript に変換
- MiniCssExtractPlugin.loader で CSS を 抽出して別ファイルとして出力
指定する際は、MiniCssExtractPlugin.loader, css-loader, sass-loader の順に指定し、後ろから順番(sass-loader → css-loader → MiniCssExtractPlugin.loader の順)に適用されます。
以下は このサンプルの webpack.config.js の例です。
//path モジュールの読み込み const path = require('path'); //MiniCssExtractPlugin の読み込み const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { //エントリポイント(デフォルトと同じなので省略可) entry: './src/index.js', //出力先(デフォルトと同じなので省略可) output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ //SASS 及び CSS 用のローダー { //拡張子 .scss、.sass、css を対象 test: /\.(scss|sass|css)$/i, // 使用するローダーの指定(後ろから順番に適用される) use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ], }, ], }, //プラグインの設定 plugins: [ new MiniCssExtractPlugin({ // 抽出する CSS のファイル名 filename: 'style.css', }), ], //source-map タイプのソースマップを出力 devtool: 'source-map', // node_modules を監視(watch)対象から除外 watchOptions: { ignored: /node_modules/ //正規表現で指定 }, };
MiniCssExtractPlugin
MiniCssExtractPlugin はプラグインなので require() を使って別途読み込む必要があります(4行目)。
また、plugins プロパティに new 演算子で MiniCssExtractPlugin プラグインのインスタンスを生成し、引数に filename プロパティで出力される CSS のファイル名を指定します(27〜32行目)。
devtool
css-loader には CSS のソースマップを有効にするオプション sourceMap がありますが、sourceMap のデフォルトの値(有効かどうかの真偽値)は devtool の設定に依存します。
この例では devtool オプションに source-map を指定して CSS のソースマップも有効にしています(34行目)。JavaScript もバンドルされていればそれらのソースマップも有効になります。
watchOptions
watch オプションを指定して処理対象のファイルを監視する場合に、watchOptions で node_modules ディレクトリを監視対象から除外するように指定しています(36〜38行目)。
sass-loader implementation オプション
sass-loader の implementation オプションは使用する Sass の実装(Dart Sass か LibSass)を決定します。デフォルトでは、ローダーは依存関係に基づいて実装を解決するので、package.json に記述されている実装(sass なら Dart Sass、node-sass なら LibSass)を使用します。
但し、sass と node-sass の両方のモジュールがインストールされている場合は、sass-loader は sass (Dart Sass) を選択しますが、implementation オプションを使って以下のように明示的に sass (Dart Sass) を使用するように指示することもできます。
// Sass ローダー { loader: 'sass-loader', options: { // ローダーに dart-sass を使用することを明示的に指定 implementation: require('sass'), }, },
npm script
package.json の scripts フィールドにコマンド(npm script)を追加して npm run コマンドで webpack を実行できるようにしておきます。
以下では build(ビルド)、dev(開発モード)、watch(監視モード)及び sass-ver(Sass のバージョン表示) のコマンドを追加しています。
{ "name": "myproject", "version": "1.0.0", "description": "", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1" } }
以下は Sass のバージョンを表示する例です。
$ npm run sass-ver return > myproject@1.0.0 sass-ver > sass --version 1.45.2 compiled with dart2js 2.15.1
ビルド
npm script に登録した build コマンド(npm run build)を実行するとビルド時に Sass を CSS に変換して出力することができます。
上記を実行すると、dist フォルダに Sass ファイル(style.scss )がコンパイルされた CSS ファイル style.css が出力されます。
main.js という Javascript ファイルが出力されますが、この例ではエントリポイント(index.js)で Sass を読み込んでいるだけなので、main.js は空のファイルになります。
また、ソースマップを有効にしているので、style.css.map や main.js.map も生成されます。
myProject ├── dist //ビルド時に自動的にコンパイルやバンドルされたファイルが出力されるビルドディレクトリ │ ├── main.js │ ├── main.js.map //ソースマップファイル(main.js が空の場合は出力されない) │ ├── style.css │ └── style.css.map //ソースマップファイル ├── index.html ├── node_modules ├── package-lock.json ├── package.json ├── src │ ├── index.js │ └── style.scss └── webpack.config.js
npm run build
build コマンド(npm run build)の場合、style.css は以下のように outputStyle は compressed で出力されます。
p{color:green;background-color:#ff0} /*# sourceMappingURL=style.css.map*/
npm run dev
dev コマンド(npm run dev)の場合、style.css は以下のようにコメントと共に outputStyle は expanded で出力されます。
/*!***********************************************************************!*\ !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./src/style.scss ***! \************************************************************************/ p { color: green; background-color: yellow; } /*# sourceMappingURL=style.css.map*/
npm run watch
watch コマンド(npm run watch)を実行すると、処理対象のファイルを監視してファイルが変更されると自動的に dvelopment モードでリビルド(再コンパイル)します。
dvelopment モードでリビルドするのは npm script で "watch": "webpack --mode development --watch" と登録しているためです。
watch モードを終了するには control + c を押します。
$ npm run watch return
CSS の画像
CSS で画像を読み込む設定をしている場合、v5 では新しく組み込まれた Asset Modules により画像がロードされるようになっています。
例えば、style.scss(Sass)を以下のように背景画像(background-image)を使うように変更し、src フォルダの中に images フォルダを作成してその中に画像を配置します。
$p_color: green; $p_bg_color: yellow; p { color: $p_color; background-color: $p_bg_color; } div { /* 背景画像を指定 */ background-image: url("./images/sample.jpg"); background-size: cover; padding: 30px; max-width: 640px; }
myProject ├── index.html ├── node_modules ├── package-lock.json ├── package.json ├── src │ ├── images │ │ └── sample.jpg //background-image で使う背景画像を配置 │ ├── index.js │ └── style.scss //背景画像のスタイルを追加 └── webpack.config.js
npm run build や npm run dev などでビルドを実行します。
$ npm run dev return > myproject@1.0.0 dev > webpack --mode development asset 98c94d5ec5a800ed1bf8.jpg 192 KiB [emitted] [immutable] [from: src/images/sample.jpg] (auxiliary name: main) //画像が出力される asset main.js 2.41 KiB [emitted] (name: main) 1 related asset asset style.css 542 bytes [emitted] (name: main) 1 related asset Entrypoint main 2.94 KiB (194 KiB) = style.css 542 bytes main.js 2.41 KiB 3 auxiliary assets orphan modules 4.87 KiB (javascript) 192 KiB (asset) 1.02 KiB (runtime) [orphan] 10 modules runtime modules 274 bytes 1 module cacheable modules 122 bytes (javascript) 251 bytes (css/mini-extract) ./src/index.js 72 bytes [built] [code generated] ./src/style.scss 50 bytes [built] [code generated] css ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/style.scss 251 bytes [built] [code generated] webpack 5.65.0 compiled successfully in 433 ms
出力先の dist フォルダには style.css などの他に background-image に指定した画像がコピーされて出力されます。
myProject ├── dist //ビルド時に自動的に出力されるビルドディレクトリ │ ├── 98c94d5ec5a800ed1bf8.jpg //背景画像が出力される │ ├── main.js │ ├── main.js.map │ ├── style.css │ └── style.css.map ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── images │ │ └── sample.jpg │ ├── index.js │ └── style.scss └── webpack.config.js
コンパイルされて出力された style.css を確認すると以下のようにコピーされた画像が設定されています。
コピーして出力される画像のファイル名(デフォルトはハッシュ値)や出力先などは Asset Modules のオプションで設定できます。
p { color: green; background-color: yellow; } div { background-image: url(98c94d5ec5a800ed1bf8.jpg); /* コピーされた画像 */ background-size: cover; padding: 30px; max-width: 640px; }
Asset Modules
webpack のバージョン4 までは画像などのアセットファイルを読み込むには url-loader や file-loader などの追加のローダーをインストールして設定する必要がありましたが、version 5 からは Asset Modules が導入され、デフォルトで画像などのアセットファイルを扱えるようになっています。
version 5 では url-loader や file-loader、raw-loader は非推奨になっていて、代わりに Asset Modules を使うことが推奨されています。
以下は Asset Modules の設定を追加した webpack.config.js の例です。
15行目では出力先及びコピーして出力されるファイル名を指定しています(出力先の変更)。
29行目では対象とするアセットファイルの拡張子を正規表現で指定し、31行目で type に asset/resource を指定して、画像などのアセットファイルをコピーして出力先に指定しているディレクトリに出力するようにしています。
//path モジュールの読み込み const path = require('path'); //MiniCssExtractPlugin の読み込み const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { //エントリポイント(デフォルトと同じなので省略可) entry: './src/index.js', //出力先 output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), //Asset Modules の出力先の指定 assetModuleFilename: 'images/[name][ext][query]' }, module: { rules: [ //SASS 及び CSS 用のローダー { //拡張子 .scss、.sass、css を対象 test: /\.(scss|sass|css)$/i, // 使用するローダーの指定 use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ], }, //Asset Modules の設定 { //対象とするアセットファイルの拡張子を正規表現で指定 test: /\.(png|svg|jpe?g|gif)$/i, //画像をコピーして出力 type: 'asset/resource' }, ], }, //プラグインの設定 plugins: [ new MiniCssExtractPlugin({ // 抽出する CSS のファイル名 filename: 'style.css', }), ], //source-map タイプのソースマップを出力 devtool: 'source-map', // node_modules を監視(watch)対象から除外 watchOptions: { ignored: /node_modules/ //正規表現で指定 }, };
上記のように webpack.config.js を変更してビルドすると、画像ファイルは dist/images に元の画像ファイルと同じ名前でコピーされて出力されます。
myProject ├── dist │ ├── images │ │ └── sample.jpg //ビルドでコピーされて出力される画像ファイル │ ├── main.js │ ├── main.js.map │ ├── style.css │ └── style.css.map ├── index.html ├── package-lock.json ├── package.json ├── src │ ├── images │ │ └── sample.jpg //背景画像のファイル │ ├── index.js │ └── style.scss └── webpack.config.js
コンパイルされて出力された style.css を確認すると以下のようにコピーされた画像が設定されています。
p { color: green; background-color: yellow; } div { background-image: url(images/sample.jpg); /* コピーされた画像 */ background-size: cover; padding: 30px; max-width: 640px; }
Asset Modules は画像以外にもフォントなどのファイルに使用できます(関連:フォントのロード)。
ソースマップの出力の制御
以下は環境変数 NODE_ENV を使って production モードと development モードでソースマップの出力を変更する例です。
webpack を実行する際に、NODE_ENV にパラメータとして production または development を渡して webpack.config.js で process.env.NODE_ENV の値を取得してモードを判定します。
この例では以下のように package.json の scripts フィールドに NODE_ENV を指定したビルドコマンド(npm script)を追加します(3行目)。
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "NODE_ENV=production webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version" },
{ "name": "myproject", "version": "1.0.0", "description": "", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "NODE_ENV=production webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1" } }
webpack.config.js で以下のように変数 devMode を定義することで、右辺(process.env.NODE_ENV !== 'production')が評価され production モード以外の場合は devMode は true になります(6行目)。
そして devtool の設定で devMode の値を判定し、production モード以外の場合は source-map タイプのソースマップを指定します(45行目)。
devtool オプションに eval を指定すると、production モードではソースマップは出力されません。
//path モジュールの読み込み const path = require('path'); //MiniCssExtractPlugin の読み込み const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //変数 devMode は production モードの場合は false でその他の場合は true const devMode = process.env.NODE_ENV !== 'production'; module.exports = { //エントリポイント(デフォルトと同じなので省略可) entry: './src/index.js', //出力先 output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), //Asset Modules の出力先の指定 assetModuleFilename: 'images/[name][ext][query]' }, module: { rules: [ //SASS 及び CSS 用のローダー { //拡張子 .scss、.sass、css を対象 test: /\.(scss|sass|css)$/i, // 使用するローダーの指定 use: [ MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ], }, //Asset Modules の設定 { //対象とするアセットファイルの拡張子を正規表現で指定 test: /\.(png|svg|jpe?g|gif)$/i, //画像をコピーして出力 type: 'asset/resource' }, ], }, //プラグインの設定 plugins: [ new MiniCssExtractPlugin({ // 抽出する CSS のファイル名 filename: 'style.css', }), ], //production モード以外の場合は source-map タイプのソースマップを指定 devtool: devMode ? 'source-map' : 'eval', // node_modules を監視(watch)対象から除外 watchOptions: { ignored: /node_modules/ //正規表現で指定 }, };
上記の設定と package.json に指定した npm script により、npm run build を実行するとソースマップファイルは生成されず、npm run dev または npm run watch を実行するとソースマップファイルが生成されます。
CSS や Sass のソースマップの設定はそれぞれのローダーの sourceMap オプションを使って指定することもできます(CSS のソースマップ)。
output.clean
output.clean オプションを使うと、ビルドの実行前に出力先の dist フォルダーをクリーンアップして、実際に使用しているファイルのみが生成されるようにすることができます(version 5.20.0 以上)。
例えば、前述のようにソースマップの出力をモードにより変更している場合、npm run build を実行するとソースマップファイルは生成されませんが、それ以前に npm run dev または npm run watch を実行して生成されたソースマップファイルはそのまま dist フォルダに残っています。
以下は output の clean に true を指定して、ビルドする前に出力先の dist フォルダー内をクリーンアップ(ファイルをすべて削除)してから、新たにファイルを出力するようにする例です(17行目)。
※ 単純に clean: true を指定すると、ビルド実行前に出力先フォルダ(ビルドディレクトリ)内のすべてのファイルが削除されます。手動で配置したファイルなども削除されてしまうので、必要に応じて keep オプションを使ってファイルやディレクトリを削除の対象から除外することができます。
postCSS
必要に応じて postCSS のプラグイン(モジュール)をインストールして利用することができます。
postCSS のモジュールを利用するには postcss-loaderと postcss をインストールする必要があります。
プラグイン | 説明 |
---|---|
PostCSS Preset Env | 後方互換性を持って変換及びベンダープレフィックスを付与 |
CSS Declaration Sorter | CSS プロパティをソート |
PostCSS Sort Media Queries | メディアクエリをまとめる |
PostCSS Preset Env
PostCSS Preset Env は CSS の新しい仕様を後方互換性を持ってフォールバック(変換)するプラグインで、JavaScript での Babel の babel/preset-env のようなものです。
また、PostCSS Preset Env には Can I use を参照し CSS プロパティに自動でベンダープレフィックスを付与する機能(Autoprefixer)も含まれています。
以下は PostCSS Preset Env を利用する例です。
postcss-loader と postcss、postcss-preset-env をインストールします。
$ npm install -D postcss-loader postcss postcss-preset-env return added 60 packages, and audited 224 packages in 4s
{ "name": "myproject", "version": "1.0.0", "description": "", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "NODE_ENV=production webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "postcss": "^8.4.5", "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.2.0", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1" } }
webpack.config.js に設定を追加します。
css-loader と sass-loader の間に postcss-loader を追加します(css-loader や style-loader の前に使用しますが、sass などの他のプリプロセッサローダーの後に使用します)。
css-loader の設定では importLoaders オプションを追加して css-loader の前に適用されるローダーの数(2)を設定します(この設定は将来的には変更になる可能性があるようです)。
PostCSS の設定では、plugins に PostCSS Preset Env などのオプションを設定することができます。
//path モジュールの読み込み const path = require('path'); //MiniCssExtractPlugin の読み込み const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //変数 devMode は production モードの場合は false でその他の場合は true const devMode = process.env.NODE_ENV !== 'production'; module.exports = { //エントリポイント(デフォルトと同じなので省略可) entry: './src/index.js', //出力先(デフォルトと同じなので省略可) output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), //ファイルを出力する前にディレクトリをクリーンアップ clean: true, //Asset Modules の出力先の指定 assetModuleFilename: 'images/[name][ext][query]' }, module: { rules: [ //SASS 及び CSS 用のローダー { //拡張子 .scss、.sass、css を対象 test: /\.(scss|sass|css)$/i, // 使用するローダーの指定 use: [ //CSS を別ファイルとして出力するプラグインのローダー MiniCssExtractPlugin.loader, { loader: "css-loader", options: { // postcss-loader と sass-loader の場合は2を指定 importLoaders: 2, // 0 => no loaders (default); // 1 => postcss-loader; // 2 => postcss-loader, sass-loader }, }, // PostCSS の設定 { loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //必要に応じてオプションを指定 //stage: 0, //browsers: 'last 2 versions', //autoprefixer のオプション //autoprefixer: { grid: true } }, ], ], }, }, }, //Sass ローダー 'sass-loader', ], }, //Asset Modules の設定 { //対象とするアセットファイルの拡張子を正規表現で指定 test: /\.(png|svg|jpe?g|gif)$/i, //画像をコピーして出力 type: 'asset/resource' }, ], }, //プラグインの設定 plugins: [ new MiniCssExtractPlugin({ // 抽出する CSS のファイル名 filename: 'style.css', }), ], //production モード以外の場合は source-map タイプのソースマップを出力 devtool: devMode ? 'source-map' : 'eval', // node_modules を監視(watch)対象から除外 watchOptions: { ignored: /node_modules/ //正規表現で指定 }, };
オプション
以下は PostCSS Preset Env のオプションの一部です。
オプション | 説明 |
---|---|
stage | ポリフィルする CSS 機能を決定するオプションで 0(experimental)〜4(stable) の値、または false を指定できます(デフォルトは Stage 2 features)。0 や 1 を指定すると仕様策定中の次世代 CSS 構文などもトランスパイルすることができます。false を指定するとすべてのポリフィルが無効になります。The Staging Process/cssdb.org |
features | features オプションを使用して、設定されている stage オプションに関係なく、特定の CSS 機能のみを有効にすることができます。features は特定のポリフィルを有効または無効にします。特定の機能の ID(feature ID)に true を渡すとそのポリフィルが有効になり、false を渡すと無効になります。feature ID のリスト |
browsers | サポートするブラウザを指定できます。例: browsers: 'last 2 versions, > 0.5%'(各ブラウザの最後の2つのバージョンまたはシェア率0.5%以上のブラウザ)。標準の browserslist もサポートされています。 |
autoprefixer | autoprefixer オプションを指定すると、追加のオプションを autoprefixer に渡すことができます。autoprefixer: false を指定すると autoprefixer を無効にできます。 |
browserslist
以下は browsers オプションに指定する browserslist の記述例です。複数の条件を指定する場合はカンマで区切るか or を使います。
記述例 | 意味 |
---|---|
> 0.5% | 0.5%以上のシェアがあるブラウザ |
> 1% in JP | 日本で 1%以上のシェアがあるブラウザ |
last 2 versions | 最後の2バージョンのブラウザ |
last 2 major versions | 最新の2メジャーバージョンのブラウザ |
last 2 iOS major versions | iOS の最新の2メジャーバージョン |
Firefox ESR | 最新の Firefox ESR(Extended Service Release)版 |
dead | 公式サポートが終了または24か月間の更新のないブラウザ |
not dead | dead ではないブラウザ(dead を除外したブラウザ) |
not IE 11 | IE 11 を除外 |
ie >= 9 | IE 9以上 |
ie 6-8 | IE 6~8 |
defaults | > 0.5%, last 2 versions, Firefox ESR, not dead(デフォルト) |
以下はブラウザの最後(最新)の2つのバージョンのみを対象とし、stage 3以降のすべての機能を使用し、stage 1の機能である nesting-rules を含めます。また、autoprefixer のオプションとして Grid Layout のベンダープレフィックスを有効にしています。
{ loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { /* オプション */ browsers: "last 2 versions", stage: 3, features: { "nesting-rules": true }, autoprefixer: { grid: true }, }, ], ], }, }, },
例えば、以下のような CSS を style.scss に記述して PostCSS Preset Env のオプションを指定せず(デフォルトで)ビルドすると、
※以下の場合、背景画像を指定しているので、指定した画像が存在しない場合はコンパイル時に css-loader によりエラーになります。
$color: green; $main_color: yellow; ::placeholder { color: $color; } @media (min-resolution: 2dppx) { .image { background-image: url(./images/sample.jpg); } } :root { --mainColor: #{$main_color}; /*カスタムプロパティと Sass のインターポレーション*/ } body { color: var(--mainColor); font-family: system-ui; overflow-wrap: break-word; }
PostCSS Preset Env により以下のようにベンダープレフィックスが付与され、カスタムプロパティなどが変換されます。この例の場合、Sass(sass-loader)も使っているので Sass もビルド時に CSS に変換されています。
::-moz-placeholder { color: green; } :-ms-input-placeholder { color: green; } ::placeholder { color: green; } @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) { .image { background-image: url(images/sample.jpg); } } :root { --mainColor: yellow; } body { color: yellow; color: var(--mainColor); font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif; word-wrap: break-word; }
例えば、以下のように custom-media-queries や custom-selector を使った CSS の場合、
@custom-media --viewport-medium (width <= 50rem); @custom-selector :--heading h1, h2, h3, h4, h5, h6; :--heading { background-image: image-set(url(./images/sample.jpg) 1x, url(./images/sample.jpg) 2x); @media (--viewport-medium) { margin-block: 0; } }
デフォルトの stage では変換されないので、stage オプションに 1 や 0 を指定するか、
{ loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //stage オプションを指定 stage: 1, }, ], ], }, }, },
または、stage はデフォルトのままで、features オプションを指定して、
{ loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //features オプションを指定 features: { "custom-media-queries": true, "custom-selectors": true }, }, ], ], }, }, },
ビルドすると以下のように変換されます。
h1,h2,h3,h4,h5,h6 { background-image: url(images/sample.jpg); background-image: -webkit-image-set(url(images/sample.jpg) 1x, url(images/sample.jpg) 2x); background-image: image-set(url(images/sample.jpg) 1x, url(images/sample.jpg) 2x); } @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { h1,h2,h3,h4,h5,h6 { background-image: url(images/sample.jpg); } } @media (max-width: 50rem) { h1,h2,h3,h4,h5,h6 { margin-top: 0; margin-bottom: 0; } }
CSS Declaration Sorter
CSS Declaration Sorter を使うと CSS プロパティをソートすることができます。
CSS Declaration Sorter を利用するには css-declaration-sorter をインストールします。
$ npm install -D css-declaration-sorter return added 2 packages, and audited 226 packages in 943ms
{ "name": "myproject", "version": "1.0.0", "description": "", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "NODE_ENV=production webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-declaration-sorter": "^6.1.3", "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "postcss": "^8.4.5", "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.2.0", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1" } }
webpack.config.js の postcss-loader に設定を追加します。order に指定できる値は以下になります。
- alphabetical:アルファベット順(デフォルト)
- smacss:最も重要なフローに影響を与えるプロパティから最も重要でないプロパティの順
- Box
- Border
- Background
- Text
- Other
- concentric-css:ボックスモデルの外側に適用されるプロパティから内側の順
- Positioning
- Visibility
- Box model
- Dimensions
- Text
以下は order にデフォルトの alphabetical を指定しているので15〜17行目のオプションの部分は省略しても同じです。
{ loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //postcss-preset-env と autoprefixer のオプション }, ], //css-declaration-sorter を追加 [ 'css-declaration-sorter', { order: 'alphabetical' //アルファベット順 } ], ], }, }, },
//path モジュールの読み込み const path = require('path'); //MiniCssExtractPlugin の読み込み const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //変数 devMode は production モードの場合は false でその他の場合は true const devMode = process.env.NODE_ENV !== 'production'; module.exports = { //エントリポイント(デフォルトと同じなので省略可) entry: './src/index.js', //出力先(デフォルトと同じなので省略可) output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), //ファイルを出力する前にディレクトリをクリーンアップ clean: true, //Asset Modules の出力先の指定 assetModuleFilename: 'images/[name][ext][query]' }, module: { rules: [ //SASS 及び CSS 用のローダー { //拡張子 .scss、.sass、css を対象 test: /\.(scss|sass|css)$/i, // 使用するローダーの指定 use: [ //CSS を別ファイルとして出力するプラグインのローダー MiniCssExtractPlugin.loader, { loader: "css-loader", options: { // postcss-loader と sass-loader の場合は2を指定 importLoaders: 2, // 0 => no loaders (default); // 1 => postcss-loader; // 2 => postcss-loader, sass-loader }, }, // PostCSS の設定 { loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //postcss-preset-env と autoprefixer のオプション }, ], [ 'css-declaration-sorter', ], ], }, }, }, //Sass ローダー 'sass-loader', ], }, //Asset Modules の設定 { //対象とするアセットファイルの拡張子を正規表現で指定 test: /\.(png|svg|jpe?g|gif)$/i, //画像をコピーして出力 type: 'asset/resource' }, ], }, //プラグインの設定 plugins: [ new MiniCssExtractPlugin({ // 抽出する CSS のファイル名 filename: 'style.css', }), ], //production モード以外の場合は source-map タイプのソースマップを出力 devtool: devMode ? 'source-map' : 'eval', // node_modules を監視(watch)対象から除外 watchOptions: { ignored: /node_modules/ //正規表現で指定 }, };
例えば、以下のような CSS を style.scss に記述してコンパイルすると、
.foo { display: block; z-index: 1; animation: none; color: #C55; border: 0; }
以下のようにアルファベット順にソートされます。また、この例ではベンダープレフィックスも付与されています。
.foo { -webkit-animation: none; animation: none; border: 0; color: #C55; display: block; z-index: 1; }
PostCSS Sort Media Queries
PostCSS Sort Media Queries を使うと分散されたメディアクエリをまとめることができます。
PostCSS Sort Media Queries を利用するには postcss-sort-media-queries をインストールします。
$ npm install --save-dev postcss-sort-media-queries return added 2 packages, and audited 228 packages in 2s
{ "name": "myproject", "version": "1.0.0", "description": "", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "NODE_ENV=production webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-declaration-sorter": "^6.1.3", "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "postcss": "^8.4.5", "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.2.0", "postcss-sort-media-queries": "^4.2.1", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1" } }
webpack.config.js の postcss-loader に設定を追加します。sort に指定できる値は以下になります。
- mobile-first:モバイルファーストでまとめる(デフォルト)
- desktop-first:デスクトップファーストでまとめる
- 独自の関数を指定
以下は sort にデフォルトの mobile-first を指定しているので21〜23行目のオプションの部分は省略しても同じです。
{ loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //postcss-preset-env と autoprefixer のオプション }, ], [ 'css-declaration-sorter', { order: 'alphabetical' } ], [ //PostCSS Sort Media Queries(mobile-first でソート) 'postcss-sort-media-queries', { sort: 'mobile-first' } ], ], }, }, },
//path モジュールの読み込み const path = require('path'); //MiniCssExtractPlugin の読み込み const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //変数 devMode は production モードの場合は false でその他の場合は true const devMode = process.env.NODE_ENV !== 'production'; module.exports = { //エントリポイント(デフォルトと同じなので省略可) entry: './src/index.js', //出力先(デフォルトと同じなので省略可) output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), //ファイルを出力する前にディレクトリをクリーンアップ clean: true, //Asset Modules の出力先の指定 assetModuleFilename: 'images/[name][ext][query]' }, module: { rules: [ //SASS 及び CSS 用のローダー { //拡張子 .scss、.sass、css を対象 test: /\.(scss|sass|css)$/i, // 使用するローダーの指定 use: [ //CSS を別ファイルとして出力するプラグインのローダー MiniCssExtractPlugin.loader, { loader: "css-loader", options: { // postcss-loader と sass-loader の場合は2を指定 importLoaders: 2, // 0 => no loaders (default); // 1 => postcss-loader; // 2 => postcss-loader, sass-loader }, }, // PostCSS の設定 { loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //postcss-preset-env と autoprefixer のオプション }, ], [ 'css-declaration-sorter', { order: 'alphabetical' } ], [ 'postcss-sort-media-queries', { sort: 'mobile-first' } ], ], }, }, }, //Sass ローダー 'sass-loader', ], }, //Asset Modules の設定 { //対象とするアセットファイルの拡張子を正規表現で指定 test: /\.(png|svg|jpe?g|gif)$/i, //画像をコピーして出力 type: 'asset/resource' }, ], }, //プラグインの設定 plugins: [ new MiniCssExtractPlugin({ // 抽出する CSS のファイル名 filename: 'style.css', }), ], //production モード以外の場合は source-map タイプのソースマップを出力 devtool: devMode ? 'source-map' : 'eval', // node_modules を監視(watch)対象から除外 watchOptions: { ignored: /node_modules/ //正規表現で指定 }, };
例えば、以下のような CSS を style.scss に記述してコンパイルすると、
@media screen and (max-width: 640px) { .head { color: #cfcfcf } } @media screen and (max-width: 768px) { .footer { color: #cfcfcf } } @media screen and (max-width: 640px) { .main { color: #cfcfcf } } @media screen and (min-width: 1280px) { .mobile-first { color: #cfcfcf } } @media screen and (min-width: 640px) { .mobile-first { color: #cfcfcf } } @media screen and (max-width: 640px) { .footer { color: #cfcfcf } }
mobile-first の場合、以下のようにまとめられます。
@media screen and (min-width: 640px) { .mobile-first { color: #cfcfcf; } } @media screen and (min-width: 1280px) { .mobile-first { color: #cfcfcf; } } @media screen and (max-width: 768px) { .footer { color: #cfcfcf; } } @media screen and (max-width: 640px) { .head { color: #cfcfcf; } .main { color: #cfcfcf; } .footer { color: #cfcfcf; } }
webpack-dev-server
watch オプション(--watch)を利用すればファイルが変更されると自動的に webpack コマンドを実行するようにはできますがブラウザには反映されません。webpack-dev-server を使えばファイルの変更が自動的にブラウザに反映されるようにできます。
以下は webpack-dev-server を使って開発用サーバを立ち上げる例です。
webpack-dev-server をインストールします。
npm install -D webpack-dev-server return added 196 packages, and audited 424 packages in 7s
npm scripts を追加
コマンドラインで簡単にサーバを起動できるように package.json の scripts フィールドに npm scripts を設定します(以下7行目)。
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "NODE_ENV=production webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version", "start": "webpack serve --mode development" },
{ "name": "myproject", "version": "1.0.0", "description": "", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "NODE_ENV=production webpack --mode production", "dev": "webpack --mode development", "watch": "webpack --mode development --watch", "sass-ver": "sass --version", "start": "webpack serve --mode development" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-declaration-sorter": "^6.1.3", "css-loader": "^6.5.1", "mini-css-extract-plugin": "^2.4.5", "postcss": "^8.4.5", "postcss-loader": "^6.2.1", "postcss-preset-env": "^7.2.0", "postcss-sort-media-queries": "^4.2.1", "sass": "^1.45.2", "sass-loader": "^12.4.0", "webpack": "^5.65.0", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.7.2" } }
これでコマンドラインで npm start または npm run start で開発サーバを起動することができます。
オプションの設定
webpack.config.js に以下の webpack-dev-server のオプションを追加します。
この例の場合、公開するリソース(html ファイル)のドキュメントルートは webpack.config.js と同じ位置なので static オプションは './' としています(デフォルトは ./public)。
また、サーバー起動時にブラウザを自動的に起動するように open: true を指定しています。
devServer: { //表示する静的ファイルのディレクトリを指定 static: './', //または static: path.join(__dirname, ''), //サーバー起動時にブラウザを自動的に起動 open: true, },
myProject ├── dist //ビルド先ディレクトリ ├── index.html //HTML ファイル(表示する静的ファイル) ├── node_modules ├── package-lock.json ├── package.json └── src ├── index.js └── style.scss
バンドルされたファイルを出力する
デフォルトでは webpack-dev-server で生成された(バンドルされた)ファイルはメモリ上に保存されて実際には出力されないので、ファイルを出力する(実際に書き出す)には devMiddleware オプションに writeToDisk: true を指定します。
devServer: { static: './', open: true, //webpack-dev-middleware 関連の設定 devMiddleware: { writeToDisk: true, //バンドルされたファイルを出力する(実際に書き出す) }, },
//path モジュールの読み込み const path = require('path'); //MiniCssExtractPlugin の読み込み const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //変数 devMode は production モードの場合は false でその他の場合は true const devMode = process.env.NODE_ENV !== 'production'; module.exports = { //エントリポイント(デフォルトと同じなので省略可) entry: './src/index.js', //出力先(デフォルトと同じなので省略可) output: { filename: 'main.js', path: path.resolve(__dirname, 'dist'), //ファイルを出力する前にディレクトリをクリーンアップ clean: true, //Asset Modules の出力先の指定 assetModuleFilename: 'images/[name][ext][query]' }, //webpack-dev-server の設定 devServer: { //表示する静的ファイルのディレクトリを指定 static: './', // または static: path.join(__dirname, ''), //サーバー起動時にブラウザを自動的に起動 open: true, //webpack-dev-middleware 関連の設定 devMiddleware: { writeToDisk: true, //バンドルされたファイルを出力する(実際に書き出す) }, }, module: { rules: [ //SASS 及び CSS 用のローダー { //拡張子 .scss、.sass、css を対象 test: /\.(scss|sass|css)$/i, // 使用するローダーの指定 use: [ //CSS を別ファイルとして出力するプラグインのローダー MiniCssExtractPlugin.loader, { loader: "css-loader", options: { // postcss-loader と sass-loader の場合は2を指定 importLoaders: 2, // 0 => no loaders (default); // 1 => postcss-loader; // 2 => postcss-loader, sass-loader }, }, // PostCSS の設定 { loader: "postcss-loader", options: { postcssOptions: { plugins: [ [ "postcss-preset-env", { //postcss-preset-env と autoprefixer のオプション }, ], [ 'css-declaration-sorter', { order: 'alphabetical' } ], [ 'postcss-sort-media-queries'], ], }, }, }, //Sass ローダー 'sass-loader', ], }, //Asset Modules の設定 { //対象とするアセットファイルの拡張子を正規表現で指定 test: /\.(png|svg|jpe?g|gif)$/i, //画像をコピーして出力 type: 'asset/resource' }, ], }, //プラグインの設定 plugins: [ new MiniCssExtractPlugin({ // 抽出する CSS のファイル名 filename: 'style.css', }), ], //production モード以外の場合は source-map タイプのソースマップを出力 devtool: devMode ? 'source-map' : 'eval', // node_modules を監視(watch)対象から除外 watchOptions: { ignored: /node_modules/ //正規表現で指定 }, };
main.js の読み込み
今までの例では Javascript をバンドルしていないので html ファイル(index.html) では main.js の読み込みをコメントアウトしていましたが、コメントアウトを外して読み込むようにします。
<!doctype html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="dist/style.css"> <title>Sass 読み込みサンプル</title> </head> <body> <div class="sass_sample"> <h1>Sass</h1> <p>sample text.</p> </div> <script src="dist/main.js"></script><!-- main.js を読み込む --> </body> </html>
webpack-dev-server を起動すると、main.js に以下のような内容が書き込まれて出力されます(main.js を読み込んでいないとファイルに変更があった場合にライブリロードされません)。
開発サーバの起動
package.json の scripts フィールドに npm scripts を指定してあるので、コマンドラインで npm start または npm run start を実行すると開発サーバが起動します。
または、以下のように npx コマンドを実行しても同じです(--mode development は開発モード用のオプションです)。
$ npx webpack serve --mode development return
この例では port オプションでポート番号を指定していないので、デフォルトの http://localhost:8080/ でページが開きます。
index.html や style.scss を変更するとブラウザがリロードされ変更が自動的に反映されます。
サーバの終了
開発サーバを終了するには control + c を押します。
詳細は webpack の基本的な使い方 webpack-dev-server を御覧ください。