Динамическая отрисовка с помощью Rendertron

Четверг, 31 января 2019 г.

Многие фреймворки, используемые при создании сайтов, основаны на JavaScript. Из-за этого роботам Google может требоваться много времени на индексирование вашего контента, в том числе обновленных материалов.

На конференции Google I/O в 2018 г. мы обсудили один из способов решения этой проблемы – динамическую отрисовку. Реализовать эту функцию можно различными способами, например с помощью Rendertron – инструмента с открытым кодом, основанного на консольном браузере Chromium. Этот способ описан ниже.

В каких случаях стоит использовать динамическую отрисовку

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

Мы рекомендуем использовать динамическую отрисовку при работе с часто обновляемым контентом, для показа которого требуется JavaScript. Чтобы сделать ваш сайт более удобным для посетителей, например ускорить первую значимую отрисовку, попробуйте использовать гибридную отрисовку. В частности, для этого подходит технология Angular Universal.

Как работает динамическая отрисовка

Принцип работы динамической отрисовки

Динамическая отрисовка позволяет предоставлять некоторым агентам пользователя контент страницы, предварительно обработанный на сервере.

Для выполнения кода JavaScript и создания статических HTML-страниц мы будем использовать Rendertron – отрисовщик с открытым исходным кодом, основанный на консольном браузере Chromium. Одностраничные приложения часто загружают данные в фоновом режиме или делают паузу, чтобы выполнить отрисовку контента. Rendertron использует алгоритмы, позволяющие определять, завершил ли сайт отрисовку контента. Он ожидает завершения всех сетевых запросов и операций обработки.

В этой публикации мы рассмотрим:

  1. Пример веб-приложения.
  2. Создание небольшого сервера на express.js для работы веб-приложения.
  3. Установку и настройку Rendertron в качестве промежуточного ПО для динамической отрисовки.

Пример веб-приложения

Веб-приложение Kitten Corner с помощью JavaScript получает от API разнообразные изображения кошек и располагает их на странице в виде сетки.

В веб-приложении есть забавные картинки с кошками и кнопка, чтобы загрузить больше изображений.

Вот его код JavaScript:

const apiUrl = 'https://api.thecatapi.com/v1/images/search?limit=50';
   const tpl = document.querySelector('template').content;
   const container = document.querySelector('ul');
   function init () {
     fetch(apiUrl)
     .then(response => response.json())
     .then(cats => {
       container.innerHTML = '';
       cats
         .map(cat => { const li = document.importNode(tpl, true); li.querySelector('img').src = cat.url; return li;
         }).forEach(li => container.appendChild(li));
     })
   }
   init();
   document.querySelector('button').addEventListener('click', init);

В этом веб-приложении используется современная версия JavaScript (ES6), которую пока не поддерживает робот Googlebot. Чтобы узнать, виден ли этому роботу контент, проверим оптимизацию для мобильных устройств:

На скриншоте не видно ни одной кошки, в то время как проверка показала, что страница оптимизирована для просмотра на мобильных устройствах. Заголовок и кнопка есть, а изображений нет.

Эту проблему легко решить, однако сейчас у нас другая задача – научиться настраивать динамическую отрисовку. Благодаря ей робот Googlebot сможет обрабатывать изображения кошек, в то время как код веб-приложения останется прежним.

Настройка сервера

При помощи библиотеки express для node.js мы создадим веб-сервер для нашего приложения.

Ниже приведен код сервера (вы также можете ознакомиться с полным кодом проекта).

const express = require('express');
const app = express();
const DIST_FOLDER = process.cwd() + '/docs';
const PORT = process.env.PORT || 8080;
// Serve static assets (images, css, etc.)
app.get('*.*', express.static(DIST_FOLDER));
// Point all other URLs to index.html for our single page app
app.get('*', (req, res) => {
  res.sendFile(DIST_FOLDER + '/index.html');
});
// Start Express Server
app.listen(PORT, () => {
  console.log(`Node Express server listening on https://localhost:${PORT} from ${DIST_FOLDER}`);
});

Попробуйте открыть опубликованную версию веб-приложения. Если вы пользуетесь современным браузером, то увидите подборку изображений кошек. Чтобы запустить это приложение на своем компьютере, вам понадобится node.js. Введите следующие команды:

npm install --save express rendertron-middleware
node server.js

Откройте в браузере страницу https://localhost:8080. Теперь можно настраивать динамическую отрисовку.

Развертывание экземпляра Rendertron

Rendertron запускает сервер, который принимает URL и возвращает статический HTML-код, используя консольный браузер Chromium. Мы последуем рекомендации от участников проекта Rendertron и воспользуемся сервисом Google Cloud Platform.

Форма для создания нового проекта в сервисе Google Cloud Platform

Вы можете начать с бесплатного тарифа, однако использование таких решений для реальных задач может повлечь расходы в соответствии с расценками Google Cloud Platform.

  1. Создайте проект в Google Cloud Console. Обратите внимание на идентификатор проекта под полем для ввода названия.
  2. Установите Google Cloud SDK согласно инструкциям и выполните вход.
  3. Клонируйте проект Rendertron с сайта GitHub:
    git clone https://github.com/GoogleChrome/rendertron.git
    cd rendertron
  4. Выполните следующие команды, чтобы установить зависимости и собрать Rendertron на своем компьютере:
    npm install && npm run build
  5. Активируйте кеш Rendertron, создав в каталоге rendertron файл под названием config.json со следующим содержанием:
    { "datastoreCache": true }
  6. Выполните приведенную ниже команду в каталоге rendertron. Вместо YOUR_PROJECT_ID введите идентификатор своего проекта (см. шаг 1).
    gcloud app deploy app.yaml --project YOUR_PROJECT_ID
  7. Выберите нужный регион и подтвердите развертывание. Дождитесь завершения процесса.
  8. Введите URL проекта (YOUR_PROJECT_ID.appspot.com). После этого должен появиться интерфейс Rendertron с полем ввода и несколькими кнопками.
Интерфейс Rendertron после развертывания в Google Cloud Platform

Если вы видите веб-интерфейс Rendertron, значит ваш собственный экземпляр этого инструмента успешно развернут. Сохраните URL своего проекта (YOUR_PROJECT_ID.appspot.com), так как он понадобится вам на следующем шаге.

Добавление Rendertron на сервер

Веб-сервер использует express.js, а в Rendertron есть промежуточное ПО для express.js. Выполните следующую команду в каталоге, содержащем файл server.js:

npm install --save rendertron-middleware

Эта команда установит из nmp промежуточное ПО rendertron-middleware, которое затем можно будет добавить на сервер, как показано в примере ниже:

const express = require('express');
const app = express();
const rendertron = require('rendertron-middleware');

Настройка списка роботов

Чтобы определить, является ли источником запроса браузер или робот, Rendertron анализирует HTTP-заголовки user-agent и сравнивает их с собственным актуальным списком роботов. По умолчанию в этом списке нет робота Googlebot, поскольку он способен интерпретировать код JavaScript. Чтобы запросы от этого робота также обрабатывались с помощью Rendertron, добавьте его в список с помощью следующего кода:

const BOTS = rendertron.botUserAgents.concat('googlebot');
const BOT_UA_PATTERN = new RegExp(BOTS.join('|'), 'i');

Теперь Rendertron будет сравнивать заголовок user-agent также и с этим регулярным выражением.

Добавление промежуточного ПО

Чтобы отправлять запросы роботов своему экземпляру Rendertron, нам нужно добавить промежуточное ПО на сервер express.js. Это ПО проверяет, какой агент пользователя указан в соответствующем HTTP-заголовке, и перенаправляет запросы от известных роботов экземпляру Rendertron. Добавьте приведенный ниже код в файл server.js и не забудьте заменить элемент YOUR_PROJECT_ID на идентификатор своего проекта в сервисе Google Cloud Platform.

app.use(rendertron.makeMiddleware({
  proxyUrl: 'https://YOUR_PROJECT_ID.appspot.com/render',
  userAgentPattern: BOT_UA_PATTERN
}));

Роботы, запрашивающие упомянутый в нашем примере сайт, смогут получать статические HTML-страницы от Rendertron и не должны будут обрабатывать код JavaScript для показа контента.

Тестирование

Чтобы выяснить, правильно ли реализовано решение Rendertron, ещё раз выполните проверку оптимизации для мобильных устройств.

На скриншоте видны кошки, а проверка показала, что страница оптимизирована для просмотра на мобильных устройствах.

В отличие от результатов первой проверки, сейчас изображения должны быть видны. На вкладке "HTML" представлен весь HTML-код, созданный при выполнении JavaScript. Благодаря Rendertron роботу не нужно выполнять JavaScript для показа контента.

Заключение

Мы настроили динамическую отрисовку, ничего не меняя в веб-приложении, и теперь можем предоставлять поисковым роботам статическую HTML-версию веб-приложения.