共通部分はパーツ化してHTMLページを作りたい!ということでPugに入門してみた

共通部分はパーツ化してHTMLページを作りたい!ということでpugに入門してみた

もともと1枚の静的HTMLで作っていた事業用サイト

こちらに少しページを足したくなったのですが、いざ静的HTMLでページを増やそうと思うと、ちょっとした悩みが…

「HTMLファイルを増やして後からヘッダーとかフッターとか変更した時に各ページにコピペは面倒だなぁ… パーツ化して使えるようにしたいなぁ…」

ということで、やり方は色々あると思いますが、今回はお勉強を兼ねて「Pug」というテンプレートエンジンを使ってみました!

その入門備忘録をまとめます

Pugとは

今回はざっくりとした説明とさせていただきますが、「Pug」とはHTMLを書くためのJavaScriptテンプレートエンジンです

Pugファイルをそのままサーバーにアップせず、HTMLに変換する

Pugで書いたファイルはサーバー上にアップロードしてもそのままWebページとしては表現できないので、Pug→HTMLに変換する必要があります

Sassを使ったことがあれば、Sass→CSSに変換して使う…といった流れに似た形になりますのでイメージしやすいかと思います!

今回やりたかったこと

今回Pugに入門するにあたり、期待していたことはこちら▼

  • ページ自体は静的なHTMLで作りたい
  • header,footerなど各ページ共通な部分はパーツ化して変更に強い状態にしておきたい

とりあえずコレだけ。

他の方法もあったかもしれませんが、ひとまずキーワード的に頭にあったのと、gulpで簡単に開発環境構築できそうだったのでPugを使ってみることにしました

Pugの書き方と開発環境構築

まずはPugの構文についてのまとめと、gulpでの開発環境についてまとめます

Pugの書き方

※各コードの説明の先頭行にある//Pug,<!--HTML-->は本記事での説明用に付けているもので、実際の変換結果とは違います。ご了承下さい

タグの書き方

PugでHTMLタグを書く場合、「[HTMLタグ] + スペース + テキスト」のように書いていきます

閉じタグなどは必要ありません

// Pug

p ああああ
<!-- HTML -->

<p>ああああ</p>

入れ子の書き方

Pugはインデントで階層を表現します

インデントはスペースでもタブでも大丈夫ですが、スペースとタブが混在するとエラーになるので注意が必要です

(Editorconfig等で固定しておくと安心)

// Pug

h1 第1階層
div 
  h1 第2階層
  div 
    h1 第3階層
    div ああああああ
<!-- HTML -->

<h1>第1階層</h1>
<div> 
  <h1>第2階層</h1>
  <div> 
    <h1>第3階層</h1>
    <div>ああああああ</div>
  </div>
</div>

id,classの付け方

id,classは#,.を使って表現します

Emmetを使ったことがあれば特に難しいことは無いと思います

idとclassをつける順に指定はなく、複数のクラスを付ける場合はそれぞれ.でつなげていきます

// Pug

div#id-sample
div.class-sample

div.class-sample#id-sample.class-sample2.class-sample3
<!-- HTML -->

<div id="id-sample"></div>
<div class="class-sample"></div>

<div class="class-sample class-sample2 class-sample3" id="id-sample"></div>

属性の付け方

aタグのhrefだったり、titleなどの属性は「HTMLタグ + (属性)」の形で書いていきます

// Pug

a(href="#") コレはリンクです

img(src="hoge.jpg" title="画像")

div(v-bind:title="message")
<!-- HTML -->

<a href="#">コレはリンクです</a>

<img src="hoge.jpg" title="画像"/>

<div v-bind:title="message"></div>

テキストを改行する

長い文章などを改行して書きたい場合は|brを使います

// Pug

p
  | 1行目
  br
  | 2行目
<!-- HTML -->

<p>1行目<br/>2行目</p>

HTMLタグをそのまま書く

HTMLタグの後ろに.を付けて入れ子にすることで書いたタグをそのままHTMLに反映してくれます

// Pug

div.
  <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3211.764543391398!2d139.05838716530198!3d36.39069363003499!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x601ef322960966dd%3A0xcfe5b33052dd7d72!2z44CSMzcxLTAwMjYg576k6aas55yM5YmN5qmL5biC5aSn5omL55S677yR5LiB55uu77yRIOe-pOmmrOecjOW6gQ!5e0!3m2!1sja!2sjp!4v1512255596808" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
<!-- HTML -->

<div>
  <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3211.764543391398!2d139.05838716530198!3d36.39069363003499!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x601ef322960966dd%3A0xcfe5b33052dd7d72!2z44CSMzcxLTAwMjYg576k6aas55yM5YmN5qmL5biC5aSn5omL55S677yR5LiB55uu77yRIOe-pOmmrOecjOW6gQ!5e0!3m2!1sja!2sjp!4v1512255596808" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
</div>

コメント

Pugのコメントは行の先頭に//を書きます。

また、//-のように二重スラッシュの後にハイフンをつけることでHTMLに残らないコメントにできます

// Pug

// コメント
//- HTMLに変換されないコメント
<!-- HTML -->

<!-- コメント -->

Pugの開発環境をgulpで構築

自分がいつも使っているということもありまして、本記事ではgulpを使ってPugの開発環境を構築してみます

Pugを使ってHTMLファイルを作るフォルダ構成

▲今回はこんな感じなフォルダ構成になるようにしてみました

pugフォルダ以下の階層はHTML変換後も保ってくれるのでひと安心

gulpのインストール

npm init等は済んでいるものとします

gulpとPugの変換に必要なパッケージgulp-pugをインストールしておきます

$ npm install gulp --save-dev
$ npm install gulp-pug --save-dev

gulpfile.js

今回は以下のようなgulpfile.jsを用意しました

var gulp = require('gulp');
var pug = require('gulp-pug');

var src_pug = [
  './src/pug/**/*.pug',
  '!./src/pug/**/_*.pug'
];

gulp.task('pug', function(){
  return gulp.src(src_pug)
  .pipe(pug({
    pretty: true
  }))
  .pipe(gulp.dest('./'));
});

準備ができたら以下のコマンドでPug→HTMLの変換を実行します

$ gulp pug

無事変換が出来ればOKです

Pugファイルの変更を監視して自動で変換する

これまでの状態だと、Pug→HTMLの変換は毎回コマンドを叩く必要がありますので、ファイルの変更があったら自動で変換してくれるようにカスタマイズしてみます

ファイル監視用のパッケージとエラー処理用のパッケージをインストールします

$ npm install gulp-watch --save-dev
$ npm install gulp-plumber --save-dev

gulpfile.jsも編集します

var gulp = require('gulp');
var pug = require('gulp-pug');
var plumber = require('gulp-plumber');
var watch = require('gulp-watch');

var src_pug = [
  './src/pug/**/*.pug',
  '!./src/pug/**/_*.pug'
];

gulp.task('pug', function(){
  return gulp.src(src_pug)
  .pipe(plumber({
    errorHandler: function(err){
      console.log(err.messageFormatted);
      this.emit('end');
    }
  }))
  .pipe(pug({
    pretty: true
  }))
  .pipe(gulp.dest('./'));
});

gulp.task('watch',['pug'],function() {
    watch( './src/pug/**/*.pug', function(event) {
        gulp.start('pug');
    });
});

あとは以下コマンドを1回実行すれば、ファイルが変更されるたびに自動でPug→HTMLの変換を実行してくれます

$ gulp pug

おまけ:atomユーザーはlanguage-pugを入れておくといい

僕はエディタにatomを使っているので、atomの話を少し…

もし、pugファイルを編集中にシンタックスハイライトが効かない場合は「language-pug」というパッケージをインストールすることをオススメします

だいぶ編集しやすくなると思います

Pugファイルを分割してパーツごとに読み込む

これまでPugの基礎的な部分を学んだので、ここからは実際にやりたかった「パーツごとに分割したファイルをくっつけて1つのHTMLを作る」ということに挑戦します

「include」でファイルを読み込む

別のPugファイルを読み込むためにはincludeという構文を使います

今回は例としてindex.pugからinc/_header.pugファイルを読み込んで1つのHTMLを作ってみます

※読み込むファイルはindex.pugと同階層にincというフォルダを作りその中にまとめて置きました

// index.pug

doctype html
html(lang="ja")
  head
    meta(charset="utf-8")
    title Pugに挑戦
  body
    include inc/_header
    main
      h2 コンテンツ部分です
      p コンテンツコンテンツコンテンツ…
// inc/_header.pug

header
  h1 ここはヘッダーです

includeにつづいて読み込むファイルまでのパスを記述します

includeするファイルの拡張子は省略して書くことができます

出来上がったHTMLはこちら▼

<!-- index.html -->

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>Pugに挑戦</title>
  </head>
  <body>
    <header>
      <h1>ここはヘッダーです</h1>
    </header>
    <main>
      <h2>コンテンツ部分です</h2>
      <p>コンテンツコンテンツコンテンツ…</p>
    </main>
  </body>
</html>

無事、index.pug_header.pugを組み合わせて1つのHTMLファイルを作ることができました!

「extends」でレイアウトを継承する

includeだけでも僕のやりたいこととしては十分そうですが、extends(継承)を使うと複数ページを作る時にもっと効率よくできそうなので頑張って覚えてみます

まずはHTMLの型とでも言ったらいいでしょうか…レイアウトを定義するファイルを用意します

// layout/_layout.pug

doctype html
html 
  head 
    meta(charset='utf-8') 
    block title
  body 
    include ../inc/_header

    block content 
      h1 Default Content

    include ../inc/_footer

_layout.pugでincludeしている_header.pug_footer.pugはこちら▼

// inc/_header.pug

header
  h1 ここはヘッダーです
// inc/_footer.pug

footer
  p フッター

ここまでのファイルは個々のページで読み込むファイルになります。

実際に作成するページをindex.pugとして作ってみます

// index.pug

extends layout/_layout

block title
  title Pugの練習

block content
  section
    h1 ココはコンテンツ部分
  section
    h1 block + [ブロック名]で対応するブロックの内容を書いていきます

先頭のextends layout/_layout.pugで、_layout.pugを元にページを構成していきます

extendsより下に書かれているblock [ブロック名]_layout.pug内のblock [ブロック名]に対応しています

対応する_layout.pug内のblockの内容がindex.pugに書いたblockの内容に置き換わります

block [ブロック名]部分を個々のページで拡張していくイメージですかね

出来上がったHTMLはこんな感じになります▼

<!-- index.html -->

<!DOCTYPE html>
<html> 
  <head> 
    <meta charset="utf-8">
    <title>Pugの練習</title>
  </head>
  <body> 
    <header>
      <h1>ここはヘッダーです</h1>
    </header>
    <section>
      <h1>ココはコンテンツ部分</h1>
    </section>
    <section>
      <h1>block + [ブロック名]で対応するブロックの内容を書いていきます</h1>
    </section>
    <footer>
      <p>フッター</p>
    </footer>
  </body>
</html>

_layout.pugでincludeしたヘッダー・フッターが展開されていることはもちろん、index.pugに書いたblockの内容がちゃんと展開されました!

まとめ

それでもページ内の要素をパーツごとに分割して使えるのは非常にありがたいですね

あとは、pugファイル内で変数やfor文が使えるなど、プログラミングチックなことも出来るようなので、徐々に挑戦していきたいと思います。

今回お勉強に使ったファイルはGitHubに上がっています▼

Pug→HTMLへ変換する為の環境を用意しなければならないという点がEmmetに比べてちょっと面倒ですが、LP制作案件とか来たら効率よくなりそうなので仲良くしていこうと思います!

ワンワン

ではまた。