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

我正在尝试创build一个采用模板名称的函数,并能够将呈现的模板作为string返回。 我正在使用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(…);”来加载模板文件时, 直接调用或需要()它我首先得到一个“尘埃未定义”的错误,然后当我把“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时将自己注册到垃圾caching中,但是会一直抛出“无方法”写入错误。 这样做,即使我将这些模板直接复制/粘贴到我正试图加载它们的.js文件中。 我应该用“module.exports”代码包装已编译的模板文件吗? 也许在一个函数里面? 我不知道为什么这不工作,或者甚至如何正确编译/加载模板。 任何帮助表示赞赏! 谢谢!


编辑 要点的原始模板


编辑

这是对接受的答案的一个很好的解释。 然而,我仍然有一个问题,但它似乎是不正确的了解什么时候调用.render(),什么灰尘,而事实上,我不得不在Edge.js / .NET中这样做。

注意:编译好的模板,带有分号;)在一个文件中,需要在顶部有灰尘库,否则就是前面提到的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); } 

我可以看到caching中的模板。 但是,如果我然后更改'myFunction'它仍然看到caching但返回未定义:

 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环境中那样将模板加载到caching中。 我可以加载文件很好,我甚至可以输出它作为一个string,但是当我窥视dust.cache(PITA由于console.log不工作在.NET上下文)它返回为空。 正是这个问题导致我尝试将编译后的模板转储到数组中,然后迭代在每个数组项上调用dust.loadSource的数组,但不想工作。

我正在清理项目,并在今天的某个时候发布到GitHub上。

2014-8-21回答编辑

现在你正在谈论asynchronous和同步之间的区别。

Dustasynchronous渲染模板。 事实上,这是其他模板系统的主要优点之一。 那么让我们来看看第二个代码块中发生了什么:

  1. require地方 – 代码块作为一个模块。 为了简单起见,我们假设代码块位于名为/myFunction.js的文件中。 所以,在别的地方,你说:

     var myFunction = require('./myFunction'); var output = myFunction({ my: 'Model' }); // output === undefined 
  2. myFunctionloggingdust.cache并返回dust.cache的返回值

  3. dust.render需要callback,并立即返回undefined (所以你看到预期的行为)
  4. 灰尘做它做的,调用你提供的callback,当它完全呈现模板string
  5. 你的callback回来out但是你没有叫你的callback – 灰尘,所以你的回报值被迅速放在地板上

你想要做的是获得访问模板string灰尘返回到callback。 唯一的方法就是保持对callback的控制。

考虑以下:

 // 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); } }); 

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


编辑 :猜猜这有助于阅读完整的问题。 你试过这个,它不起作用。 这是如何生成模板的问题。

双编辑 :固定。 将分号添加到您的IIFE的末尾。 = P

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

首先,如果你可以使用一个可以利用预编译模板的视图引擎,那就去做吧。 你必须有自己的文件,模板名称将不得不匹配文件path,但它当然是最简单的。 例如, adaro可以呈现预编译的模板。 你可以用下面的东西注册它:

 var dust = require('adaro'); app.engine('js', dust.js()); app.set('view engine', 'js'); app.set('views', __dirname + '/views'); 

接下来,如果你不能或不能把这些模板分解成自己的文件或者改变名字来反映文件path,那么下一个最简单的事情就是利用这两个事实:1)节点caching模块和2) dustjs-linkedin返回一个单身人士。 这意味着如果你require('dustjs-linkedin')在一个文件中,你会得到你require('dustjs-linkedin')任何其他文件中的同一个对象require('dustjs-linkedin') *。 值得一提的是,这是一个黑客。

所以这意味着,如果你在任何时候发现了dust.register ,那么你可以dust.render这个模板来dust.render 。 你必须避开明确的“查看渲染才能使之工作,但这是可能的。 我已经写了一个例子,并把它扔在github上,但缺点是:

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

     // /templates/combined.js var dust = require('dustjs-linkedin'); // your templates below (function () {dust.register('myTemplate', /* ... */})(); 
  2. 把灰尘拉进你的路线处理程序,并用灰尘来渲染,而不是expression

     // /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); }); }; 

由于您没有使用Express方便的渲染方法,因此您可以使用尘埃的stream接口将输出stream式传输到客户端,而不是将渲染的模板caching在内存中。 实际上,stream式传输是我考虑使用这种模式的唯一原因,因为虽然这是一种function性的解决方法,但是它有点不雅观,并且依赖于我个人build议的依靠(从模块中的单例) 。

另一个select是编写自己的视图引擎,而不是专门查看模板的文件系统,可以先检查垃圾caching,然后公开一个setup方法,以便提前填充caching。

最后,如果您不喜欢这些解决scheme,请查看krakenjs (完全披露:我在此工作)。 它和它支持的模块(比如kraken-devtools )一起被抛弃,不得不考虑很多这样的东西。 使用yeoman生成器轻松实现。

* – 节点caching模块文件path,所以只有当您的require语句parsing为相同的文件path时才是如此。 换句话说,一个子依赖的dustjs-linkedin将与你的dustjs-linkedin依赖不同。

所以我要回答我自己的问题,这个问题将适用于我的具体问题,但是我不会像Jean-Charles所做的那样,提供加载Dust.js模板的一般问题的全面答案。 他会保留接受的答案,我的答案可能是人们试图手动呈现预编译模板的脚注。 具体模板预编译成单个文件。 也可能是Adaro可以做的,希望通过parsing多个文件来提高效率

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

对我来说,解决办法就是改变我的咕task声:

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

对此:

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

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

麻烦的部分是[singletons]区域。 不可避免的是,部分意志要求它是同侪,而同侪则以字母上的部分之前的字母命名。 这将导致我在装载布局模板之前遇到与索引模板需要布局模板相同的条件。 除非我错过了一些东西,否则这将会失败。 它将成功地将每个模板加载到caching中,但是需要模板尚未加载的模板将不正确地编译,并且在调用时无法呈现。