Как стать автором
Обновить

Современный Frontend: проблемы и пути решения. Пишем React-like приложение со строгой типизацией без сборщиков

Время на прочтение 5 мин
Количество просмотров 13K
Всего голосов 34: ↑32 и ↓2 +30
Комментарии 55

Комментарии 55

НЛО прилетело и опубликовало эту надпись здесь

Это только для тех, у кого сохранилась бритва Оккама.

проприетарный синтаксис

Я не совсем уверен, что вы понимаете значение слова "проприетарный". Синтаксис jsx расширяет спецификацию ЭКМА-262. А спецификация jsx, ЕМНИП, даже распространяется на условиях CC BY 4-й версии.

Корпорации продвигают проприетарные вещи, а не развивают стандарты — «Hello, World» на любом популярном фреймворке не работает в браузере;

Что?

Колоссальное количество зависимостей в приложениях, сложности настройки сборки.

Безусловно, чего только стоит история с left-pad. Хотя эта проблема прослеживается не только во форнте.

Проблема зависимостей остро прослеживается и в backend из экосистемы JS. Для более «legacy» вещей по типу java особых проблем с пакетами и сборкой не наблюдается уже лет 10-15 как минимум. Хотя, например, в плюсах/сях дела совсем плохи, но там и требования другие.

Rust, кстати, с карго очень неплох на первый(да и второй) взгляд.

Причины кроются как в изначальных недостатках npm, так и в общей скорости изменений на изначальном этапе развития, относительной молодости экосистемы, и количества софта. Про качество тоже можно порассуждать, хотя «рыночек порешает» пока что никто опровергнуть не смог —условное «деньги платят, SpaceX пишет на JS» не перебьёшь без слива кармы, да и стоит ли?

java особых проблем с пакетами и сборкой не наблюдается уже лет

А там случаем нет "бинарной совместимости" с тем, что уже не получается собрать? Мне кажется это сильная сторона (ещё одна) статически типизированных языков.


Ну и, как мне кажется, вне web разработки, мало кого интересует вес получившегося бинарника. Нередкое явление когда какое-нибудь, скажем, десктопное приложение просит зависимостей под 50 MiB. Во фронте за такое бьют ногами, ибо каждому пользователю это всё грузить… Отсюда и перегибы с DRY в виде left-pad и подобных штук.


А ещё безалаберность приводит к тому, что пакет где полезной нагрузки 15 строк тащит за собой в node_modules кучу тестов, криво указанные dev-зависимости, всякие ридми и документацию. В итоге node_modules под 400 MiB, а итоговый JS-bundle со всем этим добром меньше MiB до gzip.


Я к тому что везде есть свои нюансы.

Отсюда и перегибы с DRY в виде left-pad и подобных штук.

11 строк --- это, простите, уже слишком. Я всё ещё буду думать, что это из-за того, что люди прочитали "Don’t repeat yourself" и побежали применять этот принцип везде, не оценивая риски.

Согласен. Всякий раз подключая такую крошечную библиотеку я думаю, что никто не мешает все эти left-pad сгруппировать в какой-нибудь один пакет где будет сразу несколько десятков типовых утилит для работе со строками. Никто ведь не мешает сделать много endpoint-ов, как например сделано в lodash.


Вот пример такого left-pad: @mapbox/geo-viewport. 73 строки кода. Неужели их нельзя было засунуть в сам mapbox :)

Согласен. Всякий раз подключая такую крошечную библиотеку я думаю, что никто не мешает все эти left-pad сгруппировать в какой-нибудь один пакет где будет сразу несколько десятков типовых утилит для работе со строками. Никто ведь не мешает сделать много endpoint-ов, как например сделано в lodash.

+1, иногда появляется ощущение, что нормальных программистов на жс просто нет. Это, конечно, не так, но всё же некоторые моменты выглядят странно.

Вот пример такого left-pad: @mapbox/geo-viewport. 73 строки кода. Неужели их нельзя было засунуть в сам mapbox :)

Посмотрите на isarray, там совсем печально.

This module is proudly supported by my Sponsors!

Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my Patreon. Not sure how much of my modules you're using? Try feross/thanks!

var toString = {}.toString;

module.exports = Array.isArray || function (arr) {
  return toString.call(arr) === '[object Array]';
};

А он хорош! :-) И даже сюда автор затащил зависимость от какого-то tape. Благо хоть dev-зависимость.

Я с вами полностью согласен, хотя достаточно сложно сравнивать джаву и жс.

Я не совсем уверен, что вы понимаете значение слова "проприетарный". 

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

Что?

Примеры, приведенные в документации angular и react, не запустятся в браузере без инструментов сборки.

С Vue поторопился такие выводы делать, спасибо что отметили!

Примеры, приведенные в документации angular и react, не запустятся в браузере без инструментов сборки.

Это я понял, но при чём тут

Корпорации продвигают проприетарные вещи, а не развивают стандарты

? Необходимые инструменты сборки не являются проприетарными, да и само их использование не является чем-то плохим.

ES модули… в браузере… Поэтому их можно и нужно использовать в продакшене.

Зачем и кому нужно? Одна из проблем — каждый последующий уровень вложенности это очередной последовательный запрос. Условно с latency в 1000ms и глубиной в 10, ваше приложение будет грузиться 10 секунд (вместо одной). Никакой HTTPS2 не спасёт. В первых имплементациях импортов доходило до того, что lodash грузился 21 секунду.


В лучшем случае вы сможете как-то заранее уведомить браузер о полном древе всех задействованных ресурсов… коих в большом проекте может быть много тысяч. Не помню завезли это уже или ещё нет. Так или иначе вам снова потребуется автоматизация. А заодно вы лишаетесь dead code elimination и прочих оптимизаций.


Импорты и экспорты удобны для разработки. Но come on, для чего они вам в production-е? По крайней мере в текущем виде.


Чтобы решить эту проблему сейчас разрабатывается сложная спецификация нового формата файлов — bundle-ов. Недавно что-то бегло читал про них. Но они ещё дальше от ваших идей. Это снова нужно натравливать софт на кодовую базу.


Следующий инструмент, который может помочь нам, это HTM. Удобная библиотека, с помощью которой можно писать JSX-like-синтаксис с помощью tagged templates, который будет работать прямо в браузере.

Который парсит ваши шаблоны прямо в браузере. Для небольших проектов ещё сгодится. Но прошу не тащите подобное в крупные. Ahead of time — наше всё.


писать все типы в JSDocs.

Как человек который длительное время страдал такой фигнёй (вынужденно, не было возможности моментально перевести большую кодовую базу на TS), я торжественно заявляю — это адов изврат. Не делайте так без острой необходимости.


На мой взгляд, такой подход хорошо подойдет как для быстрой проверки гипотез, так и для приложений среднего размера

А ещё лучше для проверки гипотез и приложений среднего размера подойдёт единожды сделанный простой шаблон. Он же вам поможет и тестовые задания в разные компании проходить.

Чтобы решить эту проблему сейчас разрабатывается сложная спецификация нового формата файлов — bundle-ов. Недавно что-то бегло читал про них.

А не поделитесь? У меня как раз месяц назад была задача по разъезду общего репозитория на две команды и три репозитория. И я только на неожиданное поведение зависимостей при использовании npm link угробил день и кучу нервных клеток пока в ходе отладки не понял в чём дело.

Было бы приятно хотя бы пофантазировать про появление нормальных jar-ников / dll-ников, у которых не нужно будет писать скрипт генерирующий пять немного отличающихся объектов с алиасами (для импортов webpack на основе алиасов tsconfig, для импортов webpack на основе peerDependencies, для импортов jest на основе алиасов tsconfig, для импортов jest на основе peerDependencies, для параметра shared в ModuleFederation на основе peerDependencies).

Кажется вот оно


npm link

Любые мои попытки использовать npm link оборачивались вселенскими страданиями. Избегаю symlink-ов в nodejs всеми силами.

Зачем и кому нужно?

К сожалению, сборки для продакшена не избежать из-за проблемы о которой говорите вы, минификации и прочих оптимизаций. Но можно настроить сборку в которой таргет будут ES модули. Приложение нужно будет собрать, но только один раз для релиза.

Который парсит ваши шаблоны прямо в браузере.

Это также решается продакшен сборкой и использованием babel-plugin-htm

Это также решается продакшен сборкой и использованием babel-plugin-htm

Что и требовалось доказать. Убегали от babel, вернулись к babel. Осталась разве что возможность запустить проект в dev-режиме без сборки. Неплохо, но не сказать, чтобы уж сильно нужно.

Осталась разве что возможность запустить проект в dev-режиме без сборки.

Пока сборка в dev-режиме у меня занимает меньше времени, чем переключение из IDE в браузер (а она обычно столько занимает, даже на очень больших проектах — инкрементальные билды уже давно побороли проблему роста времени сборки при росте объема кода) — эта возможность в принципе нафиг не сдалась.

Везёт вам. А мы обмазались тайпскриптами, линтерами и бабель плагинами. В итоге мало того что даже инкрементальная сборка подтормаживает, так ещё и приходится пару раз в день\два её убивать и перезапускать. Либо она сама от Out of memory дохнет. Особенно у меня умиляет, что из-за разных AST у меня одновременно работает минимум 4 instance-а от typescript-а: vscode ts, vscode eslint ts, webpack ts, webpack eslint ts. Ух. Но, имхо, оно того стоит. Но во мне ещё теплится надежда, что когда-нибудь это всё перестанет так сильно глючить и лагать.

Но во мне ещё теплится надежда, что когда-нибудь это всё перестанет так сильно глючить и лагать.

За прошедшие годы чуваки-олимпиадники отшлифовали код инструментов до блеска. Сомневаюсь, что будет прорыв в скоростях.

Babel написан быть гибким, а не быстрым. Неспроста esbuild уделывает его на два десятичных порядка по скорости. Typescript тоже написан быть гибким и удобным. А если учесть, что Babel и Typescript и Eslint имеют свои собственные AST (т.е. все делают одно и то же с нуля, без коллаборации), то там есть что оптимизировать. А если подружить webpack и редактор...


В общем всё возможно.

Я тоже обмазался. Не тормозит. Понятно, что зависит от объема проекта и сколько там всего подтаскивается, но на проектах в 20 и в 60Кloc без особого зверинца в сторонних зависимостях — не тормозит. При том что полный билд очень неспешен, а вот инкрементальный — очень быстр.


Причем на меньшем из них сборка идёт через бабель, а не через tsc (tsc стоит в параллель чисто для проверки типов), а на большем — через tsc. Разницы особой нет, времена когда tsc шибко тормозил — кажется вполне прошли.

а вот инкрементальный — очень быстр.

У нас где-то 1.5-2 секунды на JS часть, и 5-10 секунд на TS часть (она в отдельном потоке и не блокирует билд). +- 80-90K LOC. Вспоминая как на моей машине Scala проект по 20-30 секунд на инкрементальный билд тратил, а на полный больше 2 минут… соглашусь с вами. Во фронте это ещё по божески.

Я вот давно отказался от проверки типов по всему проекту при каждой пересборке — при блокирующем режиме это блочит билд и отображение в браузере, при неблокирующем — медленнее, чем бабель с вырезанием ts-типов, при неблокирующем параллельном — отстает от реального кода, который мог несколько раз измениться, а ошибки выдадутся нерелевантные.


При необходимости (после завершения куска логики) можно вручную вызвать проверку типов, и обязательно — на pre-commit+CI. Это максимально удобно, и скорость инкрементальной сборки на современных сборщиках почти мгновенная.


Еще в Бабеле запилили хороший кеш, который тоже значительно сокращает время сборки (перешел на него с happypack/thread-loader и стало быстрей, чем параллельная сборка в нескольких процессах).


А про один AST на разные инструменты, конечно, согласен, но вряд ли в обозримом будущем смогут договориться Eslint+TS+babel+IDE на единый всем подходящий формат, так как это будет блочить развитие и оптимизацию каждого инструмента в отдельности.

Это максимально удобно

Не сказал бы. Да, за счёт запаздывания ошибки бывают нерелевантными, и это бесит. Но вот выяснить, что у тебя полпроекта развалилось на pre-commit очень обидно. Хочется своевременной реакции. И желательно быстрой. Я бы так работать не смог, т.к. рефакторинг спутник моей жизни. Он как ремонт. Никогда не заканчивается.


при неблокирующем — медленнее, чем бабель с вырезанием ts-типов

Не совсем понял мысль. При неблокирующем как раз и получается что одновременно babel+плагин и ts-fork. Получается быстрый инкрементальный билд, и медленный догоняющий TS.


У вас какая-то другая схема?

Под "блокирующим" я подразумевал ts-loader без transpileOnly, т.е. билд не будет собираться, если есть ошибки в типах — это на удивление распространенный, но на мой взгляд неэффективный подход. Под неблокирующим имел в виду как раз ваш вариант.


Сам люблю часто рефакторить, но тут все зависит от архитектуры. Если в приложении нет связки по строкам и динамических названий структур, то в 95% случаев достаточно делать findUsages в IDE и при рефакторинге интерфейсов и параметров все места легко открыть и поправить. Поэтому ситуация, когда на pre-commit ругается ts у меня крайне редкая, и в целом намного удобнее использовать IDE чем потом в консоли смотреть, что развалилось, и вручную переходить на каждый файл и искать строчку с ошибкой.


Если архитектура не подходит и findUsages не работает корректно — тогда да, ваш вариант имеет место быть, и поможет найти развалившиеся места.

Понятно, спс. Да, у нас очень много алгебры типов, поэтому ломается в очень неочевидных местах. Нужен весь граф связей, которых никаким find usages не получить. Да и пробегать всё это вручную то ещё удовольствие.

По статистике реакта много вопросов. Никто не знает наверняка сколько из этих загрузко реальных проектов а сколько загрузок от изучающих реакт. А этим собственно и должна заниматься наука статистика.
У реакта есть сильные и слабые стороны. Сборщики тут не при чем. Я сам максимально держался без сборщиков пока не понял что загружать все amd это путь в никуда. А раз использовать сборщики то уходит аргумекнты про JSX и вариант поддержки модульности.
Я могу конечно ошибаться но если убрать учащхся ии любопытсвующих реакт будет не более популярен чем vue.js
Но vue.js будет набирать популярность а реакт ее терять и вот почему.
Какое-то время фронтенд (собственно верстка) разрабатывался версталщиками ("версталами") в виде html/css
В 2000-е эта верстка нтегрироваалсь бэкендерами в роекты через шаблонизаторы например twig. Потом было некоторое безвременье с ajax/web2.0 и переход angular/react. Появилась специализация интеграторов верстки в js-фреймворки. Эти разработчики занли понмемного и css и js о преимущественно знали фреймворк. Естественно что это нерациональный процесс. Одни верстают другие нтегрируют в компоненты. И сейчас идет полным ходом становление новой спецализации фронтенд разработчик который отлично знает верстку и знает фреймворк. И вот для такого типа angular/react оказался сложен. React сам по себе не сложен но он для раоты требует redux/mobx и т.п. а вот это уже сложно. Поэтому новое поколение фронтендеров выбирает преимущественно vue.js

React + MobX сложный? это вы так пошутили?

Mobx проще чем redux. Но это не значит что он прост для восприятия верстальщиками.

Как только мы переходим от фронтэнда, как от чего-то создаваемого в стиле fire & forget к сильно переиспользуемому многофункциональному коду — там что угодно не будет простым для восприятия верстальщиками.

Много ли функционального и переисмользуемого сделано на реакта в результате. Я знаю только react admin и везде его использую и materialUI. А так даже календаря выпадающего нормального нет.
Тут я бы сказал даже больше. Вместо того чтобы сделать проект просто, как бы сделал его средний верстальщик продвинутый сеньор реакт начинает мудрствовать и делать то что по сути не нужно. А после этого спрашивает хотел бы я узнать как это бы мог сделать рядовой верстальщик.

Много ли функционального и переисмользуемого сделано на реакта в результате.

Внутри компаний — очень много. Я бы даже сказал, что я пока еще не видел ни одной конторы, которая бы плотно сидела на реакте и не имела бы приемлемой библиотеки компонентов для своей предметной области (это если они не пользуются material или если его не хватает).

Воспринимать ли это как плюс реакта иликак его минус?

Так а с чем сравнивать? Вы пишете на ваших "простых для верстальщиков" решениях что-то, что потом хотя бы полдюжину лет живет, эволюционирует, и непрерывно изменяется? Вы имеете статистику расходов по поддержке этих простых в написании решений?

Как правило, "универсальные" кулибокомпоненты самодеятельных реакт разработчиков вообще не подлежат поддержке

Я видел самого разного качества компоненты уровня кнопочек и списочков, но никогда настолько плохие, чтоб они "не подлежали поддержке". Это далеко не rocket science.
Самое "не подлежащее поддержке" — это как раз полное отсутствие переиспользуемых компонент.

Если из статистико по Реакту убрать изучающих, то и из статистики по Vue/Angular тоже. Более того, количество интересующихся React'ом это тоже отражение его популярности.
Ещё можно глянуть на колучество вакансий по фреймворкам. У меня вышло соотношение примерно 6.5/3/1 React/Angular/Vue

Да конечно. Статистику хотелось бы иметь реальную.
Я говорю о тенденции. Реакт будет реально снижаться Вью расти. Как только бизнес поймет что вместо одного верстальщика и одного сеньора реакт можно нанять одного верстальщика на Вью. При этом экономия будет не Только в зарплате а в сроках разработки эта ситуация стремительно поменяется
А что до популярности у учащихся один из 30 может быть найдет работу

можно нанять одного верстальщика на Вью.

А давно во Вью не нужно писать логику?

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

Стихия рынка оставит оптимальный вариант, отсеяв верстальщиков которые не смогут развиться в сторону логики и сеньоров реактив которым скушно изучать вёрстку. Вью более подходит для работы полноценного фронтенд разработчика так как включает в себя работу со стором. Только и всего. Как шаблонизатор angular, react, vue, svelte, marko это практически одно и то же.

Вью более подходит для работы полноценного фронтенд разработчика так как включает в себя работу со стором.

Vuex вообще-то отдельная библиотека и ни разу не проще чем тот же redux (она с него внезапно писалась).


А для всего остального работает "теорема Эскобара" (тем более Вью при необходимости в jsx тоже умеет)

Вью вообще писалось с реакта и разработчиком реакта. Я исходу не из умозрительных построений сих реальной практики. Вью на порядок легче для освоения чем реакт. Код фронтен разработчика на Вью достаточно хорошего качества. Аналогичный фронтенд разработчик пытающийся разрабатывать на react redux mobx производит очень плохой код. Нужен отдельный сеньор реакт для интеграции. Мой вывод это организационно и экономически невыгодно и поэтому исход предрешён этим.

React сам по себе не сложен но он для раоты требует redux/mobx и т.п. а вот это уже сложно. Поэтому новое поколение фронтендеров выбирает преимущественно vue.js

Все верно, поэтому сеньоры выбирают react.

Эти сеньоры скоро останутся без работы. Так как css и верстку толком не знают.

Многие из этих людей:
— начали свой путь с книг типа «Bulletproof CSS»
— писали свои reset.css
— застали «зоопарк браузеров»
— прошли через «Верстку независимыми блоками» к БЭМ
— писали свои сборщики
— etc
… и ничего, пользуются реактом.

А в чем собственно проблема использовать сборщик? Для традиционных языков/технологий требующих компиляции никого почему то не смущает наличие компилятора, SDK, IDE и даже наоборот - богатый SDK более привлекателен из-за наличия многих полезных функций упрощающих написание и проверку кода. Искренне не понимаю этого стремления к простоте.

Тогда придётся признать успех Svelte, что совершенно неприемлемо для react-сообщества основанного на хейтерстве.

Свелт вирусно распространялся но что то последний год тормознул немного чисто по субъективной оценке. Так как реально сталкивался с мелкими проектами на свелте а сейчас нет. Кстати проекты с которыми я сталкивался были все на sapier который Харрис решил дальше не разрабатывать. Это было таким неожиданным разочарованием.

В какой то статье, то ли об WebKit то ли от Blink, читал что быстрее всего броузер умеет работать с HTML и медленнее с JS. Поэтому для меня всегда казался странным подход писать HTML внутри JS и потом через WebPack запаковывать все это в монстр бандлы.

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

Соглашусь с автором, текущее положение дел с реатом как негласным стандартом, не годится.

js фреймворки решают задачу устранения сложности и раздробленности проекта с которым столкнулись разрабротчики ajax/web2.0 Естественно этот процесс получился итеративным. Получили новые проблемы как Вы правильно сказали с промзводительностью. Воьбщем-то решение нашлось в виде universal приложений это nex.js/nuxt.js
Но в реальности многие разработчики да и заказчики сейчас на волне марктингово хайпа на это не обращают внимание и говорят "реакт хочунимагу" Потом проавда приходит SEO аудит и все начинают думать а как вообще выполнить указание если с сервера приходит HTML


<body><div id=app></div></body>

«Hello, World» на любом популярном фреймворке не работает в браузере

На Vue.js -- работает. Без сборщика, без разделения файлов. Это описано на первой странице документации, а Vue.js входит в тройку популярных фреймворков.

https://vuejs.org/v2/guide/

Для «Hello, World» команда React предлагает инструмент create-react-app, который загружает на вашу машину 2,5 миллиона строк кода зависимостей на JavaScript.

Ну так потому что реакт это не язык. А на js, вывод строки вполне компактный. Не путайте теплое с мягким. Аргумент в стиле - а вот чтобы в Андроид студии вывести hello world ее нужно скачать установить и создать андроид проект...Серьезно?Уже на этом аргументе желание читать статью поубавилось.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий