本文へジャンプ

テンプレートエンジン事始め

Posted by MONSTER DIVE

テンプレートエンジン事始め

ECT等のテンプレートエンジンについては、弊社ブログでもその導入方法使い方について既に何度か取り上げていますが、今回はちょっと立ち戻ってのそもそも論から、誰にも聞かれていない個人的な使い方までご紹介したいと思います。

テンプレートエンジンとは

G先生を介して、テンプレートエンジンとはと諸先輩方に聞いてみたところ、
「データとテンプレートを合体させ、文字列を作る仕組みのこと」
と教えていただいたのですが、なんだかよくわからなかったので、今回ご紹介するところのテンプレートエンジンについての自分なりの概念図を作ってみました。

テンプレートエンジン概念図

世にテンプレートエンジンは多々ありますが、大体こんなかんじの概念かと思います(たぶん)。

構成(レイアウト)ファイルを各ページでextend(継承)し、「title」「body」という構成要素の中身だけをページごとに設定(コーディング)していくイメージです。

もちろん、headerやfooter等、共通化できるコンテンツはモジュールとしてパーツ化することで、各ページにいちいち長いコードを書く必要がなくなり、そしてここが真骨頂→もし修正が入った場合にそのモジュールファイルさえ直せば、読み込んでいる全ページにおいてするっとまるっと修正できるのです。
いままでは、Dreamweaverのサイト管理なんかでわざわざ修正したり、なんなら全ページ開いてひたすら検索&置換するとかいうことで賄っていた作業が一瞬で終わるという、嗚呼「素晴らしき哉、効率化!」

ということで次は、弊社で使われている2大テンプレートエンジン、ECTJADEについてご紹介します。

ECT

  • HTML記法をそのまま使えて学習コストが低い
  • CoffeeScriptが書ける
  • 実行速度が速いらしい

SAMPLE

<article>
  <header id="header">
    <div class="inner">
      <h1 class="title"><%- @title %></h1>
      <ul class="btns">
        <li class="btn"><a href="<%- @url %>map/">map</a></li>
        <li class="btn"><a href="<%- @url %>contact/">contact</a></li>
      </ul>
    </div>
  </header>
</article>

普通にコーディングしていく中で、モジュール化や定数を設定したりが簡単に行なえるので非常に導入しやすそうです。

JADE

  • 記法が特徴的。いろいろな記述を簡略化できる
  • HTML要素の < > や閉じタグ、divのタグ名が不要
  • DOMの構造に沿ったインデントが必要
  • class、idの書き方がCSS記法と同じ
  • プログラミングチックに開発できる

SAMPLE

article
  header#header
     div.inner
         h1.title= _const_title
         ul.btns
             li.btn: a(href="#{const_url}map/") map
             li.btn: a(href="#{const_url}contact/") contact

ECT、JADEそれぞれの「SAMPLE」をコンパイルすると全く同じ出力結果になるのですが、JADEのほうがだいぶ記述を簡略化できることがわかります。
クセはありますが、キーボードのタッチ数?が確実に減るので指にも優しいですね。

MovableTypeにECT

ここからは、ごく個人的なテンプレートモジュールの使い方をご紹介していきます。

私がテンプレートエンジンを使いたい理由として、

  1. ヘッダーやフッター等をモジュール化して一括管理したい
  2. HTMLタグで普通に書きたい
  3. MovableType組み込み時に便利になっていると嬉しい

がありまして、「HTMLタグで普通に書きたい」と宣っている時点で私が使うべきは完全にECT一択となっております。

ではまず、ディレクトリ構造から。

ect/
  └ _include/
   ├ _head.ect
   ├ _header.ect
      .
      .

  └ _setting/
   └  _variables.js

  └ htdocs/
   ├ index.ect
   └  hoge/
     ├ index.ect
     ├ hoge.ect
     └ hogehoge/
        ├ index.ect
              .
              .
  • 「_include」配下に、headタグやheader要素等、共通コンテンツをモジュール化した読み込み専用ファイルを設置
  • 「_setting」には、サイト内にて共通で使用する定数を設定する読み込み専用ファイルを設置
  • 「htdocs」には、実際のディレクトリ構造ママにコンパイルするファイルを設置

次に、上記ECTファイルと、実際MovableType(以下MT)に移植した場合の中身を比較して見てみます。

まずは、読み込み専用の定数設定ファイルから。

MTを構築する際、弊社では(というか一般的にそうなんでしょうか?)サイトのテンプレートモジュールに各ページ(各テンプレート)におけるtitleタグやdescription等、変数や定数をある程度設定しまくったファイルを置くのが基本なので、それに移植しやすいよう作りたいなと思っている次第です。

ECT

_setting/_variables.js

var config = {
  websiteName: 'サイト名',
  websiteURL: 'サイトURL',
  websiteDescription: 'サイトdescription'
};
module.exports = config;

MT

テンプレートモジュール > [conf] websiteSetting

<mt:SetVars>
websiteName=<$mt:WebsiteName$>
websiteURL=<$mt:WebSiteURL$>
websiteDescription=<$mt:WebsiteDescription$>
websiteURL_ROOT=/
</mt:SetVars>

次に、実際に出力されるページの中身を見てみます。

ECT

htdocs/index.ect

<% param = { page: 'top', dir: '1' } %>
<% path = '' %>
<% block 'path': %><% end %>
<% block 'title': %><%- @websiteName %><% end %>
<% block 'pageURL': %><%- @websiteURL %><% end %>
<% block 'description': %><%- @websiteDescription %><% end %>

<% block 'head_css': %>
<link rel="<% content 'path' %>css/top.css">
<% end %>
<% block 'foot_js': %>
<script src="<% content 'path' %>js/top.js"></script>
<% end %>

<% include path + '../_include/head.ect', param %>
<% include path + '../_include/header.ect', param %>
.
.
.

1行目→paramと名付けたパラメータに、ページの情報(このページがなんたるか、カテゴリとか階層とか)を設定して、_header.ect等をインクルードする際に投げてあげると、インクルードファイル内でifの分岐処理ができて便利です。

MT

インデックステンプレート > メインページ

<$mt:SetVar name="top" value="1"$>
<$mt:Include module="[conf] websiteSettings" parent="1"$>

<mt:SetVarBlock name="head_css">
<link rel="<$mt:Var name="websiteURL_ROOT"$>css/top.css"></link>
</mt:SetVarBlock>
<mt:SetVarBlock name="foot_js">
<script src="<$mt:Var name="websiteURL_ROOT"$>js/top.js"></script>
</mt:SetVarBlock>

<$mt:Include module="[inc] Head" parent="1"$>
<$mt:Include module="[inc] Header" parent="1"$>
.
.
.

このページだけで読み込むべきCSSやJS等は大体こんなかんじで設定しています。
ECTからも大体そのまま移植できるようにします。

最後、インクルードするモジュールファイルです。

ECT

_include/header.ect

<header class="header" id="data-header">
  <<% if @page is 'top': %>h1<% else: %>span<% end %> class="header-logo">
    <a href="<% content 'path' %>"><img src="<% content 'path' %>images/common/logo_header.svg" alt="<%= @websiteName %>" class="header-logo-image"></a>
  </<% if @page is 'top': %>h1<% else: %>span<% end %>>
  <div class="header-btn_nav" id="data-nav-btn"><span class="ico">menu</span></div>
</header>

<% content 'path' %>では、htdocsの各ECTで<% block 'path': %><% end %>として設定したルートからの相対パスが入る想定です。ex) ../
こうすることで、どの階層のECTファイルからインクルードしてもリンクが繋がります。

MT

テンプレートモジュール > [inc] Header

<header class="header" id="data-header">
  <<mt:If name="top">h1<mt:Else>span</mt:Else></mt:If> class="header-logo">
    <a href="<$mt:Var name="websiteURL_ROOT"$>"><img src="<$mt:Var name="websiteURL_ROOT"$>images/common/logo_header.svg" alt="<$mt:Var name="websiteName "$>" class="header-logo-image"></a>
  </<mt:If name="top">h1<mt:Else>span</mt:Else></mt:If>>
  <div class="header-btn_nav" id="data-nav-btn"><span class="ico">menu</span></div>
</header>

ECTファイルとMTテンプレートを同じ構造にしておけば、誰が見ても大体理解でき、「みなまで言うな」的に引き継げますね。ハイ効率化効率化!

なお、とっくにお気づきかと思いますが、MTにそういう機能がなかったもので、実は所謂extendファイルというものを使っておりませんすみません。。。

最後に...

最近、弊社の開発環境がGruntからgulpへ移行したのですが、grunt-ectでやっていたことがgulp-ectだとできない...という憂き目に遭って困ったので(gulp ECTは2014年から更新が止まっているのです。※2016年8月現在)、ここまで書いておいてなんですが、
EJSにも手を出してみようかな」
などと密かに思っていることをお伝えして締めの言葉とさせていただきます。
ご清覧ありがとうございました!

Recent Entries
MD EVENT REPORT
What's Hot?