Pull to refresh

Comments 141

Aphrodite — это, получается, исток более мощного формата, чем JSX, некого файла с расширением (в будущем) *.JS_CSSX.

Почему так?

Сначала в React придумали написать HTML в файлах *.JS. Получилось, как всегда, трудночитаемо, хотя старались сделать максимум читабельности, как в Aphrodite. Следующим шагом был *.JSX. А CSS нормально уживался в JSX, потому что это — те же теги. Но когда появляется желание внести в инлайновые стили переменные (а оно появляется, и решают его через переменные Less/Sass/Stylus), появляется закономерно Aphrodite. Дальше смотрим, и видим, что что-то не то, как и ранее с HTML в JS. Дальше кто-то финансирует *.JSX, какая-то конторка, её стараются поругать, назвать костылями, неосиливателями своего же нативного кода (компоненты на *.JS). Но больше тех, кто молча уминает с удовлетворением.

И это — над React, не его часть. Вот, к примеру, есть плагин JSX для Vue.
JSX — достаточно удобное решение, при условии, что в него перестанут пихать бизнес-логику (идеально — исключительно функциональные stateless-компоненты, что достигается использованием redux или flux).

Вероятно, можно было бы избежать такого количества хейта, назвав технологию не JSX, а HTMLX.
в него перестанут пихать бизнес-логику (идеально — исключительно функциональные stateless-компоненты, что достигается использованием redux или flux).

И куда ее тогда пихать, если компоненты — без логики, а редакс-слой в идеале тоже логики не содержит, только редьюс? Или редакс — только для приложений без логики?
В контексте связки React + Redux, есть «компоненты», которые не имеют ни состояния, ни бизнес-логики, а только принимают на вход свойства и выдают на выходе DOM. Есть «контейнеры», которые сами никакого JSX не содержат, но умеют правильно внедрять глобальное состояние и действия в «компоненты».

Соответственно, бизнес-логика распределяется между действиями и контейнерами. Последние, как правило, содержат логику на уровне «взять event.target.value и использовать его как аргумент name у действия changeName». Если бизнес-логика простая (отправить несложный HTTP-запрос к REST API), то можно оставить ее в действиях (точнее, action creators). Если логика сложная, то можно вынести ее в отдельный класс типа PostService, получив классическое Multitier-приложение (но ни Redux, ни React, тут уже ни при чем).
В контексте связки React + Redux, есть «компоненты», которые не имеют ни состояния, ни бизнес-логики, а только принимают на вход свойства и выдают на выходе DOM. Есть «контейнеры», которые...

На самом деле компонентами называют и те, и те, а они уже делятся на Presentational и Container. Хотя, де-факто, это просто хипстерские названия для обычных View и толстого Controller'а.

Что я не понял — зачем вы в оригинальном комментарии упомянули о Редаксе, если такое разделение возможно и без него.
Теоретически, конечно, возможно. Я, кстати, тоже исходил в своих объяснениях из упомянутой вами статьи. На практике, вы все-равно либо придете к Redux, либо напишете свой аналог.

толстого Controller'а
Где же он «толстый», если это просто инжектор зависимостей, занимающий, как правило, десяток строк? Реальной бизнес-логики в нем нет (а то, где она должна быть, вы решаете уже сами — я предлагаю классическое разделение на UI-, Service- и Domain-layer).
Ну вы уже тащите «корпоративного» Фаулера в радужный мир хипстеров, где его отрицают. Тут уже начнутся аргументы вроде «ООП И ФП не отрицают, а отлично дополняют друг друга», а следовательно спор не имеет смысла, потому что оба элемента можно отлично использовать вместе — ООП для архитектуры, а ФП — для локальной обработки данных.

На практике, вы все-равно либо придете к Redux, либо напишете свой аналог

Либо использование MobX
Я не считаю себя сторонником ФП, но когда есть возможность описать представление «чистыми» функциями, то я ей пользуюсь. В конце концов, можно посадить «хипстеров» писать UI-слой, а бизнес-логику отдать суровому enterprise'у, и транспилировать ее потом из какой-нибудь Java (привет, GWT!). Для извращенцев в Java 8 добавлен новый JavaScript-движок, так что можно повторить процесс и в обратном направлении.
ООП, кстати, не отрицает чистоту, а очень даже поощряет в необходимых мерах.
А что мешает в ООП создавать чистые методы или даже классы, которые делают свою работу и умирают?
Но зачем тогда ООП? Класс со стейтом противоречит идее «чистоты». Чистый метод не привязан к инстансу, зачем его тогда держать в классе?
С натягом, можно притянуть сюда const-методы из C++:

class Hello {
public:
    Hello() : value(6) {}

    int GetValue() const { return value; }

private:
    int value;
};

Формально, это как-бы «чистая функция», ведь она возвращает одинаковый результат для побайтово равных объектов (в данном случае, для всех, потому что Hello::value не меняется).
Я, к сожалению, не могу похвастаться экспертизой в плюсах и слабо понимаю, что тут вообще написано, полькольку большую часть времени пишу на js и компании, но если уж ничего нигде не меняется, то я напишу const HelloValue = 6;.
В C++ у каждого метода есть «скрытый» аргумент *this. Модификатор const после названия метода сообщает компилятору, что this ссылается на константу, т. е. создается контракт, согласно которому функция Hello::GetValue не изменяет внутреннего состояния объекта.

Это можно «притянуть» к тому, что для двух равных объектов метод всегда вернет одинаковый результат. Точно также, как какая-нибудь
int foo(int a) { return a + 1; }
вернет одинаковое значение для одинаковых a.
Но зачем тогда ООП?

А затем, что он не заставляет использовать чистоту там, где она не нужна, а нужен изменяемый стейт.

Класс со стейтом противоречит идее «чистоты».

Частично, ведь сам по себе он не чистый, но вы иногда можете использовать его чисто.

Чистый метод не привязан к инстансу, зачем его тогда держать в классе?

Почему вы мыслите столь ограничено? Почему чистый метод не привязан к инстансу?
Почему вы мыслите столь ограничено? Почему чистый метод не привязан к инстансу?
Ну почему ограниченно? Я просто стараюсь минимизировать количество сущностей и абстракций. JS предоставляет модули, в которых я могу складывать все, что ни попадя, в том числе и эти чистые функции и константы. Зачем наворачивать вокруг них лишние сущности в виде классов?
Вы, скорей всего, ошибочно приняли мою точку зрения, я не против ООП в языках, не поддерживающих module/package-level сущности, кроме классов (привет java). Я просто не вижу смысла наворачивать классы.

Поинт про комбинирование подходов полностью поддерживаю.
То есть вы не пишите классы просто чтобы не писать классы? И в JS их не пишите только потому что можете не писать?

Да, я понимаю, что вместо класса можно сделать структуру, содержащую данные и функции, которые этот объект обрабатывают как чисто, так и грязно. Получится старый добрый процедурный стиль конца 60-х. А со строгой типизацией это будет даже работать так же как в ООП только будет другая форма записи.

Как на меня, механика ООП просто поприятнее:
— не нужно импортировать эти функции, когда ты получаешь структуру в процедуру или объект в метод
— ide автоматически подсветит тебе все возможные варианты, когда ты напишешь myItem.<alt-space>
— ты получаешь дополнительные удобные механизмы вроде полиформизма в ООП понимании этого слова
— Удобную функцию-конструктор
— Возможность использовать более короткие имена:

unit.move({ y: 1 })

// значительно приятнее, чем

moveUnit(unit, { y: 1 }})

// я уж молчу об

newWorld = { ...world, {
  units: { ...world.units, [
    [unitId]: {
      ...world.units[unitId],
      y: world.units[unitId].y + 1
    }
  ]}
}}

// Ну или если завернуть это в чистую функцию:

newWorld = { ...world, {
  units: { ...world.units, [
    [unitId]: moveUnit(world.units[unitId], { y: 1 })
  ]}
}}

// Или покороче:

newWorld = moveUnitInWorld(world, unit.id, { y: 1 })


Вы ведь не будете называть свою процедуру «move», ведь двигать можно что угодно?

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

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

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

Я просто пишу код используя ООП и, при этом не отказывают от чистого кода, когда это облегчит поддержку приложения.
при этом не отказывают от чистого кода
Мне кажется, у вас какой-то культ слова «чистый», потому что выражение «чистый код» — это даже близко не про «чистые функции» и «неизменяемые объекты».
Что ж, дайте ваше определение термина «Чистота». Я говорю о детермированности и отсутствии побочных эффектов. А вы?

И почему культ именно у меня, если я как раз говорю, что делать культ из чистоты — глупо и вредно. Какое-то странное у вас понимание термина «культ».
Я говорю о детермированности и отсутствии побочных эффектов. А вы?
«Чистый код» — это красиво спроектированный код, противопоставление т. н. «спагетти-коду». Он может как использовать функциональный подход, так и не использовать его (изменяемое состояние, побочные эффекты, недетерминированность и т. д.)

И почему культ именно у меня, если я как раз говорю, что делать культ из чистоты — глупо и вредно.
Ну вот, опять. Смиритесь с тем, что не все, что имеет в своем названии «чистый», связано с ФП :-) В данном случае было бы правильнее: «И почему культ именно у меня, если я как раз говорю, что делать культ из функциональщины — глупо и вредно».
Ну хорошо, что мы выяснили, что я подразумеваю под термином.

что имеет в своем названии «чистый», связано с ФП

Конечно, чистота в смысле детермированности и отсутствии побочных эффектов (видите, как вы все усложнили, теперь приходится уточнять термин) — не обязательно показатель функциональности, но функциональность — обязательно чистота (все целые числа — числа, но не все числа — целые).

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

делать культ из функциональщины — глупо и вредно

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

И вот чистоту в смысле детермированности и отсутствии побочных эффектов, которая так популярна в ФП можно взять на вооружение и в ОО программировании для определенных задач. И этот код не обязательно будет функциональным.
Мне кажется, вам пора спать :-) Перечитайте еще раз всю ветку отсюда. Все это время я вообще никак не комментирую ваше мнение, а просто пытаюсь предостеречь от использования неправильных терминов. То, что вы имели ввиду под словом «чистый» и так ясно из контекста, но это просто неправильное слово.
Ну вот на википедии сказано очень коротко: Чистота́ (в отношении языка программирования) — отсутствие побочных эффектов. Если перейти на английскую статью — там есть интересное уточнение:
An expression is said to be referentially transparent if it can be replaced with its corresponding value without changing the program's behavior

Но вот я не нашел ни одного упоминание, что термин «Чистота» можно применять исключительно к ФП. Аргументируйте или дайте пруфы, пожалуйста. Потому что пока это выглядит как «это ведь наше, ФПшное, не забирайте, пожалуйста»
Вам точно стоит выспаться :-)
Потому что пока это выглядит как «это ведь наше, ФПшное, не забирайте, пожалуйста»
Напротив, я говорю, что «чистая функция» — это из ФП, все остальное, что имеет в своем названии прилагательное «чистый», к нему не относится. Потому что это вы упоминали выше «чистый метод», «чистый код» и т. д. в контексте ФП. Откройте поиск по странице и введите туда «чистый», сильно удивитесь.
Раз мне стоит выспаться — вам стоит быть точнее. Можете, пожалуйста, цитировать мои слова, а не абстрактно про поиск. Я ввел и меня ничего не удивило.

Вы все еще не привели аргументов, почему общий термин программирования «Чистота» можно применять только в контексте ФП. Я понимаю, что есть также общий и синонимичный термин, но раз вы меня поняли, то функция языка общения выполнена корректно и вы просто придираетесь.

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

Еще раз вы почему-то отожествляете понятия ФП и остальные названные. Да, ФП — это неизменяемое состояние, отсутсвие побочных эффектов, детерминированность. Но

Неизменяемое состояние само по себе — не ФП
Отсутсвие побочных эффектов само по себе — не ФП
Детерминированность сама по себе — не ФП

Почему вы стараетесь меня убедить, что если какой-то код не изменяет состояние, не имеет побочных эффектов и детерминированный — обязательно ФП? Смотрите, такой логический вывод можно сделать из ваших слов:

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


Я запишу ваши слова псевдокодом:

if (ФП) {
  ...
} else {
  изменяемое _состояние();
  побочные_эффекты();
  недетерминированность();
}


Простите, но я с этим совершенно не согласен.
Еще раз, я не спорю с вами о том, что относить к ФП, а что нет. Более того, признаться, я читаю ваши аргументы по-диагонали, поэтому не могу ни согласиться, ни не согласиться с вами. Я просто уточняю термины:
А что мешает в ООП создавать чистые методы или даже классы, которые делают свою работу и умирают?
Этот ваш комментарий вызвал недоумение не только у меня, потому что нет такого термина «чистый метод» или «чистый класс». То, что вы хотели сказать, называется «неизменяемый объект».

Я просто пишу код используя ООП и, при этом не отказывают от чистого кода, когда это облегчит поддержку приложения.
Термин «чистый код» существует, но означает совершенно другое. То, что вы хотели сказать, называется «код, написанный в функциональном стиле». Аббревиатура ФП также была бы к месту.
Вы зачем-то перевели обсуждение из конструктивного русла в терминологический спор, при этом не приводите аргументы к своим словам, а просто говорите, что вам не нравится, как я применяю термины и предлагаете мне применять неподходящие термины.

То, что вы хотели сказать, называется «неизменяемый объект».

Нет, я не хотел сказать «неизменяемый объект». Вот пример:

var nVector = new Vector3(5, 3, 1).normalized

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

«код, написанный в функциональном стиле».

Нет, это код написанный в объектно-ориентированном стиле, а не функциональном, но он не имеет побочных эффектов, он детерминированный и он не изменяет состояние. Он чистый.

И вы всё-еще не привели аргументов для своего субъективного мнения, что слово «чистый» в контексте отсутствия побочных эффектов и детерминированности можно применять только для ФП.
Я сразу дал понять, что не спорю и не собираюсь с вами спорить по существу, потому что используемый подход очень сильно зависит от задачи и личных предпочтений. Термины уточняю, потому что у других комментаторов возникли проблемы с пониманием.

var nVector = new Vector3(5, 3, 1).normalized
Это «временный объект», в JS было бы логичнее привести более распространенный случай
var ts = +new Date();

Нет, это код написанный в объектно-ориентированном стиле, а не функциональном, но он не имеет побочных эффектов, он детерминированный и он не изменяет состояние. Он чистый.
Согласен, такого термина еще не придумали, потому что «stateless-объект» — оксюморон. Еще раз, «чистый код» — это термин, который другие люди стали использовать раньше вас. Есть также одноименная книга довольно известного автора.
Роберт Мартин, лежит такая у меня дома. И что — никогда не слышали про синонимы? Тем более, это не более чем заслуга переводчика.

в JS было бы логичнее привести более распространенный случай

Какой вы молодец, что придумали пример. Вот только он обращается к внешнему состоянию (ОС), следовательно не Pure, следовательно не равносилен моему примеру.

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

Кто? Вы меня поняли, raveclassic — тоже, сомневаюсь, что wheercool написал бы следующее, если бы понял меня в вашей странной манере, особенно учитывая, что «Чистый код» как раз об ООП.
Интересно каким образом?

И, скорее всего, в следующем сообщении вы просто неправильно расставили акценты:
Вы заявили то, что ООП поощряет чистоту, а не то что позволяет писать методы, к-ые не используют состояние.

Так кто и где меня неправильно понял?

Это «временный объект»,

А еще впомните о переменных, операторах, буквах, пикселях. Ок, это временный объект. А вот тоже временный объект: getMoved(unit, { x: 1 }). И что это характеризует?

Я не понимаю, чего вы хотите добиться. Просто повторяя свое мнение, которое я считаю ошибочным — вы меня не переубедите.

Чистый («Pure», не «Clean») код — это код, который не имеет побочных эффектов и детерминированный. Чистой не обязана быть функция, им может быть и выражение:



Вы заставляете писать меня «Pure» вместо «Чистый»? Зачем? Чтобы меньше людей меня поняло? Зачем вы стараетесь нарушить работу коммуникативной функции языка?
только он обращается к внешнему состоянию
Согласен, не удачный пример в контексте ФП, пытался придумать пример временному объекту.

И, скорее всего, в следующем сообщении вы просто неправильно расставили акценты:
И, скорее всего, вы перепутали меня с другим комментатором.

А еще впомните о переменных, операторах, буквах, пикселях. Ок, это временный объект.
Поверьте, я не придумываю слова на ходу, а обращаюсь к устоявшемуся понятию Temporary Objects (по ссылке C++, но относится и к другим языкам). И, таки да, временные (безымянные) переменные бывают (что вы имеете ввиду под временными пикселями, уже не совсем понятно — возможно, пиксели, которые затираются в процессе подготовки кадра).

Я не понимаю, чего вы хотите добиться.
Теперь уже я сам не понимаю, тем более, что к CSS это не имеет никакого отношения. Но надеюсь, что другие читатели теперь смогут понять ваши комментарии благодаря моим усилиям.
Согласен, не удачный пример в контексте ФП, пытался придумать пример временному объекту.

В контексте чистоты. При чем тут ФП? Почему вы эти два куска кода называете ФП? Первый — классический ООП, пусть и чистый, второй — не имеет ни чистоты, ни декларативности.
var nVector = new Vector3(5, 3, 1).normalized
var ts = +new Date();


И, скорее всего, вы перепутали меня с другим комментатором.

Нет. Я имел ввиду, что вы, своим внутренним голосом неправильно расставили акценты в комментарии другого автора.

вы имеете ввиду под временными пикселями

А где я говорил о временных пикселях? Я говорил о просто пикселях, о просто переменных, о просто операторах и о других просто терминах, которые можно применить к моему примеру, которые будут корректны и которые, при этом, так само будут не соответствовать тому, что я хотел донести.

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

Нет, благодаря вашим усилиям теперь сложно найти полезную информацию в этой ветке, потому что вы все залили никому не нужной водой.
var nVector = new Vector3(5, 3, 1).normalized

На всякий случай еще раз акцентирую, это чистое выражение (Pure Expression), согласно определению из книги. То, что вы путаете Pure и Clean, и уж тем более, почему-то, считаете понятия «Чистота» («Pure») и «Функциональное программирование» тождественными — это лично ваши ошибки, которые лично вам стоит исправить. Выражение может быть чистым, но при этом не быть функциональным, что я и показал на примере.
Я не пишу классы там, где они мне не нужны, так как не решают задачу, которую призваны решать — инкапсуляция состояния. Там где нужно — использую. А по вашему примеру это обычный неймспейсинг. Не, это тоже удобно и иногда даже удобнее, чем import * as Vector from 'vector';.

Вы явно путаете процедурное и функциональное программирование.

Можно усовершенствовать ваш пример до const moveUnit => where =>
unit; (moveUnit :: TPlace -> unit -> unit)
, сдвигая последний оперируемый объект в конец, как это делается ну практически во всех функциональных языках для удобства композиции частично примененных функций. Бонус в «явности» передачи состояния (объекта) и передачи таких функций в фвп без необходимости ручного байндинга на инстанс и без класс пропертей). Но JS тут как всегда со своим синтаксисом.

Вы ведь не будете называть свою процедуру «move», ведь двигать можно что угодно?
Именно так бы я ее назвал в purescript, как раз таки потому, что двигать можно что угодно, так это более общий алгоритм. И накидал бы type-class'ов. Но JS тут как всегда.
Вы явно путаете процедурное и функциональное программирование

Не, я прекрасно понимаю разницу между ними. Я прекрасно понимаю разницу между С и Лисп. Или между тем, как писали на ЖС в 96-м и стараются писать в 2016-м.

Признаюсь вам честно, слышал, что говорят, что Лисп — ненастоящее ФП, а настоящее — только Хаскель. Из-за математики. Но вот это я уже не понимаю. И вчера применял термин «процедурное» именно там, где считал нужным. Если мы говорим просто о том, чтобы пользоваться процедурами в неймспейсах, которые изменяют данные в отдельно лежащих структурах, то это процедурное программирование. Для функционального необходимо кое-что большее чем «не писать классы».

Можно усовершенствовать ваш пример до const moveUnit => where => unit; (moveUnit :: TPlace -> unit -> unit)

Напишите полностью, пожалуйста.

что двигать можно что угодно, так это более общий алгоритм.

Двигать можно что угодно, но не все одинаково.
Напишу попозже развёрнутый ответ, с телефона неудобно
Итак.

По поводу 96 и 2017. Парадокс в том, что различие между процедурой и функцией минимальное — первая императивно указывает что сделать с передаваемой структурой данных (само собой мутабельно), вторая же показывает, что должно находиться в конце, после выполнения списка преобразований. Ну то есть вместо «подвинь туда, поверни сюда», у нас результат операции над объектом — это такой объект, который был подвинут туда и повернут сюда.
Да что я вам тут рассказываю, вы и так это знаете.

По поводу Лиспа и Хаскеля — оба выходят за рамки моей повседневной практики, так что чего-то дельного и подкрепленного серьезным опытом сказать по этому поводу не смогу (хотя мне тут все пытаются продать Кложу). Но я помню Алана Кея, помню эти истории про Лисп, Смолтолк и компанию. Единственное, что могу сказать, так это что Эрланг гораздо более ООП-шный (в оригинальном смысле), чем его везде форсят как ФП.

Красота же Хаскеля и смежных языков в том, что там есть type-class'ы. Это очень похоже на привычные ООП-шные интерфейсы. Разница в том, что в ООП мне нужен явный объект (инстанс класса, имплементирующего интферфейс), чтобы на нем (явно) вызывать нужные методы. Type-class'ы же позволяют определить множество, определяемое типом данных (ну например, Moveable), над которым определена операция move. Причем «глобально». Ну то есть я не вызываю метод move на инстансе класса, имплементирующего интерфейс Moveable. Я просто пишу move some_instance, а возможность операции move и, главное, ее реализация описаны в расширении множества Moveable для конкретного типа данных, реализующего (через, например, instance в Хаскеле) нужный type-class (интерфейс).

Да уж, действительно достаточно туманно и непонятно.

Но, смотрите, это позволяет писать алгоритмы более высокого уровня абстракции. Если мне нужно что-то подвинуть, например в перекомпоновке сцены, мне не нужно знать что именно, и главное как, я двигаю. Алгоритм перекомпоновки знает только (ну грубо говоря) про свою координатную ось, у него (допустим) есть список неких объектов (думаю, вы уже догадались, что они должны имплементить интерфейс Moveable). И теперь ему достаточно на списке (допустим list) этих объектов выполнить операцию map move list. Кратко и красиво. Данные отдельно (объекты), операции отдельно (алгебра над ними).

По поводу moveUnit. На TS это было бы что-то вот такое уродливое:
type Point = {
  x: number,
  y: number
};
type Unit = Point;
const move = (where: Point) => (target: Unit) => ({
  where //ну тут понятно, что операция move должны быть сложнее и над структурой Unit
});

В том же purescript это выглядело бы вот так:
type Place = {
  x :: Number,
  y :: Number
}

type Unit = Place

move :: Place -> Unit -> Unit
move place unit = unit {
  x = unit.x,
  y = unit.y
}

Изюминка в том, что частично примененную функцию move (или rotate или что угодно) можно использовать в функциональной композиции, опустив реальный аргумент (последний unit), «склеив» тем самым все операции в одну. И если у вас над типом Unit определены все нужные операции (move, rotate etc, причем отдельно от самого алгоритма), вы можете просто запихнуть структуру типа Unit в результат композиции этих функций. Если же что-то не сходится, вам компилятор тут же выплюнет ошибку.

В общем-то вышеописанное отвечает и на ваш последний вопрос — двигать можно что угодно и без разницы как. А «двигающему алгоритму» абсолютно по барабану как двигается переданный в него объект, главное чтобы для множества, описывающего его (объекта) тип, была определена функция move. Да, такая же история достигается и через интерфейсы, но гораздо более многословно, вот и вся разница.

Резюмируя, обе парадигмы решают одни и те же задачи, просто одна эффективнее в плане перфоманса (ООП), но с большим шумом, а другая элегантнее и кратче (ФП) но с большим майндшифтом и пенальти по перфомансу.

PS. На JS писать красивое ФП нереально, но мечтать хочется.
Резюмируя, обе парадигмы решают одни и те же задачи, просто одна эффективнее в плане перфоманса (ООП), но с большим шумом, а другая элегантнее и кратче (ФП) но с большим майндшифтом и пенальти по перфомансу.

Ну, как на меня, на мелких примерах ФП краше почти всегда)

Интересно вот еще что — покажи как на purescript как в итоге поменять Юнит. Ну то есть функция изменения — это понятно, просто создает юнит. А как она используется в реальном приложении, когда мне, сообственно, необходимо сдвинуть этот юнит и перерисовать потом всю сцену.
Тут какая история — для того, чтобы обновить список юнитов функцией, нужны обычные filter, map и fold.
Проблема в том, что не всегда нужно такое топорное обновление и вообще это все в вакууме и нужно где-то держать состояние, ну той же сцены, допустим. И чтобы не писать сейчас заклинание из монад, чтобы аккуратно обработать все эффекты, я просто оставлю ссылку на классную статейку.
Вы заявили то, что ООП поощряет чистоту, а не то что позволяет писать методы, к-ые не используют состояние.

Не нужно ходить далеко, проведите эксперимент. Попросите ваших знакомых написать сложение двух чисел.
Могу поделиться своим результатом. В большинстве случаев решение будет выглядеть примерно так:
class Sum {
   public int Value {get; private set;}
   public Sum(int initial) {
       Value = initial;
   }
   public void Add(int value) {
      Value += value; 
   }
}
Я сказал «в необходимых мерах». У вас всё в крайности впадает, потому архитектура жс-приложений на ФП так сложно поддерживается. Ну вот, смотрите, Unity, Vector3 — у вас есть возможность вызвать грязный метод Normalize, или чистых normalized. Если вам необходимо изменить состояние — изменяете состояние. Если необходимо обработать данные — обрабатываете и получаете чистые данные. Ну вот допустим, я в игре хочу получить все строения, которые я могу построить — напишу что-то вроде:

return buildings.Where(b => b.isAvailable)


А если у меня есть 20 строений и одно из них построилось — я напишу что-то вроде:
b.isReady = true


Или вот у меня есть маркдаун парсер на JS. Что-то вроде такого:

class UniqueAppRenderer : DefaultMarkdownRenderer { 
  public Image (token: ImageToken) {
    return <SuperAppImage token={token} />
  }
}

var tree = new MarkdownTree(input);
return tree.render(new UniqueAppRenderer());


Чем этот пример не чистый? Ну или из классики:

var square = new Rectangle(100, 50).getSquare();


На ООП вы пишете чистый код тогда, когда вам необходим чистый код. Комбинируете оба метода. И вам не приходится пересоздавать весь мир, потому что где-то открылась дверь. Именно потому на ООП написано так много столь сложного софта и так мало его написано на ФП.
Ясно. То, что вы имеете ввиду, в ООП называется immutable objects, и это не совсем тоже самое, что pure functions.
А я не говорил про «чистые функции», если один раз услышали чистоту вместе с функциями, то чистыми могут быть только функции?

Объекты, что я привел не иммутабельны. У Rectangle может измениться любая сторона и getSquare будет выдавать иной результат, ровно так и с вектором.
Согласен. Но вы же можете описать function getSquare(rectangle: Rectangle): number; и это будет то же самое.
Ухты! А на ФП, оказывается тоже можно писать чисто?!
Это басни, могу сказать из личного опыта. Когда отключаешь разум и начинаешь слушать непонятно кого, то да, так и получается. Я сначала противился редаксу, потом понял что люди были правы и что если писать так, как говорят, то реально получается редакс и что уж лучше взять оригинал. Затем я понял что редакс, это очень сложно на сложных интерфейсах, что это медленно на мобильных и образовался временный вакуум. Но потом я перешел на angular2, а после, когда пришлось вернуться на реакт, я отказался от редакса в пользу mobx + старая добрая сервисная архитектура и не поверите, все что говорят о реакте я вообще забыл. Нет вообще проблем и самое главное компоненты стали очень переиспользуемыми.
Поэтому заявления что все равно получится редак неверны.

Мне тоже очень не нравится JSX, хотя сама идея вложенных компонентов в react хорошая. Кто-нибудь пробовал вместо JSX использовать такие шаблоны?


https://github.com/wix/react-templates


Хотя все равно кросс-трансляция будет, которая тоже неприятна :( Сейчас у меня никакой кросс-трансляции, ES5 + Knockout.js.

UFO just landed and posted this here
UFO just landed and posted this here
Никакой но некоторым фронтэндерам нужно как то отбивать свой хлеб, вот и придумывают всевозможные способы извратится.
Решает проблему переопределения стилей при «наследовании». Серьезно, "!important" — это просто ад какой-то, по сравнению с inline-стилями.
Грамотное построение графа зависимостей в слое компонентов прекрасно справляется с задачей переопределения и дополнения чего бы то ни было. И никаких импортантов.
const Button = ({className, text}) => (
    <button className={`Button ${className}`}>
        {text}
    </button>
);

const SuperButton = ({className, text}) => (
    <Button
        className={`SuperButton ${className}`}
        text={text}
    />
);

.SuperButton {
    color: red;
}

.Button {
    color: green;
}
Ну так вам надо с css-модулями ознакомиться:
//Button.css
.Button {
  color: green;
}

//Button.jsx
import css from './Button.css';
export const Button = ({className}) => <button className={`${css.Button} ${className}`}></button>;

//SuperButton.css
.SuperButton {
  color: red;
}

//SuperButton.jsx
import { Button } from './Button.jsx';
import css from './SuperButton.css';
export const SuperButton = ({className}) => <Button className={`${css.SuperButton} ${className}`}/>;


А еще лучше с react-css-themr, который элегантно решает проблему мерджа класснеймов.
UFO just landed and posted this here
Ну так вы грубо нарушаете инкапсуляцию, когда внутри SupperButton знаете, какие классы висят на Button.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
СSS внутри javascript — глупейший тренд последнего времени.

React фанбоям должно понравиться, JSX ведь им нравится.

UFO just landed and posted this here
Полный бред. Статью даже не читал, так как не хочется забивать мозг лозунгами недальновидных людей.
Скоро появятся css переменные, которые позволят управлять стилями из js. И на этом точка.
Ну да, можно конечно отказаться от быстрого sass написанного на си и начать делать его аналог на js,
при условии что он все рано будет компилироваться в css, да пожалуйста, делайте, тратьте время, если получится на отлично, то им будут пользоваться. Но это будет заменой sass, а не css у которого будущие только в js.
Полный бред. Статью даже не читал

Отличное начало здравого обсуждения этой темы.

которые позволят управлять стилями из js
Уже. См. document.styleSheets.
Во времена jqery это все называлось спагетти-кодом, jsx сам по себе гадость, а с css так это вообще прямой наследник лапши.
это все называлось спагетти-кодом
jsx сам по себе гадость

Вот вот, ноги то ведь из Facebook растут, корни у которого с PHP связаны ...

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


0. CSS-in-JS это не инлайн стили


Определение стилей <div style="..."></div> это совсем не про CSS-in-JS, инлайн-стили здесь тоже не привествуются. В статье рассказывается совсем о другом. Мы просто помещаем определение стилей в тот же JS файл, что и остальной код компонента, а CSS оттуда вытаскивается на этапе сборки или server-side-рендеринга. Ваши пользователи получат такой же CSS как и всегда, все :hover, медиа-запросы будут работать как и раньше.


Когда мы разобрались, что CSS-in-JS уж как минимум не хуже обычного CSS, давайте разберемся, что мы можем от этого выиграть.


1. Переиспользование констант между JS и CSS


Довольно часто в responsive-сайтах нужно не только менять стили, в зависимости от размера экрана, но еще и исполнять какой-то Javascript. Например, зачем подписываться на клик на кнопку, которая все равно в мобильной версии не видна? Переиспользовать SASS-константы в Javascript — не самая простая задача. С CSS-in-JS вы сможете использовать JS-константы и для стилей, и для кода.


2. Упрощение кода


Вы когда-нибудь пытались взять квадратный корень из переменной в SASS? В Javascript для уже есть Math.sqrt, а в SASS придется попотеть. Кроме квадратного корня вам может понадобиться еще какая-нибудь логика в стилях, и в SASS с ней однозначно хуже, потому что он не предназначен для написания сложных алгоритмов. Кроме того, JS-функции проще покрыть тестами, чем SASS-миксины.


3. Оптимизация неиспользуемых стилей


На страницу очень часто грузятся стили для динамических блоков, которые не видны на странице сразу после загрузки. Разделять CSS на критический и второстепенный не так просто, а в CSS-in-JS, если у вас есть серверный рендеринг, это проще простого. В упомянутой в статье библиотеке Aphrodite есть поддержка server-side. Когда вы отрендерите на сервере изначальное состояние html, библиотека вернет вам стили только тех компонентов, что были на самом деле использованы при рендеринге, а остальные стили доставятся на клиент уже потом, вместе с JS.


4. Динамический CSS


С помощью CSS-in-JS можно отказаться от инлайновых стилей вообще! Определение стиля в JS может быть не только статической строкой, но и функцией:


const styles = {
    left: (props) => props.x + props.offset
}

В Aphrodite я этой фичи не нашел, но в JSS, которым я иногда пользуюсь, такая фича есть.


При изменении свойств компонента это значение будет пересчитываться, и библиотека синхронизирует его в CSS через document.styleSheets, упомянутый выше в комментариях. В классическом подходе с CSS все равно иногда не получается избежать инлайновых стилей (сделать анимацию, задать координаты для попапа), а в CSS-in-JS вы сможете сгруппировать все стили в одном месте, как всегда этого и хотелось.


Так что, в следующий раз, когда вы будете решать в своем проекте одну из проблем, описанных выше, на секунду задумайтесь, что при использовании CSS-in-JS эта проблема могла бы быть решена проще.

1, Грамотно написанный css за глаза можно сделать более чем динамическим изменяя лишь css-var из js.

2. И что? Если одному человеку из миллиона, раз в жизни потребуется квадратный корень в CSS, то это оправдывает все остальное? Зачем такие вещи в css? То что делают с квадратными корнями нормальные делают на canvas или webgl. В крайнем случаи в js оставляете логику и результаты устанавливаете, кому? css-var!

3. Вы беспокоитесь о том что мощный комп или телефон пользователя будет грузить стили на 0,005 секунды медленнее и поэтому увеличиваете нагрузку на сервера?

4. Ну вот тебе радость! В оправдание привели безумную идею инлайнстилей. Покупайте у меня аэрозоль, после применения которого можно не совать голову под автомобиль, что спасет Вам жизнь…

1) Во-первых, css-переменные нативно еще не поддерживаются, поэтому это лишь мечты о будущем, а фичи надо делать уже сегодня. Во-вторых, а переменную вы чем выставлять будете? Можно написать руками, а можно взять уже готовое решение, например JSS (5кб весит библиотечка)


2) Этот пункт больше про то, что миксины на SASS получаются очень уж громоздкие. Вот пример из Bootstrap. На JS то же самое смотрится читабельнее. Ну и как тестировать SASS-миксины по-прежнему непонятно.


3) В комментарии я привел ссылку на рассказ про то, почему критический CSS это важно и это совсем не 5мс разницы. Я понимаю вашу фрустрацию, но лучше прочитать материалы, прежде чем высказывать мнение "это всего 5 милисекунд и нагрузка на сервера мне дороже".


4) Возьмем для примера тултип. Его нужно спозиционировать с учетом того, что у него влево выступает стрелочка. Довольно типичная задача в верстке. В CSS-in-JS это будет в одном месте, очень наглядно


const arrowSize = 10;
const tooltipStyles = {
   '&:before': {
       borderWidth: arrowSize,
       // тут остальные стили для стрелочки
   },
   left: (props) => props.left + arrowSize,
   top: (props) => props.top
};

А если делать это на CSS, то часть стилей будет написана в js через $().css({top: xxx, left: xxx}), а часть про размеры стрелочки написана в другом месте в CSS? Мы снова возвращаемся к вопросу, как нам прокинуть значение размера стрелочки из CSS в JS.

1) Ну да, это завтра, но статья о том что будет ЗАВТРА.
2) Зачем Вам тестировать миксины css? Вы явно пишите что-то не в том месте.
3) Те места, где важна скорость настолько, что лишние ,5ms важны не используют пререндер на сервере, а используют сервера на java, c# или в крайнем случаи ruby или pyton.
4) Зачем Вы тултипу в js ширину задаете? В будущем тултипы вообще не будут нуждаться в влезаньи в них, ведь появятся attr + *-data.

Поэтому тема, как таковая, неверна, ведь она о будущем, а я сказал что у этой ерунды нет будущего, если они не сделают альтернативу sass, которая, как я сказал, если будет быстрее и если она будет так же компилироваться в css, то даже я ей буду пользоваться.

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

То есть ваша позиция в том, что скоро в браузеры по полной поддержат CSS-переменные, Shadow DOM, веб-компоненты, и после этого все эти временные решения будут не нужны.


Скорее всего так и будет, только Shadow DOM стандарт так до конца и не устаканился (недавно его переписали целиком заново и он называется Shadow DOM v1 в противовес прошлому v0).


В общем, можно долго ждать и надеяться на разработчиков браузеров, а задачи как-то решать надо. Поэтому я и изучаю варианты использования CSS-in-JS, в ближайшие пару лет это точно пригодится

Нет. Статья гласит «CSS в JavaScript: будущее компонентных стилей», а мое мнение, что это бред.
Обоснование этому все то что я уже сказал + то что многие делают ошибку в одном месте, а пытаются решить её в другом. И вот из-за этого появляются подобные идеи.

Будущее бывает разное.
Есть совсем далекое будущее, с межзведными перелетами, есть поближе, где все бразуеры начнут поддерживать Shadow DOM.


А есть вопрос, на чем начать пилить админку в следующем месяце.


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

  • 3. По пункту 3 не совсем ясно. Скажем сгенерировали мы CSS для некоторой страницы, без лишнего кода. Юзер кликает на другую страницу и получает новый набор CSS, большую часть из которого он уже встречал на прошлой странице. Но загружает повторно, всякий раз… Даже если юзер вернулся на ту же самую страницу. Тут уже какой-то прямо commonChunk как в webpack-е нужен? Или я сбился с толку? Как предполагается решать такие задачи?
  • 4. Я правильно понял этот пункт? Это автоматически генерируемые стили в runtime? Там же вроде речь шла о предварительной компиляции всего этого добра в отдельную CSS?
  • 5. Так и не понятно в итоге, что с каскадами? Просто похоронить как избыточную сложность? Возможно это решение, но выглядит радикально. В качестве альтернативы городить трудно-читаемых монстров через интерполяцию и зависимости (подключать наследуемые имена классов из соответствующих файлов и пробрасывать их внутрь зависимых, где подключать через ${}).

Мне сама идея более тесной взаимосвязи CSS и JS кажется интересной, т.к., на мой взгляд, в больших проектах, есть почти нерешаемая проблема в виде кучи не используемого legacy кода. А тут вроде можно всё так к друг другу поджать, чтобы оно на уровне резолва зависимостей отрабатывало. Посему всё жду серебрянной пули, идеального решения. Но куда бы я пока не глянул ― выглядит вторично и "не вкусно". Особенно когда некогда простые стили превращаются в нагромождение интерполяций, методов и разных хаков.

А смотрели themr? мне даже как-то неудобно дважды в топике советовать

Нет не смотрел, не попадался. Спасибо, присмотрюсь.

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

3) Обычно в веб-приложениях переходы по ссылкам происходят без перезагрузки страницы. Повторно ни скрипты, ни стили не загружаются.


4) Предварительно выносится критический CSS — тот что юзер увидит еще до подгрузки Javascript. Стили для попапов и других динамических штук остаются в JS, потому что все равно у пользователей с отключенными скриптами они не будут видны


5) Каскады на месте. Из нашего JS кода сгенерируется совершенно обычный CSS, hover, каскады, все можно использовать как и раньше. Вот пример из JSS: http://cssinjs.org/jss-nested?v=v4.0.1


По поводу того как это выглядит в больших проектах, можно посмотреть на документацию JSS: https://github.com/cssinjs/cssinjs Этот сайт использует их же технологию для стилей. По-моему, читаются стиили так же, как и если бы были в CSS. Пример одного файла.

Ну и кроме того CSS-переменные должны иметь глобальные имена, поэтому мы возвращаемся обратно в БЭМ, только теперь в именах переменных --my-button--background-color-default

Короче ясно одно, что сие чудо является будущим для тех, кто —
1. собирает из css картины, по очень сложным алгоритмам, для которых нужно писать тесты в миксинах.
2. для тех кто не хочет учить css и ему проще забабахать все из js.
3. для тех кто не знает сегодня что будет в css завтра, им видимо лень читать спеки.
4. тем кто делает супербыстрые сайты на медленном пререндере и ему приходится экономить на на размере css.
5. Тем кто в подобный рассказ может поверить прочитав пару таких же рассказов приведенных в доказательство.

Ну погодите. Вам привели пример 100%-ой проблемы, с которой сталкиваются ну просто все, кто так или иначе использует css — global scope. Ну устроен css так. Переменные решают другую проблему и не предоставляют адекватного инструмента для их инкапсуляции.
Мне кажется, весь спор из-за того, что одни пишут веб-страницы, а другие веб-приложения.

Для классических страниц (например, таких, как эта статья), конечно, классический CSS идеален. Автор один раз верстает HTML-страницу, а вы потом накладываете на нее какие угодно стили.

Для веб-приложений классический CSS — это скорее зло, потому что стили одного компонента начинают негативно влиять на стили другого, становится трудно их переопределить и т. д. Усложняется повторное использование кода. Только inline-стили выручают (аргумент с «весом» страницы не рассматриваем — веб-приложение и так может определить, как именно оно хочет себя закешировать, и какие данные загружать повторно не нужно).

Описываемый вами подход с «динамическим» CSS, это скорее, компромисс между двумя крайностями.

Вы правы, все так и есть.


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

Да, если я сегодня напишу .button {color: red;} а завтра пущу в свой код сбежавшего из лаборатории бурундука и он не зная о моем коде напишет .button {color: green;}, то я согласен, будет беда. Но есть конвенции для конкретного проекта, документация, в которой все подробно описано. Если Вас что-то не устраивает, то есть бэм, есть css модули.
И Вы не представляете, я много раз писал очень сложные приложения с нуля на реакте и ангуляр и у меня ни разу не было того, о чем Вы говорите.

И хватит уже ерунду нести с глобальным пространством. Вы вот когда вэбпаком все импорты в одном месте собираете для вывода наружу не испытываете сложности? Нет! А почему? Потому что все имена разные!
Ну это если Вы понимаете о чем я, если Вы действительно не пишите только легкие приложения.
Если вы сегодня пишите компонент <Button />, а завтра наследуете от него <SuperButton />, то у вас уже большие проблемы с CSS. От того, в каком порядке соберутся стили, будет зависеть внешний вид вашей кнопки. В случае с inline-стилями такой проблемы не будет.

хватит уже ерунду нести с глобальным пространством
Простите, я разве что-то где-то об этом говорил?
Скажите честно, Вы наследуете в react или angular SuperButton от Button?
Или возможно Вы никогда не писали на bootstrap и считаете twetter маленьким или вымышленным?
Все что здесь привели ЗА из разряда «а что будет, если годзила встретит кинконга».
Если вы имеете ввиду наследование JS-классов, то, конечно, нет, а компоненты — да, постоянно.

Twitter Bootstrap, как раз таки, от этого страдает. Всякие ".btn .btn-default" тому подтверждение (совершенно немасштабируемое решение, если вы решите «унаследовать» свою кнопку от стандартной).
Поражает на самом деле, когда приводят бутстрап в качестве «хорошего инженерного решения». Это классическая наколенщина для наибыстрейшего прототипирования, которую в серьезный проект брать вообще нельзя.
Поражает на самом деле то, что Вы думаете о том, что кто-то говорит «брать бутстрап».
Я говорю о том, что можно написать нужные Вам классы самому с самого нуля, как это сделано в бутстрап и обойтись вообще без чего-либо. Но не в коем случаи не тащить бутстрап туда, где придется все переписывать и переопределять, ведь он не затачивался под конкретный случай.
что Вы думаете о том, что кто-то говорит «брать бутстрап».
Вы, видимо, не представляете, сколько таких заказчиков, которые хотят космолет, но слышали про бутстрап и думают, что будет быстро и дешево. Еще и упрутся рогами.
Ну всё таки в современной верстке bootstrap — это только grid(и возможно типография).
Те, кто минус поставили могут объяснить что не так?
минус не ставил, но от себя добавлю, в современной верстке бутстрепчик это как опухоль. Он вообще не нужен, ни его сетка ни типография.
Для нормальных проектов брать нормальное, для всяких одностраничников и домашних проектов берут бутстрап. Как-то так же?
нет, не так. Зависит от уровня разработчика. Новичок берет бутстрап, те кто уже поняли что он нахер не нужен, берут и пишут свою сетку, свои компоненты и все что им нужно в проекте.
Что в большинстве сайтов в интернете(лендинги, бложики и прочее) не нужна своя сетка, когда есть бутстрап? Про компоненты я и написал что их не берёт никто.

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

Только не нужно называть CSS-in-JS inline-стилями.
Инлайн стили это <div style="..."></div>, и никаких CSS-селекторов, медиа-запросов, ховеров.


А CSS-in-JS — это про генерацию обычного CSS, как будто JS теперь стал препроцессором для CSS, таким же как SASS или LESS.


Очень важно различать эти понятия, чтобы не было ложного впечатления "нафиг этот CSS-in-JS, там :hover" не работает". Работает, также как и везде.

Вы лукавите :) Если у вас в ховере динамическое значение из js — оно пропишется инлайном

Сейчас проверил. Есть стили:


const styles = {
  button: {
    background: 'blue',
    '&:hover': {
      background: props => props.hoverColor
    }
  },
}

Когда меняется props.hoverColor, обновляется правило в CSS, никаких инлайнов, все честно.

Ух ты, видимо эту проблему решили…
А как, новый тэг style пишется или в styleSheet обновляется?
А, ну то есть styleSheet. Интересно, надо ознакомиться.
если вы следите за порядком импортов и сначала подключаете js, а потом css (это простейшая и вполне адекватная конвенция при расширении), то проблем у вас не будет с порядком, вебпак все сам решит
Вы, зачем то, оставили 2 комментария с одинаковым смыслом в двух разных местах. Ответил выше.

Зато такие решения как requirejs порядок не гарантируют.

Ну так, наверное, это проблема requirejs?

Это проблема идеи замены дерева зависимостей компонентов на зависимости модулей — вторые не совсем точно повторяют первые.


Проявиться она может в любых системах динамической загрузки модулей — requirejs, systemjs, webpack с настроенными чанками.

Если у вас каждый компонент лежит в отдельном модуле (что логично), а стили к нему лежат в соседнем таком же отдельном модуле (что тоже логично), и компонент явно импортирует модули компонентов, которые использует, то зависимости работают.
С другой стороны, согласен про динамическую загрузку. Тут не очень понятно, как решать.
Хотя, казалось бы, тот же вебпак при дозагрузке своего чанка, должен правильно переразрулить зависимости и поменять порядок стилей…

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


Решить эту проблему можно если отказаться от неявной установки стилей в момент их загрузки, заменив ее на явный вызов:


import { Button } from './Button.jsx';
import css from './SuperButton.css';
export const SuperButton = ({className}) => <Button className={`${css.SuperButton} ${className}`}/>;

css.install();

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

Ну как это не должен, вы же намеренно указываете ему распилить собранный им же граф зависимостей на чанки. Раз уж он один раз его собрал, то и при дозагрузке чанков в рантайме должен пересобрать его заново. Другое дело, если у вас вообще независимые бандлы, собранные по отдельности, тогда да.

Что вы понимаете под "пересборкой"?

Я не про ту «пересборку», о которой вы подумали. А о перераспределении тегов style в соответствии с изначальным графом зависимостей, когда догружается чанк.

Так ведь webpack не управляет тегами style, вот в чем проблема.

Поэтому я и пишу «должен». Хотелось бы, чтобы был механизм синхронизации ядра, грузящего чанки и лоадеров, в частности style-loader'а.

Причем, есть предчувствие, что он даже есть, через какие-нибудь ивенты.

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


Более точно — зависимости модулей неправильно отражают желания программиста.

«Типографика может создать или разрушить дизайн: выбор типа» (Typography can make or break your design: a process for choosing type)

«Type» тут — это «шрифт», а не «тип»

Забавно читать такое, когда буквально недавно закончил рефакторинг ряда компонентов своего проекта с переносом практически всей логики и вариативности отображения в CSS. Утверждаю, что CSS в JS — это проблема скорее React-разработчиков и их мета-платформы. У них таких проблем много, но погрязнув в React-е они начинают эти проблемы экстраполировать на всю веб-разработку. И говорить о "будущем" тут очень некорректно, будущее (а для кого-то уже давно настоящее) — за веб-компонентами и нативными CSS.

Посмотрите мой комментарий выше, пункт 0 именно о том, что вы говорите.


Не надо заблуждаться что CSS-in-JS это про то, что стили теперь делаются на JS. Нет, анимации все так же делаются на CSS, каскад и :hover тоже доступны. Зато, от переноса исходного кода стилей (именно исходного, а не конечного результата) в JS можно получить некоторое удобство.


Утверждаю, что CSS в JS — это проблема скорее React-разработчиков и их мета-платформы.

CSS-in-JS не проблема, а решение. Как вы осуществляете ленивую подгрузку стилей на своей любимой платформе? Как вы изолируете стили, чтобы они применялись только к конкретному компоненту?


CSS-in-JS предлагает по максимуму переиспользовать уже готовые инструменты для JS, вместо изобретения дополнительных инструментов для CSS.

Я видел ваш комментарий выше и даже плюсанул его. А в остальном — вы, прежде чем говорить о дополнительных инструментах, ленивой подгрузке, изоляции стилей и т.д, поинтересуйтесь хотя-бы что такое веб-компоненты, почитайте их актуальные спецификации, посмотрите доклады на эту тему с последнего Google I/O на ютубе… Это не очень объемные материалы, но обещаю — это очень полезно и позволяет во многом по новому взглянуть на современную веб-платформу и на ее ключевые отличия от популярных мета-платформ и прочих костылей.
Лично я эти вещи использую уже довольно давно, успел наработать свой эффективный подход, и мне, порой, просто дико смотреть на все эти "решения" несуществующих проблем. Ну и PostCSS поизучайте вдогонку.

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


И Shadow DOM так просто не полифиллится, там такие костыли и проблемы с производительностью, что я уж лучше на JSS посижу, пока в браузерах нормальная поддержка не появится.

Ну и shadow dom все еще в working draft. А зная, как эти ребята любят все менять (вспомнить флексбоксы), я пока держусь от всего этого безобразия подальше.

У нас в команде Хром — референсный браузер, но мы также все детально тестируем в остальных (кроме экзотики конечно). Часто сталкиваюсь с заявлениями о том, что полифилы тормозят. Блин, я бы согласился с этим пару лет назад, но сейчас мне непонятно откуда вы это берете. А мы делаем довольно сложный фронт. Ну и нельзя сказать, что только в Хроме компоненты поддерживаются (а это, если что, самый популярный браузер и он сейчас задает темп для остальных), ибо не только. Есть конечно нюансы, технология проходит долгий и трудный путь, но, если сравнивать с остальным зоопарком — для меня выбор очевиден.

Подозреваю, что вы пользуетесь не чистыми веб-компонентами, а Polymer. Это важно, потому что последние версии Polymer достигли более-менее приличной производительности, только когда перешли с честных полифиллов, на упрощенные, которые по своей сути работают так же как с CSS-modules или CSS-in-JS. Вся разница только в том, как это называть, а суть одна и та же: мы генерируем СSS с динамическими именами классов.


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

У меня сейчас есть три проекта: на чистых компонентах, на Polymer 1.9.1 и на Polymer 2.0.1 ))) То, что вы говорите относится только к версиям 1.x

В современных браузерах, которых большинство, как раз все отлично работает, без полифиллов и костылей с именами классов. На смартфонах Polymer — один из лучших вариантов для PWA в плане производительности.

Пример приложения https://shop.polymer-project.org/

В Firefox, Internet Explorer не поддерживается. Так что все равно придется думать о фоллбеке. И в качестве фоллбека там работает такой же точно механизм, что и с CSS-in-JS с процессингом и динамической генерацией стилей в браузере пользователя.


Кроме того, синтаксис определения Polymer компонентов мне кажется неудобным, уж лучше CSS в JS писать. Но это уже тема другой дискуссии.

Не так уж и неудобно. А кому надо, так есть набор декораторов для TS.
И в качестве фоллбека там работает такой же точно механизм, что и с CSS-in-JS с процессингом и динамической генерацией стилей в браузере пользователя.

И почему же это плохо?

Я не говорю что это плохо.


Просто я не понимаю, почему на CSS-in-JS такая негативная реакция, в то время как Polymer делает то же, и всех это устраивает.

Сейчас вам начнут петь о каких-то разделениях, которые необходимы, иначе все, капец. И JSX еще припомнят.

Потому что важен язык разметки, а не его реализация.

Ну вот почему никто не может принять, что jsx — это не разметка, не маркап, не html, да как угодно. Это инструмент компоновки самодостаточных блоков интерфейса. То, что он похож на html — это лишь деталь. Ну а если мы настолько от привычной разметки абстрагируемся, то какая разница, какой dsl использовать для описания внешнего вида этих блоков? Css, jss, да что угодно.
Лично я эти вещи использую уже довольно давно, успел наработать свой эффективный подход, и мне, порой, просто дико смотреть на все эти "решения" несуществующих проблем.

Расскажите поподробнее, как вы делаете лениво загружаемые стили и рендерите критический CSS. Без троллинга, реально интересно, как это можно сделать, не перенося CSS в JS.

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

UFO just landed and posted this here
CSS уже доволно хорошо поддерживает множество фишек, типа переменных и т.д. А плохо структурированный код можно написать и в SASS с LESS, так же как и сделать хорошо оформленный CSS. Как мне кжется такие статьи просто для того, тобы сказать: «Ух, какая прикольная штука. Давайте пользоваться все».
Sign up to leave a comment.