HTML MVC рендеринг на стороне клиента и рендеринг на стороне сервера через NodeJS

Мы ищем варианты в нашей команде, чтобы выбрать между клиентским подходом MVC на основе Angular и серверным подходом рендеринга NodeJS / ExpressJS на стороне сервера.

Наше приложение Angular загружается как один index.html и делает XHR-запросы для заполнения страницы. Поскольку нам нужна предварительная отрисовка страницы, мы использовали PhantomJS для сохранения копии каждой страницы, когда содержимое меняется на местоположение на сервере. Это позволяет поддержку SEO.

Есть ли какие-нибудь примеры приложений на полностраничной магистрали или угловых приложений, на которые люди могут указать, чтобы мы видели, делают ли это другие.

В качестве альтернативы приведены примеры рендеринга приложений на стороне сервера NodeJS, которые мы можем увидеть в дикой природе.

Наконец, у кого-нибудь есть мнения по поводу такой архитектуры?

4 ответа

Я работал над приложениями, в основном для рендеринга серверов и в основном для рендеринга клиентов. Каждый тип имеет свои преимущества и недостатки. Однако идея о том, что вам нужно выбирать между тем или иным, является ложной дихотомией. Если у вас есть ресурсы, вы можете объединить оба, чтобы получить лучшее из обоих миров.

Я вижу 4 основных проблемы с чисто клиентскими средами:

  • SEO и аналитика
  • Кэширование
  • объем памяти
  • Задержка

SEO

Поскольку вы используете Node.JS, проблему SEO можно решить, просто используя клиентскую среду на сервере для вывода статических страниц для googlebot и компании. Недавно Google создал хороший API-интерфейс Analytics для одностраничных приложений, но это будет немного больше работы, чем просто добавление нескольких строк в конец вашего основного шаблона.

Кэширование

Кэширование - действительно важный способ ускорить работу любого веб-приложения. Для небольших объемов данных может быть быстрее кэшировать данные на клиенте в памяти или в localStorage, но объем хранилища очень ограничен (в настоящее время около 5 МБ). Кроме того, в localStorage довольно сложно сделать аннулирование кэша.

объем памяти

Память - это то, что я дорого заплатил за просмотр. Прежде чем я знал это, я случайно сделал приложение, которое занимает более 200 МБ оперативной памяти. Возможно, мне удастся свести это вдвое к минимуму с помощью оптимизации, но я сомневаюсь, что это заняло бы больше 20 МБ, если бы я отобразил все это на сервере.

Задержка

Латентность также легко пропустить. Например, Drupal выполняет от 50 до 100 SQL-запросов для каждой страницы. Когда сервер базы данных находится рядом с сервером приложений, вам не нужно беспокоиться о задержке, и все эти запросы могут быть выполнены менее чем за пару сотен миллисекунд. Вашему клиентскому приложению обычно требуется сто миллисекунд, чтобы сделать один AJAX-запрос. Это означает, что вам нужно потратить много времени на разработку API на стороне сервера, чтобы минимизировать эти циклы, но в этот момент на сервере уже есть все данные, необходимые для создания HTML. Наличие клиентского приложения, которое взаимодействует с должным интерфейсом RESTful, может оказаться слишком медленным, если вы не будете осторожны.

37 Signals недавно опубликовали в блоге информацию о гибридной архитектуре клиент-сервер, которую они реализовали для новой версии Basecamp. Этот гибридный подход использует сервер для рендеринга HTML, но использует что-то вроде PJAX на клиенте, чтобы избавиться от полного обновления страницы. Эффект действительно быстрый и это то, что я рекомендую.

При использовании node.js на сервере, в принципе, вы можете использовать один и тот же код для рендеринга как на клиенте, так и на сервере. Каркасами, которые реализуют этот подход, являются Meteor и Derby, они также осуществляют прозрачную синхронизацию моделей данных между клиентом и сервером. Оба по-прежнему считаются в альфа-версии, но, похоже, уже работают достаточно хорошо.

Между тем, как на стороне клиента, так и на стороне сервера рендеринг имеет свои плюсы и минусы:

  • Недостатком рендеринга на стороне клиента является то, что начальная загрузка страницы занимает много времени, но как только все ресурсы загружены, пользователь может легко перемещаться по сайту без страницы. Возможно, вы захотите минимизировать количество вызовов Ajax и / или использовать клиентский кеш (например, кеш данных в контроллере Angular.js).
  • Рендеринг на стороне сервера обеспечивает быструю начальную загрузку страницы и хорош для SEO, но каждый раз, когда пользователь перемещается, вся страница на секунду становится пустой, пока он загружает новый URL.

Так что все зависит от того, хотите ли вы быстрой начальной загрузки страницы, но не ожидаете, что пользователи останутся так долго (затем используйте рендеринг на стороне сервера), или не так важно, чтобы страница загружалась быстро (как в Gmail), но пользователи будут перемещаться в течение длительного времени (затем использовать рендеринг на стороне клиента).

В настоящее время мы тестируем этот безумный подход: у нас есть приложение angularJS, которое работает на клиенте. Когда мы обнаруживаем робот Googlebot в качестве агента, мы запускаем экземпляр PhantomJS и отвечаем на сканер выходными данными. Сложно понять, когда клиентское приложение завершило загрузку, чтобы вы могли выбрать и вернуть его. Если вы сделаете это раньше, чем загрузится JS-приложение на стороне клиента, сканер не получит много данных, в основном только index.html.

Простую реализацию можно найти здесь: http://pastebin.com/N3w2iyr8

ОБНОВЛЕНИЕ: В то время, когда я писал оригинальный ответ, ничего подобного prerendr.io не существовало, но я могу указать вам сейчас.

Мое решение сделать приложение на Angular Crawlable от Google. Используется в http://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="!">

Полные условия от Google здесь: https://developers.google.com/webmasters/ajax-crawling/docs/specification

Другие вопросы по тегам