Pugと仲良くする方法

この記事は [J2complexed Advent Calendar 2016](http://qiita.com/advent-calendar/2016/j2complexed) の14日目の記事です。

みなさんはパグと仲良くできていますか？
パグはかわいいですね。なによりもマークアップの効率が良くなります！
Pugは以前までJadeと名乗っていましたが、Pugの方がいいですね。いいセンスをしてます。
詳しくは公式を見ていただいたほうが、いいと思います！
![pug.png](https://qiita-image-store.s3.amazonaws.com/0/109382/f7ff8e44-25ef-21f4-976a-d6d29425340f.png)

[Getting Started - Pug](https://pugjs.org/api/getting-started.html)

# Pugの簡単な紹介
PugはJST (JavaScript Templates)って言われてるJavaScriptで動くテンプレートエンジンです。
Expressでも動かすことができます。（動かしたことはありませんが）
[Express でのテンプレート・エンジンの使用](http://expressjs.com/ja/guide/using-template-engines.html)

Githubに載っている例を見てみると、書き方がわかると思います。

```jade:example.pug
doctype html
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) bar(1 + 5)
  body
    h1 Pug - node template engine
    #container.col
      if youAreUsingPug
        p You are amazing
      else
        p Get on it!
      p.
        Pug is a terse and simple templating language with a
        strong focus on performance and powerful features.
```

これが、こうなります。

```html:example.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Pug</title>
    <script type="text/javascript">
      if (foo) bar(1 + 5)
    </script>
  </head>
  <body>
    <h1>Pug - node template engine</h1>
    <div id="container" class="col">
      <p>You are amazing</p>
      <p>Pug is a terse and simple templating language with a strong focus on performance and powerful features.</p>
    </div>
  </body>
</html>
```

この例でわかるところといえば、以下でしょうか。

* 閉じタグがいらない
* インデントが重要
* classやidはCSSセレクタと同じ
* 属性は()の中で書く
* if文で分岐ができる
* 変数を使える
* .を付けると、次のインデントは文字列としてそのまま出力できる
* divは省略できる

例にはありませんでしたが、for文も書けますよ！

# Pugでテンプレートをつくる
Pugについて理解が深まったところで、さらに仲良くなるためにテンプレートの用意です。
※ これは自己流なので、よりよい方法をご存じの方、情報をお待ちしてます

簡単に概要を説明すると、まず、 `パーツのpug` を用意して、 `レイアウトのpug` に読み込ませます。
次に `設定ファイルのpug` を `実際にhtml化するpug` に読み込ませて、 `レイアウトのpug` を継承させます。
・・・なんだかごちゃごちゃしてますが、用意するファイルはこんな感じです。

```
index.pug         ・・・ 実際にhtml化するpug
_config.pug       ・・・ 設定ファイルのpug
_layout.pug       ・・・ レイアウトのpug
include/          ・・・ パーツのpugのディレクトリ
  _inc_head.pug
  _inc_header.pug
  _inc_nav.pug
  _inc_footer.pug
```

## パーツを用意

パーツを分けておきます。Pugはincludeで別のpugやhtmlを読み込むことができるので、いろいろと使いまわすことができるのです。

### _inc_head.pug
headタグ内のパーツです。pageというオブジェクトから値を受け取ってセットしています。
keyやcss_path、domainも変数です。

```:_inc_head.jade

meta(charset="utf-8")
meta(http-equiv="X-UA-Compatible", content="IE=edge")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
meta(name="format-detection", content="telephone=no")

title #{page.title}

meta(content=page.description, name="description")
meta(content=page.keywords, name="keywords")
meta(content=page.title, property="og:title")
meta(content=page.description, property="og:description")
meta(content=domain + page.image, property="og:image")
meta(content=domain + page.url, property="og:url")
meta(content=(key == "top" ? "website" : "article"), property="og:type")
meta(content="ja_JP", property="og:locale")

link(rel="stylesheet", href=css_path+"/style.css")
script(src="https://code.jquery.com/jquery-1.11.2.min.js")
```

### _inc_header.pug
次にheaderタグのパーツです。
pages、image_pathも変数です。

```jade:_inc_header.pug
header
  .header_logo
    if key=='top'
      h1
        a(href=pages.top.url)
          img(src=image_path+"/shared/header_logo.png" alt=pages.top.name)
    else
      p
        a(href=pages.top.url)
          img(src=image_path+"/shared/header_logo.png" alt=pages.top.name)
```

### _inc_nav.pug
次にnavタグのパーツです。
content_d_stateも変数で、状況に応じて出力するタグの内容が変わったりすることもテンプレートに埋め込んでおけます。便利。

```:_inc_nav.pug
nav
  ul
    li
      a(href=pages.content_a.url)
        img(src=image_path+"/shared/nav_content_a.png", alt=pages.content_a.name)
    li
      a(href=pages.content_b.url)
        img(src=image_path+"/shared/nav_content_b.png", alt=pages.content_b.name)
    li
      a(href=pages.content_c.url)
        img(src=image_path+"/shared/nav_content_c.png", alt=pages.content_c.name)
    if content_d_state=="public"
      li
        a(href=pages.content_d.url)
          img(src=image_path+"/shared/nav_content_d_public.png" alt=pages.content_d.name)
    else if content_d_state=="comingsoon"
      li
        img(src=image_path+"/shared/nav_content_d_comingsoon.png" alt=pages.content_d.name+" Coming Soon...")
```

### _inc_nav.pug
次にfooterタグのパーツです。
js_pathも変数です。

```:_inc_footer.pug
footer
  p
    small copyright
script(type='text/javascript' src=js_path+"/js/functions.js")
```

## 設定ファイルを用意
titleやページのurlなど、変更があったときにファイルが分かれていると不便ですよね。
そんなときのために、変数をまとめてあります。

`var` で変数が宣言できます。

```:_config.pug
- var image_path = 'assets/img'
- var css_path = 'assets/css'
- var js_path = 'assets/js'
- var domain = 'https://example.com/'
- var content_d_state = "comingsoon"
- 
  var pages = {
    top : {
      url : 'index.html',
      name : 'トップページ',
      title : 'トップページ',
      description : 'トップページです',
      keywords : 'トップページ',
      image : 'assets/img/ogp.jpg'
    },
    content_a : {
      url : 'content_a.html',
      name : 'コンテントA',
      title : 'コンテントA',
      description : 'コンテントAです',
      keywords : 'コンテントA',
      image : 'assets/img/ogp.jpg'
    },
    content_b : {
      url : 'content_b.html',
      name : 'コンテントB',
      title : 'コンテントB',
      description : 'コンテントBです',
      keywords : 'コンテントB',
      image : 'assets/img/ogp.jpg'
    },
    content_c : {
      url : 'content_c.html',
      name : 'コンテントC',
      title : 'コンテントC',
      description : 'コンテントCです',
      keywords : 'コンテントC',
      image : 'assets/img/ogp.jpg'
    },
    content_d : {
      url : 'content_d.html',
      name : 'コンテントD',
      title : 'コンテントD',
      description : 'コンテントDです',
      keywords : 'コンテントD',
      image : 'assets/img/ogp.jpg'
    }
  }
```

## レイアウトファイルを用意
レイアウトっていうと分かりにくいかもしれませんが、パーツを組み合わせる骨組みみたいなものです。
ここで、 `block` という新しい言葉が出てきます。
ブロックに `vars` や `contents` という名前を付けておいて、あとで読み込む事ができます。

```:_layout.pug
doctype html
block vars
html(lang="ja")
  head
    include _inc_head.pug

  body(class=key)
    .l_contents
      include _inc_header.pug
      include _inc_nav.pug
      block contents
    include _inc_footer.pug
```

## 実際にHTMLにするファイルを用意
extendでレイアウトファイルを継承してます。
継承後にblockでレイアウト側に送るイメージです。

```:index.pug
extends _layout.pug

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

block contents
  h2 page.title
  .keyvisual_container
    p.keyvisual_image
      img(src=image_path+"/top/top_keyvisual.jpg", alt="")
```

# gulpで実行
package.jsonから必要なものをインストールします。
見慣れないものが混じっているかもしれませんが、入れましょう。

```json:package.json
{
  "name": "love-pug",
  "version": "1.0.0",
  "description": "i love pug",
  "main": "index.js",
  "scripts": {
    "gulp": "gulp"
  },
  "keywords": [
    "pug"
  ],
  "author": "j2complexed",
  "license": "ISC",
  "devDependencies": {
    "browser-sync": "^2.18.5",
    "gulp": "^3.9.1",
    "gulp-plumber": "^1.1.0",
    "gulp-pug": "^3.2.0",
    "node-notifier": "^4.6.1"
  }
}
```

上記のファイルを用意したらコマンドでインストールです。

```bash
$ npm install
```

次にgulpを実行するための設定をします。
このままコピペです。

```js:gulpfile.js
const gulp = require('gulp');
const browserSync = require("browser-sync");
const plumber = require('gulp-plumber');
const pug = require('gulp-pug');
const notifier = require('node-notifier');

const errorHandler = function(error) {
    notifier.notify({
      message: 'しっぱいしたワン',
      title: 'パグ',
      appIcon: __dirname + '/pug.png',
    }, function () {
      console.log(error.message);
    });
  };

gulp.task('browser-sync', () => {
    browserSync({
        server: {
            baseDir: "./dist/"
        }
    });
    gulp.watch("./*.html", browserSync.reload);
});

gulp.task('views', function() {
  return gulp.src(['views/**/*.pug', '!views/**/_*.pug'])
    .pipe(plumber({errorHandler: errorHandler}))
    .pipe(pug({pretty: true}))
    .pipe(gulp.dest('dist/'));
});

gulp.task('watch', () => {
  gulp.watch(['./views/**/*.pug'], () => {
    gulp.start(['views']);
  });
});

gulp.task('default', ['browser-sync', 'views', 'watch']);
```

あとはコマンドで実行です。

```bash
$ npm run gulp
```

そうすると、distというディレクトリにindex.htmlができて、ブラウザが起動し `http://localhost:3000/` が開いたと思います。
cssとかはないので、崩れているとは思いますが。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <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">
    <meta name="format-detection" content="telephone=no">
    <title>トップページ</title>
    <meta content="トップページです" name="description">
    <meta content="トップページ" name="keywords">
    <meta content="トップページ" property="og:title">
    <meta content="トップページです" property="og:description">
    <meta content="https://example.com/assets/img/ogp.jpg" property="og:image">
    <meta content="https://example.com/index.html" property="og:url">
    <meta content="website" property="og:type">
    <meta content="ja_JP" property="og:locale">
    <link rel="stylesheet" href="assets/css/style.css">
    <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  </head>
  <body class="top">
    <div class="l_contents">
      <header>
        <div class="header_logo">
          <h1><a href="index.html"><img src="assets/img/shared/header_logo.png" alt="トップページ"></a></h1>
        </div>
      </header>
      <nav>
        <ul>
          <li><a href="content_a.html"><img src="assets/img/shared/nav_content_a.png" alt="コンテントA"></a></li>
          <li><a href="content_b.html"><img src="assets/img/shared/nav_content_b.png" alt="コンテントB"></a></li>
          <li><a href="content_c.html"><img src="assets/img/shared/nav_content_c.png" alt="コンテントC"></a></li>
          <li><img src="assets/img/shared/nav_content_d_comingsoon.png" alt="コンテントD Coming Soon..."></li>
        </ul>
      </nav>
      <h2>page.title</h2>
      <div class="keyvisual_container">
        <p class="keyvisual_image"><img src="assets/img/top/top_keyvisual.jpg" alt=""></p>
      </div>
    </div>
    <footer>
      <p><small>copyright</small></p>
    </footer>
    <script type="text/javascript" src="assets/js/js/functions.js"></script>
  </body>
</html>
```

どうでしょう！テンプレートが完成です！
他のページを作るときには、 `extends _layout.pug` と `include _config.pug` のディレクトリに気をつけて貰えば、コピペでテンプレートを使うことができます！

# もっと仲良くなりたい人のために
先ほどの `gulpfile.js` でお気づきかもしれませんが、コンパイルに失敗すると、パグが失敗したことを通知で教えてくれます。
![pug.gif](https://qiita-image-store.s3.amazonaws.com/0/109382/d57c0c05-2b89-72ef-09cb-089d03d50d83.gif)

よくgulpに監視させて、オートリロードとかにしてるとエラーしてるのに気がつかなくて修正が反映されなくて焦ることが合ったかもしれませんが、これで大丈夫です！
エラーでささくれた気持ちもパグで癒やされること間違いなしですよ！

※ 読み込むアイコン画像は各自で用意してくださいね！