本文へジャンプ

EJS"オレオレ"テンプレート備忘録 - 2018年春

Posted by MONSTER DIVE

EJS

以前、テンプレートエンジンについてご紹介したのですが、結局あれからEJSへ移行しまして1年余。
今回は、とにかくラクしたい自分のためのごく個人的EJSテンプレート構成 with MT(Movable Type)についてお伝えします。

「- 2018年春」とまさしく取ってつけたタイトルなのは、1年後...否、もはや半年後には全然違うこと言ってる可能性があるという保険であることはどうかお察しください。

EJSを動かす

MDではgulpを採用しているので、gulp-ejsを使っていきます。

インストール後、gulpfile.jsにこのようなことを書く。

const gulp = require('gulp');
const ejs = require('gulp-ejs');
gulp.task('default', function(){
gulp.src(['templates/*.ejs','!templates/_*.ejs'])
.pipe(ejs({},{},{ext: '.html'}))
.pipe(gulp.dest('dist'))
})

フォルダ構成は例えばこんなかんじ。

├── dist //出力先
├── gulpfile.js
├── node_modules
├── package.json
└── templates //ejsを格納

この辺は、お使いのタスクランナーや使いやすい構造などに合わせて適宜ごにょごにょしていただければ幸いです。

「EJS MT 基本設計」

EJS自体のフォルダ構成は大抵こんなかんじにしといてます。※「templates」の中身。

├── _data //仮データ
├── _module //モジュール要素
└── htdocs //実際の出力ディレクトリ
└── index.ejs

以前ご紹介したECTもそうですが、EJSはhtmlタグで書いてあるので、そのまままるっとコピペ&EJS→MT仕様のタグに修正すればいけるという親和性の高さが一番の魅力です。

隙あらばモジュール化してまとめておく

「ここモジュール化できるな」とマークアップの時点で判断→EJS実装するので大抵まとめはしますが、MT作業的に、何を、どこを、テンプレートモジュールにすれば良いかがわかりやすいので、地味に助かります。

EJS

└── _module
├── _bodyend.ejs //body閉じタグ直前で読み込むJSとか
├── _bodystart.ejs //bodyタグ開始直後に読み込むJSとか
├── _breadcrumb.ejs //パンくずリスト
├── _globalfooter.ejs //フッター
├── _globalheader.ejs //ヘッダー
├── _globalnav.ejs //グロナビ
└── _htmlhead.ejs //headタグ

MT

MTの構成

同じ名前にしておけば、修正が入った時にもどこ見て直せば良いかわかりやすく、他の人が作業するときも説明&指示しやすいはず。
他に、ページネーションなんかもモジュール化しときたい要素候補です。

「EJS MT 時短テク」

要素をデータで管理

記事やカテゴリーなど、なんらかの一覧はいろいろなページにいろいろな形で読み込まれがちなので、json形式の仮データを作成しておくと使い回せてとても便利です。

EJS

  • _data/_entrylist.ejs
<%
entryList = [
{
EntryDate: '2018.02.23',
EntryPermalink: 'detail/seitennohekireki.html',
EntryTitle: '青天の霹靂',
EntryExcerpt: 'THEバランサー',
AssetThumbnailURL: 'seitennohekireki.jpg',
CategoryLabel: 'あっさり'
entrycheck: 1
},
{
EntryDate: '2018.02.22',
EntryPermalink: 'detail/shinnosuke.html',
EntryTitle: '新之助',
EntryExcerpt: '時代を先取るニューカマー',
AssetThumbnailURL: 'shinnosuke.jpg',
CategoryLabel: 'もっちり'
},
{
EntryDate: '2018.02.21',
EntryPermalink: 'detail/milky_queen.html',
EntryTitle: 'ミルキークイーン',
EntryExcerpt: 'もっっちりやわらか',
AssetThumbnailURL: 'milky_queen.jpg',
CategoryLabel: 'もっちり'
entrycheck: 1
},
{
EntryDate: '2018.02.20',
EntryPermalink: 'detail/koshihikari.html',
EntryTitle: 'コシヒカリ',
EntryExcerpt: 'お米といえば',
AssetThumbnailURL: 'koshihikari.jpg',
CategoryLabel: 'もっちり'
entrycheck: 1
},
{
EntryDate: '2018.02.19',
EntryPermalink: 'detail/tsuyahime.html',
EntryTitle: 'つや姫',
EntryExcerpt: 'あっさりツヤツヤ粒ぞろい',
AssetThumbnailURL: 'tsuyahime.jpg',
CategoryLabel: 'あっさり'
}
]
%>

ここはMTタグと同じような名前にしておいて損はなし。
記事でどんなカスタムフィールドが必要かも大体わかる、というかマークアップの時点でMTの設計にも手を出してしまっているという(ハタ迷惑だったらごめんなさいな)時短テクでもあります。

一覧関係をループ処理

前述のjson形式で作っておいたデータを活用して、一覧コンテンツと見るやいなや、ループ処理でバババ、バババババーっと出力してしまいます。

EJS

<%- include( param.path + '_data/_entrylist'); _%>
<% entryList.forEach(function(item) { %>
<article class="kome">
<header class="kome-head">
<span class="category"><%= item.CategoryLabel %></span>
<h2 class="name"><a href="<%= item.EntryPermalink %>"><%= item.EntryTitle %></a></h2>
</header>
<div class="kome-summary">
<time datetime="<%= item.EntryDate.replace(/\./g,'-') %>"><%= item.EntryDate %></time>
<figure><img src="images/<%= item.AssetThumbnailURL %>" alt="<%= item.EntryTitle %>"></figure>
<p><%= item.EntryExcerpt %></p>
</div>
</article>
<% }) %>

MT

<mt:Entries>
<article class="kome">
<header class="kome-head">
<span class="category"><$mt:EntryCategory$></span>
<h2 class="name"><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$></a></h2>
</header>
<div class="kome-summary">
<time datetime="<$mt:EntryDate format="%Y-%m-%d"$>"><$mt:EntryDate format="%Y.%m.%d"$></time>
<figure><img src="<mt:entryImageAsset><$mt:AssetThumbnailURL width="200"$></mt:entryImageAsset>" alt="<$mt:EntryTitle$>"></figure>
<p><$mt:EntryExcerpt$>></p>
</div>
</article>
</mt:Entries>

出力結果

<article class="kome">
<header class="kome-head">
<span class="category_assari">あっさり</span>
<h2 class="name"><a href="detail/seitennohekireki.html">青天の霹靂</a></h2>
</header>
<div class="kome-summary">
<time datetime="2018-02-23">2018.02.23</time>
<figure><img src="images/seitennohekireki.jpg" alt="青天の霹靂"></figure>
<p>THEバランサー</p>
</div>
</article>
<article class="kome">
<header class="kome-head">
<span class="category_mocchiri">もっちり</span>
<h2 class="name"><a href="detail/shinnosuke.html">新之助</a></h2>
</header>
<div class="kome-summary">
<time datetime="2018-02-22">2018.02.22</time>
<figure><img src="images/shinnosuke.jpg" alt="新之助"></figure>
<p>時代を先取るニューカマー</p>
</div>
</article>
<article class="kome">
<header class="kome-head">
<span class="category_mocchiri">もっちり</span>
<h2 class="name"><a href="detail/milky_queen.html">ミルキークイーン</a></h2>
</header>
<div class="kome-summary">
<time datetime="2018-02-21">2018.02.21</time>
<figure><img src="images/milky_queen.jpg" alt="ミルキークイーン"></figure>
<p>もっっちりやわらか</p>
</div>
</article>
<article class="kome">
<header class="kome-head">
<span class="category_mocchiri">もっちり</span>
<h2 class="name"><a href="detail/koshihikari.html">コシヒカリ</a></h2>
</header>
<div class="kome-summary">
<time datetime="2018-02-20">2018.02.20</time>
<figure><img src="images/koshihikari.jpg" alt="コシヒカリ"></figure>
<p>お米といえば</p>
</div>
</article>
<article class="kome">
<header class="kome-head">
<span class="category_assari">あっさり</span>
<h2 class="name"><a href="detail/tsuyahime.html">つや姫</a></h2>
</header>
<div class="kome-summary">
<time datetime="2018-02-19">2018.02.19</time>
<figure><img src="images/tsuyahime.jpg" alt="つや姫"></figure>
<p>あっさりツヤツヤ粒ぞろい</p>
</div>
</article>

最新3件だけでよければ、↓こんなのとか

<% var _counter = 0; %>
<% entryList.forEach(function(item) { %>
<% if (_counter < 3) { %>
<article class="kome">
.
.
</article>
<% } %>
<% _counter++; %>
<% }) %>

チェックついてるのだけでよければ、↓こんなのとか

<% entryList.forEach(function(item) { %>
<% if (item.entrycheck) { %>
<article class="kome">
.
.
</article>
<% } %>
<% }) %>

EJSの段階でループしてあれば、ループ要素を探し出さずともすんなりMTに組み込めて、時短、コスパも最高です。

マークアップ的にも、ちょっとあのクラス名いけてなかったから差し替えたい、DOM構造見直したというときなど、1つ修正すればあとはループで処理されるのでラク。
単純なコピペだって大量にあると手間です。

そしてカテゴリーの一覧なんかもループで処理してみたり。

EJS

<%
categories = [
{
CategoryLabel: '漬物・発酵食品',
CategoryBasename: 'hakko',
CategoryDescription: '振り返ればそこに',
SubCategories: [
{ CategoryLabel: '納豆', CategoryBasename: 'natto' },
{ CategoryLabel: '梅干し', CategoryBasename: 'umeboshi' },
{ CategoryLabel: 'しば漬け', CategoryBasename: 'shibaduke' }
]
},
{
CategoryLabel: '魚卵',
CategoryBasename: 'gyoran',
CategoryDescription: '魚卵はだいたいごはんに合う',
SubCategories: [
{ CategoryLabel: 'いくら', CategoryBasename: 'ikura' },
{ CategoryLabel: '明太子', CategoryBasename: 'mentaiko' },
{ CategoryLabel: 'たらこ', CategoryBasename: 'tarako' },
{ CategoryLabel: '数の子', CategoryBasename: 'kazunoko' }
]
}
]
%>
<%- include( param.path + '_data/_categorylist'); _%>
<% categories.forEach(function(item) { %>
<section class="otomo">
<header class="otomo-head">
<h3 class="category"><a href="<%= item.CategoryBasename %>/"><%= item.CategoryLabel %></a></h3>
</header>
<div class="otomo-content">
<p><%= item.CategoryDescription %></p>
<% if (item.SubCategories) { %>
<ul>
<% item.SubCategories.forEach(function(item) { %>
<li><a href="<%= item.CategoryBasename %>/"><%= item.CategoryLabel %></a></li>
<% }) %>
</ul>
<% } %>
</div>
</section>
<% }) %>

ループを知ってしまうと、すべてのものをループしたくなるという、その名の通り「無限ループ」に陥りますのでどうぞご自愛ください。

まとめ

初めてEJSでマークアップされたテンプレートをMTに組み込んだとき、あまりにも作業しやすくて感動してしまったほどで、さらにもっとラクできないか...などと、血まなこで手探っている次第です。
たかが1分の時短でも、見たいテレビの時間に間に合うかの瀬戸際だったりするから侮れません。

あくまで「オレオレ」なので、他の方が使いやすいかどうかはあれですが、みなさんもよかったらそれぞれの「オレオレ」を作ってあれしてみてはいかがでしょうか。

Recent Entries
MD EVENT REPORT
What's Hot?
日本各地の酒蔵との直取引により厳選して仕入れた日本酒を世界に販売
こんな僕たちの仲間に入りませんか?
Movable Type AWS 移管&アップグレード サービス
SNS・ブログ・メールからの流入数が一目でわかる
50,000円からのシネマグラフ(Cinemagraph)制作
TAKUYAが教えるギター・レッスン
KenKenが教えるベースギター教則アプリ
SNS連動型クチコミ拡散システム「レビュー ジェネレーター サービス」
1時間1万円の撮影スタジオ
すべてのコンテンツ/プラットフォームを、ひとつのコンテンツ管理システムで。