Ownedmedia ウェブ制作に役立つコンテンツを発信中!

Pug 2020.09.07

Pugでテンプレートとデータでファイルを切り分けた開発を行う

Tags: ,,,

Pugを使うことでHTMLを効率よくコーディングすることができますが、ルールなどを決めておかないとファイル構成が複雑になってしまい、管理コストが上がってしまうことになり本末転倒ですよね。そこで、Pugを使う場合にはテンプレートとメタ情報などのデータでファイルを切り分けておくことをオススメします。

 

ちょうど過去記事「EJSでテンプレートとデータでファイルを切り分けた開発を行う」でも紹介していますが、このようなテンプレートエンジンを使った開発ではページ情報を変数として値を持たせておくことがポイントになります。今回は、変数を定義する際にPugファイル内に変数を持たせる方法と、JSONファイルに値を持たせる方法の2パターンについてまとめていきます。

 

データ用Pugファイルを用意してデータを読み込む

まずは、変数用のPugファイルを使った方法です。今回はこのようなファイル構成を想定しており、PugのコンパイルにはGulpを使います。Gulpを使ったPugのコンパイル方法については過去記事「GulpでJavascriptのテンプレートエンジンPugの開発環境を構築する」をこ参考ください。

 

Pugファイルをまとめたsrcディレクトリには、ページテンプレートのindex.pugとページ全体のレイアウト用としてcomponents/_layout.pugを用意しました。そこにページ情報をまとめた変数を記載している_data.pugを新たに追加します。

src
┣ index.pug
┣ _data.pug
┗ components
  ┗ _layout.pug
dist
┗ index.pug
node_modules
gulpfile.js

 

まずは今回のポイントであるデータ用のPugファイルの中身を見ていきます。と言っても内容はシンプルで、ページ別にメタ情報をまとめたオブジェクト型の値を定義するだけです。もちろんこれらはページテンプレートのPugファイル内で定義してもOKですが、ページ数が多くなってくると一元管理できなくなるので、別ファイルで運用するのがいいのではないでしょうか。

【_data.pug】

- 
  var global = {
    siteName: 'サンプルサイト',
    siteUrl: 'https://example.com',
    pageMeta: {
      home: {
        id: 1,
        name: 'home',
        title: 'トップページ',
        description: 'サイトのトップページです',
        ogpImage: 'assets/img/icon/ogp_default.jpg',
        type: 'website',
        path: '/'
      },
      page1: { 
        id: 2,
        name: 'page1',
        title: 'ページ1',
        description: 'ページ1のディスクリプションです',
        ogpImage: 'assets/img/icon/ogp_default.jpg',
        type: 'website',
        path: '/page1.html'
      },
    }
  }

 

続いてページテンプレートのPugファイルです。最初にページ全体のレイアウトに使うPugファイルへextendsで読み込まれるようにしています。続いて、blockで変数をまとめて定義します。この部分は_layout.pugで読み込むようになります。その中で先ほど作成したデータ用のPugファイルをインクルードしておきます。こうすることで、_data.pugで定義した変数を使うことができます。あとは、メタタグの部分で変数からキーを取得し、その値が出力されるようにしていきます。

【index.pug】

extends components/_layout.pug

block variables
  - include _data.pug
  - var page = 'home'
  - var siteInfo = global
  - var meta = siteInfo.pageMeta[page]
  - var isFrontPage = true

block append pageMeta
  meta(name="description" content=meta.description)
  meta(property="og:title" content=meta.title)
  meta(property="og:description" content=meta.description)
  meta(property="og:url" content=siteInfo.siteUrl + meta.path)
  meta(property="og:type" content=meta.type)
  meta(property="og:image" content=meta.ogpImage)
  if isFrontPage
    title #{siteInfo.siteName}
  else
    title #{meta.title} | #{siteInfo.siteName}

block pageContent
      main.
        メインコンテンツ

 

最後にページ全体の共通レイアウト部分のPugファイルです。ここではそんなに特別なことはしていませんが、ページテンプレートで定義したページ別情報の変数と、データ用のPugファイルから値を取得したmetaタグを出力されるようにblockで呼び出しています。

【_layout.pug】

doctype html

block variables

html(lang="ja")
  head
    meta(charset="utf-8")

block pageMeta

  body
    header.
      ヘッダーコンテンツ

block pageContent

    footer.
      フッターコンテンツ

 

Pugファイルのコーディングは以上となりますが、Gulpでコンパイルするタスクも見ていきます。データ用のPugファイルを読み込む場合には特別な設定は不要です。そのままPugファイルをHTMLにコンパイルできるようなタスクを作成します。(詳しくは「GulpでJavascriptのテンプレートエンジンPugの開発環境を構築する」をご参照)

【gulpfile.js】

const { src, dest, watch, parallel } = require("gulp"),
  plumber = require('gulp-plumber'),
  notify = require('gulp-notify'),
  pug = require('gulp-pug'),
const taskPug = (done) => {
  src([
    'src/pug/**/*.pug',
    '!' + 'src/pug/**/_*.pug'
  ])
  .pipe(plumber(
    { errorHandler: notify.onError('Error: <%= error.message %>') }
  ))
  .pipe(pug({ pretty: true }))
  .pipe(dest('dist'));
  done();
};

const taskWatch = (done) => {
  watch('src/pug/**/*.pug', taskPug);
  done();
}
exports.default = taskWatch;

 

これで、データ用のPugファイルを使って、ページテンプレートとデータでファイルを切り分けて開発することができます。

 

外部JSONファイルからデータを読み込む

先ほどはデータ用のPugファイルを使いましたが、変数の中にオブジェクトの値としてデータをまとめていくため、データ量が多い場合には少々読みにくいかと思います。そんな時には外部のJSONファイルに値を記述し、それをコンパイル時に読み込む形でHTML上に出力することも可能です。

 

ファイル構成はこのような形で、先ほどのデータ用のPugファイルがJSONファイルに置き換わった以外は同じですね。(srcディレクトリ以外は省略しています)

src
┣ index.pug
┣ data.json
┗ components
  ┗ _layout.pug
..........

 

まずはデータ用のJSONファイルの中身を見ていきます。基本的にデータ用のPugファイルで定義した変数のオブジェクトの構成をそのままJSON用に変えた形となります。この方が読みやすくデータが増えた場合も安心ですね。同じくキーを取得して値を出力するようになります。

【data.json】

{
  "global": {
    "siteName": "サンプルサイト",
    "siteUrl": "https://example.com",
    "pageMeta": {
      "home": {
        "id": 1,
        "name": "home",
        "title": "トップページ",
        "description": "サイトのトップページです",
        "ogpImage": "assets/img/icon/ogp_default.jpg",
        "type": "website",
        "path": "/"
      },
      "page1": {
        "id": 2,
        "name": "page1",
        "title": "ページ1",
        "description": "ページ1のディスクリプションです",
        "ogpImage": "assets/img/icon/ogp_default.jpg",
        "type": "article",
        "path": "/page1.html"
      },
    }
  }
}

 

続いてページテンプレートのPugファイルです。JSONではなくPugファイルを使う場合とほとんど同じですが、変数の中でPugファイルをインクルードする必要がないのでその分の記述がなくなっています。

【index.pug】

extends components/_layout.pug

block variables
  - var page = 'home'
  - var siteInfo = global
  - var meta = siteInfo.pageMeta[page]
  - var isFrontPage = true

block append pageMeta
  meta(name="description" content=meta.description)
  meta(property="og:title" content=meta.title)
  meta(property="og:description" content=meta.description)
  meta(property="og:url" content=siteInfo.siteUrl + meta.path)
  meta(property="og:type" content=meta.type)
  meta(property="og:image" content=meta.ogpImage)
  if isFrontPage
    title #{siteInfo.siteName}
  else
    title #{meta.title} | #{siteInfo.siteName}

block pageContent
      main.
        メインコンテンツ

 

データを外部のJSONファイルで扱う場合にはGulpのタスクを少し変更する必要があります。というのも、JSONを読み込むのにPugではなくGulp側で処理をする形になるからです。この際には「fs」というモジュールが必要になりますがnode.jsにデフォルトで含まれているので、特に追加でのインストール作業は必要ありません。これでローカルのファイルを読み込むことができます。

 

モジュールがインストールできたらGulpのタスクを下記のように作成していきます。タスクの最初にJSONデータを読み込み、JSON.parseでオブジェクトの形にしておきます。データを読み込む際には、データ用のJSONファイルのパスを指定します。

【gulpfile.js】

const { src, dest, watch, parallel } = require("gulp"),
  plumber = require('gulp-plumber'),
  notify = require('gulp-notify'),
  pug = require('gulp-pug'),
  fs = require('fs'),
const taskPug = (done) => {
  const jsonData = JSON.parse(fs.readFileSync('src/data.json'));
  src([
    'src/pug/**/*.pug',
    '!' + 'src/pug/**/_*.pug'
  ])
  .pipe(plumber(
    { errorHandler: notify.onError('Error: <%= error.message %>') }
  ))
  .pipe(pug({
    locals: jsonData,
    pretty: true
  }))
  .pipe(dest('dist'));
  done();
};

const taskWatch = (done) => {
  watch('src/pug/**/*.pug', taskPug);
  done();
}
exports.default = taskWatch;

 

Pugのコンパイル時にlocalsオプションでJSONデータを読み込む指定をするのを忘れないようにしましょう。それ以外は先ほどのデータ用のPugファイルを使う場合と同じですね。これで外部のJSONファイルを使って、ページテンプレートとデータでファイルを切り分けて開発することができます。実際にPugからHTMLへコンパイルすると下記のように読み込んだデータが指定された通りに出力されているのがわかります。

【index.html】

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="description" content="サイトのトップページです">
    <meta property="og:title" content="トップページ">
    <meta property="og:description" content="サイトのトップページです">
    <meta property="og:url" content="https://example.com/">
    <meta property="og:type" content="website">
    <meta property="og:image" content="assets/img/icon/ogp_default.jpg">
    <title>サンプルサイト</title>
  </head>
  <body>
    .............

 


 

今回はPugでページテンプレートとデータを切り分けた開発方法についてまとめてみました。EJSの場合(参考記事「EJSでテンプレートとデータでファイルを切り分けた開発を行う」)と同じく、大量の静的ページを量産する場合に効果的ですが、データ量が増えてくる可能性を見ると外部のJSONファイルで管理した方がいいのではないでしょうか。これで効率よくPugを使ったページコーディングができるようになりますので、ぜひ試してみてください。

この記事を書いた人

オガワ シンヤ

DesignSupply.代表 / ディレクター・ウェブデザイナー・フロントエンドエンジニアをやっています。「ウェブとデザインでヒト・モノ・サービスを繋げ新しい価値を生み出す」をコンセプトに日々奮闘中!制作中はチョコレートが欠かせない三十路Webクリエイター。

  • Twitter

コメントフォーム

記事に関するご質問やご意見などありましたら下記のコメントフォームよりお気軽に投稿ください。なおメールアドレスは公開されませんのでご安心ください。

内容に問題なければ、お名前・ハンドルネームとメールアドレスを入力いただき、下記の「コメントを送信」ボタンを押してください。

CAPTCHA


この記事もよく読まれています

Scroll to Top
ご質問・ご相談はありませんか ?