Турболинки - самая крутая технология, которую использует не так много сайтов. И я попытаюсь убедить вас в этом, когда мы вместе создадим простое приложение. Как вы спрашиваете? В три шага: во-первых, мы создадим наше приложение, как в давние времена (например, примерно в 2008 году). Во-вторых, мы прореагируем и рассмотрим добавленную сложность. И, наконец, мы посмотрим, как мало нам нужно изменить в нашей первой версии, чтобы реализовать большую часть преимуществ, которые мы получили, в первую очередь добавив React!

Так что давай повеселимся, как в 2008 году! 🎊

Даже не шутя, это была нирвана веб-разработки. Браузеры (не разработчики) отправляли данные на серверы, а серверы отправляли обратно HTML. Полный, каждый раз туда и обратно. Разработчики фактически отображали <form> теги! Конечно, иногда мы отправляли немного JavaScript, но для любой реальной работы мы полностью ожидали, что пользователи будут отправлять запросы обратно на наш сервер. Приложения в основном не имели гражданства. А жизнь была проста 🏕

На мгновение вернемся к этому. Давайте создадим приложение TodoMVC, как в 2008 году!

Если вы никогда раньше не видели ничего подобного, они выглядят так:

Итак, некоторые требования:

  1. Давайте будем настоящим приложением. Многие (все?) Примеры на TodoMVC просто записываются в локальное хранилище. Насколько это полезно? Таким образом, мы сохраним задачи в базе данных, связанной с сеансом пользователя, чтобы при обновлении страницы задачи не терялись (но они могут исчезнуть, когда пользователь закрывает свой браузер).
  2. Добавьте новую задачу в поле вверху.
  3. Полные индивидуальные задачи.
  4. Удалите отдельные задачи («x» справа от задачи).
  5. Заполните все отображаемые задачи (щелкнув шеврон вверху).
  6. Очистить все, показывая завершенные задачи (ссылка внизу).
  7. Дважды щелкните, чтобы отредактировать существующий. Сохраняет размытость. Escape отменяет редактирование.
  8. Фильтр по «Все», «Активные» и «Завершенные» (ссылки внизу).

Так что это не пустяк. Давайте построим! Используя Express ... как будто это 2008 год ... хотя Node не появился до 2009 года ... и, э, Express ... ну, не раньше 2010 года ... хорошо, мы построим его, как будто это 2008 год! 😬

Старая версия Skool

База данных

Честно говоря, мы это сразу замалчим. Для всех версий этого приложения требуется одна и та же версия, и на самом деле она не меняется. Код связан внизу, если вы хотите узнать больше, но вкратце мы будем использовать Sequelize, SQLite и одну todos таблицу со столбцами session_user_id, title, completed. Плюс к вашим типичным столбцам id, created_at и updated_at.

next() 👈 Хех, понял? Это шутка Экспресса, хотя и плохая.

Маршруты

Быть RESTful кажется разумным. Давайте поместим их в таблицу и подумаем о пути, HTTP-глаголе, который мы хотим использовать, и описании того, что он делает.

Хорошо, давайте посмотрим несколько кодов:

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

На мой взгляд, в этой простоте есть элегантность 😍

Текущий пользователь (session_user_id)

Мы передадим управление вашей сессией некоторому промежуточному программному обеспечению, называемому экспресс-сессия. И добавьте это к нашему app.js:

hex() - это функция, которую я, несомненно, украл, но не могу вспомнить, откуда 😬 В любом случае, ее реализация не важна, но она здесь для любопытных.

Вид

Статические активы

У нас не будет много приложений без CSS. И нам понадобится хотя бы немного JavaScript, чтобы переключить нашу задачу на редактирование. Итак, давайте расскажем Express, как обращаться с этими активами:

  1. Скопируйте это в public/css/application.css. И создайте пустой public/js/application.js file.
  2. Добавьте это в app.js перед listen

Круто, теперь нам просто нужно добавить эти файлы в наш «‹head›», о котором мы поговорим в следующей части.

index.ejs

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

Поскольку мы создаем приложение Express, мы будем использовать шаблоны EJS. Во-первых, мы должны сообщить Express, что это план:

А затем создадим наш шаблон. Давайте заполним часть скелета, который будет отображать наше последнее приложение. И мы можем пойти дальше и заняться включением наших статических ресурсов в <head> часть нашего HTML:

И на этом мы должны зайти так далеко:

Создание и отображение Todos

Мы займемся этим вместе, поскольку ни один из них сам по себе не очень полезен.

Создание

Во-первых, нам нужен способ получать задачи от наших пользователей. В 2008 году мы использовали <form> tags. Итак, давайте добавим один к нашему <header> скелету:

И это все, что нам нужно со стороны браузера для создания задачи - немного HTML. Тем не менее, мы должны рассказать Express о нашем плане:

И теперь мы можем прочитать содержимое off req.body в нашем маршруте:

Что подводит нас к…

Отображение Todos

Давайте добавим к нашему маршруту GET /, чтобы мы могли получить доступ к задачам в нашем шаблоне:

Теперь мы можем получить доступ к переменной с именем todos в нашем шаблоне. Давайте добавим к скелету <ul>, который мы добавили ранее:

Это приведет нас так далеко:

И это все! У нас нет JavaScript в браузере. У нас просто есть сервер, который будет отвечать на запрос GET к /, отображая HTML с формой и с некоторыми задачами с переменным числом в теге <ul>. Когда браузер отправляет эту форму POSTs в /, где у нас есть обработчик маршрута, ожидающий, чтобы прочитать title вне тела, userId вне сеанса, вставить строку в базу данных, и перенаправить браузер обратно туда, где это было. Наш браузер отправляет еще GET на /, и мы получаем ту же форму с нашим новым делом, добавленным в HTML.

Формы, формы, формы и другие формы

Мы можем продолжать использовать этот шаблон отправки данных на сервер, позволяя серверу выполнить некоторое обновление, а затем сообщая нашему браузеру, куда идти дальше. И <forms> являются строительным блоком для этого.

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

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

Удаление задачи

Форма с кнопкой отправки:

И способ поддержки этого:

Удаление всех выполненных задач

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

А на сервере мы сможем получить доступ к этим идентификаторам в req.body.ids. Итак, мы можем написать наш маршрут так:

Переключение задачи

Хорошо, наконец-то нам нужно написать немного JavaScript, чтобы получить желаемое взаимодействие. Для реализации этой функции мы по-прежнему будем использовать <form>, но на нем не будет кнопки отправки. Вместо этого у него будет всего лишь один флажок <input>, и когда пользователь щелкнет его, наш JavaScript отправит для него форму. Давайте взглянем:

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

Итак, следующее, что мы делаем, - это определяем функцию, которую мы хотим запускать всякий раз, когда событие click распространяется на элемент, соответствующий селектору [data-behavior~=submit_form_when_clicked]. И эта функция находит ближайший к этому совпадающему элементу тег <form> и отправляет его.

Давайте посмотрим на HTML:

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

На нашем сервере req.todo.completed будет либо "0", если флажок снят, либо ["0", "1"], если он установлен. Посмотрим на маршрут:

Array.from(completed).slice(-1)[0] берет completed и превращает его в ["0"], если он "0", оставляет его в покое, если он уже ["0", "1"], затем захватывает только последний элемент. Затем мы можем проверить, равно ли оно "1", чтобы определить, следует ли помечать задачу как выполненную или нет.

Выполнение всех задач

Для предпоследнего <form> мы можем объединить идеи из двух последних в одну форму, которая помечает все задачи как выполненные:

Итак, мы поместили все ids в <form>, мы добавили скрытый <input> для флажка и подключили прослушиватель JavaScript для отправки формы при щелчке флажка, а затем на сервере:

Редактирование задачи

Это требует от нас немного большего на стороне JavaScript, чтобы построить взаимодействие, которое мы хотим. Конкретно:

  1. Пользователь может дважды щелкнуть задачу для редактирования. Благодаря нашему CSS, для этого все, что нам нужно сделать, это добавить класс editing к <li> для задачи.
  2. При размытии мы отправим правку на сервер.
  3. Они могут отменить редактирование, ускользнув.

Напишем обработчики для этих трех случаев:

И HTML:

И нам нужно немного изменить наш маршрут PATCH /:id, чтобы обработать title изменение:

И это не так уж плохо. Нам действительно пришлось написать пару «уловок», чтобы немного обойти поведение HTML. И нам действительно пришлось написать небольшой JavaScript, чтобы получить желаемое взаимодействие. Но мы по-прежнему можем использовать <forms> в качестве строительного блока для нашего взаимодействия. И пока мы это делаем, мы позволяем браузеру быть рабочей лошадкой для связи с нашим сервером.

Фильтрация

Последнее, что нам нужно решить, - это фильтры внизу. Нам не нужно ничего особенного, только обычные ссылки, и мы передадим нашему шаблону немного больше контекста с нашего сервера. Начнем с HTML:

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

И теперь у нас есть GIF сверху! 👏

Хорошо, и что? Зачем так писать? Так что мы можем сравнивать подходы. Это наша база. Это простое приложение, написанное максимально просто. Нет никаких реальных зависимостей (пара промежуточных программ, но это всего лишь экосистема). Инструментов для сборки нет. Нет интерфейсных библиотек / фреймворков. Просто сервер, который отправляет в основном HTML плюс немного JavaScript и CSS.

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

А теперь держитесь за эту версию нашего приложения, мы вернемся к ней. Но сначала давайте вернемся в 2019 год. И что может быть лучше, чем переписать то, что мы только что написали, для работы на клиенте?

Реагировать на версию

Я, наверное, немного пропущу. Это вообще не учебник по React. Этот первый раздел был небольшим учебником, но, поскольку мы так редко пишем приложения таким образом, я хотел обратить особое внимание на эту настройку. Здесь я просто хочу взглянуть на некоторые сложности, которые мы добавляем, когда переносим логику во внешний интерфейс.

Нет больше HTML

Мы этого больше не пишем. Вот что будет отображать наш сервер:

Прохладный. Вот код JavaScript, который мы отправим для заполнения этого #root элемента на стороне клиента:

Прохладный. Я предполагаю, что серверы плохо генерируют и отправляют действительно полезный HTML? Теперь мы взяли на себя ответственность определить, что делать, пока пользователь ожидает загрузки наших ресурсов JavaScript, и как остановить службы, которые сканируют Интернет (например, индексаторы Google), воспринимая нашу веб-страницу как пустую. Да, есть способы исправить и то, и другое, и это даже не обязательно для каждого приложения, но это решение остается за нами.

Теперь нам нужно синхронизировать Todos

Источником правды для задач наших пользователей, несомненно, является наша база данных. Если его там нет, значит, его не существует. Раньше, когда мы просто позволяли серверу отображать шаблонный HTML, мы могли просто читать из базы данных непосредственно перед обработкой шаблона. Когда мы перемещаем рендеринг на клиента, мы больше не контролируем время таким же образом, и теперь нам нужно совмещать два хранилища данных: то, что существует в базе данных, и то, о чем знает наше клиентское приложение.

Так что это значит для нашего приложения React? Во-первых, мы должны определить, как мы загружаем задачи изначально. И во-вторых, как мы выполняем обновление задач. Это приносит множество вещей, которые мы теперь должны решить и за которые нести ответственность (читать, писать код для обработки), например: Что мы визуализируем во время загрузки задач? Как нам загрузить наш первоначальный список задач? Когда пользователь обновляет задачу, как мы ее визуализируем - на мгновение наша локальная копия задач более актуальна, чем наши базы данных? Мы должны отправить эти обновления на сервер, но это асинхронный процесс - должны ли мы отображать самые свежие данные, которые у нас есть, и согласовывать любые различия после попытки обновления на сервере?

В этом приложении мы постараемся упростить:

  1. Мы получим задачи с сервера, как только наше приложение будет отрисовано. Пока он загружается, мы будем относиться к нему так же, как и к отсутствию задач.
  2. Каждый раз, когда мы выполняем обновление, мы отправляем этот запрос на сервер, а при успешном ответе с сервера мы повторно загружаем _все_ задачи.

Итак, давайте изменим наш GET /, чтобы он поддерживал это:

Поэтому, если мы нажмем / с запросом GET, ищущим HTML (как определено заголовком ACCEPT), мы отправим обратно этот HTML только с div#root, в противном случае, если мы нажмем ту же конечную точку, ищущую JSON, мы отправим наши задачи как JSON.

Это не проще ... и реагирует:

У нас есть эффект, который отвечает за загрузку задач всякий раз, когда мы выполняем рендеринг, и либо наш фильтр запроса (search) изменился, либо наш cacheKey. cacheKey - это неиспользуемая часть состояния, которую мы отслеживаем, чтобы дать нашим дочерним компонентам возможность запускать повторный рендеринг, а затем повторную выборку задач. Вот что делает refresh. Эту функцию мы можем передать потомкам, которые при вызове будут вызывать setCacheKey с новым UUID. О, и мы должны передать эту refresh функцию всем

Внутри нашего эффекта у нас есть функция get, которая является легкой оболочкой вокруг fetch. Поскольку связь с сервером больше не предоставляется бесплатно, как в случае с <forms>, - за это мы несем ответственность. каждый. Пользователь. взаимодействие.

И это версия simple.

Рендеринг Todos

Давайте подробнее рассмотрим наши компоненты Todos и Todo.

Наш Todos компонент принимает все наши задачи, отображает форму для переключения всех наших задач и выполняет итерацию по каждому из них, отображая отдельный Todo компонент:

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

А что касается компонента Todo, давайте разберем его по частям. Сначала настройка:

Каждый Todo отслеживает два элемента состояния: 1) редактируется ли он и 2) какой новый заголовок. Я ненавижу бит 83. Опять же, мы должны взять на себя то, что браузер раньше делал за нас - управление значением, которое в настоящее время находится во входных данных. Этот шаблон - это то, что мы должны делать в React. И это определенно не проще, чем было раньше. На самом деле React явно плох в обработке форм.

Но, честно говоря, жонглирование нашим «в настоящее время редактируемым» состоянием стало лучше. Давайте добавим JSX:

Хорошо, по общему признанию, есть элегантность для className={editing && “editing”} и onDoubleClick={() => { setEditing(true) }} 😍 То же самое для нашей кнопки уничтожения - onClick={destroyTodo} - это намного лучше, чем рендеринг формы со скрытым _method=delete вводом и с кнопкой отправки. Но это должно быть. В этом вся ценность (хех, еще одна плохая шутка 😬) React!

Знаете, что не стало лучше? Это заголовок ввода. Обработчик onChange для обновления нашего состояния значением ввода? Это грубо. И нам нужно такое решение для обработки состояний и обновлений для каждого. не замужем. Вход. любая из наших форм сбора.

Также посмотрите на этот onBlur. Теперь мы отвечаем за синхронизацию состояния после получения ответа от нашего сервера. Раньше можно было отправить форму и, так сказать, забыть. Сервер собирался сказать нам, куда идти дальше. Теперь мы несем ответственность за то, чтобы представление сбрасывалось после обновления, как путем вызова refresh() для сброса состояния нашего родителя, так и путем вызова setEditing(false) для сброса нашего собственного. Мне это не нравится.

Маршрутизация

Или, на самом деле, больше компонентов и больше состояний, теперь они просто хранятся в адресной строке. Опять же, я в основном пропущу это, но я просто хочу отметить, что это еще одна вещь, которую браузер использовал для нас. Теперь мы отвечаем за синхронизацию адресной строки с состоянием нашего приложения. Как? Сначала мы передаем это состояние нашему App с помощью компонента <Route>. Затем мы используем эти специальные Link компоненты здесь, чтобы сообщить адресной строке и нашему приложению: Эй, обновите , как если бы кто-то перешел по этой ссылке.

Инструменты для сборки

Я не хочу бить давно мертвого коня, но Господи, почему это так сложно? Я мог бы использовать create-react-app, но у него есть собственный сервер Express, поэтому я застрял в том, чтобы передать ему запросы прокси обратно к тому, который мы только что создали, и дважды запускали yarn start. Это чертовски мерзко.

Вот то, что я сделал вместо этого. Я думаю, это круто. Я мог бы быть единственным.

В любом случае, об этом хватит.

Так действительно ли все, что было в React, лучше, чем то, что было раньше? Что ж, это точно не проще. Но это избавляет нас от необходимости выполнять полные обходы сервера, и это всегда будет быстрее. Но это не единственный способ добиться такого результата ...

Турболинки

Полный гребаный круг, детка! ⚫ Так что же такое Turbolinks? Это интерфейсная библиотека, которая ускоряет навигацию по нашему веб-приложению, особенно в той версии 2008 года, которую мы написали выше, с минимальными изменениями в этом HTML-стиле, отображаемом на сервере. Если наша старая версия skool представляет собой базовый подход, построенный на нативных конструкциях, предоставленных нам HTML, HTTP и браузером, и если наша версия React в значительной степени избавляется от этих шаблонов для создания более настраиваемых клиентских конструкций - Turbolinks находится где-то в центре.

Если мы просто включим его в наш <head> и запустим, Turbolinks превратит все наши последующие ссылки в удаленные запросы для нового HTML в этом месте, заменит <body> новым результатом и объединит новые теги <script> в <head> - все без перезагрузки страницы. Если бы все, что мы хотели сделать, это отправить GET-запросы для HTML-страниц, Turbolinks превратит наше приложение в одностраничное приложение всего для одной строчки клиентского кода и вообще без настройки нашего сервера.

Это восхитительно! 😲 Но ... это не все, что нужно нашему приложению - Turbolinks не может сделать для нас две вещи без нашего участия:

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

Чтобы исправить №1, Turbolinks дает нам заголовок Turbolinks-Location, который мы можем установить в окончательном ответе на наш перенаправленный запрос. Чтобы получить решение, которое работает через любое количество перенаправлений, нам нужно будет сохранить, куда мы перенаправляемся в сеансе, и в маршруте, который обрабатывает этот перенаправленный запрос, мы будем искать это значение в сеансе, и если он существует, напишите заголовок.

Вот как это может выглядеть для нашего приложения Express (помните, что мы уже использовали промежуточное программное обеспечение сеанса для userId):

В маршруте с перенаправлением мы ищем заголовок Turbolinks-Referrer, потому что, если он установлен, мы знаем, что Turbolinks попадает в эту конечную точку, и если мы его находим, мы переходим в магазин, куда мы перенаправляемся в сеансе.

Затем мы добавляем в наше приложение специальное ПО промежуточного слоя, которое при каждом запросе будет проверять, установлено ли это значение сеанса, и если оно установлено, мы запишем соответствующий заголовок:

Хорошо, это решает №1.

Для №2 нам нужно внести некоторые изменения в интерфейс и бэкэнд. На сервере, если мы получаем форму, отправленную удаленно, нам нужно ответить полезной нагрузкой JavaScript, которая вызывает Turbolinks.visit с адресом, в который мы хотим выполнить перенаправление. На стороне клиента нам нужно 1) отправить форму удаленно и 2) оценить возвращенный фрагмент JavaScript.

Давайте сначала посмотрим на клиентский код:

Мы можем использовать этот обработчик для отправки любого тега <form>, украшенного data-remote="true". По сути, он отправляет форму так же, как браузер, только с fetch. Затем, когда он получает ответ - и помните, что ответ должен быть небольшим фрагментом JavaScript - он добавляет тег <script> к <head>, чтобы браузер оценил этот ответ.

Честно говоря, я бы даже не стал этого делать сам. Ознакомьтесь с библиотекой rails-ujs. Он из Rails, но на самом деле не привязан к нему. Это дает вам data-remote материал и многое другое.

Хорошо, и на стороне сервера:

И это решает # 2. Теперь наш <form> может быть отправлен удаленно, и когда это произойдет, мы ответим двумя строчками JavaScript, которые сообщают Turbolinks, что делать.

Так что да, это было бы чертовски противно - писать каждый раз. Но оба пути через это if / else делают одно и то же - они redirect. Просто если мы знаем, что это была удаленная отправка / настройка Turbolinks, которая привела нас сюда, нам нужно «перенаправить» немного иначе.

Так что, если вместо того, чтобы писать все это каждый раз, мы заставим res.redirect просто выполнять if проверку за нас? Мы, конечно, можем это сделать, и это именно то, что turbolinks-express делает для нас. Он также выполняет Turbolinks-Location хранение и настройку за нас. Таким образом, если вы добавите промежуточное ПО из turbolinks-express в свое приложение, вам фактически не придется ничего писать для поддержки серверной части Turbolinks. Просто используйте res.redirect, как всегда! 🎉

Так что все, что есть в Turbolinks, лучше нашей версии 2008 года? Что ж, это также определенно не проще. Но он позволяет избежать повторных обращений к серверу, поэтому работает быстрее. Почти всегда скорость и сложность противостоят друг другу. Но здесь мы использовали почти все преимущества производительности одностраничного приложения по цене удаленной отправки форм и примерно 60 строк кода на стороне сервера для res.redirect функции monkeypatch Express 🐵

Возможно, более важным, чем объем кода, который потребовался, является то, насколько точно это вписывается в нашу парадигму написания веб-приложений с 2008 года. Это почти без проблем! И для этого мы устранили множество проблем, которые нам пришлось бы решать при использовании React. Нет обмена данными. Нет синхронизации двух версий истины. Нет необходимости иметь дело с асинхронной структурой SPA. Никаких других бесчисленных других проблем и сложностей, связанных с React, мы не берем на себя, когда присоединяемся к этой экосистеме.

Кроме того, то, как Turbolinks заменяет весь наш <body>, позволяет нам просто сосредоточиться на нашем первоначальном рендеринге. Да, это все еще просто файл index.ejs. Нам никогда не нужно беспокоиться об обновлении отдельных разделов, что мы немного видели, когда нам приходилось отменять состояние нашего todo, которое было переключено для редактирования. Мы просто всегда выбрасываем то, что у нас есть, и все заново рендерим - весь index.ejs файл.

Есть ли у Turbolinks недостатки? Конечно. Нам действительно нужно быть немного более структурированными, когда мы пишем интерфейсный JavaScript, который преобразует наш HTML. И замена всего <body> не всегда будет самым эффективным способом что-то сделать. Будут времена, когда React будет быстрее. Но это честно. Как мы уже говорили ранее, простота почти всегда достигается за счет некоторой скорости.

В конце концов, Turbolinks - отличный способ получить (большую часть) производительности от одностраничного приложения с (большей частью) простотой серверного рендеринга 🌆

Вывод

Я думаю, что по мере развития отрасли появляется тенденция выплескивать ребенка вместе с водой в ванну, поскольку мы учимся строить вещи по-новому. React (и другие фреймворки SPA) являются текущим воплощением этой тенденции. Определенно бывают случаи, когда React добавляет ценности, даже необходимо, но не для большинства приложений. В большинстве случаев это не стоит дополнительных сложностей. Возникает вопрос, почему это так повсеместно?

Трудно сказать наверняка. Но я думаю, что отчасти это связано с тем, что как только мы узнаем инструмент или способ создания вещей, естественно использовать их для каждой вещи. Кроме того, я думаю, что в отрасли преобладают люди без исторического контекста. Я работаю с большим количеством разработчиков, которые не знают, на что было похоже создание веб-сайтов в 2008 году, - некоторые из них не создавали веб-сайты до React, - и это затрудняет сравнение подходов. И я сомневаюсь, что это уникальная история.

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

Коды

Сложно включить все, поэтому, если вы хотите присмотреться, это все в этом репо в разных ветках:

Изначально опубликовано в Gray Matter.