在node.js中加载已编译的Dust.js模板

时间:2014-08-18 14:11:04

标签: node.js edge.js dust.js

我正在尝试创建一个采用模板名称的函数,并且能够将呈现的模板作为字符串返回。我正在使用linkedin的版本的灰尘。我正在将模板(使用 grunt-dustjs 任务)预编译到一个如下所示的文件中:

(function(){dust.register("collections-nav",body_0);function body_0(chk,ctx){return chk.write("\t<div id=\"collection-loop\"><div class=\"section-title lines desktop-12\"><h2>Shop by Collection</h2></div>").section(ctx.getPath(false, ["bigMutha","TopNavigation"]),ctx,{"block":body_1},{}).write("</div>");}function body_1(chk,ctx){return chk.write("<div class=\"collection-index desktop-3 tablet-2 mobile-3 first\" data-alpha=\"").reference(ctx.get(["Title"], false),ctx,"h").write("\">  <div class=\"collection-image\"><a href=\"").reference(ctx.get(["Url"], false),ctx,"h").write("\" title=\"").reference(ctx.get(["Title"], false),ctx,"h").write("\"><img src=\"//cdn.shopify.com/s/files/1/0352/5133/collections/d_cb_20140312_m_handpicked_grande.jpg?v=1394885208\" alt=\"").reference(ctx.get(["Title"], false),ctx,"h").write("\" /></a>     </div><div class=\"collection-info\"><a href=\"/collections/mens-designer-clothing\" title=\"Browse our ").reference(ctx.get(["Title"], false),ctx,"h").write(" collection\"><h3>").reference(ctx.get(["Title"], false),ctx,"h").write("</h3><p>16 items</p></a></div></div>");}return body_0;})()

(function(){dust.register("index",body_0);var blocks={"body":body_1};function body_0(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.partial("layouts/mainfull",ctx,{});}function body_1(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.write("<ul>").section(ctx.get(["TopNavigation"], false),ctx,{"block":body_2},{}).write("</ul>").section(ctx.get(["Products"], false),ctx,{"block":body_3},{});}function body_2(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.write("<li>").reference(ctx.get(["Title"], false),ctx,"h").write("</li>");}function body_3(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.reference(ctx.get(["Name"], false),ctx,"h");}return body_0;})()

(function(){dust.register("layouts.mainfull",body_0);function body_0(chk,ctx){return chk.write("<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>Dust.js Test Template</title></head><body>").block(ctx.getBlock("body"),ctx,{},{}).write("</body></html>");}return body_0;})()

我认为我的最终问题是,如何从节点加载/使用这些模板(在单个文件中)?还是我错误地编译它们?我应该将这些IIFE包装在module.exports中吗?我做到了,但没有成就。这就是我在.js文件头部要求模板文件的方式:

var dust = require('dustjs-linkedin');
require('dustjs-helpers');
require('templates/all.js');
var JSON = require('json3');

当我通过“var templates = require(...);”按原样加载模板文件时直接调用或require()它我首先得到“灰尘未定义”错误,然后当我在前面添加“var dust = require('dustjs-linkedin');”到模板文件我收到一个错误,指出对象没有写入方法。

Object function (){dust.register("index",body_0);var blocks={"body":body_1};function body_0(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.partial("layouts/mainfull",ctx,{});}function body_1(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.write("<ul>").section(ctx.get(["TopNavigation"], false),ctx,{"block":body_2},{}).write("</ul>").section(ctx.get(["Products"], false),ctx,{"block":body_3},{});}function body_2(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.write("<li>").reference(ctx.get(["Title"], false),ctx,"h").write("</li>");}function body_3(chk,ctx){ctx=ctx.shiftBlocks(blocks);return chk.reference(ctx.get(["Name"], false),ctx,"h");}return body_0;} has no method 'write'

问题是,为什么它认为没有'写'方法?我试图加载这个怎么办?从理论上讲,每个已编译的模板都应该在加载文件并执行IIFE时将自身注册到灰尘缓存中,但它会不断抛出“无方法'写'错误。即使我将这些模板直接复制/粘贴到我试图加载它们的.js文件中,它也会这样做。我应该使用“module.exports”代码包装已编译的模板文件吗?也许在函数里面?我不知道为什么这不起作用,甚至可能是如何正确编译/加载模板。任何帮助表示赞赏!谢谢!


修改 Gist of raw templates


修改

对于接受的答案,这是一个很好的解释。然而,我仍然遇到一个问题,但似乎是在正确理解调用.render()时灰尘的作用,以及我必须在Edge.js / .NET中执行此操作的事实。< / p>

注意:已编译的模板,带分号;),在一个文件中,需要顶部的灰尘库,否则只是前面提到的IIFE。在我的Mac上,在Node.js中有以下工作:

var dust = require('dustjs-linkedin');
dust.helpers = require('dustjs-helpers');
require('./templates/all.js');

var myFunction = function(data) {
    console.log(dust.cache);
}

module.exports = function(data) {
    return myFunction(data);
}

我可以在缓存中看到模板。但是,如果我然后将'myFunction'更改为this仍然会看到缓存但返回undefined:

var dust = require('dustjs-linkedin');
dust.helpers = require('dustjs-helpers');
require('./templates/all.js');

var myFunction = function(data) {
    console.log(dust.cache);
    return dust.render('index', data, function(err, out) {
        return out;
    }
}

module.exports = function(data) {
    return myFunction(data);
}

这是一个问题。我在.NET上下文中使用Edge.js时引入的另一个问题是,相同的设置不会像在我的Mac上直接node.js环境中那样将模板加载到缓存中。我可以正常加载文件,我甚至可以将它作为字符串输出,但是当我查看dust.cache(因为console.log不能在.NET上下文中工作而导致PITA)时它返回为空。正是这个问题导致我尝试将已编译的模板转储到一个数组中,然后遍历调用每个数组项上的dust.loadSource的数组,但这也不想工作。

我正在努力清理项目,以便在今天的某个时间发布到GitHub。

2 个答案:

答案 0 :(得分:2)

回答2014-8-21编辑

现在您正在谈论异步和同步之间的区别。

Dust以异步方式呈现模板。事实上,这是尘埃比其他模板系统的主要好处之一。因此,让我们逐步了解您的第二个代码块中发生的事情:

  1. 在某个地方你将{1}作为一个模块。为简单起见,我们假设代码块位于名为require的文件中。所以,在其他地方,你说的是:

    /myFunction.js
  2. var myFunction = require('./myFunction'); var output = myFunction({ my: 'Model' }); // output === undefined 记录myFunction并返回dust.cache

  3. 的返回值
  4. dust.render接受回调并立即返回dust.render(这样您就可以看到预期的行为)
  5. dust会做它做的事情,在完全呈现模板字符串
  6. 时调用你提供的回调
  7. 你的回叫会返回undefined,但你没有给你的回调打电话 - 所以你的返回值很快被丢弃在地板上
  8. 您要做的是获取模板字符串灰尘返回到回调。唯一的方法是保持对该回调的控制。

    请考虑以下事项:

    out

    关于第二个问题,我将等待回购。 ;)


    编辑:猜猜阅读完整的问题会有所帮助。你试过这个并没有用。这是模板生成方式的问题。

    DOUBLE EDIT :已修复。在IIFE结束时添加分号。 = P

    有几种方法可以解决这个问题。

    首先,如果您可以使用可以利用预编译模板的视图引擎,那就去做吧。您必须将每个文件放在自己的文件中,并且模板名称必须与文件路径匹配,但它肯定是最简单的。例如,adaro可以呈现预编译的模板。您可以使用以下内容进行注册:

    // a little shortcut since `dustjs-helpers` requires and returns dust anyway
    var dust = require('dustjs-helpers');
    require('./templates/all.js');
    
    // `myFunction` uses dust which is async, therefore it needs to be async (take a callback)
    var myFunction = function(data, cb) {
        console.log(dust.cache);
        dust.render('index', data, cb);
    }
    
    module.exports = myFunction;
    
    // ... and here's example usage ...
    
    var myFunction = require('./myFunction);
    myFunction({ my: 'Model' }, function (err, templateStr) {
        if (err) {
            // ... dust had a problem ...
        } else {
            // ... do something with `templateStr` like ...
            console.log(templateStr);
        }
    });
    

    接下来,如果您不能或不能将这些模板分解为自己的文件或更改名称以反映文件路径,那么下一个最简单的事情就是利用这两个事实:1)节点缓存模块和2)var dust = require('adaro'); app.engine('js', dust.js()); app.set('view engine', 'js'); app.set('views', __dirname + '/views'); 返回单例。这意味着,如果您在一个文件中dustjs-linkedin,那么您将在任何其他文件中获得与您require('dustjs-linkedin') *相同的对象。值得一提的是,这有点像黑客。

    这意味着,如果您require('dustjs-linkedin')在任何时候,您可以dust.register该模板。你必须规避快递&#39;查看渲染以使其工作,但它是可能的。我已经写了一个例子thrown it up on github,但缺点是:

    1. 在渲染的模板文件中添加对灰尘的引用

      dust.render
    2. 将灰尘拉入路线处理程序并使用灰尘进行渲染而不是表达

      // /templates/combined.js
      var dust = require('dustjs-linkedin');
      // your templates below
      (function () {dust.register('myTemplate', /* ... */})();
      
    3. 由于您未使用快递&#39;方便的渲染方法,您可以使用灰尘的流接口将输出流式传输到客户端,而不是缓存内存中的渲染模板。事实上,流式传输是我考虑使用这种模式的唯一原因,因为虽然这是一种功能性的解决方法,但它有点不优雅并且依赖于我个人推荐的事情。依靠(模块中的单身人士)。

      另一种选择是编写自己的视图引擎,而不是仅仅查看文件系统上的模板,可以先检查灰尘缓存,然后公开一个允许你填充缓存的// /routes/index.js var dust = require('dustjs-linkedin'); module.exports = function (req, res, next) { // instead of res.render ... dust.render('myTemplate', {my: 'Model'}, function (err, compiled) { if (err) return next(err); res.send(compiled); }); }; 方法提前。

      最后,如果您不喜欢这些解决方案,请查看krakenjs(完全披露:我正在处理此问题)。它,以及它支持的模块演员(如kraken-devtools)摆脱了必须考虑很多这些东西。使用yeoman generator轻松试用。

      * - node缓存模块文件路径,因此只有在require语句解析为同一文件路径时才会出现这种情况。换句话说,子依赖的dustjs-linkedin将与您的dustjs-linkedin依赖性不同。

答案 1 :(得分:0)

所以我将回答我自己的问题,这个问题将适用于我的具体问题,但我不会尝试提供有关加载Dust.js模板的一般问题的全面答案让 - 查尔斯做到了。他的意志将保留为已接受的答案,我的回答可能是试图手动渲染预编译模板的人的注意事项。特别是模板预编译成单个文件。也许也许是Adaro可以做的转换,希望能够获得超过解析多个文件的效率

最终我的问题是单个文件'templates.js'以错误的顺序加载编译的模板。所以index.js,它使用了一个布局(实际上只是一个奇特的部分),但是没有为索引模板加载布局模板以尝试用作布局。

我的解决方案是改变我的grunt-dustjs任务:

[{ 
    "templates/all.js": ["theme/**/*.dust"] 
}]

到此:

[{
"templates/all.js":    [
                        "theme/partials/[singletons]/*.dust",
                        "theme/partials/*.dust",
                        "theme/layouts/*.dust",
                        "theme/*.dust"
                       ]
}]

这会向后遍历目录树,强制执行一种结构,其中模板只能使用作为对等或后代的部分。这基本上是对编译器说“首先给我个人(最常用的)部分,然后我的组件级别部分,然后我的布局(这将是部分的主要消费者,以及顶级灰尘文件),然后我的顶级灰尘文件,可以被认为是页面“。页面将是布局的使用者和服务器端模板请求的入口点。

麻烦的部分是[单身人士]区域。不可避免地,部分将需要它的对等体,并且该对等体将以字母表中的所述部分之前的字母命名。这将导致我在加载布局模板之前遇到需要布局模板的索引模板时遇到的相同情况。除非我遗漏了什么,否则这将无声无息。它会成功地将每个模板加载到缓存中,但是需要尚未加载的模板的模板将被错误地编译并且在调用时无法呈现。