TL;DR: Тропа SPA темна и полна ужасов. Ты можешь бесстрашно сражаться с ними… или выбрать другой путь, который приведёт тебя к нужному месту: современный Rails.
Я вспоминаю, как думал, что Rails фокусируется на неправильной цели, когда DHH анонсировали Turbolinks в 2012 году. Тогда я был убеждён в том, что мгновенное время ответа во время взаимодействия с пользователем — это ключ к превосходному UX. Из-за возникающих задержек сети, такая интерактивность возможна, только если вы минимизируете зависимость от сети и вместо сетевых обращений поддерживаете большую часть состояния на клиенте.
Я думал, что это необходимо для приложений, над которыми я работал. И с таким мнением я перепробовал множество подходов и фреймворков для реализации одного и того же шаблона: Single-page applications (SPA). Я верил, что SPA — это будущее. Несколько лет спустя, я не уверен в том, каково же будущее, но я точно хочу найти альтернативу.
Кроличья нора SPA
Одностраничное приложение — JavaScript приложение, которое, единожды загруженное, получает полный контроль без необходимости перезагружать страницу: рендеринг, получение данных с сервера, обработка взаимодействия с пользователем, обновление экрана…
Такие приложения выглядят более нативно чем традиционные веб-страницы, где приложение зависит от сервера. Например, если вы используете Trello, вы можете заметить насколько быстро создаются карточки.
Конечно же, с большой силой приходит большая ответственность. В традиционных веб-приложениях ваше серверное приложение включает доменную модель и бизнес-правила, технологию доступа к данным для работы с базой данных и слой контроллеров для управления тем, как HTML страницы собираются в ответ на HTTP запросы.
C SPA всё несколько сложнее. Вам всё ещё нужно серверное приложение, включающую вашу доменную модель и правила, веб-сервер, база данных и какая-то технология доступа к данным… и ещё куча дополнительных штук сверху:
Для сервера:
API, удовлетворяющий потребности вашего клиента в данных
Система сериализации в JSON для обмена данными с клиентом и система кэширования, которая поддерживает это
Для нового JavaScript клиента:
Система шаблонов для преобразования данных в HTML
Представление вашей доменной модели и правил
Слой доступа к данным в клиентском приложении для передачи данных серверу
Система обновления представлений при изменении данных
Система для связи URL-адресов и экранов (надеюсь, вы не будете использовать один адрес для всего, это выглядит не совсем как веб-приложение)
Система для склеивания всех компонентов, необходимых для отображения экранов и получения данных для этого
Новые шаблоны и архитектура для организации всего когда
Система для обработки ошибок, логгирования, отслеживания исключений и т.д.
Система для генерации JSON для серверных запросов
Фреймворк для автоматизированного тестирования, поддерживающая ваш SPA
Дополнительный набор тестов для написания и поддержки
Дополнительный набор инструментов для сборки, упаковки и развёртывания нового приложения
Суммируя, с SPA у вас будет ещё одно приложение для поддержки. И новый набор проблем для решения. И заметьте, вы не можете заменить одно приложение другим. Вам всё ещё нужно серверное приложение (теперь оно будет рендерить JSON вместо HTML).
Если вы никогда не работали с SPA, вы можете недооценивать сложности, с которыми вы столкнётесь. Я знаю это, потому что я допустил те же ошибки в прошлом. Отрендерить JSON? Я могу с этим справиться. Богатая модель доменных объектов в JavaScript? Звучит забавно. И, знаешь, этот фреймворк решит все эти проблемы. Отличный пирог!
Неверно.
API и обмен данными.
Обмен данными между вашим новым приложением и сервером — сложная проблема.
Есть две противоположных силы:
Вы захотите делать так мало запросов к серверу, как только можно, чтобы улучшить производительность
Преобразование одной записи в JSON это просто. А вот смешение больших моделей различных записей для минимизации количества запросов — совсем нет. Вам понадобится аккуратно разработать логику сериализации для оптимизации количества запросов к базе данных и сохранения производительности на уровне.
Кроме этого, вам нужно подумать о том, что загружать, и когда это делать для каждого их экранов. Я имею в виду, что вам нужен баланс между начальной загрузкой, тем, что нужно сразу, и тем, что может быть загружено лениво, и разработать API, который позволяет это делать.
Некоторые стандарты могут тут помочь. JSON API, чтобы стандартизировать JSON формат; или GraphQL, для выборки только нужных данных, таких сложных как потребуется, одним запросом. Но ни один из них не спасёт вас от:
Проработки каждого обмена данными
Реализации запросов, позволяющих выбрать данные эффективно на сервере
И оба эти аспекта представляют собой достаточный объём дополнительной работы.
Время начальной загрузки
Люди привыкли ассоциировать SPA со скоростью, но правда такова, что заставить их загружаться быстро не так-то уж и просто. Этому есть множество причин:
Приложению нужны данные перед тем, как отрендерить что-то, и чтобы распарсить достаточно большой объём JavaScript нужно время.
Сверх начального HTTP запроса для загрузки приложения, обычно нужно сделать один или больше запросов для получения JSON данных, необходимых для рендеринга экрана.
Клиент должен преобразовать JSON в HTML, чтобы показать хоть что-то. В зависимости от устройства и количества JSON для преобразования это может вносить заметные задержки.
Это не значит, что невозможно заставить SPA загружаться быстро. Я просто говорю, что это сложно и вам стоит позаботиться об этом, поскольку это не придёт само вместе с архитектурой SPA.
Например, Discourse, SPA на базе Ember, имеет фантастическое время загрузки, но помимо всего прочего, они предзагружают большой объём JSON данных в виде части начального HTML, чтобы не делать дополнительные запросы. И отмечу, что команда Discourse помешаны в хорошем смысле на скорости и их навыки сильно выше среднего. Подумайте об этом перед тем, как с лёгкостью воспроизводить то же самое в вашем SPA.
Амбициозное решение этой проблемы — изоморфный JavaScript: отрендерите вашу начальную страницу на сервере и быстро отдайте клиенту, пока в фоне SPA загружается и получает полный контроль, когда готово.
Этот подход требует исполнения JavaScript рантайма на сервере, и он тоже не без технических проблем. Например, разработчики должны учитывать события загрузки SPA, поскольку процесс загрузки меняется.
Мне нравится возможность переиспользования кода в этой идее, но я не видел реализации, позволившей бы мне идти в противоположном направлении. Кроме того, мне кажется очень забавным такой процесс рендеринга страниц:
— Server: запрос к серверному API
— Server: запрос к базе данных
— Server: сгенерировать JSON
— Server: преобразовать JSON в HTML
— Client: отобразить начальный HTML
— Client: загрузить SPA
— Client: распарсить начальный HTML и подписаться на события DOM
Не могли бы вы просто запросить данные из БД, сгенерировать HTML и начать работать?
Это не совсем честно, потому что вы будете не SPA и потому что большая часть этой магии спрятана за фреймворком, но это всё ещё кажется мне неправильным.
Архитектура
Разрабатывать приложения с богатым пользовательским интерфейсом сложно. Это всё потому, что это одна из проблем, которая вдохновила появление объектно-ориентированного подхода и многих шаблонов проектирования.
Управлять состоянием на клиенте сложно. Традиционные веб-сайты обычно фокусируются на экранах с одной ответственностью, которые теряют состояние, когда перезагружаются. В SPA же приложение отвечает за то, чтобы всё состояние и обновления экрана во время использования были консистентными и проходили гладко.
На практике, если вы начинали писать JavaScript небольшими порциями, чтобы улучшить взаимодействие, то в SPA вам придётся писать тонны дополнительного JavaScript кода. Тут вам стоит убедиться, что вы делаете всё правильно.
Существует столько же разных архитектур, сколько SPA-фреймворков:
Большинство фреймворков отличаются от традиционного шаблона MVC. Ember поначалу был вдохновлён Cocoa MVC, но достаточно сильно поменял свою программную модель в последних версиях.
Прослеживается тенденция, что разработчики предпочитают компоненты, а не традиционное разделение на контроллер и представление (некоторые фреймворки, такие как Ember и Angular, перешли к такому подходу в последних версиях). Все фреймворки реализуют некоторое подобие одностороннего биндинга данных. Двусторонний биндинг не приветствуется из-за побочных эффектов, которые он может вносить.
Большинство фреймворков включают систему роутинга, которая позволяет сопоставлять URL-адреса и экраны, и определяет, как создавать экземпляры компонентов для рендеринга. Это уникальный подход веб, который не существует в традиционных настольных интерфейсах.
Большинство фреймворков отделяют HTML шаблоны от JavaScript кода, но React ставит на смешение HTML-генерации и JavaScript и делает это вполне успешно, учитывая его массовое использование. Сейчас также наблюдается хайп вокруг встраивания CSS в JavaScript. Facebook со своей архитектурой Flux довольно сильно повлиял на индустрию, и контейнеры, такие как Redux, vuex и др., находятся под сильным влиянием от него.
Из всех фреймворков, что я видел, Ember — мой любимый. Я обожаю его согласованность и то, что он довольно упрямый. Мне также нравится его модель программирования в последних версиях, сочетающая традиционный MVC, компоненты и роутинг.
С другой стороны, я сильно против Flux/Redux лагеря. Я видел так много умных людей, применяющих их, что приложил все усилия к его изучению и пониманию и ни один раз. Я не могу не трясти головой от разочарования, когда я вижу код. Я не вижу себя счастливым во время написания такого кода.
Наконец, Я не могу смириться со смешением HTML и CSS в компонентах, полных JavaScript логики. Я понимаю какую проблему это решает, но проблемы, которые привносит этот подход, не делают его стоящим этого.
Оставим личные предпочтения, суть в том, что если вы выберете путь SPA, то у вас появится очень сложная проблема: создать архитектуру вашего нового приложения правильно. И индустрия довольно далеко от того, чтобы прийти к согласию по вопросу — как это делать. Каждый год появляются новые фреймворки, шаблоны и версии фреймворков, что слегка меняет модель программирования. Вам потребуется писать и поддерживать тонну кода, основываясь на вашем архитектурном выборе, так что подумайте об этом как следует.
Дублирование кода
При работе с SPA вероятно вы встретитесь с дублированием кода.
Для вашей SPA логики, вы захотите создать богатую модель объектов, представляющих вашу доменную область, и бизнес логику. И вам все ещё нужно всё то же самое для серверной логики. И это вопрос времени, когда вы начнёте копировать код.
Например, представим, что вы работаете с инвойсами. Вы возможно имеете класс Invoice в JavaScript, который содержит метод total, который суммирует цену всех элементов, чтобы вы могли отрендерить стоимость. На сервере, вам также понадобится класс Invoice с методом total для вычисления этой стоимости, чтобы отправить её по e-mail. Видишь? Клиентский и серверный класс Invoice реализуют одинаковую логику. Дублирование кода.
Как сказано выше, изоморфный JavaScript мог бы нивелировать эту проблему, позволяя проще переиспользовать код. И я говорю нивелировать, потому что соответствие между клиентом и сервером не всегда 1-к-1. Вы захотите быть уверены, что некоторый код никогда не покидает сервер. Большое количество кода имеет смысл только для клиента. А также, некоторые аспекты просто отличаются (например, серверный элемент может сохранять данные в БД, а клиент может использовать удалённый API). Переиспользование кода, даже если это возможно, — это сложная проблема.
Вы можете поспорить, что вам не нужна богатая модель в вашем SPA и что вы вместо этого будете работать с JSON/JavaScript объектами напрямую, распределяя логику по компонентам UI. Теперь у вас есть то же самое дублирование кода, перемешанное с вашим кодом UI, удачи с этим.
И то же самое случится если вы захотите шаблоны для рендеринга HTML между сервером и клиентом. Например, для SEO, как насчёт сгенерировать страницы на сервере для поисковых роботов? Вам потребуется заново написать ваши шаблоны на сервере и убедится, что они синхронизированы с клиентскими. Опять дублирование кода.
Необходимость воспроизводить логику шаблонов на сервере и клиенте, по моему опыту, — источник возрастающего несчастья программистов. Сделать это один раз — это нормально. Когда вы сделаете это в 20ый раз, вы схватитесь за голову. Сделав это в 50ый раз, вы задумаетесь, нужны ли все эти SPA штуки.
Хрупкость
По моему опыту, разрабатывать хорошие SPA — это намного более сложная задача, чем написание веб-приложений с генерацией на сервере.
Во-первых, неважно насколько вы осторожны, неважно как много тестов вы пишете. Чем больше кода вы пишете, больше багов у вас будет. И SPA представляет (извините, если я сильно давлю) огромную кучу кода для написания и поддержки.
Во-вторых, как упоминалось выше, разработка богатого GUI это сложно и выливается в сложные системы, состоящие из множества элементов, взаимодействующих друг с другом. Чем более сложную систему вы создаёте, тем больше у вас багов. И по сравнению с традиционными веб-приложениями, использующими MVC, сложность SPA просто безумная.
Например, для сохранения консистетности на сервере вы можете использовать ограничения в БД, валидации модели и транзакции. Если что-то пойдёт не так, вы отвечаете с сообщением об ошибке. В клиенте, всё слегка сложнее. Очень многое может пойти не так просто потому, что слишком много всего происходит. Может быть так, что какая-то запись сохраняется удачно, а какая-то другая запись нет. Возможно, вы перешли в оффлайн посередине какой-то операции. Вы должны убедиться, что UI остаётся консистентным, и что приложение восстанавливается после ошибки. Всё это возможно, конечно, только намного сложнее.
Организационные вызовы
Это звучит глупо, но для разработки SPA, вам нужны разработчики, которые знают, что с этим делать. В то же время, вам не стоит недооценивать сложность SPA, вам не стоит думать, что любой опытный веб-разработчик с правильной мотивацией и пониманием может написать отличное SPA с нуля. Вам нужны правильные навыки и опыт или ожидайте, что важные ошибки будут сделаны. Я знаю это, потому что это в точности мой случай.
Это возможно более важный вызов для вашей компании, чем вы думаете. Подход SPA поощряет команды узкой специализации вместо команд из специалистов общего профиля:
SPA фреймворки представляют собой сложные части программного обеспечения, в которых требуется бесчисленное количество часов опыта, чтобы быть продуктивным. Только люди из вашей компании, проводящие эти часы за кодом, смогут поддерживать эти приложения.
SPA фреймворки требуют продуманных и производительных API. Выполнение этих требований требует совершенно иного набора навыков, чем те, что необходимы работы с SPA.
Шансы таковы, что вы окажетесь с людьми, которые не могут работать с SPA, и которые не могут работать на серверной стороне, просто потому что они не знают как.
Эта специализация может идеально подходить для Facebook или Google и их команд, состоящих из нескольких слоев инженерных войск. Но будет ли это хорошо для вашей команды из 6 человек?
Современный Rails
Есть 3 вещи, входящих в современный Rails, которые могут изменить ваше мнение о разработке современных веб-приложений:
другая — старый друг, которого сегодня упускают из вида: SJR ответы и простые AJAX запросы для рендеринга
и последняя была добавлена недавно: Stimulus
Трудно понять, какого это применять какой-то подход, не поиграв с ним. Поэтому я сделаю несколько отсылок на Basecamp в следующих разделах. Я не имею никакого отношения к Basecamp, кроме как счастливый пользователь. Что касается этой статьи, это просто хороший живой пример современного Rails, который вы можете попробовать бесплатно.
Turbolinks
Идея Turbolinks проста: ускорьте ваше приложение, полностью заменив перезагрузку страниц на AJAX запросы, которые заменяют `` элемент. Внутреннее колдовство, выполняющее эту работу, скрыто. Как разработчик, вы можете сосредоточиться на традиционном серверном программировании.
Turbolinks вдохновлён pjax и прошёл через несколько ревизий.
Раньше я беспокоился о его производительности. Я был неправ. Ускорение огромно. То, что меня убедило, это то, как я использовал его в проекте, но вы можете просто попробовать пробную версию в Basecamp и поиграться с ней. Попробуйте создать проект с некоторыми элементами, а затем перемещайтесь по ним, щелкая по разделам. Это даст вам хорошее представление о том, как выглядит Turbolinks.
Я не думаю, что Turbolinks просто потрясает своей новизной (pjax — 8 лет). Или своей технической утонченностью. Меня поражает то, как простая идея может повысить вашу производительность на порядок по сравнению с альтернативой SPA.
Позвольте мне выделить некоторые проблемы, которые он устраняет:
Обмен данными. У вас его нет. Не нужно сериализовывать JSON, создавать API-интерфейсы или думать о запросах данных, которые удовлетворяют потребности клиентов с учётом производительности.
Начальная нагрузка. В отличие от SPA, этот подход стимулирует быстрое время загрузки (by design). Для рендеринга экрана вы можете получить данные, которые вам нужны непосредственно из базы данных. И эффективный запрос данных из реляционных баз данных или кэширование HTML — это хорошо решаемые проблемы.
Архитектура: Вам не нужна сложная архитектура для организации вашего JavaScript-кода. Вам нужно всего лишь сосредоточиться на правильной архитектуре вашего серверного приложения, что вам всё равно нужно делать при использовании SPA.
MVC на сервере, в варианте, используемом Rails и многими другими фреймворками, намного проще, чем любой из шаблонов, используемых для архитектуры богатых графических интерфейсов: получить запрос, поработать с БД для его удовлетворения и отобразить страницу HTML в качестве ответа.
Наконец, ограничение, что всегда заменяется имеет замечательный эффект: вы можете сосредоточиться на первоначальном рендеринге страниц вместо того, чтобы обновлять определенные разделы (или обновлять некоторые состояния в мире SPA). В общем случае он просто все делает.
Дублирование кода. Существует только одно представление вашего приложения, которое живет на сервере. Ваша доменная модель, её правила, экраны приложений и т.д. Нет необходимости дублировать концепции в клиенте.
Хрупкость. По сравнению с SPA, JavaScript для работы на ваших страницах и его сложность сокращены до небольших долей, и поэтому количество ошибок. Кроме того, вы можете полагаться на атомарное выполнение операций на сервере, используя транзакции базы данных, ограничения и валидации.
Заметьте, я говорю не об обозначении проблем, а об их устранении. Например, GraphQL или SPA-регидратация — это суперумные решения для очень сложных проблем. Но что, если вместо того, чтобы пытаться найти решение, вы ставите себя в ситуацию, когда эти проблемы не существуют? Это изменение подхода к проблеме. И мне потребовались годы, чтобы в полной мере оценить способность этого подхода решать проблемы.
Разумеется, Turbolinks не является беспроблемной серебряной пулей. Самая большая проблема заключается в том, что он может сломать существующий JavaScript код:
Turbolinks поставляется со своим пользовательским событием «загрузка страницы», и существующие плагины, полагающиеся на регулярные загрузки страниц, не будут работать. Сегодня есть лучшие способы добавить поведение к DOM, но устаревшие виджеты не будут работать, если не будут адаптированы.
JavaScript-код, изменяющий DOM, должен быть идемпотентным, поскольку его могут запускать несколько раз. Опять же, это делает недействительным много существующего JavaScript.
Скорость отличная, но это не совсем как в SPA, который может обрабатывать некоторые взаимодействия, не загружая сервер. Я расскажу больше о компромиссах позже.
AJAX рендеринг и SJR ответы
Помните, когда рендеринг HTML через Ajax был в тренде 15 лет назад? Угадай, что? Это все еще замечательный инструмент, который есть в вашем арсенале:
Получение фрагмента HTML с сервера и добавление его в DOM, ощущается супербыстрым (на 100мс быстрым).
Вы можете рендерить HTML на сервере, что позволяет повторно использовать ваши представления и извлекать необходимые данные непосредственно из базы данных.
Вы можете видеть, как этот подход ощущается в Basecamp, открыв меню вашего профиля, нажав на верхнюю правую кнопку:
Открывается мгновенно. Со стороны разработки вам не нужно заботиться о сериализации JSON и клиентской стороне. Вы можете просто отобразить этот фрагмент на сервере, используя все возможности Rails.
Похожий инструмент, который Rails включает в себя в течение многих лет, — это серверные ответы JavaScript (SJR). Они позволяют вам отвечать на запросы Ajax (обычно формировать представления) с JavaScript, который исполняется клиентом. Он дает те же преимущества, что AJAX-рендеринг HTML-фрагментов: исполняется очень быстро, вы можете повторно использовать код на стороне сервера, и вы можете напрямую обращаться к базе данных для создания ответа.
Вы можете увидеть, как это происходит, если вы зайдёте в Basecamp и пытаетесь создать новый todo. После того, как вы нажмете «Добавить todo», сервер сохранит todo и ответит фрагментом JavaScript, который добавляет новый todo в DOM.
Я думаю, что многие разработчики сегодня смотрят на AJAX-рендеринг и SJR-ответы с презрением. Я тоже это помню. Они являются инструментом и, как таковые, могут подвергаться злоупотреблениям. Но при правильном использовании это потрясающее решение. Позвольте вам предложить отличный UX и интерактивность по очень низкой цене. К сожалению, как и Turbolinks, их сложно оценить, если вы ещё не сражались с SPA.
Stimulus
Stimulus — это JavaScript фреймворк, опубликованный несколько месяцев назад. Он не заботится о рендеринге или об управлении состоянием на основе JavaScript. Вместо этого, это просто хороший, современный способ организации JavaScript, который вы используете для добавления HTML:
Он использует MutationObserver для привязки поведения к DOM, то есть ему не важно, как HTML появляется на странице. Конечно, это отлично работает с Turbolinks.
Он сэкономит вам кучу шаблонного кода для привязки поведения к DOM, для привязки обработчиков к событиям и для размещения элементов в указанном контейнере.
Он нацелен на то, чтобы ваш HTML-код был читабельным и понятным, что приятно, если вы когда-либо сталкивались с проблемой поиска того, какая часть JavaScript действует на этом проклятом элементе.
Он поощряет сохранение состояния в DOM. Опять же, это означает, что ему не важно, как генерируется HTML, что подходит для многих сценариев, в том числе Turbolinks.
Если вы примете Rails-путь, ваш JavaScript будет сосредоточен на изменении HTML-кода, созданного на стороне сервера, и улучшении взаимодействия (c небольшим количеством JavaScript). Stimulus предназначен для организации такого кода. Это не система SPA и не претендует на то, чтобы быть таковой.
Я использовал Stimulus в нескольких проектах, и мне это очень нравится. Он избавляет от кучи шаблонного кода, он построен на последних веб-стандартах и читается очень красиво. И что-то, что я люблю особенно: теперь это стандартный способ сделать что-то, что до сих пор приходилось решать в каждом приложении.
Игра компромиссов
Turbolinks обычно продается как «Получите все преимущества SPA без каких-либо неудобств». Я не думаю, что это полностью верно:
Приложения, построенные с использованием современного Rails, выглядят быстрыми, но SPA по-прежнему будет быстрее реагировать на взаимодействия, которые не зависят от сервера.
Существуют сценарии, в которых SPA имеет больше смысла. Если вам нужно предложить высокий уровень интерактивности, вам нужно управлять большим количеством состояний, выполнять сложную логику на стороне клиента и т.д., SPA фреймворк сделает вашу жизнь проще.
Теперь разработка — это игра компромиссов. И в этой игре:
Современный Rails позволяет вам создавать приложения, которые достаточно быстры и отлично выглядят.
Для огромного множества приложений Rails позволяет реализовать те же функции с меньшим количеством кода и меньшей сложностью.
Я считаю, что с Rails вы можете получить 90% того, что предлагает SPA с 10% усилий. Что касается производительности, Rails убивает SPA. Что касается UX, я думаю, что многие разработчики делают ту же ошибку, что и я, предполагая, что SPA UX является непревзойденным. Это не так. Фактически, как обсуждалось выше, вам лучше знать, что вы делаете при создании своего SPA, или UX будет на самом деле хуже.
Заключение
Я наблюдаю за тем, как компании массово принимают SPA фреймворки, и вижу бесчисленные статьи о том, как делать причудливые вещи в стиле SPA. Я думаю, что существует много «использований неправильного инструмента для работы», поскольку я твердо верю, что типы приложений, которые оправдывают использование SPA, ограничены.
И я говорю, что оправдывают, потому что SPA сложны. Во всяком случае, я надеюсь, что убедил вас в этом. Я не говорю, что невозможно создать великолепные SPA-приложения, или что современные Rails-приложения великолепны по определению, просто один подход суперсложный, а другой намного проще.
Готовя эту статью, я наткнулся на этот твит:
Это заставило меня посмеяться, потому что я выберу первые варианты, если альтернатива не будет оправдана. Он также является представителем своего рода мышления разработчиков, который обожает сложность и процветает в этом, вплоть до того, что считает сумасшедшими других людей с другими критериями.
По прошествии многих лет я понял, что сложность часто является выбором. Но в мире программирования на удивление сложно выбрать простоту. Мы так высоко ценим сложность, что принятие простоты часто заставляет мыслить по-другому, что по определению — трудно.
Помните, что вы можете избавиться от неприятностей. Если вы выберете путь SPA, убедитесь, что он оправдан и вы понимаете проблемы. Если вы не уверены, экспериментируйте с разными подходами и убедитесь сами. Возможно, Facebook или Google, в их масштабе, не имеют роскоши принимать такие решения, но вы, вероятно, можете.
И если вы разработчик Rails, который покинул Rails много лет назад, я рекомендую вам вернуться к нему. Я думаю, вы будете в восторге.