Help us understand the problem. What is going on with this article?

Pug(Jade)記法でHTMLのテンプレート的なの

More than 1 year has passed since last update.

2017/06/23追記

今更ですが、本記事のサンプルコードをあげました

soarflat-prototype/pug-template

サンプルコードは以下の点で記事内容と異なります。

  • 拡張子がpug
  • mixinを利用する必要がなかったため利用していない
  • 現在のバージョンだと"http://#{metas.url}"のような"#{}"がサポートされていないため修正

はじめに

Pugの勉強のためにHTMLのテンプレート的なのをJadeで書きました。

Pugで書くとこうなる

もとのHTML

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="author" content="">
<meta property="og:title" content="タイトル">
<meta property="og:type" content="website">
<meta property="og:url" content="http://任意のURL">
<meta property="og:image" content="http://任意のURL/og_image.png">
<meta property="og:site_name" content="">
<meta property="og:description" content="" />
<meta property="fb:app_id" content="任意のID">
<title>タイトル</title>
<link rel="stylesheet" href="css/style.css">
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXXXXX-Y', 'example.com');
  ga('send', 'pageview');
</script>
</head>

<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script> (window.jQuery || document .write('<script src="js/jquery-1.11.2.min.js"><\/script>')); </script>
<script src="js/scripts.js"></script>
</body>
</html>

これをPugで書くと以下のようになる。

pug
doctype
html(lang="ja")
  head
    meta(charset="utf-8")
    meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")
    meta(name="viewport", content="width=device-width, initial-scale=1")
    meta(name="description", content="")
    meta(name="keywords", content="")
    meta(name="author", content="")
    meta(property="og:title", content="タイトル")
    meta(property="og:type", content="website")
    meta(property="og:url", content="http://任意のURL")
    meta(property="og:image", content="http://任意のURL/og_image.png")
    meta(property="og:site_name", content="")
    meta(property="og:description", content="")
    meta(property="fb:app_id", content="任意のID")
    title タイトル
    link(rel='stylesheet', href="css/style.css")
    script.
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

      ga('create', 'UA-XXXXXXXX-Y', 'example.com');
      ga('send', 'pageview');
  body
    script(src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js")
    script.
      (window.jQuery || document .write('<script src="js/jquery-1.11.2.min.js"><\/script>'));
    script(src="js/scripts.js")

比較してみると、ただPug記法になっただけなので「Pugで書く必要なくない?」状態。
Pugらしい書き方になるようにする。

Pugらしい書き方で書くとこうなる

index.pug
extends _layout
block var
  - metas = {}
  - metas.title = 'title'
  - metas.url = 'url'
  - metas.image = 'image'
  - metas.site_name = 'site_name'
  - metas.description = 'description'
block append meta
  +meta(metas)
  include _inc_meta_facebook
  +inc_meta_facebook(metas)
block title
  title
block body
_layout.pug
block var
doctype html
html(lang="ja")
  head
    meta(charset='utf-8')
    meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")
    meta(name="viewport", content="width=device-width, initial-scale=1")
    block meta
      mixin meta(metas)
        meta(name="description", content=metas.description)
        meta(name="keywords", content=metas.keywords)
        meta(name="author", content="")
    block title
    block link
      link(rel='stylesheet', href="css/style.css")
    block head_script
      script.
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

        ga('create', 'UA-XXXXXXXX-Y', 'example.com');
        ga('send', 'pageview');
  body
    block body
    block end_of_body
      script(src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js")
      script.
        (window.jQuery || document .write('<script src="js/jquery-1.11.2.min.js"><\/script>'));
      script(src="js/scripts.js")
_inc_meta_facebook.pug
mixin inc_meta_facebook(metas)
  meta(property="og:title", content=metas.title)
  meta(property="og:type", content="website")
  meta(property="og:url", content="http://#{metas.url}")
  meta(property="og:image", content="http://#{metas.image}/og_image.png")
  meta(property="og:site_name", content=metas.site_name)
  meta(property="og:description", content=metas.description)
  meta(property="fb:app_id", content="任意のID")

ディレクトリ構成は以下を前提とする。

.
├── index.pug
├── _layout.pug
└── _inc_meta_facebook.pug

Pugらしい書き方になった。(自信はない)

コンパイルされるHTML

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="description">
        <meta name="keywords">
        <meta name="author" content="">
        <meta property="og:title" content="title">
        <meta property="og:type" content="website">
        <meta property="og:url" content="http://url">
        <meta property="og:image" content="http://image/og_image.png">
        <meta property="og:site_name" content="site_name">
        <meta property="og:description" content="description">
        <meta property="fb:app_id" content="任意のID">
    <title></title>
    <link rel="stylesheet" href="css/style.css">
    <script>
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

      ga('create', 'UA-XXXXXXXX-Y', 'example.com');
      ga('send', 'pageview');
    </script>
  </head>
  <body>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script>(window.jQuery || document .write('<script src="js/jquery-1.11.2.min.js"><\/script>'));</script>
    <script src="js/scripts.js"></script>
  </body>
</html>

mixinの箇所にインデントが発生していまうのが気になる。

今回利用したPugの機能

  • 変数
  • include
  • extends
  • block
  • mixin

変数

Pugでは変数が利用できる。
今回の例では変数metasが存在する。

index.pug
extends _layout
block var
  //- 変数metas
  - metas = {}
  - metas.title = 'title'
  - metas.url = 'url'
  - metas.image = 'image'
  - metas.site_name = 'site_name'
  - metas.description = 'description'
block append meta
  +meta(metas)
  include _inc_meta_facebook
  +inc_meta_facebook(metas)
block title
  title
block body

include

他のPugファイルを読み込む。

index.pug
extends _layout
block var
  - metas = {}
  - metas.title = 'title'
  - metas.url = 'url'
  - metas.image = 'image'
  - metas.site_name = 'site_name'
  - metas.description = 'description'
block append meta
  +meta(metas)
  //- _inc_meta_facebook.pugを読み込む。
  include _inc_meta_facebook
  +inc_meta_facebook(metas)
block title
  title
block body

今回の例ではinclude _inc_meta_facebookと記述されているため、
_inc_meta_facebook.pugが読み込まれる。

_inc_meta_facebook.pug
mixin inc_meta_facebook(metas)
  meta(property="og:title", content=metas.title)
  meta(property="og:type", content="website")
  meta(property="og:url", content="http://#{metas.url}")
  meta(property="og:image", content="http://#{metas.image}/og_image.png")
  meta(property="og:site_name", content=metas.site_name)
  meta(property="og:description", content=metas.description)
  meta(property="fb:app_id", content="任意のID")

extendsとblock

他のPugファイルを継承する。

index.pug
//- _layout.pugを敬承する。
extends _layout
block var
  - metas = {}
  - metas.title = 'title'
  - metas.url = 'url'
  - metas.image = 'image'
  - metas.site_name = 'site_name'
  - metas.description = 'description'
block append meta
  +meta(metas)
  include _inc_meta_facebook
  +inc_meta_facebook(metas)
block title
  title
block body

今回の例ではextends _layoutと記述されているため、
index.pug_layout.pugが継承される。

_layout.pug
block var
doctype html
html(lang="ja")
  head
    meta(charset='utf-8')
    meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")
    meta(name="viewport", content="width=device-width, initial-scale=1")
    block meta
      mixin meta(metas)
        meta(name="description", content=metas.description)
        meta(name="keywords", content=metas.keywords)
        meta(name="author", content="")
    block title
    block link
      link(rel='stylesheet', href="css/style.css")
    block head_script
      script.
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

        ga('create', 'UA-XXXXXXXX-Y', 'example.com');
        ga('send', 'pageview');
  body
    block body
    block end_of_body
      script(src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js")
      script.
        (window.jQuery || document .write('<script src="js/jquery-1.11.2.min.js"><\/script>'));
      script(src="js/scripts.js")

includeのように他のPugファイルを読み込むが、includeとは異なり、
継承先ファイルと継承元ファイルの同じ名前のblockが紐づく。(関連付く?)

継承先と継承元のblockの関係

敬承先に敬承元と同じ名前のblockが存在しない場合、敬承元のblock内の記述が読み込まれるが
敬承先にも同じ名前のblockが存在する場合、block内の記述が上書きされる。
今回の例だと上書きされるのはblock varblock titleblock body内の記述。

index.pug(敬承先)
extends _layout
//- block varを上書きする。
block var
  - metas = {}
  - metas.title = 'title'
  - metas.url = 'url'
  - metas.image = 'image'
  - metas.site_name = 'site_name'
  - metas.description = 'description'
block append meta
  +meta(metas)
  include _inc_meta_facebook
  +inc_meta_facebook(metas)
//- block titleを上書きする。
block title
  title
//- block bodyを上書きする。
block body
_layout.pug(敬承元)
//- 敬承先にblock varが存在するため、敬承先に読み込まれない。
block var
doctype html
html(lang="ja")
  head
    meta(charset='utf-8')
    meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")
    meta(name="viewport", content="width=device-width, initial-scale=1")
    block meta
      mixin meta(metas)
        meta(name="description", content=metas.description)
        meta(name="keywords", content=metas.keywords)
        meta(name="author", content="")
    //- 敬承先にblock titleが存在するため、敬承先に読み込まれない。
    block title
    //- 敬承先にblock linkは存在しないため、敬承先に読み込まれる。
    block link
      link(rel='stylesheet', href="css/style.css")
    //- 敬承先にblock head_scriptは存在しないため、敬承先に読み込まれる。
    block head_script
      script.
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

        ga('create', 'UA-XXXXXXXX-Y', 'example.com');
        ga('send', 'pageview');
  body
    //- 敬承先にblock bodyが存在するため、敬承先に読み込まれない。
    block body
    //- 敬承先にblock end_of_bodyは存在しないため、敬承先に読み込まれる。
    block end_of_body
      script(src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js")
      script.
        (window.jQuery || document .write('<script src="js/jquery-1.11.2.min.js"><\/script>'));
      script(src="js/scripts.js")

敬承先に敬承元と同じ名前のblockが存在する場合、
敬承先のblock内に記述自体がなくても、敬承元のblock内の記述は読みこまれないので注意。

block append

blockと異なり、記述を上書きをするのではなく
敬承元の記述の後に敬承先の記述を追加できる。

index.pug(敬承先)
extends _layout
block var
  - metas = {}
  - metas.title = 'title'
  - metas.url = 'url'
  - metas.image = 'image'
  - metas.site_name = 'site_name'
  - metas.description = 'description'
//- 敬承元のblock meta内の記述の後にblock append meta内の記述が追加される。
block append meta
  +meta(metas)
  include _inc_meta_facebook
  +inc_meta_facebook(metas)
block title
  title
block body
_layout.pug(敬承元)
block var
doctype html
html(lang="ja")
  head
    meta(charset='utf-8')
    meta(http-equiv="X-UA-Compatible", content="IE=edge,chrome=1")
    meta(name="viewport", content="width=device-width, initial-scale=1")
    //- 敬承先にblock append metaが存在するため、敬承先に読み込まれる。
    block meta
      mixin meta(metas)
        meta(name="description", content=metas.description)
        meta(name="keywords", content=metas.keywords)
        meta(name="author", content="")
    block title
    block link
      link(rel='stylesheet', href="css/style.css")
    block head_script
      script.
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

        ga('create', 'UA-XXXXXXXX-Y', 'example.com');
        ga('send', 'pageview');
  body
    block body
    block end_of_body
      script(src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js")
      script.
        (window.jQuery || document .write('<script src="js/jquery-1.11.2.min.js"><\/script>'));
      script(src="js/scripts.js")

イメージとしては以下のようになる。

敬承元の記述の後に敬承先の記述が追加される
mixin meta(metas)
  meta(name="description", content=metas.description)
  meta(name="keywords", content=metas.keywords)
  meta(name="author", content="")
+meta(metas)
include _inc_meta_facebook
+inc_meta_facebook(metas)

block prepend

敬承元の記述の前に敬承先の記述を追加できる。
block append metablock prepend metaにすると
イメージとしては以下のようになる。

敬承元の記述の前に敬承先の記述が追加される
+meta(metas)
include _inc_meta_facebook
+inc_meta_facebook(metas)
mixin meta(metas)
  meta(name="description", content=metas.description)
  meta(name="keywords", content=metas.keywords)
  meta(name="author", content="")

mixin

関数のような再利用できるblockを生成できる。
今回の例では_layout.pugmixin meta(metas)が存在し、

mixin meta(metas)
  meta(name="description", content=metas.description)
  meta(name="keywords", content=metas.keywords)
  meta(name="author", content="")

_inc_meta_facebook.pugmixin inc_meta_facebook(metas)が存在する。

mixin inc_meta_facebook(metas)
  meta(property="og:title", content=metas.title)
  meta(property="og:type", content="website")
  meta(property="og:url", content="http://#{metas.url}")
  meta(property="og:image", content="http://#{metas.image}/og_image.png")
  meta(property="og:site_name", content=metas.site_name)
  meta(property="og:description", content=metas.description)
  meta(property="fb:app_id", content="任意のID")

mixinを利用する時は、+を記述する。
今回の例ではblock append meta内で
mixin meta(metas)mixn inc_meta_facebook(metas)内の記述が追加される。

index.pug
extends _layout
block var
  - metas = {}
  - metas.title = 'title'
  - metas.url = 'url'
  - metas.image = 'image'
  - metas.site_name = 'site_name'
  - metas.description = 'description'
block append meta
  //- block var内の変数metasが引数として渡され、
  //- mixin meta(metas)内の記述が追加される。
  +meta(metas)
  include _inc_meta_facebook
  //- block var内の変数metasが引数として渡され、
  //- mixn inc_meta_facebook(metas)内の記述が追加される。
  +inc_meta_facebook(metas)
block title
  title
block body

参考

soarflat
フロントエンドエンジニア🐶
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした