Pull to refresh

Блог а-ля Хабр, выбор платформы

Reading time 5 min
Views 15K

В предыдущей серии (Как слямзить Хабр по-быстрому) запустил проект на базе Create React App (CRA). Но это SPA, что не очень подходит, когда требуется индексация в поисковиках. Нужен Server Side Rendering (SSR). И желательно из коробки, а не на коленке. Крайне расточительно тратить ресурсы на самостоятельную разработку базовых технологий. Как выбирать платформу с поддержкой SSR? На практике, конечно, POC. Попробую реализовать CRUD с формой ввода на Material-UI, рассматривая кандидатов: React Starter Kit (RSK), NEXT.js и Electrode (не путать с Electron).


Исходники на GitHub.


Роутинг


RSK имеет собственный велосипед — universal-router. Загружать внешние данные в Redux при серверном рендеринге предлагается через конфигурацию express (или koa, или hapi).


NEXT.js подошёл к вопросу роутинга оригинально, предложив использовать имена файлов в папке pages. Внутри обычные React-компоненты со статическим методом getInitialProps, в котором предлагается выполнять загрузку внешних данных при серверном рендеринге. Если же нужно кастомизировать обработку запросов, то это делается самым естественным способом — через конфигурацию express (или koa, или hapi).


Electrode, в отличии от других рассмотренных платформ, не заставляет отказываться от redux-router. А это значит, что на время реализации фронтенда, можно вернуться к разработке на CRA. Вся магия серверного рендеринга внутри electrode-redux-router-engine.


Производительность


Очень интересно наблюдать, как загружается сайт zeit.co, который работает на NEXT.js. Когда открываешь страничку списка постов, приходит 15 MB траффика, но дальше переходы на страницы постов происходят мгновенно — всё кешируется в браузере. Однако это безобразие можно отключить через свойство prefetch компонента Link. Offline-first обещан в NEXT.js (с оговорками), но в Electrode уже реализован. Кеширование SSR: в NEXT.js есть пример, но в Electrode решение в продакшене.


В RSK замечено не менее интересное поведение. Когда переключаю пункты списка истории строки ввода URL в Хроме, то наблюдаю выполнение роутов на сервере, хотя ещё не подтвердил свой выбор. А в результате готовая страница выдаётся с сервера быстрее.


Настройка сборки


NEXT.js и Electrode скрывают свою реализацию, но позволяют конфигурировать сборку. CRA запрещает конфигурировать сборку, только через eject (народ бился полгода за право прикручивать SCSS), но выход есть. В RSK только форк, нужно следить за обновлениями проекта и мержить их руками — плата за полный доступ к исходному коду платформы.


Сборка и деплой


RSK (как и CRA) убивает загрузкой новой страницы браузера при начальной сборке, NEXT.js и Electrode не имеют этого недостатка.


Electrode очень медленно выполняет начальную сборку.


NEXT.js предлагает замечательный сервис для деплоя now, и он не привязан к конкретной платформе.


Работа над ошибками


В RSK ужасный вывод ошибок, кроме того неправильно работает дебаг по Source Maps, курсор смещается на пару строк ниже. В Electrode просто невозможно понять, что пошло не так, если ошибка на стороне сервера. В NEXT.js ситуация значительно лучше, и обещают доработать ещё в ближайшем будущем. CRA тут эталон, и хочется сказать отдельное спасибо за вывод в консоль сообщений ESLint в процессе работы над проектом. Кстати, RSK превратил проверки ESLint в форменную пытку, я выпилил pre-commit.


Поддержка


NEXT.js подкупает разнообразием рецептов, хотя некоторые важные вопросы пока без ответа, но динамика развития проекта обнадёживает. RSK и Electrode хорошо дополняют общий набор. На примере CSRF: вообще пока ничего в NEXT.js, в Electrode праздник, в RSK нашёл отсылку на csurf.


Вчера, 27 марта вышел NEXT.js 2.0, спустя полгода после старта. Движуха вокруг NEXT.js намного больше, в сравнении с RSK и Electrode. Если судить по звездочкам на GitHub, то NEXT.js догоняет CRA, учитывая разницу в возрасте.


За технологиями стоят конкретные персоны. Это тоже важный момент выбора. NEXT.js развивает ZEIT — основатель Guillermo Rauch был техническим директором и соучредителем LearnBoost, помните TJ Holowaychuk?


P.S. По пути выяснил


Что разделение на components и containers - это лишнее

Многие проекты руководствуются рекомендациями Presentational and Container Components, но уважаемый автор признаётся в сносках, что концепция разделения спорная, и компоненты можно смешивать. А если это так, то зачем тащить чемодан без ручки? Все компоненты проекта удобнее хранить в одной общей папке. Какие плюсы:


  • Простота навигации по файловой системе.
  • Уникальные имена компонентов проекта.
  • Импорт без боли ('../../../../../..').

Когда проект вырастет, следует дробить его на приватные npm-пакеты, инкапсулируя реализацию. Но не выращивать дерево подпапок внутри папки компонентов — развивать и поддерживать такое ощутимо сложнее. Проверено.


Дальше-больше. Попробовал CSS-Modules — отказался от BEM, но после styled-jsx не могу больше смотреть на CSS-Modules. Зачем связывать каждый рутовый элемент компонента через className, ради чего переключать контекст внимания между файлами — непонятно.


Что можно объединить actions и reducers

Достигнув просветления с общей папкой компонентов, применил ducks-pattern. Но и это ещё не всё, позвонив прямо сейчас, вы получите совершенно бесплатно возможность отказаться от констант для связывания actions-reducers, используя пакет redux-act:


// Create an action creator (description is optional)
const add = createAction('add some stuff');
const increment = createAction('increment the state');
const decrement = createAction('decrement the state');

// Create a reducer
const counterReducer = createReducer({
  [increment]: (state) => state + 1,
  [decrement]: (state) => state - 1,
  [add]: (state, payload) => state + payload,
}, 0); // <-- This is the default state

Как проще всего настроить абсолютные пути для импорта модулей в Atom

Добавить плагин js-hyperclick.


Добавить пакет в проект:


$ yarn add babel-plugin-module-resolver -D

.babelrc


{
  "presets": [
    "next/babel"
  ],
  "plugins": [
    ["module-resolver", {
      "root": [""]
    }]
  ]
}

package.json


{
  "moduleRoots": [
    ""
}

пример:


import MyComponent from 'components/MyComponent'
import MyPage from 'pages/MyPage'

Кстати, NEXT.js избавляет от бессмысленной папки src в проекте. Просто не обращал внимания раньше, но как же без неё хорошо!


Что пакет redux-form не нужен

А хотелось просто валидацию полей формы. Но 462 открытых issues как бы намекают. Я не смог себя заставить. Кода для обслуживания получается больше, чем без redux-form. И нужно думать не только о поведении формы, но как ее заставить работать с помощью этой прекрасной обертки. В морг. Невозможно угодить всем и вся. Это нужно предложить решение на каждый случай применения. Был у меня подобный печальный опыт с Meteor-овскими велосипедом AutoForm. На первый взгляд — замечательно. Описываешь конфиг и оно само тебе формы выдает! Для двух полей это работает. Но когда формы большие, да со связанными полями. Божечки. Тормозит жутко. Глючит. И опять же вынуждает тебя лезть под капот с кувалдометром. Автор забил на пулл-реквесты. Остаётся форк — вешаешь на саппорт большую кучу "универсального" кода. Оно надо?


Про Material-UI

Это давний спор с техлидом маленькой но гордой веб-студии, что никакие UI-фреймворки нам не заменят ручной труд. Понятно, что разработка интерфейсов — это хлеб с маслом. Но я убеждённый сторонник применения готовых решений. Хорошо себе представляю, какая может быть проработка деталей, имея опыт реализации проекта с чистого листа по взрослому ТЗ от гуру UI/UX-дизайна. Гайдлайн Material Design — вторая космическая скорость. Но где же его реализация? Что видел — шлак. Кроме Material-UI. Повертел-прикрутил, доработал напильником. Ну да, есть несколько недочётов. Точнее 647 открытых issues. Но пациент скорее жив чем мёртв. Демо — форма добавления/редактирования поста блога.


UPDATE


Совершил забег по кругу, и теперь могу с уверенностью сказать, что предложенный способ опционального прикручивания SSR к SPA — самый правильный (хотелка сформулирована давно).


Я же был счастлив, когда сидел на CRA. До той поры, пока не прочитал "Что взять за основу React приложения". А дальше беспрерывная борьба со сложностью окружения. Начитался issues — голова пухнет.


Все исследованные решения предлагают свои велосипеды для роутинга, которые уже можно выбросить — последняя версия React-Router реализует функционал для SSR.

Tags:
Hubs:
+16
Comments 44
Comments Comments 44

Articles