客户端HTML MVC渲染与服务器端通过NodeJS重新渲染

我们正在寻找我们团队的选项来决定基于Angular的客户端MVC方法和服务器端NodeJS / ExpressJS服务器端渲染方法。

我们的Angular应用下载为一个index.html,并使XHR请求填充页面。 由于我们需要预先渲染页面,因此我们使用PhantomJS在内容更改为服务器上的某个位置时保存每个页面的副本。 这可以支持SEO。

是否有任何完整的页面骨干应用程序或angular度应用程序的例子,人们可以指向我们看看其他人是否这样做。

或者是我们可以在野外看到的NodeJS服务器端渲染的应用程序的例子。

最后有没有人对这种build筑有意见?

我曾经在大多数服务器渲染和大多数客户端渲染应用程序上工作。 每种types都有其优点和缺点。 然而,你必须在一方或另一方之间进行select的想法是错误的两分法。 如果你有资源,你可以把两者结合起来,以获得两全其美。

我看到纯粹的客户端框架有四个主要的挑战:

  • SEO和分析
  • 高速caching
  • 记忆
  • 潜伏

SEO

由于您使用的是Node.JS,因此只需在服务器上使用客户端框架为Googlebot和公司输出静态页面即可缓解SEO问题。 最近谷歌已经为单页面应用程序做了一个很好的分析API,但是这比仅仅在主模板的末尾添加几行代码要多一点点。

高速caching

caching是加速任何Web应用程序的重要方式。 对于less量数据来说,将数据caching在内存或localStorage中的客户端上可能会更快,但存储空间非常有限(目前大约为5MB)。 Pluscaching失效在localStorage中很难做到。

记忆

记忆是我付出的高昂代价。 在我知道之前,我不小心做了一个占用200MB以上内存的应用程序。 通过优化,我可能会把这个数字降低一半,但是我怀疑如果把它全部放在服务器上的话,会占用20MB以上的空间。

潜伏

延迟也很容易错过。 例如,Drupal为每个页面运行大约50到100个SQL查询。 当数据库服务器紧邻应用程序服务器时,您不必担心延迟,所有这些查询都可以在几百毫秒内执行。 您的客户端应用程序通常需要100毫秒才能发出一个AJAX请求。 这意味着您需要花费大量的时间devise您的服务器端API以尽量减less这些往返行程,但是在这一点上,服务器已经拥有了生成HTML所需的所有数据。 如果你不小心,有一个客户端应用程序可以和一个适当的REST风格的界面进行交stream。

37信号最近在博客上介绍了他们为新版Basecamp实施的混合客户/服务器体系结构 。 这种混合的方法使用服务器来呈现HTML,但利用客户端上的PJAX等东西来摆脱整个页面的刷新。 效果非常快,是我推荐的。

使用服务器上的node.js,原则上可以使用相同的代码在客户端以及服务器上进行渲染。 实现这种方法的框架是Meteor和Derby ,它们也在客户端和服务器之间进行数据模型的透明同步。 虽然两人仍然被认为是alpha,但似乎已经很好地工作了。

同时,客户端和服务器端渲染都有优点和缺点:

  • 客户端呈现的缺点是初始页面加载需要很长时间,但是一旦加载了所有资源,用户就可以无页面地无缝导航站点。 您可能希望最小化Ajax调用的数量和/或使用客户端caching(例如,Angular.js控制器中的caching数据)。
  • 服务器端的渲染提供了一个快速的初始页面加载,对SEO很有用,但是每次用户浏览时,整个页面在加载新URL的时候都会一片空白。

所以这一切都取决于你是否想要一个快速的初始页面加载,但不希望用户保持这么长时间(然后使用服务器端渲染),或者它不是那么重要,加快页面加载(如在Gmail中),但用户将浏览很长一段时间(然后使用客户端渲染)。

我们正在testing这个疯狂的aproach:我们有angularJS应用程序运行在客户端上。 当我们检测到Googlebot为代理时,我们运行PhantomJS实例并使用来自该输出的爬虫响应。 棘手的部分是知道什么时候你的客户端应用程序完成加载,以便您可以select并返回它。 如果你会尽快加载你的客户端JS应用程序,爬虫不会得到太多的数据,主要是index.html。

简单的实现可以在这里find: http : //pastebin.com/N3w2iyr8

更新:当时我写了原来的答案,没有像prerendr.io存在,但我可以指出你现在 。

我的解决scheme,使谷歌应用程序可以抓取。 用于aisel.co

  1. 通过https://github.com/localnerve/html-snapshots处理快照
  2. 将规则添加到.htaccess

    RewriteCond %{QUERY_STRING} ^_escaped_fragment_=(.*)$ RewriteCond %{REQUEST_URI} !^/snapshots/views/ [NC] RewriteRule ^(.*)/?$ /snapshots/views/%1 [L] 
  3. 为快照创buildnode.js脚本,然后在terminal: node snapshots.js中运行它

     var htmlSnapshots = require('html-snapshots'); var result = htmlSnapshots.run({ input: "array", source: [ "http://aisel.dev/#!/", "http://aisel.dev/#!/contact/", "http://aisel.dev/#!/page/about-aisel" ], outputDir: "web/snapshots", outputDirClean: true, selector: ".navbar-header", timeout: 10000 }, function(err, snapshotsCompleted) { var fs = require('fs'); fs.rename('web/snapshots/#!', 'web/snapshots/views', function(err) { if ( err ) console.log('ERROR: ' + err); }); }); 
  4. 确保一切正常,curl,inputterminal

    curl http://aisel.dev/?_ escaped_fragment _ \ = / page / about-aisel /这应该显示快照的内容… / www / aisel.dev / public / web / snapshots / views / page / about-aisel /index.html

不要关于护目镜和其他爬虫的指令。 你的应用程序应该在头部包含元规则:

  <meta name="fragment" content="!"> 

谷歌完整条款: https : //developers.google.com/webmasters/ajax-crawling/docs/specification