【问题标题】:Server side rendering with Meteor and Meteorhacks:ssr and iron-router使用 Meteor 和 Meteorhacks 进行服务器端渲染:ssr 和 Iron-router
【发布时间】:2014-10-28 11:42:27
【问题描述】:

这是最近发布的:https://meteorhacks.com/server-side-rendering.html,但似乎没有一个完整的例子来说明如何将它与 Iron-router 一起使用。

如果我有这样的模板: /private/post_page.html

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

如何使用来自对特定 ID 的请求的单个记录属性填充它?

例如请求的页面是localhost:3000/p/:idofposthere 如何用数据填充它并在该路由/服务器端的 Iron-router 中呈现它?

【问题讨论】:

    标签: meteor


    【解决方案1】:

    其实比你想象的要容易一点(我只是按照 Arunoda 的 SSR 示例,为你将其转换为 iron-router):

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

    如果您为客户端和服务器端共享相同的路由,例如,如果您希望它基于用户代理呈现客户端,它只会变得棘手。

    资料来源:我们在自己的应用中使用此策略。

    更新

    虽然上面的代码只是问题所要求的,但我们可以通过在到达客户端之前检查 ?_escaped_fragment_= 查询字符串来遵循 Google 的 Ajax 规范。

    基本上,我们对Iron-Router 最不了解的是,如果您为服务器和客户端声明了相同的路由,则首先调度服务器端路由,然后调度客户端。

    这是主要的 javascript(带注释):

    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> 
    

    结果:

    我在http://ssr_test.meteor.com/ 上传了该应用程序以查看它的运行情况,但是在使用 SSR 时它似乎崩溃了。对于那个很抱歉。如果您只是将上述内容粘贴到 Meteorpad 上,则效果很好!

    屏幕:

    这里是 Github 回购:

    https://github.com/electricjesus/ssr_test

    克隆并运行!

    【讨论】:

    • 啊,是的,在我的示例中,它将是查看博客文章。对于客户端,它将使用客户端 Iron-router,而谷歌将使用服务器端。所以你基本上必须检测用户代理?
    • 我们将以下元标记添加到头部:&lt;meta name="fragment" content="!"&gt;,这样我们就可以告诉谷歌这个页面是动态生成的。接下来,为了进行服务器端渲染,我们检测 ?_escaped_fragment_= 查询并通过 SSR 请求该 URL。这只是谷歌的第一步。对于 FB、twitter 等,我们只使用用户代理检测。我会尽快更新我的答案。
    • 你太棒了。更新答案,以便我可以向您发送赏金! :)
    【解决方案2】:

    SSR 缺乏现实生活中的例子,但这是我如何让它工作的。

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

    资产记录在这里:http://docs.meteor.com/#assets

    【讨论】:

    • 你可能想解释你的答案。 SO 的存在是为了教人,而不仅仅是回答问题
    猜你喜欢
    • 2023-03-30
    • 2015-02-27
    • 2015-08-18
    • 1970-01-01
    • 2014-03-27
    • 2016-08-06
    • 2016-04-11
    • 1970-01-01
    • 2013-11-23
    相关资源
    最近更新 更多