21

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

我们的 Angular 应用程序下载为一个 index.html,并发出 XHR 请求来填充页面。因为我们需要预渲染页面,所以当内容更改到服务器上的某个位置时,我们使用 PhantomJS 保存每个页面的副本。这允许对 SEO 的支持。

是否有任何全页主干应用程序或 Angular 应用程序的示例可供人们指出,以便我们查看其他人是否正在这样做。

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

最后,有人对这种架构有意见吗?

4

4 回答 4

34

我从事过主要是服务器渲染和主要是客户端渲染的应用程序。每种类型都有自己的优点和缺点。但是,您必须在其中一个或另一个之间进行选择的想法是错误的二分法。如果你有资源,你可以将两者结合起来,以获得两全其美的效果。

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

  • 搜索引擎优化和分析
  • 缓存
  • 记忆
  • 潜伏

搜索引擎优化

因为您使用的是 Node.JS,所以可以通过简单地使用服务器上的客户端框架为 googlebot 和公司输出静态页面来缓解 SEO 问题。最近 Google 为单页应用程序制作了一个不错的 Analytics API,但这比简单地在主模板的末尾添加几行要多一些工作。

缓存

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

记忆

记忆是我为忽视而付出的沉重代价。在不知不觉中,我不小心制作了一个占用超过 200MB RAM 的应用程序。我也许可以通过优化将它降低到一半,但我怀疑如果我将它全部呈现在服务器上,它会占用超过 20 MB 的空间。

潜伏

延迟也很容易被忽略。例如,Drupal 为每个页面运行大约 50 到 100 个 SQL 查询。当数据库服务器就在应用程序服务器旁边时,您不必担心延迟,所有这些查询都可以在不到几百毫秒的时间内执行。您的客户端应用程序通常需要一百毫秒来发出一个 AJAX 请求。这意味着您需要花费大量时间设计服务器端 API 以尽量减少这些往返,但此时服务器已经拥有生成 HTML 所需的所有数据。如果您不小心,拥有一个与正确 RESTful 接口对话的客户端应用程序可能会变得非常缓慢。

37 Signals 最近在博客中介绍了他们为新版 Basecamp 实施的混合客户端/服务器架构。这种混合方法使用服务器来呈现 HTML,但利用客户端上的 PJAX 之类的东西来摆脱整页刷新。效果真的很快,是我推荐的。

于 2012-09-06T04:32:43.647 回答
8

使用服务器上的 node.js,原则上您可以使用相同的代码在客户端和服务器上呈现。实现这种方法的框架是MeteorDerby,它们还在客户端和服务器之间进行数据模型的透明同步。尽管两者都仍被认为处于 alpha 阶段,但似乎已经很好地工作了。

同时,客户端和服务器端渲染各有利弊:

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

所以这完全取决于您是否想要快速的初始页面加载但不要期望用户停留那么长时间(然后使用服务器端呈现)或者页面加载速度并不重要(如在 Gmail 中)但用户会导航很长时间(然后使用客户端渲染)。

于 2012-09-06T01:02:52.253 回答
5

我们目前正在测试这种疯狂的方法:我们有在客户端上运行的 angularJS 应用程序。当我们检测到 Googlebot 作为代理时,我们运行PhantomJS实例并用它的输出响应爬虫。棘手的部分是知道您的客户端应用程序何时完成加载,以便您可以选择并返回它。如果您在加载客户端 JS 应用程序之前执行此操作,则爬虫将不会获取太多数据,主要是 index.html。

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

更新:在我写原始答案的时候,不存在像 prerendr.io 这样的东西,但我现在可以指出

于 2013-01-02T14:20:57.063 回答
0

我的解决方案是让 Google 可以抓取 Angular 上的应用程序。用于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. 为快照创建 node.js 脚本,并在终端中运行它: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,输入终端

    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

于 2014-04-29T10:49:34.267 回答