Гем под названием Turbolinks способен неплохо ускорить ваше приложение, используя JavaScript для обновления контента на странице. Он включен по умолчанию в Rails 4, но я покажу, как можно использовать его уже сейчас в программах, написанных на Rails 3. Также вы узнаете о некоторых подводных камнях.
Cодержание цикла «Тонкости Rails 4»
- Cache digests
- Turbolinks
Turbolinks позволяет ускорить практически любое Rails-приложение, поскольку загружает только тело страницы страницы, а не всю ее целиком. Да, делается это все добро с помощью JavaScript. В этой статье мы опробуем работу гема на приложении, написанном на третьих рельсах.
Сам сайт достаточно прост — это набор проектов со своим списком задач, которые необходимо выполнить. Каждая новая задача помечается как неоконченная, но легким движением мышки (а вернее, нажатия в соответствующем чекбоксе) задача превращается в завершенную.
Добавление Turbolinks
Теперь добавим Turbolinks в наше приложение и посмотрим, как все это работает. В первую очередь необходимо вписать имя гема в gemfile и затем запустить bundle install.
/Gemfile
gem 'turbolinks'
Теперь необходимо добавить в Javascript манифест приложения строчку для добавления turbolinks:
/app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
К слову, гем не требует наличия JQuery, что в некоторых случаях может быть очень даже удобно.
Перегрузив после этого сервер рельс и полазив немного по приложению возможно вы не увидите особой разницы. Чтобы проверить, а работает ли собственно Turbolinks необходимо открыть network inspector браузера и затем уже побродить по сайту. В моем случае, после описанных выше шагов я увидел, что при переходе на какую-либо страницу она загружается целиком, таким образом вывод: гем не заработал. Это может происходить в том случае, если ваш браузер не поддерживается Turbolink’ом, в таком случае стоит его сменить (и, желательно, на что-то известное), либо обновиться (если это возможно). Гем ожидает, что используется наиболее свежая версия одного из популярных браузеров. Иначе он просто не будет работать, но при этом приложение будет функционировать нормально и без него.
В моем случае я поменял мой браузер на новую версию Chrome и открыл в нем разрабатываемый сайт. Запустив веб-инспектор и покликав по ссылкам будет видно, что страница не перегружается полностью, поскольку теперь гем работает и turbolinks.js уже генерирует ajax-запрос для открываемой страницы.
Использование гема позволяет сайту загружаться быстрее, поскольку браузер не занимается заново интерпретацией JS и CSS кода, но как же все же это работает?
Turbolinks для всех ссылок на странице слушает событие click. Как только оно происходит, к нужной странице делается GET-запрос через JavaScript и после этого анализируются полученные данные, а затем обновляются элементы title и body. Гем также использует Push State API для изменения URL обновленной страницы. Подобная техника очень похожа на PJAX.
Проблемы с уже существующими скриптами
Написанное для этого урока приложение, казалось бы, работает с Turbolinks довольно неплохо, но тем не менее, даже в нем возникают проблемы с существующими скриптами на JavaScript. Увидеть эту проблему очень просто, стоит всего лишь попытаться переключить значение в чекбоксе задачи. Ничего не произойдет. Вообще. Однако, если вручную обновить страницу, то проблема волшебным образом испарится.
Собственно, вот код, с которым возникают проблемы:
/app/assets/javascripts/projects.js.coffee
jQuery ->
$('.edit_task input[type=checkbox]').click ->
$(this).parent('form').submit()
Код ожидает событие click в одном из чекбоксов задач. Как только оно произошло, форма с чекбоксом отправляется на сервер, после чего задача помечается как завершенная.
Приглядитесь к первой строке кода. Она очень важна, поскольку именно в ней происходит ожидание события ready для страницы, срабатывающий только после того, как DOM страницы целиком загрузился. Поэтому, если не использовать этот код, то jQuery попытается приаттачить event'ы к чекбоксам еще до их загрузки.
При использовании Turbolinks этот callback исполняется только один раз, при загрузке страницы. Это подводит нас к другой важной мысли: при переходе на другую страницу, благодаря вышеописанным особенностям гема чисто технически мы остаемся на той же самой странице. Однако сам Turbolinks генерирует несколько различных событий при загрузке новой странице и один из них — page:load. Это позволяет эмулировать загрузку DOM:
/app/assets/javascripts/projects.js.coffee
ready = ->
$('.edit_task input[type=checkbox]').click ->
$(this).parent('form').submit()
$(document).ready(ready)
$(document).on('page:load', ready)
Теперь можно определить переменную ready, сохранить в ней нашу многострадальную функцию, после чего передать переменную в document.ready и page:load. Таким образом, события теперь прикреплены к чекбоксам в независимости от того, используется Turbolinks или нет. Теперь функциональность восстановлена: при проставлении галочки в чекбоксе задачи она будет автоматически помечена как завершенная. И также легко оконченную задачу можно превратить в незавершенную.
Для решения похожих проблем можно воспользоваться Jquery Turbolinks gem. Кроме того, существует еще одно решение для обхода подобных подводных камней. Вместо того, чтобы находить элементы и отслеживать их click события можно слушать событие click для всего документа и при его возникновении проверять, что оно было вызвано для чекбокса с задачей:
/app/assets/javascripts/projects.js.coffee
$('document').on 'click', '.edit_task input[type=checkbox]', ->
$(this).parent('form').submit()
При таком подходе даже нет необходимости проверять, что DOM загружен. И также есть дополнительное преимущество: код будет корректно обрабатывать все задачи с чекбоксами, добавленные с помощью AJAX.
Хорошей идеей будет следить за баг-трекером Turbolinks, поскольку на момент публикации статьи у него были серьезные проблемы со сторонними библиотеками, такими как Twitter Bootstrap, Jquery UI Calendar. При этом над ними идет с работа с целью добавления совместимости.
Тем не менее существуют нечастые ситуации, в которых при возврате на предыдущую страницу Turbolinks мило делает POST-запрос, вместо GET. Как решить эту проблему? Просто отключите Turbolinks в подобных ситуациях. Эти детские болезни должны быть вылечены в скором будущем.
Посмотрев на такую кучу проблем можно подумать: «А стоит ли оно того?». Помочью решении может тест скорости Turbolinks, из которого видно, что в некоторых случаях загрузка страницы повышается в 2 раза. Конечно, все приложения разнятся, но вы можете попробовать гем у себя и проверить, насколько улучшится отзвычивость сайта.
Если же хочется использовать Rails 4 и при этом Turbolinks вам категорически не нравится или не подходит, то его спокойно можно отключить. Для этого необходимо убрать гем из gemfile, а затем удалить соответствующую строку с require из главного JavaScript манифеста приложения.
Спасибо за внимание!
Обо всех найденных ошибках, неточностях перевода и прочих подобных вещах просьба сообщать в личку.
Приложение
Автор: Loremaster