Pug 2.0.3

Pug(パグ)は HTML を効率的に書ける Node.js + JavaScript 製のテンプレートエンジンです。元は Jade(ジェード)という名前でしたが、商標の関係で改名されました。繰り返しや属性などの書き方が変更されているので、Jade 時代のコードを流用する場合はシンタックスエラーに注意しましょう。

単一ファイルの拡張子は .pug となりますが、そのままではブラウザで解釈できません。Web として表示させるには HTML へとコンパイルする必要があります。

Example

Pug は Ruby のようにインデントで階層化を行い書いていく記法を基本としており、コンパイルすることで HTML が出力できます。閉じタグは不要。JavaScript のように変数・繰り返し・条件分岐も書けます。また、Pug ファイルは分割して複数ページで使い回せます。

doctype html
html(lang="ja")
  head
    meta(charset="UTF-8")
    title タイトル
  body
    main#main
      ul.btns
        li
          a.btn(href="/") ボタン

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>タイトル</title>
</head>
<body>
  <main id="main">
    <ul class="btns">
      <li><a href="/" class="btn">ボタン</a></li>
    </ul>
  </main>
</body>
</html>

Compile

Pug を HTML にコンパイルして Web で表示させる方法は大きく分けて 3 種類あります。

Basic Compile

Pug のコンパイルとしてはもっとも簡単な手法。コンパイラーアプリや CLI ツールで Pug ファイルを監視、随時 HTML を生成しサーバーに上げます。アプリは Win/Mac 対応シェアウェアの Prepros、CLI ツールは gulp が多く使われています。

10 ページ程度の静的な Web サイトを制作する際には効率的ですが、20 ページを超える頃にはコンパイルにかかる時間がストレスになります。ディレクトリ分割か監視対象のカスタマイズを検討しましょう。

Temporary Compile

Node.js が動くローカルサーバーで一時的に Pug をコンパイルしながら開発する手法。webpack Serve(旧 webpack-dev-server)で pug-loader などを使って随時 HTML を返します。Vue や React テンプレートの HTML 部分を Pug で書く場合もこの手法に当たります。

開発環境がホットリロードに対応しているため、ファイル数が増えてもストレスがありません。時間がかかる作業は最終的なビルドのみです。

Server Compile

Node.js が動くサーバーに Express などを導入して Pug ファイルを動かす手法。ページにアクセスがあった際、動的に Pug を HTML に変換して表示させます。

Decompile

既存の HTML を Pug にしたい場合は逆コンパイルを行う必要があります。一番手軽なのは、Web 版の HTML2Jade(Pug)で変換することです。

Comment

Pug のコメントは // だと HTML に出力、//- と書くことで出力されないコメントにできます。

// 出力されるコメント
//- 出力されないコメント

<!-- 出力されるコメント-->

Include

Basic Include

include でパスを書くことで分割した Pug ファイルを読み込めます。

include section/_header.pug

main#main
  ul.btns
    li
      a.btn(href="/") ボタン

include section/_footer.pug

<header>
  <h1>
    <a href="#"><img src="img/logo.svg" alt="Pugの説明ページ|Pugの説明サイト" class="logo"></a>
  </h1>
</header>
<main id="main">
  <ul class="btns">
    <li><a href="/" class="btn">ボタン</a></li>
  </ul>
</main>
<footer>
  <p class="copylight">&copy; 運営会社名</p>
</footer>

Root Include (gulp)

gulp で複数ページを制作している際、include をルートパスにしたいと考えるでしょう。その場合は、gulpfile.js 内にオプションで basedir を設定します。

project
├── gulpfile.js
├── docs
│   └── index.html
└── src
    └── pug
        ├── index.pug
        └── section
            ├── _footer.pug
            ├── _header.pug
            └── _main.pug
//- index.pug
include /section/_header.pug
include /section/_main.pug
include /section/_footer.pug
// gulpfile.js
const gulp = require("gulp")
const pug = require("gulp-pug")

const paths = {
  src_pug: "src/pug/",
  out_html: "docs/"
}

const pugOptions = {
  basedir: src_pug
}

gulp.task("pug", () => {
  return gulp
    .src([paths.src_pug + "**/*.pug", "!" + paths.src_pug + "**/_*.pug"])
    .pipe(pug(pugOptions))
    .pipe(gulp.dest(paths.out_html))
})

Variable

- var で変数を宣言して Pug 内で使い回せます。

- var title = "Pugの説明ページ|色々と説明するサイト";

doctype html
html(lang="ja")
  head
    meta(charset="UTF-8")
    title #{title}
  body
    header
      h1
        a(href="#")
          img.logo(src="img/logo.svg" alt=title)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Pugの説明ページ|色々と説明するサイト</title>
</head>
<body>
  <header>
    <h1>
      <a href="#"><img src="img/logo.svg" alt="Pugの説明ページ|色々と説明するサイト" class="logo"></a>
    </h1>
  </header>
</body>
</html>

変数は JSON 形式で入れ子にできます。そのため、複数ページ・複数コンテンツのメタデータを 1 箇所にまとめておき、必要に応じて引き出す管理方法を取れます。

//- base/_config.pug
-
  var pages = {
    index: {
      id: "index",
      title: "QRANOKO",
      desc: "CREATIVE PARTNERS",
      class: [ "qranoko", "qranoko-index" ],
      url: "index.html",
      ogp: "ogp.png",
      agent: "rwd",
      login: "no"
    },
    about: {
      id: "about",
      title: "ABOUT - QRANOKO",
      desc: "CREATIVE PARTNERS",
      class: [ "qranoko", "qranoko-about" ],
      url: "about.html",
      ogp: "ogp.png",
      agent: "rwd",
      login: "no"
    }
//- about.pug
include /base/_config.pug
- var key = "about"
- var page = pages[key]

h1= page.title

<h1>ABOUT - QRANOKO</h1>

Case

変数で条件分岐させる際に case が使えます。when で値を指定。default はすべて当てはまらないときに実行されます。

- var page = "index";

case page
  when "index"
    h1 タイトル
  when "guide"
    h1 ページ|タイトル
  default
    p タイトル

<h1>タイトル</h1>

if else

変数で条件分岐させる際に if が使えます。if で変数に値が入っている場合だけ出力・特定の値の場合だけ出力、else で合致しない場合の出力を書けます。

- var item_01 = "ペンシル";
- var item_02 = "";
- var item_03 = "消しゴム";

if item_01
  p= item_01

if item_02
  p= item_02

if item_03 === "鉛筆"
  p えんぴつ
else if item_03 === "筆箱"
  p ふでばこ
else
  p なし

<p>ペンシル</p>
<p>なし</p>

each

each で繰り返しの出力ができます。画像のパスとタイトルだけ変えて繰り返す場合などによく使います。

ul
  each val in [1, 2, 3, 4, 5]
    li= val

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

入れ子の変数を用いることで柔軟な制作が可能になります。

-
  var nav = {
    index : {
      title : "HOME",
      url : "/"
    },
    about : {
      title : "ABOUT",
      url : "about.html"
    },
    works : {
      title : "WORKS",
      url : "works.html"
    },
    /*service : {
      title : "SERVICE",
      url : "service.html"
    },*/
    contact : {
      title : "CONTACT",
      url : "contact.html"
    }
  }

nav.nav.is-global
  each val in nav
    a.nav-item(href=val.url)
      span.text= val.title

<nav class="nav is-global">
  <a class="nav-item" href="/"><span class="text">HOME</span></a>
  <a class="nav-item" href="about.html"><span class="text">ABOUT</span></a>
  <a class="nav-item" href="works.html"><span class="text">WORKS</span></a>
  <a class="nav-item" href="contact.html"><span class="text">CONTACT</span></a>
</nav>

while

while を使うことで回数を決めて繰り返すことができます。

- var n = 0;

ul
  while n < 4
    li= n++

<ul>
  <li>0</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>

Extends

extends で型として作った別ファイルを呼び出してデータを流し込むことができます。主に基本構造を _layout.pug として用意してページを量産する場合に使います。

//- _layout.pug
doctype html
block vars
html(lang="ja")
  head
    include _head.pug
  body(class=site.body class=page.body)
    block contents
    include _script.pug
//- index.pug
extends /base/_layout.pug

block vars
  include /base/_config.pug
  - var key = "index"
  - var page = pages[key]

block contents

Mixin

mixin で型を用意して使い回すことができます。主に細かいモジュールの繰り返しで使います。

mixin pet(name)
  li.pet= name

ul
  +pet('cat')
  +pet('dog')
  +pet('pig')

<ul>
  <li class="pet">cat</li>
  <li class="pet">dog</li>
  <li class="pet">pig</li>
</ul>

Piped Text

| を先頭に書くことによって文章やタグを改行せずに出力できます。長文の管理や、途中にリンクタグを入れる場合に便利です。

p
  | 文章の途中に
  a(href="#") リンクタグ
  | を入れる。

<p>文章の途中に<a href="#">リンクタグ</a>を入れる。</p>

Block in a Tag

タグの末尾を . にすることで、内包する要素の Pug 構文を解除できます。主に、インラインでスタイルやスクリプトを書く場合に使用します。

script.
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments)};
  gtag('js', new Date());
  gtag('config', 'UA-XXXXXXXX-XX');

<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments)};
  gtag('js', new Date());
  gtag('config', 'UA-XXXXXXXX-XX');
</script>

Markdown

gulp 等では、jstransformer-markdown-it をインストールし Pug 内で Markdown を書く・Markdown ファイルを読み込むことができます。

$ npm i -D jstransformer-markdown-it
.wysiwyg
  :markdown-it
    ## ソースコード

    MarkdownがPug内で書けるとは。

  include:markdown-it article.md

<div class="wysiwyg">
  <h2>ソースコード</h2>
  <p>MarkdownがPug内で書けるとは。</p>
  <h3>読み込んだMarkdown</h3>
  <p>読み込んだMarkdownテキスト。</p>
</div>

:markdown-it に続けてオプションを設定できます。よく使うオプションは以下。

option default detail
html false Markdown 内で HTML タグを有効にする
breaks false 改行箇所に <br/> タグを差し込む
langPrefix 'language-' コードブロックにプレフィックス class を付与
linkify false URL を自動的に <a> タグへ変換
.wysiwyg
  :markdown-it(breaks="true")
    ## ソースコード
Last Updated: 2018-9-29 16:06:02