2014 год. Ниндзя-рок-звезды веба идут против забытой ныне техники прогрессивного улучшения. Они отказываются от истоков веба и всего того, за что они когда-то стояли. В этой статье я собираюсь громко заявить о том, как мы разрушаем веб; о не всегда явных причинах, почему мы должны перестать это делать, и отчего хорошей идеей будет это прекратить.
TL;DR Мы уничтожаем веб. Рендеринг исключительно на клиенте — отстой. Полифилы используются совсем не для того. Отвратительного вида хеш-роутинг ужасен, и мы от этого должны чувствовать себя ужасно. Мы годами говорили друг другу, что прогрессивное улучшение — это замечательно, и мы всё ещё почти ничего для него не делаем!
Скриншот ниже — всего лишь рекламный трюк: попытка захватить технический медиа-мир врасплох. Но тот факт, что мы не уверены, трюк это или решение всерьёз, заставляет меня сжиматься от страха за будущее веба.
Оговорка: эта статья — не брюзжание об Angular 2.0. Мысли, озвученные в ней, начали зарождаться у меня давно, до появления Angular 2.0. Так случилось, что объявление планов развития Angular совпало с публикацией этой статьи. И хотя эти новости больше подкрепляют точку зрения его противников, утверждения, стоящие за этой статьей, являются чем-то большим, чем просто критика изменений в публичном API Angular.
Мне грустно от понимания, что мы как сообщество подвели веб. Что вообще случилось с прогрессивным улучшением? Знаете такое простое правило: помещайте содержимое на первый план? Все остальное вторично по отношению к содержимому, правильно? В первую очередь люди хотят увидеть ваше содержимое. Как только оно на месте, возможно, они захотят взаимодействовать с ним. Как бы там ни было, если содержимое не появляется первым, потому что ваша страница слишком медленная, или потому что вы загружаете шрифты синхронно до того, как пользователь может что-нибудь прочитать, или потому что вы решили использовать рендеринг исключительно на клиенте — тогда, кажется, людей очень сильно надули. Верно?_
Конечно, сейчас интернет-соединения гораздо быстрее. Но у всех ли? Множество людей имеют доступ в сеть через мобильные соединения, вроде 2G и 3G, и они ожидают, что ваш сайт будет таким же быстрым, как на десктопе. А этого трудно добиться, когда вы блокируете содержимое загрузкой JavaScript.
Все чаще и чаще это становится нормой. Пофиг на людей, нам нужны все эти клёвые фреймворки, чтобы делать крутой веб! Подождите, но нам нужны люди. У них есть деньги, информация и всё такое. О, я знаю! Давайте дадим им роутинг на клиенте, даже если они на IE6. Это сделает их счастливыми, верно? Ох, тупой IE6 не поддерживает History API. Ладно, в топку IE6. Что? IE9 тоже не поддерживает History API? Хорошо, я буду делать все под IE10. Нет, погодите, это плохо, я использую хеш-роутер — и тогда обеспечу поддержку все IE, вплоть до IE6! О да, жизнь прекрасна, давайте сделаем наш сайт доступным через адреса типа /#/products/nintendo-game-cube
— и сделаем JavaScript обязательным, чтобы наш роутер работал! А ещё давайте рендерить страницы исключительно на стороне клиента. Да, вот это точно сработает!
Тем временем, мы добавляем тонны дополнительного веса нашим страницам, «уравнивая» браузеры в правах, снижая удобство в современных браузерах, пытаясь улучшить использование сайта в старых. И вот какая проблема в таком подходе. Люди, использующие старые браузеры, не ожидают самых новых возможностей. Они довольны тем, что у них есть. Это и есть основная причина, почему они используют старый браузер. Вместо попыток сделать всё удобнее для таких пользователей (и эти попытки чаще всего проваливаются), нужно включать дополнительные возможности, только если они поддерживаются браузером пользователя — вместо создания хаков для обхода ограничений.
Люди, использующие старые браузеры, будут более чем довольны вашим сайтом, если вы оставите только ту часть, что рендерится на сервере, поскольку им на самом деле не нужен ваш потрясный-и-необыкновенно-сложный кошмарно поддерживаемый хеш-роутинг. Но нет, подождите! Хеш-роутинг такой распрекрасный, разве нет? Кому нужен этот рендеринг на сервере!
Ладно, хорошо, давайте примем, что вы согласны со мной. Хеш-роутинг отстой. Он ничего не делает, чтобы помочь современным браузерам (за исключением замедления работы, это он делает!), и делает всё, чтобы усложнить разработку и запутать людей, которые пользуются старыми браузерами.
Заботимся ли мы на самом деле о вебе так, как говорим об этом? Скопировать ссылку
Недавно некто опубликовал на Медиуме статью, озаглавленную «Что не так с Angular.js». Меня вывело из себя, что, кажется, мы совсем не заботимся о рендеринге на стороне сервера, пока у нас есть возможность разрабатывать приложения на нашем любимом фреймворке. Тогда как каждая из упомянутых проблем Angular была так или иначе опровергнута, проблема рендеринга на стороне сервера осталась практически незамеченной. Как будто никого это не волнует, или же никто не понимает суть претензии.
Без сомнительных хаков — никакого рендеринга на сервере. Никогда. Вам не починить то, что сломано изначально. Пока-пока, изоморфные веб-приложения.
Единственное место, где я представляю себе использование фреймворка, основанного исключительно на клиентском рендеринге — это разработка прототипов или внутренних бэкенд-приложений (примерно как мы сейчас используем Bootstrap в основном для внутренних штук). В таких делах эти безразличные к пользователю фреймворки хороши, потому что они повышают продуктивность без особых затрат, так как люди не страдают в процессе. За исключением редких случаев, когда отсутствие возможности рендеринга на стороне сервера ничему не вредит, допускать это бесспорно нельзя, это слишком медленно, недопустимо, шаг назад и вообще безответственно.
Медленно, потому что люди теперь вынуждены загружать всю вашу разметку, ваш CSS, ваш JavaScript, прежде чем этот JavaScript сможет отрисовать информацию, которую пользователь ожидает в первую очередь. С каких пор мы согласны жертвовать быстродействием ради фреймворков?
Это шаг назад, поскольку вы должны доставлять информацию в доступной человеку форме в первую очередь, а не после того, как каждый блокирующий рендеринг запрос будет исполнен. Это означает, что доступное человеку HTML-представление должно быть отрендерено на сервере и доставлено пользователю, и лишь затем можно добавить вашу прикольную JavaScript-магию поверх него, пока пользователь занят информацией, которую вы ему предоставили.
Держи людей занятыми, или им станет некомфортно.
Это неосмотрительно, потому что мы годами учили друг друга избегать подобных ситуаций — только другими словами. Мы говорили себе о важности отложенной загрузки скриптов при помощи вставки тегов <script>
в самый низ страницы, и, может быть, даже добавляли атрибут async
, чтобы они загружались в последнюю очередь. Использование рендеринга на клиенте без поддержки серверной стороны означает, что эти скрипты, которые вы поместили в низ своей страницы, теперь мешают вашим пользователям — потому что загрузка отложена, а без JavaScript нельзя получить содержимое для отображения. Только не начинайте перемещать теги <script>
обратно в <head>
. Просто поймите, насколько далеко идущие негативные последствия имеет рендеринг на клиенте, когда не берется в расчёт возможность серверного рендеринга.
Но не верьте мне на слово. Тут вот у Твитера есть что сказать. Помните Твитер? Да, они переключились обратно на распределенный рендеринг в середине 2012 г. и не жалеют об этом.
Глядя на составляющие, из которых складывается [время до первого твита], мы обнаружили, что только парсинг и исполнение JavaScript вызывают большие провалы в скорости рендеринга. При нашей архитектуре, полностью основанной на клиентском рендеринге, вы не видели ничего, пока JavaScript не был загружен и выполнен. Проблема обостряется ещё сильнее, если у вас не супермощный компьютер или вы пользуетесь старым браузером. Суть в том, что архитектура на клиенте приводит к снижению быстродействия, поскольку бо́льшая часть кода исполняется на компьютере пользователя, а не на нашей стороне.
Существуют различные методы ускорения JavaScript, но мы хотели сделать всё ещё лучше. Мы полностью исключили исполнение JavaScript из процесса рендеринга. Благодаря рендерингу на стороне сервера и отложенному исполнению любого JavaScript, пока весь этот контент не будет отображён, мы в пять раз снизили время до первого твита.
Мы заботимся не о тех вещах. Вчера Хенрик Йортег озвучил несколько справедливых опасений относительно тяжелого будущего AngularJS. Хотя многие из них спорны. Вам могут нравиться эти изменения, вы можете думать, что они к лучшему, но что в действительности вы получите от большого рефакторинга, который вам предстоит? По правде говоря, Angular — блестящий фреймворк в том, что касается продуктивности разработчика, и он «спонсируется Гуглом», иными словами, Гугл его поддерживает. Но обратная сторона этого — порог входа в Angular невероятно высок, и вам нечем похвастаться, когда вы вынуждены менять работу.
Мы делаем всё наоборот. Мы рассматриваем современные браузеры как «статус кво», и, вполне логично, если какой-то браузер не соответствует «статусу кво», мы добавляем ему наши клёвые поведенческие полифилы. Таким образом они, как минимум, получают хеш-роутинг!
Мы заботимся не о тех вещах.
Первым должно идти содержимое Скопировать ссылку
Что бы нам стоило сделать вместо этого, так это вернуться к истокам. Пустим содержимое по проводам так быстро, как это возможно с помощью серверного рендеринга. Затем, как только страница загружена и пользователь видит и может использовать содержимое, добавим дополнительную функциональность на JavaScript. Если вы хотите использовать что-то недоступное устаревшим браузерам (например, History API), в первую очередь подумайте, стоит ли это вообще делать. Может быть, вашим пользователям будет лучше без этого. В случае с History API, вероятно, лучше оставить старые браузеры на модели «запрос-ответ», чем пытаться имитировать History API при помощи хеш-роутинга.
Тот же принцип применим и к другим аспектам веб-разработки. Нужно дать возможность оставлять комментарии? Используйте <form>
— или AJAX, если доступен JavaScript и как следует поддерживается XMLHttpRequest
. Хотите отложить загрузку CSS, чтобы избежать блокировки рендеринга, и использовать встроенный в страницу критический CSS? Прекрасно, но, пожалуйста, используйте тег <noscript>
как запасной вариант для тех, у кого отключен JavaScript. Иначе рискуете поломать стили для них!
Упоминал ли я одно очевидно кривое свойство хеш-адресации? Когда вы не можете рендерить на сервере, поскольку вам неизвестна хеш-часть запроса? Правильно, Твитер будет вынужден поддерживать специальный рендеринг на клиенте и в обозримом будущем — до тех пор, пока хеш-запросы не перестанут стучаться на их сервера.
Прогрессивно улучшать всё на свете! Скопировать ссылку
Резюмируя: мы должны перестать изобретать необычайно умные решения для рендеринга на клиенте, которые при этом не дают какой-либо возможности рендеринга на сервере. За исключением тошнотворных костылей вроде использования PhantomJS, чтобы рендерить клиентские страницы на сервере. Я уверен, никто не в восторге от анонса Angular 2.0 — слишком много критических изменений при фактическом отсутствии выгоды. Подождите, вы говорите, тут есть выгода? Я не слышу вас из-за грохота, с которым обваливается поддержка браузеров.
Полагаю, вот что случается, когда вы не беспокоитесь о прогрессивном улучшении.
В следующий раз, когда вы начнете какой-нибудь проект, не надо просто вслепую совать в него AngularJS, Bootstrap и jQuery, да и дело с концом. Найдите возможность сделать распределяемый рендеринг, используйте React или Taunus, или что-нибудь ещё, что позволит вам не писать одно и то же дважды. Иначе не делайте рендеринга на клиенте вообще.
Стремитесь к простоте. Используйте прогрессивное улучшение. Делайте это не ради людей, у которых отключен JavaScript. Делайте это не ради людей, которые пользуются старыми браузерами. Делайте это не для того даже, чтобы покончить с прошлым подходом. Сделайте это, потому что вы осознаете важность доставки содержимого первым. Сделайте это, потому что осознаете, что ваш сайт никогда не должен выглядеть одинаково на каждом устройстве и в каждом браузере. Сделайте это, потому что сайт станет удобнее. Сделайте это, потому что люди с мобильном интернетом не должны страдать от болезненного пользования кривым вебом.
Опирайтесь на основы веба, стройте на них, вместо того чтобы всё ухудшать и требовать, чтобы ваши клёвые вебдванольные JavaScript-фреймворки загружались, парсились и исполнялись до того, как вы начнете заниматься рендерингом содержимого, доступного людям.
Вот чеклист, который вам пригодится:
- HTML первым делом: выдайте людям полноценную разметку сразу, как только возможно
- Отдайте немного CSS, встройте внутрь страницы критически важные стили (кстати, а ведь эта штука тоже пришла из Google!)
- Отложите загрузку остального CSS при помощи JavaScript до срабатывания
onload
, но обеспечьте запасной вариант при помощи<noscript>
- Отложите загрузку картинок со вторых экранов
- Отложите загрузку шрифтов
- Отложите весь JavaScript
- Никогда больше не полагайтесь только на клиентский рендеринг
- Приоритизируйте загрузку содержимого
- Кэшируйте статические ресурсы
- Экспериментируйте с кэшированием динамических ресурсов
- Кэшируйте запросы к базе данных
- Кэшируйте вообще всё
А также в первую очередь пользуйтесь элементами <form>
, а затем достраивайте сверху всякий AJAX. Нет! Это не для сумасшедших противников JavaScript. Если JavaScript всё ещё грузится, ваш сайт будет бесполезен без элементов <form>
, гарантирующих, что функциональность будет доступной. Некоторые люди вынуждены иметь дело с медленными мобильными соединениями, смиритесь с этим. Например, вы можете пользоваться Google Chrome, чтобы эмулировать мобильное соединение.
Не приковывайте себя к всеобъемлющей технологии, которая может просто умереть в ближайшие несколько месяцев и оставить вас на мели. С прогрессивным улучшением вы никогда не прогадаете. Прогрессивное улучшение означает, что ваш код всегда будет работать, поскольку вы всегда фокусируетесь в первую очередь на предоставлении минимальной доступности, а затем добавляете возможности, функциональность и дополнительное поведение — уже поверх содержимого.
Пользуйтесь фреймворками, но выбирайте те, что дружат с прогрессивным улучшением: такие как Taunus, hyperspace, React или Backbone с Rendr. Все они так или иначе позволяют вам сделать распределенный рендеринг, и, хотя Rendr слегка нескладный, он работает. Taunus и hyperspace
позволяют работать «модульным способом» — они дополнены небольшими модулями, и вы можете извлечь из этого выгоду. React по-своему ужасен, но, по крайней мере, вы можете использовать его для рендеринга на сервере, и как минимум Facebook им пользуется.
Исследуйте способы разработки более модульных архитектур. Прогрессивное улучшение не подразумевает, что в результате вы получите монолитное приложение. На самом деле совсем наоборот. «Прогрессивность» подразумевает, что вы получите приложение, основанное на принципах веба. Это означает, что по большей части оно будет работать, даже когда выключен JavaScript. Оно может даже потерять некоторые ключевые составляющие своей функциональности, если, скажем, вы забыли добавить запасной вариант в виде <form>
в важные места вашего сайта.
Но даже это было бы нормально, потому что вы бы поняли значение прогрессивного улучшения, и могли бы добавить этот <form>
, чтобы ваш сайт стал более дружелюбным к старым браузерам и людям с мобильниками. Вы бы научились не рендерить ваше приложение только на клиенте, и вместо этого использовать распределенный рендеринг или только лишь рендеринг на сервере. Вы бы осознали значение таких маленьких трюков, как использование элементов <noscript>
или установки OpenSearch. Вы бы научились уважать веб. Вы бы вернулись на дорогу для тех, кто действительно заботится о вебе.
Вы бы научились не разрушать веб.