memo
memo
初めての"Pug"🐕

初めての"Pug"🐕

違います、犬種ではないです。


今回は、HTMLテンプレートエンジン【Pug】について書いていこうと思います。

テンプレートエンジンについては結構前に調べたり少し書いた記憶があるんですが、以降取り入れることもなく基本フルスクラッチで書いていました。

最近いろんな場面で【Pug】を目にしたので、改めて少し触ってみてみました。
その感想などを書き留めたいと思います。

改めまして、Pugです。

犬種でなければPNGのタイポでもありません。
ちなみに、僕は初めて見た時は本気でPNGのタイポだと思いました。

Pugは、HTMLを効率的に書くためのJavaScriptテンプレートエンジンのひとつです。
テンプレートエンジンには、Pugの他にも、EJSNunjucksなどがありますね。

はて、テンプレートエンジン

テンプレートエンジンとは、データとテンプレートを合体させて文字列を作る仕組みを持った、JavaScriptライブラリを指します。

こう書かれると難しく感じるので、僕の中ではHTMLを効率的に書くためのJSライブラリというざっくりとした認識です。
(間違っていたらすみません。)

Pugの公式サイトはこちら

Pugを使う前に

HTMLの場合は拡張子が.htmlですが、Pugの場合は .pugとなります。

.pugファイルは、そのままではブラウザに認識してもらえません。
なので、.htmlファイルの形式に変換(コンパイル)する必要があります。

gulpPreprosなどのコンパイラー(アプリ)を使い、自動変換しながらコーディングする必要があります。
(じゃないとプレビューもできないので)

Pugの特徴

特徴的すぎる記法

嫌な意味ではなく、ほぼ初見だったのでそう感じたのかもしれません。
テンプレートエンジンなので、通常のHTMLとはかなり記法が異なります。
例えば、

  • 開始・閉じタグが必要ない
  • 階層構造はインデントで表現される
  • 属性は括弧内に書く

これだけでもかなり違うことがわかりますね。

参考までに、pugで書いたものが、どのようにコンパイルされるのかを見てみます。

Pugの記述

main
  h1 タイトル
  section
    h2 タイトル
    p テキスト
  section
    h2 タイトル
    p テキスト


→HTML(コンパイル後)

<main>
  <h1>タイトル</h1>
  <section>
    <h2>タイトル</h2>
    <p>テキスト</p>
  </section>
  <section>
    <h2>タイトル</h2>
    <p>テキスト</p>
  </section>
</main>


こう見ると、Pugの書き方ってなんとなくSassっぽい感じがしますね。
Sassに慣れている人であれば、すんなり入ることができるかもしれません。

ファイルを分割管理できる

ファイルをパーツごとに分割して、コンポーネント的に使いたい場所で呼び出して(include)使用できるのも大きな魅力かと思います。
予めヘッダーやフッターといった共通パーツは分割ファイルとして管理しておけば、修正があった時でも対応コストがかなり省けるかと思います。

試しに、パーツ用の格納フォルダ/include/を用意し、header/footerを格納。
index.pug に読み込み、コンパイルしてみます。

header.pug

header.header
    .header_logo
        img(src="/assets/images/logo.png" alt="companyName")
    nav.header_nav
    a.header_nav-item(href="/") home
    a.header_nav-item(href="/about/") about
    a.header_nav-item(href="/company/") company


footer.pug

footer.footer
  p.copy © companyName


index.pug

doctype html
html(lang="ja")
	body
		include include/_header // ここで _header.pug を呼び出し。拡張子は不要です
		.siteWrapper
			~~~~~~~~
		include include/_footer  // ここで _footer.pug を呼び出し。拡張子は不要です


index.html(コンパイル後)

<!DOCTYPE html>
<html lang="ja">
  <body>
    <header class="header">
      <div class="header_logo">
        <img src="assets/images/pug.jpg"  alt="companyName">
      </div>
      <nav class="header_nav">
        <a class="header_nav-item" href="/">home</a>
        <a class="header_nav-item" href="/about/">about</a>
        <a class="header_nav-item" href="/company/">company</a>
      </nav>
    </header>
    <div class="siteWrapper">
      ~~~~~~~~~
    </div>
    <footer class="footer">
      <p class="copy">&copy; sampleCompany.inc</p>
    </footer>
  </body>
</html>


過去、静的サイト内で共通パーツを呼び出す際にはパーツごとのhtmlファイルを作成して、javascriptで呼び出し文を書いていました。
正直、使い勝手があまり良くなく、苦労した記憶があります。
『これを知っていれば絶対に使ったのに...!』と、個人的に最も魅力として感じたポイントはこれでした。

繰り返し処理が使える

ブログやニュースの一覧をHTMLで書こうとすると、どうしても表示数分の要素が必要になりますよね。
そんな時には、配列が使えたりします。

試しに、ニュース部分をpugで書いたものと、コンパイル後のもので比較してみます。

.newsWrapper
	ul.newsList
		-
			const newsItems = [
				{
					'date' :'2022/01/04',
					'cat':'お知らせ',
					'title':'新年のお知らせ',
					'link':'news3.html'
				},
				{
					'date':'2021/12/26',
					'cat':'お知らせ',
					'title':'年末年始の営業のお知らせ',
					'link':'news2.html'
				},
				{
					'date':'2021/11/17',
					'cat':'お知らせ',
					'title':'ウェブサイトをリニューアルしました',
					'link':'news1.html'
				},
			]
		each val,i in newsItems
			li.newsList_item
				a(href="./news/" + val.link)
					.newsList_item-text
						time.newsList_item-date #{val.date}
						p.newsList_item-category #{val.cat}
						p.newsList_item-title #{val.title}


コンパイル後

<div class="newsWrapper">
	<ul class="newsList">
		<li class="newsList_item">
			<a href="./news/news3.html">
     			<div class="newsList_item-text">
					<time class="newsList_item-date">2022/01/01</time>
					<p class="newsList_item-category">お知らせ</p>
					<p class="newsList_item-title">新年のお知らせ</p>
				</div>
			</a>
		</li>
		<li class="newsList_item">
			<a href="./news/news2.html">
				<div class="newsList_item-text">
					<time class="newsList_item-date">2021/12/26</time>
					<p class="newsList_item-category">お知らせ</p>
					<p class="newsList_item-title">年末年始の営業のお知らせ</p>
				</div>
			</a>
		</li>
		<li class="newsList_item">
			<a href="./news/news1.html">
				<div class="newsList_item-text">
					<time class="newsList_item-date">2021/11/17</time>
					<p class="newsList_item-category">お知らせ</p>
					<p class="newsList_item-title">ウェブサイトをリニューアルしました</p>
				</div>
			</a>
		</li>
	</ul>
</div>


for文 や each文 が使えることにより、こうした記述もシンプルに書くことができました。
行数にこそ差はありませんが、修正や追加の際にかなり探しやすく、構造を変えようという場合にも対応しやすいかと思います。

変数も使える

パスのショートコードや、ページごとに変わるタイトルなどを変数として使用することができます。

// 画像パスのショートコード
// 変数宣言の前には -  (ハイフンと半角スペースが必要)
- const path_img =  '/assets/images/' 

// 変数を属性値として使用する際は、 変数 + "その後の文字列" という記法になる。
img(src= path_img + "/sample.jpg", alt="sampleimage")


コンパイルすると、

<img src="/assets/images//sample.jpg" alt="sampleimage">

となります。

使ってみての注意点

複数人での開発時には注意

もし複数人でのプロジェクトで採用する場合や、メンバー全員がpugを使えないと難しいなと思いました。
環境構築というよりは、どういう性質を持っているのかを理解しないまま触ってしまうと、修正依頼でいきなり.htmlファイルを触ってしまうなど、さまざまな懸念が挙げられるのではないかと感じました。

さいごに

目も手も慣れるまではかなり戸惑うと思います。(経験者談)
僕はまだ慣れていません。

しかしながら、emmetも使えるし、コンポーネント利用もできて、修正もしやすい。
閉じタグがないので、構造を突然変更したくなってもすぐに対応ができます。

思ったより面倒くさくもないし、メリットばかりでなぜ今まで使ってこなかったのかと自分自身を小一時間程度問いただしたい衝動に駆られています。

また、今回は書いていませんが、if文を使っての条件分岐やmixinが使えたり、レイアウトブロックを作成して使いまわせるなど、他にも便利な機能がたくさんあるようです。

記法に抵抗がなければかなり取り回しの効くものかと思います。
一度ペライチのページを作ってみて、もう少し慣れたら他のテンプレートエンジンも使ってみようかなと思います。




本当にどうでもいい話ですが、イントネーションは決まってるのでしょうか。
パ↗︎グ↘︎ ? パ↘︎グ↗︎ ?
犬種の方が前者だとすると、やはり後者なのでしょうか。
もし正解を知っている人がいらっしゃったら教えてください。