Обзор Turbo - geroi/turbo-rails GitHub Wiki

Turbo Drive: Навигация в рамках постоянного процесса

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

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

Это происходит путем перехвата всех кликов на <a href>ссылки</a> на один и тот же домен. Когда вы нажимаете на подходящую ссылку, Turbo Drive предотвращает переход браузера по ней, изменяет URL браузера с помощью History API, запрашивает новую страницу с помощью fetch, а затем отображает HTML-ответ.

То же самое происходит с формами. Их отправка превращается в fetch-запросы, из которых Turbo Drive будет следовать перенаправлению и отображать HTML-ответ.

Во время рендеринга Turbo Drive заменяет текущий элемент

прямо и объединяет содержимое элемента <head>. Объекты окна и документа JavaScript, а также элемент <html> сохраняются от одного рендеринга к другому.

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

Turbo Frames: Декомпозиция сложных страниц

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

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

Чтобы обернуть независимый сегмент в собственный навигационный контекст, заключите его в тег <turbo-frame>. Например:

<turbo-frame id="new_message">
  <form action="/messages" method="post">
    ...
  </form>
</turbo-frame>

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

Фреймы могут лениво загружать свое содержимое в дополнение к масштабированию навигации. Чтобы лениво загрузить фрейм, добавьте атрибут src, значением которого является URL, загружаемый автоматически. Как и в случае с масштабируемой навигацией, Turbo находит и извлекает подходящий фрейм из полученного ответа и подставляет его содержимое на место:

<turbo-frame id="messages" src="/messages">
  <p>This message will be replaced by the response from /messages.</p>
</turbo-frame>

Это может показаться очень похожим на фреймы старой школы или даже <iframe>, но Turbo Frames являются частью того же DOM, поэтому здесь нет никаких странностей или компромиссов, связанных с "настоящими" фреймами. Turbo Frames оформляются с помощью того же CSS, являются частью того же контекста JavaScript и не подвергаются никаким дополнительным ограничениям безопасности контента.

В дополнение к превращению ваших сегментов в независимые контексты, Turbo Frames позволяет вам:

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

  2. Распараллеленное выполнение. Каждый лениво загружаемый фрейм генерируется собственным HTTP-запросом/ответом, что означает, что он может обрабатываться отдельным процессом. Это позволяет распараллелить выполнение без необходимости вручную управлять процессом. Сложная составная страница, на выполнение которой из конца в конец уходит 400 мс, может быть разбита на фреймы, где начальный запрос может занять всего 50 мс, а каждый из трех лениво загружаемых фреймов - 50 мс. Теперь вся страница выполняется за 100 мс, потому что три фрейма, каждый из которых занимает 50 мс, работают параллельно, а не последовательно.

  3. Готовность для мобильных устройств. В мобильных приложениях обычно не бывает больших, сложных составных страниц. Для каждого сегмента нужен отдельный экран. В приложении, созданном с использованием Turbo Frames, вы уже проделали эту работу по превращению составной страницы в сегменты. Затем эти сегменты могут появляться на родных листах и экранах без изменений (поскольку все они имеют независимые URL-адреса).

Turbo Streams: Обеспечьте живые изменения страниц

Частичное изменение страницы в ответ на асинхронные действия - это то, как мы делаем приложение живым. В то время как Turbo Frames предоставляет нам такие обновления в ответ на прямое взаимодействие в пределах одного кадра, Turbo Streams позволяет нам изменять любую часть страницы в ответ на обновления, отправленные через WebSocket-соединение, SSE или другой транспорт. (Вспомните imbox, который автоматически обновляется при получении нового письма).

Turbo Streams представляет элемент с пятью основными действиями: append, prepend, replace, update и remove. С помощью этих действий, а также атрибута target, указывающего ID элемента, с которым вы хотите работать, вы можете закодировать все мутации, необходимые для обновления страницы. Вы даже можете объединить несколько элементов потока в одном сообщении потока. Просто включите HTML, который вы хотите вставить или заменить, в тег шаблона, а Turbo сделает все остальное:

<turbo-stream action="append" target="messages">
  <template>
    <div id="message_1">Мое новое сообщение!</div>
  </template>
</turbo-stream>

Этот элемент потока возьмет div с новым сообщением и добавит его в контейнер с ID messages. Так же просто можно заменить существующий элемент:

<turbo-stream action="replace" target="message_1">.
  <template>
    <div id="message_1">Это изменяет существующее сообщение!</div>
  </template>
</turbo-stream>

Это концептуальное продолжение того, что в мире Rails сначала называлось RJS, а затем SJR, но реализованное без необходимости использования JavaScript. Преимущества остаются теми же:

  • Повторное использование шаблонов на стороне сервера: Изменения страницы в реальном времени генерируются с помощью тех же шаблонов на стороне сервера, которые использовались для создания страницы первой загрузки. HTML по проводам: Поскольку мы отправляем только HTML, вам не нужен никакой JavaScript на стороне клиента (кроме Turbo, конечно) для обработки обновления. Да, полезная нагрузка HTML может быть немного больше, чем аналогичный JSON, но с gzip разница обычно незначительна, и вы экономите все усилия на стороне клиента, необходимые для получения JSON и преобразования его в HTML.

  • Более простой поток управления: Очень легко проследить, что происходит, когда сообщения приходят по WebSocket, SSE или в ответ на отправку формы. Нет необходимости в маршрутизации, нагромождении событий или других перенаправлений. Это просто HTML, который нужно изменить, завернутый в один тег, который говорит нам, как это сделать.

Теперь, в отличие от RJS и SJR, невозможно вызвать пользовательские функции JavaScript как часть действия Turbo Streams. Но это особенность, а не ошибка. Эти методы могут легко привести к запутанному беспорядку, когда слишком много JavaScript отправляется вместе с ответом. Turbo фокусируется только на обновлении DOM, а затем предполагает, что вы подключите любое дополнительное поведение с помощью действий Stimulus и обратных вызовов жизненного цикла.

Turbo Native: гибридные приложения для iOS и Android

Turbo Native идеально подходит для создания гибридных приложений для iOS и Android. Вы можете использовать существующий HTML с серверным рендерингом для получения базового покрытия функциональности вашего приложения в нативной обертке. Затем вы можете потратить все сэкономленное время на то, чтобы сделать еще лучше те несколько экранов, которые действительно выигрывают от высокоточного нативного управления.

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

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

Turbo Native предполагает, что вы используете рекомендуемые методы разработки, доступные для iOS и Android. Это не фреймворк, который абстрагируется от нативных API или даже пытается сделать так, чтобы ваш нативный код был доступен для совместного использования на разных платформах. Часть кода, которую можно использовать совместно, - это HTML, который отображается на стороне сервера. Но нативные элементы управления написаны в рекомендуемых нативных API.

Смотрите репозитории Turbo Native: iOS и Turbo Native: Android для получения дополнительной документации. Посмотрите нативные приложения для HEY на iOS и Android, чтобы понять, насколько хорошим может быть гибридное приложение на базе Turbo.

Интеграция с бэкенд-фреймворками

Для использования Turbo вам не нужен никакой бэкенд-фреймворк. Все функции созданы для использования напрямую, без дополнительных абстракций. Но если у вас есть возможность использовать бэкенд-фреймворк, интегрированный с Turbo, вам будет намного проще. Мы создали эталонную реализацию такой интеграции для Ruby on Rails.

⚠️ **GitHub.com Fallback** ⚠️