[SOLVED] SSR using picker and flow-router

Continuing the discussion from Facebook share setup:

I’m using Flow-Router with Meteor 1.5.1. Based on the topic above, I’ve tried to create the following SSR route using meteorhacks:ssr and meteorhacks:picker

I disabled my flow-router route for /blog/:post_id and implemented the following server-side route. I get a 404 error (the default flow-router route) whenever I try to navigate to a /blog/post_id route.

Any help is appreciated.

/private/layout.html

{{{getDocType}}}
<html lang="en">
  <head>
      <meta name="description" content="description"/>
     {{> Template.dynamic template=template data=data}}
  </head>
</html>

/server/seo/layout.js

SSR.compileTemplate('seoLayout', Assets.getText('layout.html'));
Template.seoLayout.helpers({
  getDocType: function() {
    return "<!DOCTYPE html>";
  }
});

/private/blogpost.html

<title>Post : {{post.title}}</title>
<!-- Open Graph Meta Tags -->
<meta property="og:type" content="website"/>
<meta property="og:title" content="{{post.title}}"/>
<meta property="og:description" content="{{post.subtitle}}"/>
<meta property="og:site_name" content="Sid Kwakkel's Blog"/>
<meta property="og:url" content="https://sidkwakkel.com/blog/{{post.id}}"/>
<meta property="og:image" content=""/>
<!-- just testing this getting in here -->
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="{{post.title}}"/>
<meta name="twitter:description" content="{{post.subtitle}}"/>
<meta name="twitter:image" content=""/>
<meta name="twitter:site" content="@SidKwakkel"/>
<meta name="twitter:creator" content="@SidKwakkel"/>

/server/seo/blogpost.js

SSR.compileTemplate('blogpost', Assets.getText('blogpost.html'));
Template.blogpost.helpers({})

/server/serverroutes.js

var seoPicker = Picker.filter(function(req, res) {
  var isCrawler = [];
  var string = req.headers['user-agent'];
  isCrawler.push(/_escaped_fragment_/.test(req.url));
  if(string){
      isCrawler.push(string.indexOf('facebookexternalhit') >= 0);
      isCrawler.push(string.indexOf('Slack') >= 0);
      isCrawler.push(string.indexOf('Twitterbot') >= 0);
  }
  return isCrawler.indexOf(true) >= 0;
});

seoPicker.route('/blog/:postid', function(params, req, res){
    var post = Posts.findOne({_id:params.postid});
    var html = SSR.render('seoLayout',{
        template:'blogpost',
        data: {post:post}
    });
    res.end(html);
});

Actually, this works as prescribed. I re-enabled the flow-router route, so now users get the reactive version. When I have Google render the page in Google Search Console, it renders the complete HTML (NIce!)

Looks like we’re good here!

Hi! I’m trying to use the same example to get Twitter and Facebook to find my metatags, it works for Facebook/OpenGraph, but for some reason doesn’t work for Twitter. Have you tried the Twitter Card validator (https://cards-dev.twitter.com/validator) with your page? Curious to know if it works for you or not :).

I got this to work by setting the response header in the route instead of trying to set it with HTML meta tags, so extending the example like this:

seoPicker.route('/blog/:postid', function(params, req, res){
    var post = Posts.findOne({_id:params.postid});
    var html = SSR.render('seoLayout',{
        template:'blogpost',
        data: {post:post}
    });
    res.setHeader( 'Content-Type', 'text/html; charset=utf-8' );
    res.end(html);
});

Quite right @gustavlrssn. the setHeader line improves my Google+ and Twitter uptake. Nicely done.

How can we test it in localhost ?

I’m using meteor 1.7.0.4