Search code examples
node.jsexpressdust.js

Error: can't find 'dust' module when rendering dust templates on node.js


I'm starting with the boilerplate code express generates for me. I'm requiring dustjs-linkedin and compiling some simple templates in app.js like so:

var dust = require('dustjs-linkedin');...

app.set('view engine', 'dust');...

var compiled = dust.compile("Hello {name}!","intro");
// add into dust.cache manually
dust.loadSource(compiled);
console.log(dust.cache);

dust.render("intro", {name: "Fred"}, function(err, out) {
  if(err){console.log(err)}
  console.log(out);
});

This is all works well and I see the HTML outputted in my terminal. Its only when I try and do the same thing from within a route when I start getting this error:

GET / 500 11.607 ms - 904 Error: Cannot find module 'dust'

app.get('/', function(req, res){
  var compiled = dust.compile("Hello {name}!", "intro");
  dust.loadSource(compiled)
  dust.render("intro", {name: "Fred"}, function(err, out) {
    console.log(out);
    res.send(out);
    res.close();
  });
});

This is all within app.js, only it works outside of a route, but not when I move it into a route callback. Does anyone know why it can't find 'dust'? I've required it and it should be visible from within the callback right?

Thanks for any help!

Edit 1 As per the comment below, 'dust' is getting required somewhere. I'm not doing it in my code; my guess is that Express is doing it behind the scenes because my templates have '.dust' file ending. I just tried deleting all my templates (wasn't using them anyways) and now I just get this error:

Error: Failed to lookup view "error" in views directory

All I want is to see the output: "Hello Fred"

Edit 2: I think I found what was wrong

Everything Interrobang posted is correct. The problem, I think, was this middleware block that was generated for me by express-generator:

app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

So for every request, this middleware would fire and throw an error. I'm not 100% sure what its doing but if I comment it out, everything works. My secondary question now, if I may have one, is what exactly is going on and why is it set for all requests?


Solution

  • You're setting the view engine to dust, but you haven't registered an engine with Express to tell it how to render Dust-- and Express can't do it by default.

    Consider using consolidate, hoffman, or adaro (among others) as your Dust rendering engine for Express.

    Here's a complete example using consolidate. I have tested and this works on my machine.

    var express = require('express'),
        cons = require('consolidate'),
        app = express();
    
    // assign the dust engine to .dust files 
    app.engine('dust', cons.dust);
    
    // set .dust as the default extension 
    app.set('view engine', 'dust');
    app.set('views', __dirname + '/views');
    
    app.get('/', function(req, res) {
        res.render('index', { name: 'Interrobang' });
    });
    
    app.listen(3000, function () {
      console.log('Visit http://localhost:3000 woo!');
    });
    

    Alternatively, simply remove the view engine line from your code. You're not using Express to do the rendering, so Express doesn't even need to know.

    Here's a very simple example without any view engine that I've tested to work. Your Dust templates go in a folder called views.

    var fs = require('fs'),
        path = require('path'),
        express = require('express'),
    
        dust = require('dustjs-helpers');
    
    dust.config.whitespace = true;
    
    dust.onLoad = function(tmpl, cb) {
      fs.readFile(path.join('./views', path.resolve('/', tmpl + '.dust')),
                  { encoding: 'utf8' }, cb);
    };
    
    var app = express();
    app.get('/', function (req, res) {
      dust.stream("hello", { "world": "World!" }).pipe(res);
    });
    
    app.listen(3000, function () {
      console.log('Visit http://localhost:3000 woo!');
    });