アンチPug派がPugのことを褒めちぎる


フロントエンドエンジニアやマークアップエンジニアと呼ばれる人たちが、HTMLのコーディングの作業効率化をする時に、よくテンプレートエンジンを使うことがあると思います。
最近では、Gatsby.jsやNuxt.jsを使って静的サイトを使って実装を行うこともありますが、
EJSやPugといったテンプレートエンジンを使うこともまだまだあります。
特にEJSやPugは、「EJS vs Pug」みたいな感じで比較対象とされることが多いかと思います。

私の場合はよくEJSを好んで使ってました。
というか、Pugはむしろ嫌いでした。
が、最近Pugを使ってみて、それは単なる食わず嫌いであったと感じさせられたので、
Pugのことを褒めちぎりたいと思います。

Pugの嫌いだったところ

Pugが何で嫌いだったか。主な理由は以下のような感じです。

  • Pugの記法を覚えないといけないところ
  • インデントでタグの入れ子構造を定義するところ
  • マスコットキャラクターがなんか好きじゃない

EJSの場合、基本的にはHTMLのタグで書けます。

index.ejs
<%
  const name = 'なまえ'
%>
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="css/style.css">
    <title>タイトル</title>
    <meta name="description" content="">
    <meta name="keywords" content="">
    <%- include('./include/_meta') %>
  </head>
  <body>
    <section id="content">
      <div class="inner">
        <p>Hello<%= name %>!</p>
      </div>
    </section>
    <script src="js/script.js"></script>
  </body>
</html>

こんな感じで基本的にHTMLのタグで書くことができ 変数を使って動的に出力したいところには <%= text %> といった感じでEJSのタグを書くことができます。
<% %>で囲まれてるところにはEJSのロジック書くんだなみたいなのも何となくわかります、。
普段HTMLをよく書いているマークアップエンジニアにとってはこっちの方が馴染みやすい。

でも、Pugの場合は独自の記法が存在します。
上記と同じように書きたいときはこんな感じになります。

index.pug
- const name = 'なまえ' 
doctype html
html(lang='ja')
  head
    meta(charset='UTF-8')
    meta(name='viewport', content='width=device-width, initial-scale=1.0')
    link(rel='stylesheet', href='css/style.css')
    title タイトル
    meta(name='description', content='')
    meta(name='keywords', content='')
    include ./includes/_meta
  body
    section#content
      .inner
        p Hello#{name}! 
    script(src='js/script.js')

あれ?divタグどこ行ったん?
#{name} が動的に出力されるのは何となく分かるけど変数はどこに書いてるの?
metaやscriptの定義なんかもなんかわかりにくいな・・・
っていう感じで記述していくのに脳内変換が必要で正直好きになれませんでした。。

でも、案件でPugで実装をしないといけないケースが発生し、渋々Pugでコーディングをしていると、
「ん?こいつ、実はめちゃめちゃ便利なんとちゃうか?」って思うようになりました。

さぁ、ここからPugを褒めちぎっていきたいと思います。

Pugのいいところその1 コードの記述が圧倒的に少ない!

EJSはHTMLと同様に、<div></div> のように、閉じタグとセットでタグを書かないといけません。
しかし、Pugはインデントでタグの入れ子構造を表現するので、 閉じタグを書く必要がありません。 そのため、
ファイルの行数が約半分くらいになり、行数が圧倒的に少なくなります。
コードを書いていてEJSや生HTMLで書くよりもファイルの見通しがかなり良いなと思いました。

Pugのいいところその2 mixinが使える!!

PugにはSASSのmixinの様に、よく使用するコードをショートコードのように定義して使い回すといったことができます。
例えば、pictureタグを使って、画像出し分けを行ったりする場合、mixinを定義しておくと以下のように書くことができます。

変換前

mixin.pug
//-
 pictureタグのmixin
 @param name 画像ファイル名
 @param exp 拡張子
 @param alt ALTテキスト
mixin picture(name, exp, alt)
    picture
        source(media="(max-width: 767px)" srcset=`/images/${name}-sp.${exp}`)
        source(media="(min-width: 768px)" srcset=`/images/${name}.${exp} 1x, /images/${name}@2x.${exp} 2x`)
        img(src="/images/" + name + exp, alt=alt, decoding="async")
index.pug
include mixin
picture('top/hoge','jpg','ALT')

変換後

index.html
<picture>
  <source media="(max-width: 767px)" srcset="/images/top/hoge-sp.jpg">
  <source media="(min-width: 768px)" srcset="/images/top/hoge.jpg 1x, /images/top/[email protected] 2x">
  <img src="/images/top/hogejpg" alt="ALT" decoding="async">
</picture>

mixinには引数を渡すことができるので、上記のように定義して使いたい場所で使い回すことができます。
これでもコードを書く量が圧倒的に減らすことができますし、
修正の際にもmixinを修正したら該当箇所すべてに反映されるので、修正の手間も大幅に削減できます。

Pugのいいところその3 テンプレート機能が使える!!!!!!

同じようなレイアウトページを量産する時には、予めテンプレートになるファイルを作っておき、そのファイルを 継承 してページを量産することができます。

例えば、サイト全体で使用するCSSファイルやJavaScriptのファイル、metaタグなどを記述したテンプレートファイルを作成し、
ページごとに可変になるブロックを block ブロック名 という形で定義しておくと、共通部分を継承しながら下層ページなどを作成する時に使い回すことができます。

例えば、以下のようにレイアウトを定義します。

_layout.pug
doctype html
html
  head
    block title
      title ページタイトル
  body
    p ここは共通部分です。以下はページごとに変わる部分です
    block content

    script(src="/js/common.js" defer)
    block script

継承するページを以下のように作成します。

page1.pug
extends _layout.pug

block title
  title 1ページ目

block content
  h1 これは1ページ目です
page2.pug
extends _layout.pug

block title
  title 2ページ目

block content
  h1 これは2ページ目です
  p 2ページ目にはテキストも入ります。

block script
  script(src="/js/page2.js" defer)

出力されるファイル

page1.html
<!DOCTYPE html>
<html>
  <head>
    <title>1ページ目</title>
  </head>
  <body>
    <p>ここは共通部分です。以下はページごとに変わる部分です</p>
    <h1>これは1ページ目です</h1>    // page1.pugのblock contentで定義した内容が追加
    <script src="/js/common.js" defer></script>
  </body>
</html>
page2.html
<!DOCTYPE html>
<html>
  <head>
    <title>2ページ目</title>
  </head>
  <body>
    <p>ここは共通部分です。以下はページごとに変わる部分です</p>
    <h1>これは2ページ目です</h1>             // page2.pugのblock contentで定義した内容が追加
    <p>2ページ目にはテキストも入ります。</p>  // page2.pugのblock contentで定義した内容が追加
    <script src="/js/common.js" defer></script>
    <script src="/js/page2.js" defer></script>  // page2.pugのblock scriptで定義した内容が追加
  </body>
</html>

_layout.pugの block contentblock script と定義したブロックに page1.pug、page2.pugそれぞれのblock contentblock scriptで定義した要素が出力されていると思います

このように、page1.htmlとpage2.htmlで基本的なレイアウトや要素を共通のままで、
ページごとに要素を変更したり、追記したりすることが可能になります。

私はこのテンプレート機能が非常に便利で気に入りました!
この機能を理解した時に Pugってめちゃくちゃいいやん!!!!!ってなりました。

これは下層ページの量産などを行うときにはすごくパワーを発揮する機能です。

最後に

Pugが嫌いだった3つの理由

  • Pugの記法を覚えないといけないところ
    • →使ってるうちに慣れました
  • インデントでタグの入れ子構造を定義するところ
    • →これも使ってるうちに慣れました
  • マスコットキャラクターがなんか好きじゃない
    • →よく見たら愛おしいやつじゃないか! って思えるようになった。

食わず嫌いみたいな感じで嫌いになってた部分が大きかったけど、PugやEJSに限らず、ライブラリやフレームワークは一度ちゃんと触ってみて良し悪しを判断しないといけないなと思いました。