HTMLファイルの作成時のコピペ祭りに嫌気がさしたので、そこでgrunt-ectを使ってHTMLのコーディングをしてみました。
そもそもECTとは?
JavaScriptのテンプレートエンジンです。
Gruntでコンパイルしてつかったり、nodeのexpressと組み合わせてつかったり出来ます。
- インヘリタンス
- パーシャル
- ブロック
などの機能もあるので普通の今時のテンプレートエンジンですね。
あとCoffeeScript書けるらしいです。
grunt-ectの導入
インストール
必要なnpmを用意する
$ npm init
$ npm install grunt --save-dev
$ npm install grunt-ect --save-dev
$ npm install grunt-contrib-watch --save-dev
Gruntfle
Gruntfileはこんな感じです。
ectの設定の中でect.render.files
でコンパイルしたいファイル名:'コンパイル後のファイル名'と指定すればそれだけで大丈夫です。
ちなみに全体の変数としてect.render.variables
で変数を設定できます。
"use strict"
module.exports = (grunt) ->
# task
grunt.initConfig
dir:
src: "src"
dest: "dist"
pkg: grunt.file.readJSON "package.json"
# grnt ect
ect:
options:
root: '<%= dir.src %>/template'
render:
files:
'<%= dir.dest %>/index.html': ['main/index.ect']
variables:
projectName: 'Sample Site'
menuList:
'about': '/about.html'
'2about': '/about.html'
watch:
ect:
files: "src/**/*.ect"
tasks: "ect"
# プラグインの読み込み
grunt.loadNpmTasks 'grunt-ect'
grunt.loadNpmTasks 'grunt-contrib-watch'
# タスク登録
grunt.registerTask 'default', ['watch']
実際にファイルを配置してみる
テンプレートの入れてあるディレクトリ構成はこんな感じ
src
└── template
├── partials
│ └── menu.ect
├── layout
│ └── default.ect
└── main
└── index.ect
srcのmainディレクトリに入っている物が、distファイルに展開される感じです。
<!-- Static navbar -->
<div class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#"><%- @projectName %></a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<% for name,link in @menuList : %>
<li><a href="<%= link %>"><%= name %></a></li>
<% end %>
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
</div>
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="<%= content 'description' %>">
<title><% content 'title' %>| sample page</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<style>
body {
padding-top: 20px;
padding-bottom: 20px;
}
.navbar {
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="container">
<% content %>
</div> <!-- /container -->
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<% content 'scripts' %>
</body>
</html>
<% block 'title': %>トップページ<% end %>
<% extend 'layout/default.ect' %>
<% include 'partials/menu.ect' %>
<h1><%= @projectName %></h1>
ここはトップページです。
<% block 'scripts': %>
<script>
$(function(){
console.log("load")
})
</script>
<% end %>
あとはGruntを実行するだけ
$ grunt
これで、distディレクトリの中にindex.htmlが生成されているはずです。
継承が使えるテンプレートってすてきですね。
一応基本的なECTの構文を書いておきます
HTMLのエスケープをしない出力
<%- someVar %>
HTMLのエスケープをする出力
今回のサンプルはこっちしか使用してません。
<%= @projectName %>
CoffeeScriptの記述
<% for article in @articles : %>
<% include 'article', article %>
<% end %>
上のテンプレートファイルだとmenu.ectの部分で使用しています。
Grunt側で定義したmenuListって変数をループしてメニューとして表示しています。
<% for name,link in @menuList : %>
<li><a href="<%= link %>"><%= name %></a></li>
<% end %>
テンプレート継承
extendをつければいいです。
<% extend 'layout/default.ect' %>
パーシャル
<% include 'partials/menu.ect' %>
おしまい
テンプレートエンジン使う事で、コーディング効率上がのと同時に、PHPやRubyなんかと連携するときも楽になります。
ということでぜひ一度試してみてください。