Single Page Application в облачном хранилище

Single Page Application

Мы уже писали о том, как наше облачное хранилище может быть использовано в качестве площадки для размещения статических сайтов (1 и 2). Сегодня мы расскажем о том, как на базе хранилища можно размещать современные cайты, в основе которых лежит популярный и актуальный в наши дни подход Single Page Application (SPA).

SPA как подход

Аббревиатура SPA расшифровывается как «single page application» («одностраничное приложение»). В узком смысле она употребляется для обозначения одностраничного сайта, непосредственно выполняемого на стороне клиента в браузере. В более широком смысле SPA (иногда также употребляется аббревиатура SPI — «single page interface») означает целый подход в веб-разработке, который в наши дни получает все более широкое распространение. В чем заключается смысл этого подхода и почему он становится всё более популярным?

Начнем несколько издалека. Сегодня самым распространенным типом сайтов являются, конечно же, динамические сайты, в которых генерация страниц осуществляется на стороне сервера. При всех очевидных удобствах для разработчиков (каждый запрос создаёт страницу с чистого листа), такие сайты порой представляют собой настоящую головную боль для клиентов. Вот далеко не полный список неудобств, с которыми им приходится сталкиваться:

  • Даже несмотря на то, что некоторые фреймворки позволяют вернуть в ответ форму с заполненными данными, введёнными клиентом в прошлый раз, необходимость перезагрузки страницы для валидации делает работу с сайтом неудобной.
  • Генерация страниц на стороне сервера сопряжена с серьёзными нагрузками.

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

  • Если раньше функции фронтенда и бэкенда были чётко разделены (бэкенд отвечает за генерацию view и логику, а фронтенд за отображение), то теперь логика дублируется на фронтенде, что вряд ли можно назвать хорошей архитектурной практикой.
  • Код, отвечающий за генерацию view, приходится постоянно дублировать и из-за этого возникают проблемы: «копипаста», расхождение разметки, поломанные селекторы, сложности в сопровождении кода и т.д.

Конечно, жить со всем этим можно. Но подход SPA во многих случаях оказывается гораздо более эффективным.

С точки зрения этого подхода сайт понимается не как набор страниц, а как набор состояний одной и той же HTML-страницы. При смене состояния происходит асинхронная подгрузка нового контента без перезагрузки самой страницы.

SPA представляет собой не сайт в классическом понимании, а приложение, которое исполняется на стороне клиента, в браузере. Поэтому с точки зрения пользователя проблем со скоростью работы почти не бывает даже при медленном или нестабильном соединении с Интернетом (например, при просмотре сайта с мобильного устройства). Высокая скорость работы обеспечивается ещё и благодаря тому, что с сервера на клиента приходит теперь не разметка, а данные (в основном в формате JSON), и размер их невелик.

В последнее время появилось немало интересных технологических решений и сервисов, значительно упрощающих создание и использование SPA. Рассмотрим некоторые из них более подробно.

BAAS (Backend as a Service)

Технологии, позволяющие отрисовывать интерфейс на стороне клиента и взаимодействовать с сервером только путём отправки запросов без перезагрузки страницы, существуют уже давно. Например, API XMLHttpRequest появился ещё в 2000 году. Но использование этих технологий было сопряжено с трудностями: нужно было переписывать бэкенд, реализующий функции авторизации запросов и доступа к данным.

Сегодня всё стало намного проще благодаря появлению многочисленных BaaS-сервисов. Аббревиатура BaaS означает Backend as a Service. BaaS-сервисы предоставляют разработчикам веб-приложений готовую серверную инфраструктуру (расположенную, как правило, в облаке). Благодаря им можно сэкономить время (а зачастую ещё и деньги) на написание серверного кода и сосредоточиться на совершенствовании самого приложения и развития его функциональности. С помощью BaaS можно подключать к приложению или сайту любой бэкенд с любым набором функций — достаточно просто добавить на страницу соответствующую библиотеку.

В качестве примера можно привести сервис MongoLab, позволяющий подключать к веб-приложениям и сайтам облачную базу данных MongoDB.

Ещё один интересный пример — FireBase. Этот сервис представляет собой облачную базу данных и API для realtime-приложений. С его помощью можно, в частности, организовать обмен данными между клиентом и сервером в режиме реального времени: достаточно просто подключить на страницу JavaScript-библиотеку и настроить события на изменения данных. На основе FireBase легко реализовать, например, чат или ленту пользовательской активности.

В числе интересных и заслуживающих внимания BaaS-сервисов стоит также выделить:

  • Backendless — платформа, предоставляющая готовую облачную серверную инфраструктуру для всех типов приложений. С её помощью на сайт можно добавить функциональность управления пользователями, хранения пользовательских данных, обмен сообщениями в режиме реального времени, рассылка уведомлений, геолокацию, управление файлами и много другое.
  • Syncano — сервис, предоставляющий API для real-time приложений, близкий по функциональности к Firebase.
  • QuickBlox — небезынтересный продукт от российских разработчиков (см. также подробную статью на Хабре).

С кратким обзором ВааS-сервисов можно также ознакомиться здесь.

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

При использовании хранилища в качестве внешнего бэкенда следует обратить особое внимание на два ключевых момента: аутентификация и работа с контентом. Ключ аутентификации (токен) можно получить с помощью запроса к auth.selcdn.ru.

Затем его нужно будет указывать в качестве значения заголовка X-Auth-Token во всех запросах работы с данными. Ответы на эти запросы будут включать заголовок Access-Control-Allow-Origin со значением «*», дающий возможность обращаться к хранилищу с любого внешнего домена.

В качестве примера веб-приложения, использующего API хранилища, можно привести нашу фотогалерею (о ней мы уже писали; см. также href=»https://github.com/selectel/photo-gallery» rel=»nofollow noopener noreferrer» >репозиторий на GitHub).

HTML5 History API

Каждая страница динамического сайта имеет cобственный URL. SPA же устроены так, что в них можно изменять состояние страницы, не изменяя при этом URL. Но в таком случае возникает проблема: пользователь не сможет сохранить ссылку и затем вернуться к посещённому ранее разделу. Решить её можно несколькими способами.

Во-первых, можно использовать хэш-фрагмент (часть ссылки, которая идёт после символа «#»). В хэш-фрагмент помещается «виртуальный» адрес страницы, по которому можно восстановить прежнее состояние. Если пользователь перезагрузит страницу, то код на JavaScript, прочитав значение хэша, загрузит нужные данные и отобразит соответствующий ему раздел. Этот вариант используется на многих сайтах, но следует отметить, что подобные URL (например, http://example.com/base/#!/section1/page2) выглядят не очень естественно. Кроме того, они состоят из двух сущностей: «реальный» адрес, по которому страница запрашивается у веб-сервера и «виртуальный», который обозначает логический раздел.

Во-вторых, можно воспользоваться HTML5 History API (см. также статью на Хабре). History API позволяет полностью изменять URL страницы в пределах текущего домена без её перезагрузки. В браузерах, поддерживающих этот API, нет никаких отличий между URL, использованных при загрузке страницы и URL, заданным из JavaScript.

Вызовы функций History API также связаны с нативными браузерными кнопками «Вперёд» и «Назад» и историей: при нажатии кнопки «Назад» браузер вызовет событие popstate, которое можно обработать в JavaScript-коде и отобразить предыдущий раздел. Посмотреть, как это работает, можно, например, здесь.

Чтобы сайт использовал описанную схему URL, нужно соответствующим образом настроить веб-сервер. Необходимо сделать так, чтобы вместо несуществующих страниц отдавалась главная страница SPA — обычно это index.html. В этом случае браузер клиента загрузит JavaScript, который уже отрисует нужный файл сайта исходя из текущего адреса страницы.

В настройках nginx это прописывается так:

location / { rewrite .* /index.html; }

Если SPA размещается на сервисах типа GitHub Pages или нашего хранилища, то настройки нужно устанавливать через панель управления.

Поисковая оптимизация

Индексация SPA поисковыми системами представляет собой отдельную проблему. Если сайт полностью генерируется на стороне клиента, то индексироваться он будет плохо, хотя в последнее время и наблюдаются улучшения в этом плане: боты постепенно начинают выполнять JavaScript при индексировании.

Одним из способов решения этой проблемы заключается в следующем: генерируются снапшоты страниц специально для ботов. Генерировать страницы следует по-разному в зависимости от того, используется ли HTML5 History API или нет.

В случае использования хэш-фрагментов Google и Yandex предлагают один и тот же подход: для разделения «реального» и «виртуального» адресов следует использовать «#!» вместо «#»; поисковые боты, увидев ссылку с таким разделителем, будут использовать специальный query-параметр «_escaped_fragment_» в URL и помещать в него часть адреса, следующую после после хэша.

Веб-сервер должен специальным образом обрабатывать такие запросы и отдавать полноценные HTML-страницы, чтобы боты могли их проиндексировать. (Потребность в этом возникает вследствие того, что часть URL после «#» по стандарту не является часть HTTP-запроса.) Рекомендуется также использовать специальный метатег (см. по ссылкам выше) т.к. некоторые страницы могут не содержать ссылок с «#!».

Если же для адресации используются полноценные URL, то сделать сайт индексируемым ещё проще: достаточно генерировать соответствующую заданному адресу страницу на сервере. Бот, посетив сайт, получит страницу c содержимым и успешно её проиндексирует.

Если сайт открыт в браузере, то страница сначала будет отображена в соответствии с HTML-разметкой, а затем уже в дело вступит JavaScript; при дальнейших переходах по ссылкам страница перезагружаться не будет. Такое поведение можно реализовать, перехватывая события нажатия на ссылки и отменяя их нативное поведение. В таком случае, бот перейдет по ссылке (атрибут «href»), а мы сможем контролировать все переходы, обрабатывая событие так, как нам нужно.

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

Как сгенерировать HTML-страницу, имея в наличии только JavaScript-код, работающий напрямую с DOM? Это можно сделать несколькими способами.

Во-первых, можно установить PhantomJS (это так называемый «headless» браузер на основе WebKit, управляемый через API) и настроить его на генерацию снапшотов страниц (см. практический пример здесь).

Во-вторых, можно воспользоваться инструментом prerender или сервисом Prerenderer.io, которые основаны также на PhantomJS.

В-третьих, в некоторых современных фреймворках (например, DerbyJS и React) эта функция уже реализована (см. также пример здесь: react-server-example).

Размещение SPA

В современном Интернете есть немало площадок, на которых можно размещать SPA. Рассмотрим наиболее популярные из них.

Dropbox

Самый простой вариант — размещение SPA в Dropbox. Для этого нужно создать в публичном каталоге Dropbox каталог для SPA, поместить в него все необходимые файлы, а затем выделить файл index.html и вызвать контекстное меню, нажав на правую кнопку мыши. В меню нужно выбрать пункт «Dropbox → Поделиться ссылкой». После этого будет создана ссылка и скопирована скопирована в буфер обмена, по которой приложение будет доступно через браузер.
В последнее время предпринимаются попытки расширить возможности по размещению сайтов в Dropbox (об этом можно почитать, например, здесь). Однако главной проблемы они не решают: в Dropbox имеются довольно жёсткие (вплоть до полной блокировки) ограничения трафика по публичным ссылкам. Поэтому описываемый вариант можно рекомендовать разве что для демонстрации SPA друзьям и коллегам.

GitHub Pages

GitHub Pages представляет собой бесплатную площадку для размещения статических сайтов и SPA. Чтобы разместить SPA на GitHub Pages, нужно создать для него репозиторий на GitHub и поместить статические файлы в ветку gh-pages для Project Pages или в ветку master для User/Organization Pages. Все вносимые изменения нужно будет коммитить в этот репозиторий. Более подробная справка доступна в официальной документации.

Bit Balloon

Bit Balloon — сервис новый, но уже достаточно популярный.
Каждому зарегистрированному пользователю бесплатно предоставляется 10 Мб дискового пространства. Чтобы разместить на нём SPA, достаточно просто загрузить все необходимые файлы. Сервис автоматически минифицирует JS, HTML и CSS, а также подключит CDN.

Премиум-аккаунт стоит 5$ в месяц. Для владельцев платных аккаунтов доступны различные дополнительные возможности — в частности, прикрепление собственных доментов и подключение разнообразных внешних сервисов.

Selectel Storage

Наше облачное хранилище представляет собой удобную площадку для хостинга SPA. В целом процедура размещения SPA почти не отличается от процедуры размещения статических сайтов о которой мы уже писали в одном из предыдущих постов. Она включает следующие шаги:

  1. Создание публичного контейнера и прикрепление домена: по ссылке выше всё подробно описано, подробно на этом останавливаться не будем.
  2. Настройка специальных страниц: процедура настройки совсем недавно была нами усовершенствована. Мы добавили ещё один вариант настройки обработки несуществующих страниц («Ошибка 404: страница»). Теперь можно указывать файл, который будет отображен при запросе несуществующей страницы, а также задавать для него код ответа (200 или 404), при этом перенаправления на другой URL не будет:

Selectel облачное хранилищездесь), а также наличие CDN и гибкой системы настроек параметров контейнеров и отдаваемых файлов.

Заключение

В этой статье мы рассказали ещё об одном аспекте использования нашего хранилища в качестве площадки для хостинга одностраничных сайтов. Надеемся, что она окажется вам полезной.
Если вы уже используете наше хранилище для размещения SPA, поделитесь своим опытом и впечатлениями.Все ваши пожелания и предложения будут обязательно учтены в дальнейшей работе.