dwi2的碎念

不能只是曬網

Handlebars Precompile Template快速上手

| Comments

Handlebars是一個JavaScript template engine, 可以在pure front-end (瀏覽器內)或是back-end (Node.js)上運行.

類似的JavaScript template engine很多, 箇中差別或是優劣比較這裡就不著墨, 網路上應該可以找到很多分析, 例如這個stackoverflow討論串這個Quora問答或是這個網頁

我選擇Handlebars的原因只有一個: 可以使用precompile的template, 因此網頁上只要多帶約6KB大小的handlebars.runtime.js即可, 使用Handlerbars帶來的overhead不大, 畢竟JavaScript Library最重要的就是要輕●薄●短●小!

不過Handlebars的官方網頁對於如何precompile template以及如何使用precompile template的說明有點少, 很急的人如果照著作可能沒辦法馬上正常運作, 因此我寫了這篇quickstart guide來幫助大家快速地在網頁前端使用Handlebars precompile template. 如果只是想要知道怎麼在你的網站前端簡單地使用Handlebars, 不太在乎頁面讀取的效能, 看官方網站就足夠了.

官方並沒有提供handlebars.runtime.js的載點, 因此想要使用precompile template, 必須自己從頭build Handlebars project!

因此你會需要以下的東西:

Build Handlebars

build Handlerbars步驟如下:

  1. 去Github抓(clone)[最新的Handlebars source code](https://github.com/wycats/handlebars.js)下來
  2. 安裝前述所需工具, Ruby(建議使用1.9.2以上版本), Bundler, Node.js和npm
  3. 用Bundler安裝需要Rubygems
  4. 1
    
    bundle install
    
  5. 然後build整個Handlebars project(此時rake會自動招喚npm幫忙安裝所需JS library):
    1
    
    bundle exec rake release
    
  6. build完之後會出現dist資料夾, 裡面的handlebars.runtime.js就是擺在網頁上的script

以上步驟只要做一次就可以, 之後的webapp project都可以直接重複使用產生好的handlebars.runtime.js, 不過如果想要用最新版的handlebars, 可以再重複上述步驟1, 4, 5以產生最新的handlebars.runtime.js

接下來的工作就是precompile template了!

Precompile Handlebars Template

假設我們有幾張靜態頁面:

index.html
about.html
archives.html

基本上這些靜態頁面的navigation區域都是一樣, 只是每張頁面的active item不同, 例如在index.html, Blog這個item是active的

Blog | About | Archives

但在about.html, 換成About這個item是active的

Blog | About | Archives

這種狀況下, 把navigation區域的HTML重複寫三遍顯得很笨拙, 此時就適合用template處理

從頁面抽出來的template長相如下:

nav.handlebars
1
2
3
4
5
6
7
8
{{#each nav}}
{{#if active}}
<li class="active">
{{else}}
<li>
{{/if}}
<a href="{{link}}">{{title}}</a></li>
{{/each}}

附檔名要叫handlebars, precompile出來的template js會以檔名作為identifier. 以nav.handlebars為例, 產生出的precompiled template如下, 從第三行可以看到產生的templates就擺放在Handlebars.templates[’nav‘]這個identifier之下

nav.template.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
(function() {
  var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['nav'] = template(function (Handlebars,depth0,helpers,partials,data) {
  helpers = helpers || Handlebars.helpers; data = data || {};
  var stack1, self=this, functionType="function", escapeExpression=this.escapeExpression;

function program1(depth0,data) {

  var buffer = "", stack1, foundHelper;
  buffer += "\n";
  stack1 = depth0.active;
  stack1 = helpers['if'].call(depth0, stack1, {hash:{},inverse:self.program(4, program4, data),fn:self.program(2, program2, data),data:data});
  if(stack1 || stack1 === 0) { buffer += stack1; }
  buffer += "\n<a href=\"";
  foundHelper = helpers.link;
  if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},data:data}); }
  else { stack1 = depth0.link; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
  buffer += escapeExpression(stack1) + "\">";
  foundHelper = helpers.title;
  if (foundHelper) { stack1 = foundHelper.call(depth0, {hash:{},data:data}); }
  else { stack1 = depth0.title; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
  buffer += escapeExpression(stack1) + "</a></li>\n";
  return buffer;}
function program2(depth0,data) {


  return "\n<li class=\"active\">\n";}

function program4(depth0,data) {


  return "\n<li>\n";}

  stack1 = depth0.nav;
  stack1 = helpers.each.call(depth0, stack1, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
  if(stack1 || stack1 === 0) { return stack1; }
  else { return ''; }});
})();

precompile的過程只會使用到Node.js以及先前build好的node script檔, 路徑是<handlebars-project-root-path>/bin/handlebars, 因此執行

    <handlebars-project-root-path>/bin/handlebars nav.handlebars -m -f nav.template.js

就可以把nav.handlebars precompile成為nav.template.js, 接下來將nav.template.js以及handlerbars.runtime.js擺放到web project內, 在所需頁面上嵌入連結並撰寫使用template的code就完成了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<div class="navbar navbar-static-top navbar-inverse">
  <div class="navbar-inner">
  <a href="#" class="brand">dwi2的碎念</a>
  <ul id="nav_list" class="nav"><!-- 之後template將會插到這裡 --></ul>
  </div>
</div>


<script src="/js/handlebars.runtime.js"></script>
<script src="/js/nav.template.js"></script>
<script>
(function () {
  var nav_list = document.getElementById('nav_list'),
    nav_template = Handlebars.templates.nav,
    nav_data = { // data that will be filled in the template
      nav: [
        {
          active: true,
          link: 'index.html',
          title: 'Blog'
        },
        {
          active: false,
          link: 'about.html',
          title: 'About'
        },
        {
          active: false,
          link: 'archives.html',
          title: 'Archives'
        }
      ]
    };
  // fill the data in the template, and insert to the page
  nav_list.innerHTML = nav_template(nav_data);
}());
</script>

Comments