Server side rendering with Meteor and Meteorhacks:ssr and iron-router

陌路散爱 提交于 2019-12-21 21:54:07

问题


This came out recently: https://meteorhacks.com/server-side-rendering.html but there doesn't seem to be a full fledged example of how to use this with iron-router.

If I had a template like: /private/post_page.html

{{title}}
{{#markdown}} {{body}} {{/markdown}}

How would I populate it with a single records attributes from a request for a specific ID ?

E.g page requested was localhost:3000/p/:idofposthere how to populate it with data and render it in iron-router for that route / server side?


回答1:


Actually a bit easier than you think (I just followed Arunoda's SSR example and converted it to iron-router for you):

if(Meteor.isServer) {
  Template.posts.getPosts = function(category) {
    return Posts.find({category: category}, {limit: 20});
  }
}

Router.map(function() {
  this.route('home');
  this.route('view_post', {
    path: 'post/:id',
    where:"server",    
    action : function() {

      var html = SSR.render('posts', {category: 'meteor'})
      var response = this.response;

      response.writeHead(200, {'Content-Type':'text/html'});
      response.end(html);
    } 
  });
});

It only gets tricky if you share the same route for client and server side for example, if you want it to render client-side based on user agent.

Source: We use this strategy on our own apps.

UPDATE

While the above code is simply what the question is asking for, we can get this working to follow Google's Ajax spec by checking the ?_escaped_fragment_= query string before we reach the client..

Basically, what we mostly don't know about Iron-Router is that if you have identical routes declared for server and client, the server-side route is dispatched first and then the client-side.

Here's the main javascript (with annotations):

ssr_test.js

Router.configure({
  layout: 'default'
});

Posts = new Mongo.Collection('posts');

// Just a test helper to verify if we area actually rendering from client or server.
UI.registerHelper('is_server', function(){
  return Meteor.isServer ? 'from server' : 'from client';
});

myRouter = null;

if(Meteor.isServer) {

  // watch out for common robot user-agent headers.. you can add more here.
  // taken from MDG's spiderable package.

  var userAgentRegExps = [
    /^facebookexternalhit/i, 
    /^linkedinbot/i, 
    /^twitterbot/i
  ];

  // Wire up the data context manually since we can't use data option 
  //   in server side routes while overriding the default behaviour.. 
  //   not this way, at least (with SSR).
  //   use {{#with getPost}} to 
  Template.view_post_server.helpers({
    'getPost' : function(id) {
      return Posts.findOne({_id : id});
    }
  });

  Router.map(function() {    
    this.route('view_post', {
      path: 'post/:id',       // post/:id  i.e. post/123
      where: 'server',        // this route runs on the server
      action : function() {
          var request = this.request;

          // Also taken from MDG's spiderable package.
          if (/\?.*_escaped_fragment_=/.test(request.url) ||
          _.any(userAgentRegExps, function (re) {
            return re.test(request.headers['user-agent']); })) {          

            // The meat of the SSR rendering. We render a special template
            var html = SSR.render('view_post_server', {id : this.params.id});
            var response = this.response;
            response.writeHead(200, {'Content-Type':'text/html'});
            response.end(html);

          } else {
            this.next(); // proceed to the client if we don't need to use SSR.
          }         
      }
    });
  });          


}

if(Meteor.isClient) {
  Router.map(function() {
    this.route('home');
    this.route('view_post', { // same route as the server-side version
      path: 'post/:id',       // and same request path to match
      where: 'client',        // but just run the following action on client
      action : function() {
          this.render('view_post'); // yup, just render the client-side only 
      }
    });
  });
}

ssr_test.html

<head>
  <title>ssr_test</title>
  <meta name="fragment" content="!">
</head>
<body></body>
<template name="default">
    {{> yield}}
</template>
<template name="home">
</template>
<template name="view_post">
    hello post {{is_server}}
</template>
<template name="view_post_server">
    hello post server {{is_server}} 
</template> 

THE RESULT:

I uploaded the app at http://ssr_test.meteor.com/ to see it in action, But it seems to crash when using SSR. Sorry about that. Works fine if you just paste the above on Meteorpad though!

Screens:

Here's the Github Repo instead:

https://github.com/electricjesus/ssr_test

Clone and run!




回答2:


SSR is lacking real life examples, but here is how I got it working.

if (Meteor.isServer)
{
    Router.map(function() {
        this.route('postserver', {
            where: 'server',
            path: '/p/:_id',
            action: function() {
                // compile
                SSR.compileTemplate('postTemplate', Assets.getText('post_page.html'));
                // query
                var post = Posts.findOne(this.params._id);
                // render
                var html = SSR.render('postTemplate', {title: post.title, body: post.body});
                // response
                this.response.writeHead(200, {'Content-Type': 'text/html'});
                this.response.write(html);
                this.response.end();
            }        
        });
    });
}

Assets are documented here: http://docs.meteor.com/#assets.



来源:https://stackoverflow.com/questions/26322794/server-side-rendering-with-meteor-and-meteorhacksssr-and-iron-router

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!