在Express項目中使用Handlebars模板引擎

原網址:http://fraserxu.me/2013/09/12/Using-Handlebarsjs-with-Expressjs/

最近在用Expressjs做一個項目,前後端都用它來完成。自己之前有用過Express一段時間,但是大部分都是用它來編寫Restful的API,而沒有真正用它所提供的前端頁面渲染功能。

所以嚴格意義來講這是第一次完整的項目。開始做之後就遇到了一些需要做出決定的地方。衆所周知,Express的默認模板引擎是Jade.我在之前學習Express的時候,因爲它是默認的引擎,所以有接觸和使用過一段時間,感覺也還行。Jade在編寫頁面時所提供的嵌套功能比較實用,可以節省很大的代碼量。

Jade is a high performance template engine heavily influenced by Haml and implemented with JavaScript for node. For discussion join the Google Group.

上面是Jade Github所在頁面的描述。可以得知它是一個注重性能,受Hamle影響,並特別針對Nodejs而編寫的前端模板引擎。

我們先來看一下Jade官方頁面所給的例子:

doctype 5
html(lang="en")
  head
    title= pageTitle
    script(type='text/javascript').
      if (foo) {
        bar(1 + 5)
      }
  body
    h1 Jade - node template engine
    #container.col
      if youAreUsingJade
        p You are amazing
      else
        p Get on it!
      p.
        Jade is a terse and simple
        templating language with a
        strong focus on performance
        and powerful features.

我們可以看到,對比原生的HTML, Jade明顯的一個優勢就是標籤數量上的減少。很多地方只要按照約定的縮進規則編寫,完全可以避免使用原生HTML時標籤忘記閉合的問題。同時Jade還提供了一些用於渲染判斷的條件,可以根據數據來決定顯示的內容等功能。

另外Jade的遍歷數據生成頁面功能,配合使用Json數據時特別好用,可以很大程度上減少代碼量。

而另外一個原因,也是覺大多數人使用Jade的原因,可能都跟我一樣,因爲是Express框架自帶的模板引擎,而它的作者也是鼎鼎有名的TJ.

看了標題也許會奇怪,既然Jade出自大神之手,而且簡單易用,我爲什麼還要去選擇Handlebarsjs呢?

同樣我們看下官方描述:

Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.

Mustache templates are compatible with Handlebars, so you can take a Mustache template, import it into Handlebars, and start taking advantage of the extra Handlebars features.

作爲一個模板引擎,它繼承於著名的Mustache模板引擎,具備了渲染頁面的基礎功能,並在其基礎上進行拓展。

而另一個值得關注的是其作者Yehuda Katz,熟悉的朋友可能知道,他是著名JavaScript MVC框架Emberjs代碼的主要貢獻者之一,而且在他的影響下也成爲了Emberjs的默認模板引擎。而另外,Yehuda本身也是W3C規範制定小組的成員之一,其影響也不亞於TJ.

拋開框架的背景,我們來看看實際的應用場景。工具無非好壞,順手纔是王道。評斷一個東西好壞關鍵還是看它是否滿足自己的應用需求。

在開始做現在的項目之前,我已經用Jade完成了所有的功能,而且對於代碼也還比較滿意。但是在提交之後問題產生了。

因爲這個項目不是我一個人在做,和我一起合作的同事之前沒有接觸過Jade,而且另外一位負責編寫樣式的同事對於JavaScript的模板引擎也不是很熟悉。這樣一來,由於我的原因,導致團隊成員之間無法協作。首先是JS開發人員需要時間來掌握和熟悉Jade語法,而另外一個更爲嚴重,Jade語法的特性決定了其不利於配套CSS的書寫(這點通過編譯之後可以解決,但是一定程度上增加了工作量)。

於是我開始思考使用Jade是否正確。這裏的兩個問題是我必須面對的,而項目的進度不能因爲這個受到影響,於是我開始考慮選擇其他的模板引擎。

前面提到Emberjs用到了Handlebarsjs,所以在選擇時我很容易就想到了它。

Handlebars的官網給出了很多例子,而且上手也很容易,前後端通用,使用起來也很簡單,這裏就不對其使用多做介紹。

回到文章重點,因爲Express並不提供對Handlerbarjs的直接支持,這樣在使用時會面臨一定問題。

要在Express中使用Handlerbars作爲模板引擎,首先需要做出一下設置:

  1. 安裝Express, Handlebars, Consolidate:

     "dependencies": {
       "express": "3.x",
       "consolidate": "0.4.0",
       "handlebars": "1.0.7"
     }
    
  2. 配置選擇引擎:

     // Use handlebars as template engine
     app.engine("html", consolidate.handlebars);
     app.set("view engine", "html");
     app.set("views", __dirname + "/views");
    
  3. 註冊模板:

     // Register partials
     var partials = "./views/partials/";
     fs.readdirSync(partials).forEach(function (file) {
       var source = fs.readFileSync(partials + file, "utf8"),
         partial = /(.+)\.html/.exec(file).pop();
         Handlebars.registerPartial(partial, source);
     })
    

這樣我們就可以在項目中使用Handlerbars來渲染頁面。但是這樣做後,我又遇到了另外一個問題。通過以上的方法我可以很容易的單獨去加載某個頁面。但是實際應用中,一般會有多個頁面,而且多個頁面之間會共享頁面的header和footer部分。這樣會導致重複編寫很多代碼。

在使用Jade是我們可以很容易的使用如下代碼來實現頁面模板功能:

include layout

但是由於Express並非直接支持Handlerbars,所以要實現這個功能還需要一定的設置。在Handlerbars中,可以通過 來實現sub-template的功能。在查找了相關模塊之後,我發現了hbs這個Express中間件。

這個模塊使用起來很簡單,可以完美解決我所遇到的問題。使用方法如下:

  1. 安裝模塊:

     npm install hbs --save
    
  2. 設置模板:

     app.set('view engine', 'html');
     app.engine('html', require('hbs').__express);
    
  3. 註冊模板:

     var hbs = require('hbs');
     hbs.registerHelper('helper_name', function(...) { ... });
     hbs.registerPartial('partial_name', 'partial value');
    

如果需要註冊整個文件夾,也可使用如下命令:

    var hbs = require('hbs');
    hbs.registerPartials(__dirname + '/views/partials');

這樣,我們就可以做到頁面模板的重複利用,可以顯著減少代碼量。

而另外一個關鍵原因,在於Handlerbars對比Jade,語法更加簡單。最重要的還是其普通元素同樣使用原生HTML的寫法,這樣,對於編寫樣式的同事來講就會更加友好。使用傳統的方式編寫樣式,可以顯著降低學習成本,從而加快項目進度。

而Handerbars所帶來的一些其他功能,也會讓項目的開發變得更加輕鬆。

下面附上我項目的基本結構,希望能對同樣使用這種方案的同學有一定幫助。

.
├── app.js
├── node_modules
│   ├── express
│   ├── handlebars
│   ├── hbs
│   ├── less-middleware
│   ├── nodemon
│   └── request
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   │   └── app.js
│   ├── lib
│   │   ├── font
│   │   ├── js
│   │   └── stylesheets
│   └── stylesheets
│       ├── style.css
│       └── style.less
├── routes
│   ├── github.js
│   └── index.js
└── views
    ├── index.hbs
    ├── orgs.hbs
    └── partials
      ├── footer.hbs
      └── header.hbs
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章