针对移动端的前端工作流(5)—Handlebars的预编译

在前后端分离的架构下,为了方便渲染,我们通常会选择模板引擎处理复杂的渲染逻辑。

我们曾纠结于mustache与handlebars,最终还是选择了功能更加强大的handlebars。

虽然handlebars功能强大,但是体积也大,在压缩后也有70K!!!

所以为了在功能强大与代码大小之间做个平衡,我们使用handlebars的预编译文件,为了方便开发,我们写了一个gulp插件
gulp-handlebars-precompile,可以提取html文件中的handlebars模板文件,预编译到指定目录,并且可以在html文件中建立script链接,在这里我们简单看下使用方法:

handlebars模板文件写在src/tpl目录下,建立一个文件如product.hbs

product.hbs文件:

  1. {{#each data}}
  2. <li href="{{itemLink}}">
  3. {{test}}
  4. </li>
  5. {{/each}}

html文件:

注意这里直接写文件名就可以了,会自动指向src/tpl目录。

  1. <!--hbs "product.hbs"-->

在开启gulp命令的情况下会实时监控html文件的变化,保存时会自动提取模板文件,在dev/tpl建立以html文件名建立的文件夹,里面有预编译的js文件,即

源文件目录:

  1. ├── gulpfile.js # gulpfile文件
  2. ├── src/ # 源文件目录
  3. └── index.html # index.html
  4. └── tpl/ # 模板目录
  5. └── product.hbs # 模板文件
  6. └── dev/ # 编译目录

dev目录:

  1. └── dev/ # 编译目录
  2. └── tpl/
  3. └── index/
  4. └── product.js
  5. └── index.html # index.html

看看编译后的product.js:

  1. this["templates"] = this["templates"] || {};
  2. this["templates"]["product"] = Handlebars.template({"1":function(container,depth0,helpers,partials,data) {
  3. var helper, alias1=depth0 != null ? depth0 : {}, alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
  4. return "<li href=\""
  5. + alias4(((helper = (helper = helpers.itemLink || (depth0 != null ? depth0.itemLink : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"itemLink","hash":{},"data":data}) : helper)))
  6. + "\">\n "
  7. + alias4(((helper = (helper = helpers.test || (depth0 != null ? depth0.test : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"test","hash":{},"data":data}) : helper)))
  8. + "\n</li>\n";
  9. },"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data) {
  10. var stack1;
  11. return ((stack1 = helpers.each.call(depth0 != null ? depth0 : {},(depth0 != null ? depth0.data : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
  12. },"useData":true});

而且src/index.html中的

  1. <!--hbs "product.hbs"-->

dev/index.html中会被替换为

  1. <script src="tpl/index/product.js" inline></script>

这里让我们看看它的具体配置文件

  1. .pipe(precompile({
  2. reg: /<!\-\-hbs\s+"([^"]+)"\-\->/g, // 设置提取文件的规则
  3. baseSrc: "src/tpl/", // 设置文件根目录
  4. dest: "dev/tpl/", // 设置编译到文件目录
  5. scriptSrc: 'tpl/', // 设置替换后的script的前缀目录
  6. inline: true // 是否要添加inline属性
  7. }))

当我们获得了预编译的文件后,我们该怎么使用呢?

举个例子:

src/index.html中引入handlebars.runtime-v4.0.5.js(压缩后13K)和要编译的模板文件,如图所示:

precompile-before

dev/index.html就会编译成:

precompile-after

如果你想使用这个模板文件:

  1. var html = templates.product(data);
  2. $("body").append(html);

让我们来解释一下:

  1. 假设 data 变量是你通过ajax请求获得的json数据
  2. templates是命名空间,默认值,如果你想自定义命名空间,点击查看
  3. product是方法名,使用的是你的模板文件的名称,传入的参数的 获得的数据,返回的是html片段

至于

  1. <script src="tpl/index/product.js" inline></script>

script标签会有inline属性呢?请接着往下看。