今回はwebpack5の設定方法について備忘録として残しておきたいと思います。
設定する内容は以下です。
- Pugのコンパイル
- Sassのコンパイル(Dart Sass)
- JavaScriptをBabelでトランスパイル
- TypeScriptのコンパイル
- 画像の圧縮
- 開発サーバーの立ち上げ、ホットリロード
- ESLintとPrettier
バージョンは以下です。
- macOS Catalina v10.15.7
- Visual Studio Code v1.67.1
- webpack v 5.72.0
- node.js v17.7.2
また、今回作成した開発環境は以下のリポジトリの方に上げさせてもらいましたので非推奨の書き方やより良い方法などありましたら教えてもらえると嬉しいです。
ディレクトリ構成
srcフォルダで作業したものが、distフォルダ直下に出力されます。

また、参考までにPugとSassのディレクトリ構成も載せておきます。
pugフォルダの中身
pug/
├─ data/
│ └─ _page-data.pug(meta情報などを管理する)
│
├─ modules/
│ ├─ _header.pug
│ ├─ _footer.pug
│ ├─ _sidebar.pug
│ ├─ _template.pug
│
├─ lower-page/(下層ページ: 名前は任意)
│ ├─ _index.pug
│
└─ index.pug(トップページ)
meta情報の管理などに関しては以下の文献を参考にさせていただきました。
pugでmeta情報などをjsonで外部ファイル化して読み込む方法
scssフォルダの中身
css設計、命名規則はFROCSSをベースにしています
scss/
├─ global/
│ ├─ mixin/(mixinの管理)
│ │ ├─ _breakpoint.scss
│ │ ├─ _font-size.scss
│ │ ├─ _line-height.scss
│ │ └─ _index.scss
│ │
│ ├─ variables/(グローバル変数の管理)
│ │ ├─ _color.scss
│ │ ├─ _font-family.scss
│ │ ├─ _z-index.scss
│ │ └─ _index.scss
│ │
│ └─ _index.scss(mixinとvariablesフォルダを読み込む用)
│
├─ foundation/(デフォルトスタイルを管理)
│ ├─ _base.scss
│ └─ _ress.scss(リセットCSS)
│
├─ layout/(レイアウト部分の管理)
│ ├─ _l-container.scss
│ ├─ _l-header.scss
│ ├─ _l-footer.scss
│ └─ _l-sidebar.scss
│
├─ component/(最小単位のコンポーネントを管理)
│ └─ _c-button.scss
│
├─ Project/(いくつかのcomponentと、他の要素によって構成される大きな単位のオブジェクトを管理)
│ ├─ _p-global-nav.scss
│ └─ _p-main-visual.scss
│
├─ utility/(ユーティリティクラスの管理)
│ └─ _u-hidden.scss
│
├─ javascript/(jsで操作するDOMの管理)
│ ├─ _js-trigger.scss
│ └─ _js-target.scss
│
├─ external/(ライブラリなど外部クラスを上書き用)
│ └─ _swiper.scss
│
└─ style.scss
webpackのインストール
npm init -y
でpackage.jsonnpm i -D webpack webpack-cli
でwebpackのインストールします。
$ npm init -y
$ npm i -D webpack webpack-cli
パッケージのインストール
各種ローダー、プラグインをインストールします。
$ npm i -D babel-loader @babel/preset-env @babel/core core-js
$ npm i -D @babel/preset-typescript
$ npm i -D typescript
$ npm i -D ts-loader
$ npm i -D html-webpack-plugin
$ npm i -D pug
$ npm i -D pug-html-loader
$ npm i -D html-loader
$ npm i -D mini-css-extract-plugin
$ npm i -D css-loader
$ npm i -D style-loader
$ npm i -D sass
$ npm i -D sass-loader
$ npm i -D globule
$ npm i -D eslint eslint-config-prettier
$ npm i -D @typescript-eslint/eslint-plugin @typescript-eslint/parser
$ npm i -D prettier
$ npm i -D image-webpack-loader
$ npm i -D autoprefixer
$ npm i -D postcss-loader
$ npm i -D clean-webpack-plugin
$ npm i -D webpack-dev-server
それぞれのバージョンは以下です。

webpack.config.jsの設定
webpack.config.jsを作成し、設定を記述します。
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const globule = require("globule");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 本番環境のときはsoucemapを出力させない設定
const enabledSourceMap = process.env.NODE_ENV !== "production";
const app = {
//エントリーポイント
entry: './src/js/main.js',
// 出力先(distの中のjsフォルダへbundle.jsを出力)
output: {
path: path.resolve(__dirname, 'dist'),
filename: "./js/bundle.js",
},
//仮想サーバーの設定
devServer: {
//ルートディレクトリの指定
static: {
directory: path.join(__dirname, "dist")
},
compress: true,
// ブラウザを自動的に起動
open: true,
// ホットリロード
hot: true,
// ポート番号指定
port: 3000,
// 監視するフォルダ
watchFiles: {
paths: ["src/**/*"],
},
// bundle先ファイルを出力する
devMiddleware: {
writeToDisk: true,
}
},
module: {
rules: [
{
//babelの設定
test: /\.(ts|js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
// 必要なポリフィルを出力させる
useBuiltIns: 'usage',
corejs: {
version: '3.22.5',
proposals: true
}
}
],
['@babel/preset-typescript']
]
}
},
]
},
{
//Sassの設定
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
url: false,
sourceMap: enabledSourceMap,
importLoaders: 2
}
},
{
loader: "postcss-loader",
options: {
// production モードでなければソースマップを有効に
sourceMap: enabledSourceMap,
postcssOptions: {
// ベンダープレフィックスを自動付与
plugins: [require("autoprefixer")({ grid: true })]
}
}
},
{
loader: 'sass-loader',
options: {
// dart-sass を優先
implementation: require("sass"),
// production モードでなければソースマップを有効に
sourceMap: enabledSourceMap
}
},
]
},
{
//画像の設定
test: /\.(jpe?g|png|gif|svg|webp)$/i,
type: 'asset/resource',
generator: {
filename: 'img/[name][ext]',
},
use: [
{
loader: 'image-webpack-loader',
options: {
webp: {
quality: 75
}
}
}
]
},
{
// Pugの設定
test: /\.pug$/,
use: [
{
loader: 'html-loader'
},
{
loader: 'pug-html-loader',
options: {
pretty: true
}
}
]
}
]
},
resolve: {
// import 文で .ts ファイルを解決
extensions: [".ts", ".js"]
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename:'./css/style.css',
}),
],
//source-mapを出力する
devtool: "source-map",
// node_modules を監視(watch)対象から除外
watchOptions: {
ignored: /node_modules/
}
}
//srcフォルダからpugを探す
const templates = globule.find("./src/pug/**/*.pug", {
ignore: ["./src/pug/**/_*.pug"]
});
//すべてのpugファイルをhtmlに変換
templates.forEach((template) => {
const fileName = template.replace("./src/pug/", "").replace(".pug", ".html");
app.plugins.push(
new HtmlWebpackPlugin({
filename: `${fileName}`,
template: template,
inject: true,
minify: false //本番環境でも圧縮するか
}),
);
});
module.exports = app;
tsconfig.jsonを設定
TypeScriptからJavaScriptへのコンパイルオプションの指定をtsconfig.jsonに書きます。
以下のコマンドでtsconfig.jsonが作成されます。
$ npx tsc --init
tsconfig.jsonにて、設定を記述します。
{
"compilerOptions": {
"target": "ES5", // // ECMAScript ターゲットのバージョンを指定
"module": "ES2015", // ES Modulesとして出力
"sourceMap": true, // soucemapを出力する
"strict": true, // 厳格モード
"moduleResolution": "node", // node_modules からライブラリを読み込む
"esModuleInterop": true, // CommonJSモジュールとESモジュール間の相互運用性を,すべてのインポート用に名前空間オブジェクトを作成することで可能に
"skipLibCheck": true, // 型宣言ファイルの型チェックをスキップする
"forceConsistentCasingInFileNames": true, // 大文字小文字を区別して参照を解決するようにする
"noImplicitAny": false // 暗黙のany型をエラーに
}
}
設定方法は以下の文献を参考にしました。
ESLintの設定
eslintrc.jsonを用意して設定を記述します。
// eslintrc.json
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"root": true,
}
.eslintignoreにESLintでチェックしなくて良いフォルダやファイルを指定します。
// .eslintignore
node_modules/
dist/
webpack.config.js
以下、細かい設定に関する参考文献です。
また、今回はvscodeの拡張機能から利用しています。
以下をインストールして有効化します。

webpack上でESLintを使用したい場合は以下の記事が参考になりました。
Prettierの設定
.prettierrc.jsonを用意し、設定を記述します。
{
"printWidth": 120, // 折り返す行の長さを指定
"trailingComma": "es5", // 末尾のカンマの設定、ES5で有効な末尾のカンマ(オブジェクト、配列など) デフォルト
"tabWidth": 2, // インデントのスペースの数を指定
"semi": true, //最後にセミコロンを追加(デフォルト)
"singleQuote": true, // シングルクォートを使う
"endOfLine": "lf" //改行コード、一般的なラインフィード(\n)のみ
}
設定に関しては以下の記事を参考にしました。
また、こちらもESLint同様、VSCode拡張機能をインストールして、有効化します。

VSCode上の設定
VSCode上でcommand + shift + P
(Windows: Ctrl + Shift + P
)でコマンドパレットを表示し、
settings
または設定
(日本語化済みの場合)と入力し、settings.jsonを開き以下を追加します。
"editor.defaultFormatter": "esbenp.prettier-vscode", // フォーマッタ-はPrettierを使用
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true // ファイル保存時に ESLint でフォーマット
},
"editor.formatOnSave": true, //ファイルを保存したタイミングでフォーマットする

ファイルを保存したタイミングで、ESLintとPrettierが機能するようになります。
Autoprefixerの設定
今回の設定項目は以下です。
- 0.2% 以上のシェアがあり、メンテナンスが行われているブラウザ
- 対象ブラウザから IE11 を除外
※IEは2022 年 6 月 16 日(日本時間)にサポートが終了します。
package.jsonに以下を追加します。
"browserslist": [
"> 0.2%, not dead",
"not IE 11"
]

webpack.config.jsの詳細
エントリーポイントと出力先を指定する
// エントリーポイント
entry: './src/js/main.js',
// 出力先(distの中のjsフォルダへbundle.jsを出力)
output: {
path: path.resolve(__dirname, 'dist'),
filename: "./js/bundle.js",
},
src/jsフォルダの中にあるmain.jsまたは.tsを読み込み、dist/jsフォルダへbundle.jsという名前で出力させています。

複数のエントリーポイントを指定する場合
entryのパスを複数定義し、outputでは[name]+パス
を指定します。
entry: {
front: './src/js/main.js',
page: './src/js/page-main.js',
},
output: {
filename: './js/[name].bundle.js',
path: path.join(__dirname, 'dist'),
},
この状態でコマンドを実行すると、outputで指定した場所とファイル名で出力がされます。

Pugの指定
ローダーを指定します。
- pug-html-loader => pugをhtmlに変換
- html-loader => HTMLを文字列として出力
注意点としてはローダーは基本下から順番に処理が走ります。
{
// Pugの設定
test: /\.pug$/,
use: [
{
loader: 'html-loader'
},
{
loader: 'pug-html-loader',
options: {
pretty: true
}
}
]
}
反復処理ですべてのpugファイルをhtmlに変換します。
//srcフォルダからpugを探す
const templates = globule.find("./src/pug/**/*.pug", {
ignore: ["./src/pug/**/_*.pug"]
});
//すべてのpugファイルをhtmlに変換
templates.forEach((template) => {
const fileName = template.replace("./src/pug/", "").replace(".pug", ".html");
app.plugins.push(
new HtmlWebpackPlugin({
filename: `${fileName}`, // ファイル名を指定
template: template, // どのフォルダから読み込むのか指定
inject: true, // scriptタグの出力先
minify: false //本番環境でも圧縮するか
}),
);
});
始めにに読み込んだHtmlWebpackPluginのinjectオプションでscriptタグの出力先を選択できます。
- true => headタグ内に出力(defer属性を付与)
- false => 出力させない
- ‘body’ => body終了タグの直前に出力
Sassの指定
ローダーを指定します。
- sass-loader => SassをCSSに変換する
- postcss-loader => ベンダープレフィックスを自動付与
- css-loader => CSSをJavaScriptファイルに埋め込むためのローダー
- MiniCssExtractPlugin => CSSを個別のファイルに抽出する
{
//Sassの設定
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
url: false,
sourceMap: enabledSourceMap,
importLoaders: 2
}
},
{
loader: "postcss-loader",
options: {
// production モードでなければソースマップを有効に
sourceMap: enabledSourceMap,
postcssOptions: {
// ベンダープレフィックスを自動付与
plugins: [require("autoprefixer")({ grid: true })]
}
}
},
{
loader: 'sass-loader',
options: {
// dart-sass を優先
implementation: require("sass"),
// production モードでなければソースマップを有効に
sourceMap: enabledSourceMap
}
},
]
},
MiniCssExtractPluginで抽出したCSSを、どのフォルダに何て名前で出力するか指定します。
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename:'./css/style.css',
}),
],
TypeScriptの指定
ts-loaderを使用する場合、以下を記述します。
{
//ts-loaderを使用する場合の設定
test: /\.ts$/,
use: "ts-loader",
exclude: /node_modules/
},
import 文で拡張子を省略するために以下を記述します。
resolve: {
// import 文で .ts ファイルを解決
extensions: [".ts", ".js"]
},
また、ts-loader を使用しなくても以下のbabelの指定で@babel/preset-typescript’を使用してTypeScriptをコンパイルすることもできます。
babelの指定
- @babel/preset-envを指定することでES6〜のコードをターゲットブラウザで動作するコードに変換
- @babel/preset-typescriptを指定することでTypeScriptをJavaScriptにコンパイル
{
//babelの設定
test: /\.(ts|js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env'], // ES2022 を ターゲットブラウザで動作するコードに変換
['@babel/preset-typescript'] // TypeScriptのコンパイル
]
}
},
]
},
package.jsonのbrowserslistの指定がターゲットブラウザとなります。
"browserslist": [
"> 0.2%, not dead",
"not IE 11"
]
また、core.jsとuseBuiltInsを指定することで、browserslistに指定したターゲットブラウザに必要なポリフィルを出力させることができます。
{
//babelの設定
test: /\.(ts|js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
// 必要なポリフィルを出力させる
useBuiltIns: 'usage',
corejs: {
version: '3.22.5',
proposals: true
}
}
],
['@babel/preset-typescript']
]
}
},
]
},
公式ドキュメント
ローカルサーバーの指定
パッケージのwebpack-dev-serverから仮想サーバーを立ち上げることができます。
今回は以下を設定しました。
- static => ルートディレクトリの指定
- open => ブラウザを自動で立ち上げるかどうか
- hot => ファイルが更新されたら、表示も変更させるか
- port => ポート番号の指定
- watchFiles => 監視するフォルダ
- writeToDisk => developmentモードでもbundle先ファイルを出力する
devServer: {
// ルートディレクトリの指定
static: {
directory: path.join(__dirname, "dist")
},
compress: true,
// ブラウザを自動的に起動
open: true,
// ホットリロード
hot: true,
// ポート番号指定
port: 3000,
// 監視するフォルダ
watchFiles: {
paths: ["src/**/*"],
},
// bundle先ファイルを出力する
devMiddleware: {
writeToDisk: true,
}
},
公式ドキュメント
画像の設定
webpack4までは、raw-loaderやurl-loader、style-loaderなどのローダーを使用してアセットファイルの依存関係を解決していましたが、
webpack5ではAsset Modulesのみで同様のことを実現できます。
Asset Modulesの設定する内容は以下です。
- test => 指定した拡張子に対して処理を実行する。
- type => アセットモジュールタイプの指定。個別にファイルを生成して、そのURLを出力する。
- generator.filename => 出力先の指定。[name]や[ext]のプレースホルダーを使用できる。
また、image-webpack-loaderを指定してpng, jpeg, gif, svg, webp画像を圧縮します。
{
//画像の設定
test: /\.(jpe?g|png|gif|svg|webp)$/i,
type: 'asset/resource',
generator: {
filename: 'img/[name][ext]',
},
use: [
{
loader: 'image-webpack-loader',
options: {
// webpを有効にする
webp: {
quality: 75
}
}
}
]
},
image-webpack-loaderでwebpを有効にする場合はoptionに追加する必要があります。
以下、公式ドキュメント。
webpackを走らせる
package.jsonに任意のコマンドを登録して、webpackを走らせます。
以下は例です。
"scripts": {
"build": "NODE_ENV=production webpack --mode production",
"dev": "webpack --mode development",
"server": "webpack serve --mode development",
},
$ npm run build // 納品時などに本番環境として出力
$ npm run dev // 開発環境として出力
$ npm run server // 仮想サーバー起動し開発環境として出力
参考文献
webpackの設定
- webpack公式
- Webpackでウェブサイト制作のHTML/CSS/JSコーディングを一気に効率化する実践講座 (Mac / Win)
- webpack 5でTypeScriptとPugの設定方法 – BabelによるIE11対策も紹介
- webpack-dev-server
- image-webpack-loader
- Asset Modules
TypeScriptの設定
ESLint Prettierの設定
- ESLint公式
- うわっ…私の.eslintrc、無駄が多すぎ…? | Zenn
- ESLint 設定を作成する技術 | Zenn
- webpackでESLintが使える環境を構築してみる
- .prettierrc
Babelの設定