webpack

【webpack】pugを使って、効率的にコーディングしよう【pug-html-loader】

HTMLをpug化するメリットって何?
webpackでpugってどう導入するんだろう?

以上の疑問の解決記事です。

 

 

HTML → pug化のメリット

pug化のメリットは下記の通り。

  1. 記述が短くて済む
  2. include可能
  3. テンプレート継承が可能

それぞれについて深堀りしていきます。

 

① 記述が短くて済む

本記事を読み進めてもらうと分かりますが、記述が短いです。
まず、閉じタグがありません。

比較すると以下の通り。

<!-- html -->
<h1>webpackチュートリアル<span>(SCSSを追加)</span></h1>
<!-- pug -->
h1 webpackチュートリアル
    span (SCSSを追加)

 

閉じタグの記述漏れがありません。

 

② include可能

各ページで、共通化可能な部分をパーツ化し、読み込むことができます

例えば、doctype宣言・header・footerなどがそれに当たります。WordPressに詳しい方であれば、header.php・footer.phpのようなものです。

※別記事で解説してます。

【webpack】pugファイルをincludeしてコーディングをさらに効率化しよう pug化するメリットって何? includeってどう書くの? このような疑問に答える記事です。 前回までで、w...

 

③ テンプレート継承が可能

こちらも②と同様、共通部分を読み込むことができます。
②との違いは、ページ毎に変えたい箇所を変更できる点です。

例えば、「headタグ」内のtitleやdescription・keywordsなどは個別設定が必要かと思います。

②では完全共通化になりますが、テンプレート継承では個別に変更することが可能です。

 

 

他にも、pug化のメリットはありますが、これらだけでも、十分に使用価値があるでしょう。何度も同じ記述を書かなくて済むので。

※ ②③の具体的な記述については、次回解説します。
※ 本記事では①のみ。

 

pug-html-loader・html-loaderを使う

pug-html-loader・html-loaderをインストールする

下記コマンドでインストールします。

npm install --save-dev pug-html-loader html-loader

 

 

package.jsonを確認

正常にインストールされているか確認。

//package.json

{
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^6.5.1",
    "file-loader": "^6.2.0",
    "html-loader": "^3.0.1", //追加
    "html-webpack-plugin": "^5.5.0",
    "mini-css-extract-plugin": "^2.4.5",
    "node-sass": "^7.0.1",
    "pug-html-loader": "^1.1.5", //追加
    "sass-loader": "^12.4.0",
    "style-loader": "^3.3.1",
    "webpack": "^5.65.0",
    "webpack-cli": "^4.9.1"
  }
}

 

 

webpack-config.jsに設定を追加する

インストールに成功したら、configファイルに下記設定を追加します。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: './src/js/index.js',
    output: {
        path: `${__dirname}/dist`,
        filename: './js/bundle.js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.(css|sass|scss)/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: 'css-loader'
                    },
                    {
                        loader: 'sass-loader'
                    }
                ]
            },
            {
                test: /\.(png|jpg|gif|svg)/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: 'images/[name].[ext]'
                        }
                    }
                ]
            },
            //ここから追加
            {
                test: /\.pug/,
                use: [
                    {
                        loader: 'html-loader'
                    },
                    {
                        loader: 'pug-html-loader',
                        //コード成形オプション(これがないとminファイルのようになる)
                        options: {
                            pretty: true
                        }
                    }
                ]
            }
            //ここまで追加
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: './css/style.css'
        }),
        new HtmlWebpackPlugin({
            //ここから変更
            template: './src/templates/index.pug'
            //ここまで変更
        }),
        new CleanWebpackPlugin()
    ]
}
  • loaderは下から読み込まれていくので順番注意
  • optionsを追加して読みやすくするとgood

 

 

src/配下にpugファイルを新規作成する

設定追加後、生成元になるsrc/配下にpugを新規作成します。

webpack-tutorial
├dist/
|   ├──css/
|   |   └──style.css
|   ├──js/
|   |   └──bundle.js
|   └──index.html
|
├node_modules/
├src/
|   ├──images/
|   ├──js/
|   |   ├──index.js
|   |   └──sub.js
|   ├──scss/
|   |   └──style.scss
|   └──templates/
|   |   ├──index.pug //新規追加
|       └──index.html
|
├package-lock.json
├package.json
└webpack.config.js

 

既存のindex.htmlに倣って、pugで書くと以下のようになります。

doctype html
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Document
    body
        h1 webpackチュートリアル
            span (SCSSを追加)
        img(src="/src/images/mountain.jpg", alt="")
        img(src="/src/images/sea.jpg", alt="")

 

  • pugのdoctype宣言は、HTML同様「! + tab」のショートカットキーが使える

 

webpackを起動する

下記コマンドでwebpackを起動します。

npm run build

 

 

ブラウザで確認する

ブラウザで確認すると・・・

画像が表示されていない。。。

 

ソースコードを見ると・・・

読み込んでいる画像ファイルが乱数になっているようです。

 

html-loaderバージョンを下げると正常読み込みされた

原因を探って試行錯誤を繰り返すと、原因はhtml-loaderのバージョンにあるようでした。

pugとhtml-loaderバージョンの相性が良くなかったようで、以下のように変更したら表示されました。

【変更前】3.0.1
【変更後】0.5.5

 

変更手順

一度パッケージをアンインストール後、再度バージョン指定をしてインストールします。

npm uninstall html-loader
npm install --save-dev html-loader@0.5.5

 

 

webpack起動後、再度ブラウザで確認

再びwebpackを起動します。

npm run build

 

 

そしてブラウザを確認すると・・・

画像が表示されました。

 

当然ソースコードも、従来のファイル名で読み込まれています。

 

 

【おまけ】複数ページを作成する場合

通常webサイトは複数ページ存在するものなので、ページ追加の方法も見ていきます。

やり方は、下記の通り。

  1. webpack-comfig.jsに記述を追加
  2. pugファイルを新規追加
  3. webpackを起動後、ブラウザで確認する

①②まで終えたら、③はここまで説明した通りなので簡単にお伝えしますね。

 

webpack-config.jsに記述を追加

webpack-config.jsに設定を追加しましょう。

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: './src/js/index.js',
    output: {
        path: `${__dirname}/dist`,
        filename: './js/bundle.js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.(css|sass|scss)/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: 'css-loader'
                    },
                    {
                        loader: 'sass-loader'
                    }
                ]
            },
            {
                test: /\.(png|jpg|gif|svg)/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: 'images/[name].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.pug/,
                use: [
                    {
                        loader: 'html-loader'
                    },
                    {
                        loader: 'pug-html-loader',
                        options: {
                            pretty: true
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: './css/style.css'
        }),
        new HtmlWebpackPlugin({
            template: './src/templates/index.pug',
            //ここから変更
            filename: 'index.html'
            //ここまで変更
        }),
        //ここから追加
        new HtmlWebpackPlugin({
            template: './src/templates/menu.pug',
            filename: 'menu.html'
        }),
        //ここまで追加
        new CleanWebpackPlugin()
    ]
}

 

※今回追加した記述がない場合、webpackがどんなファイル名にして良いか分からず、下記エラーが生じます。

ERROR in Conflict: Multiple assets emit different content to the same filename index.html

「index.htmlの同じファイル名で複数のコンテンツが出力されているよ。」

したがって、今回追加したように、テンプレート名とファイル名を追記すればOK。

 

pugファイルを新規追加

次にpugファイルを追加しましょう。

以下のような、階層構造になります。

webpack-tutorial
├dist/
|   ├──css/
|   |   └──style.css
|   ├──js/
|   |   └──bundle.js
|   └──index.html
|
├node_modules/
├src/
|   ├──images/
|   ├──js/
|   |   ├──index.js
|   |   └──sub.js
|   ├──scss/
|   |   └──style.scss
|   └──templates/
|   |   ├──index.pug
|       ├──index.html
|   |   └──menu.pug //新規追加(一例としてmenuにしてます)
|
├package-lock.json
├package.json
└webpack.config.js

 

以下は、追加するmenu.pugファイルの中身です。
(index.pugから少し変更してます)

doctype html
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title メニュー | webpackチュートリアル
    body
        h1 メニュー
            span (SCSSを追加)
        img(src="/src/images/mountain.jpg", alt="")
        img(src="/src/images/sea.jpg", alt="")

 

 

webpackを起動後、ブラウザで確認する

ここまでできたら、再度webpackを起動し、ブラウザで確認しましょう。

npm run build

 

URLもindex.html → menu.html変わるので注意です。

 

無事に表示されました!

 

 

 

まとめ

本記事では、「pugを使って、効率的にコーディングしよう」と題して、以下のことを解説しました。

  • HTML → pug化のメリット
  • pug-html-loader・html-loaderを使う
  • webpack-config.jsに設定を追加する
  • src/配下にpugファイルを新規作成する
  • webpackを起動する
  • ブラウザで確認する
  • html-loaderバージョンを下げると正常読み込みされた
  • webpack起動後、再度ブラウザで確認
  • 【おまけ】複数ページを作成する場合

アクシデントはありましたが、無事にpug化することができました。また、複数ページでのpug化にも成功しています。

次回は、冒頭でお伝えしたincludeやテンプレート継承について、どのように記述するかを見ていきましょう。

【webpack】pugファイルをincludeしてコーディングをさらに効率化しよう pug化するメリットって何? includeってどう書くの? このような疑問に答える記事です。 前回までで、w...

 

参考

ABOUT ME
ゆう
エンジニア歴6年。 大学卒業後、フィールドエンジニア職に就くがその後のキャリアに不安を感じ、ゼロスキルからWEBデザイナーに転職。 その後WEB制作会社、東証一部上場企業のECサイト運用担当を経て、現在は自社開発企業のWEBコーダーとして仕事に従事。分かりやすく伝えることに課題意識を持ってます。