- PVSM.RU - https://www.pvsm.ru -

Блог а-ля Хабр, выбор технологий

В предыдущей серии (Как слямзить Хабр по-быстрому [1]) получил MVP [2] на базе Create React App [3] (CRA). Но это SPA [4], что не очень подходит, когда требуется индексация в поисковиках. Хорошо, нужен Server Side Rendering [5] (SSR). И желательно из коробки, а не на коленке. Крайне расточительно тратить ресурсы на самостоятельную разработку базовых технологий. Как выбирать платформу с поддержкой SSR? На практике, конечно, POC [6]. Попробую реализовать CRUD [7] с формой ввода на Material-UI [8], рассматривая кандидатов: React Starter Kit [9] (RSK), NEXT.js [10] и Electrode [11] (не путать с Electron [12]).

Исходники на GitHub [13].

Роутинг

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Поддержка

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

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

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

По пути выяснил:

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

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

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

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

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

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

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

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

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

const increment = createAction('INCREMENT')

const reducer = handleActions({
  [increment]: (state, action) => ({
    counter: state.counter + action.payload
  })
}, { counter: 0 })

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

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

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

$ 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 в проекте. Просто не обращал внимания раньше, но как же без неё хорошо!

P.S. Про Material-UI

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

Автор: comerc

Источник [32]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/251156

Ссылки в тексте:

[1] Как слямзить Хабр по-быстрому: https://habrahabr.ru/post/322084/

[2] MVP: https://en.wikipedia.org/wiki/Minimum_viable_product

[3] Create React App: https://facebook.github.io/react/blog/2016/07/22/create-apps-with-no-configuration.html

[4] SPA: https://ru.wikipedia.org/wiki/%D0%9E%D0%B4%D0%BD%D0%BE%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5

[5] Server Side Rendering: https://rajdee.gitbooks.io/redux-in-russian/content/docs/recipes/ServerRendering.html

[6] POC: https://en.wikipedia.org/wiki/Proof_of_concept

[7] CRUD: https://ru.wikipedia.org/wiki/CRUD

[8] Material-UI: http://www.material-ui.com/#/

[9] React Starter Kit: https://reactstarter.com/

[10] NEXT.js: https://zeit.co/blog/next

[11] Electrode: https://habrahabr.ru/post/316818/

[12] Electron: https://electron.atom.io/

[13] Исходники на GitHub: https://github.com/comerc/yobrRSK

[14] через конфигурацию express: https://github.com/kriasoft/react-starter-kit/blob/feature/redux/src/server.js#L92-L94

[15] через конфигурацию express: https://github.com/zeit/next.js/blob/master/examples/parameterized-routing/server.js#L22

[16] zeit.co: https://zeit.co/

[17] с оговорками: https://github.com/zeit/next.js/issues/861

[18] есть пример: https://github.com/zeit/next.js/tree/master/examples/ssr-caching

[19] решение в продакшене: https://github.com/electrode-io/electrode-react-ssr-caching

[20] выход есть: https://www.npmjs.com/package/custom-react-scripts

[21] now: https://zeit.co/now

[22] CSRF: https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0

[23] праздник: https://github.com/electrode-io/electrode/blob/master/samples/universal-react-node/src/server/plugins/csrf.js

[24] csurf: https://www.npmjs.com/package/csurf

[25] Presentational and Container Components: https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.mq2t11t3r

[26] styled-jsx: https://github.com/zeit/styled-jsx

[27] ducks-pattern: https://github.com/erikras/ducks-modular-redux

[28] redux-actions: https://github.com/acdlite/redux-actions

[29] js-hyperclick: https://atom.io/packages/js-hyperclick

[30] Material-UI: http://www.material-ui.com/

[31] Демо: https://yobr-aimknojfwg.now.sh/post/add

[32] Источник: https://habrahabr.ru/post/325088/