11

I'm running into some funny stuff with the view cache in express/Jade. The controller fetches an article from MongoDB via Mongoose and hands it to the res.render function. However, after running for a couple of minutes Express starts serving the same compiled template for all requests to that route. This even happens to shared .jade includes that are used in various templates.

The database is fetching the correct articles and it doesn't matter if I pass some random strings to the template, I always get the same output.

This is the controller function:

exports.show = function(req, res) {
  var articleId;
  articleId = req.params.id;
  Article.findOne({
    _id: articleId
  }).populate('author').exec(function(err, article) {
    if (err) {
      console.log(err);
    } else {
      res.render('articles/show', {
        article: article,
        articleId: article.id
      });
    }
  });
};

And that's the route:

app.get('/articles/:id', articles.show);

The same things happen whether I'm running in production or development mode.

Has anyone run into this kind of toruble with Express/Jade?

Ólafur Nielsen
  • 151
  • 1
  • 1
  • 6
  • 2
    With "the same compiled template", do you mean the same *rendered* template? I'm not sure it's the view cache, since that's not active when run in dev mode (unless you explicitly enabled it?). Also, the view cache only stores compiled (but unrendered) templates, they will still be rendered separately for each request. What does your app setup look like? Any other middleware (or perhaps a proxying server in front of Node) that might cause the issue? – robertklep Jun 04 '13 at 19:31
  • 1
    I agree with @robertklep. I guess its your proxy which is caching. Can you check the headers of the response if you see any cache header? Also, try setting the following headers on server side. Cache-Control: no-cache, no-store, must-revalidate Pragma: no-cache Expires: 0 See if that works for you?http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers – Pradeep Mahdevu Sep 30 '13 at 18:40

2 Answers2

11

Edit: Notice that express sets view cache enabled for production: see express docs

view cache Enables view template compilation caching, enabled in production by default

Try adding this line in your app config section:

app.disable('view cache');

Also, try adding cache-control headers

res.setHeader('Cache-Control', 'no-cache');
res.render('articles/show', {
...

From w3.org docs:

Cahce-Control

The Cache-Control general-header field is used to specify directives that MUST be obeyed by all caching mechanisms along the request/response chain. The directives specify behavior intended to prevent caches from adversely interfering with the request or response. These directives typically override the default caching algorithms. Cache directives are unidirectional in that the presence of a directive in a request does not imply that the same directive is to be given in the response.

If you need a more advanced control, consider other fields like max-age, this question is also a good resource, you'll see that different browsers may implement this rfc slightly different.

Community
  • 1
  • 1
alfonsodev
  • 2,714
  • 2
  • 23
  • 30
  • Browser caching isn't the issue. Say I look at four different blog posts. After a bit, all URLs will start delivering the same blog post. It's like jade is caching the template and not bothering to use the object I pass to it... It just uses the last known values. – MikeSmithDev Oct 29 '13 at 15:58
  • Ok, I see your point, the header is not just for Browser cache, imagine you have a Varnish in production, or your DNS has a cache mechanism like Cloudflare, this header in the response must be obeyed along the chain. But I see your point. Then I would replace jade for hbs or other to discard that is a template engine problem. Or have a look in the Jade repo to see if there are known issues with cache. – alfonsodev Oct 29 '13 at 16:18
  • Yeah I think I will have to go that route. – MikeSmithDev Oct 29 '13 at 16:39
  • Follow up: I ended up just going with [doT](http://olado.github.io/doT/index.html). – MikeSmithDev Nov 20 '13 at 15:32
2

TL;DR: try

let articleId;

instead of

var articleId;

I'm just another newbro to Node.js, but I've just solved the same issue by substituting "var" keyword for "let". The thing is that "var" creates a variable scoped by a function, while "let" – a scoped to the current block one. It is re-created every time the block is executed, which is important due to asynchronous nature of Node.js.