29.04.202514:19
Ну и вот, теперь возвращаясь к тому, как Solid обновляет атрибуты DOM-узлов — он организует реактивную связь между атрибутом и значением, которое будет получено по "пути, проложенному Solid-ом". Если на том конце оказался Фиксик, который по своей природе реактивен, его изменение всегда тут же будет приводить к изменению атрибута. Таким образом, Solid ничего ни с чем не сравнивает, он просто применяет.
29.04.202514:19
Как я уже раннее сказал, в Solid нет такого понятия как ре-рендер, поэтому
Ну и наконец, как же изменения в свойствах компонентов применяются к DOM? Очень быстро и атомарно. Именно так, потому что Solid ничего ни с чем не сравнивает, пока другие смотрят, он уже делает, в нем нет никакого Virtual DOM, а свои изменения он применяет точечно для нужных атрибутов нужных DOM-узлов. Честно — я уже не знаю куда эффективнее.
Давайте вернемся к нашему примеру и перепишем его на Solid, добавив немного логики, чтобы понять прелесть технологии:
Так как в Solid значение, передаваемое в
Помните я сказал, что все свойства в компонентах Solid — сигналы? Это почти так и есть, но наверное лучше использовать термин "указатель" — все свойства в компонентах Solid являются указателями. Solid для каждого свойства объявляет нативный JS-getter в объекте
Уже чуете преимущества? Evaluation (вычисление) свойства происходит в момент обращения к нему, что позволяет не производить вычисления и аллокации памяти тогда, когда свойство оказалось неиспользованным. Таким образом, если вы не используете свойство
Представьте, что есть у вас какое-нибудь здоровое приложение, в котором от самого верхнего уровня к самому нижнему через свойства передается строка, а про контекст мы еще не слышали. Сколько раз в React эта строка будет пересоздана? Столько же раз, сколько она передавалась от одного компонента к другому.
Solid-же через getter-ы прокладывает путь к значению, и не более того. При попытке получить свойство, мы как бы идем по дорожке, которую нам проложила технологии, где в конце нас ждет значение. Мы идем к тому самому Фиксику, который даст нам информацию о том, какое значение надо использовать.
count
будет всегда одним и тем же значением-сигналом, как и функция log
. Функция log
при вызове ссылается на переменную count
, которая сама по себе никогда не меняется, но может меняться значение внутри неё, поэтому вызов этой функции будет всегда приводить к выводу актуального значения.Ну и наконец, как же изменения в свойствах компонентов применяются к DOM? Очень быстро и атомарно. Именно так, потому что Solid ничего ни с чем не сравнивает, пока другие смотрят, он уже делает, в нем нет никакого Virtual DOM, а свои изменения он применяет точечно для нужных атрибутов нужных DOM-узлов. Честно — я уже не знаю куда эффективнее.
Давайте вернемся к нашему примеру и перепишем его на Solid, добавив немного логики, чтобы понять прелесть технологии:
Так как в Solid значение, передаваемое в
createMemo
также сразу же вычисляется, как и в React, я накидал функцию createLazyMemo
, которая делает это только после того, как к сигналу было выполнено обращение. Да, может показаться это нечестным, и тут можно сказать "так в React тоже можно так сделать", но тогда вот в React при этом тип данных bigArray
поменяется с массива на функцию, а в мире Solid ничего ровным счётом не произойдет, мы всё так же будем работать с неким сигналом.Помните я сказал, что все свойства в компонентах Solid — сигналы? Это почти так и есть, но наверное лучше использовать термин "указатель" — все свойства в компонентах Solid являются указателями. Solid для каждого свойства объявляет нативный JS-getter в объекте
props
. Таким образом, props
внутри SomeComponent
в примере выше будет чем-то вроде такого объекта:
Уже чуете преимущества? Evaluation (вычисление) свойства происходит в момент обращения к нему, что позволяет не производить вычисления и аллокации памяти тогда, когда свойство оказалось неиспользованным. Таким образом, если вы не используете свойство
items
, которое в свою очередь создает массив из 10 000 элементов, лишних тяжелых аллокаций произведено не будет.Представьте, что есть у вас какое-нибудь здоровое приложение, в котором от самого верхнего уровня к самому нижнему через свойства передается строка, а про контекст мы еще не слышали. Сколько раз в React эта строка будет пересоздана? Столько же раз, сколько она передавалась от одного компонента к другому.
Solid-же через getter-ы прокладывает путь к значению, и не более того. При попытке получить свойство, мы как бы идем по дорожке, которую нам проложила технологии, где в конце нас ждет значение. Мы идем к тому самому Фиксику, который даст нам информацию о том, какое значение надо использовать.
25.04.202517:30
// Компоненты
Компоненты в Solid объявляются аналогично React и являются теми же самыми сущностями — функциями. Код базового компонента идентичный:
И там и там, компонент возвращает JSX-элемент, который в случае обеих технологий имеет совсем разный тип.
Если мы говорим о React, то в качестве результата, компонент вернет так называемый React Element, который является обычным JS-объектом, содержащим мета-информацию об отрисовываемом элементе. В нем указываются тип элемента (в данном случае строка
В Solid-же всё немного интереснее. Компоненты в случае этой замечательной технологии возвращают DOM-узлы. Да, буквально те узлы, которые мы создаем через вызов
Ввиду того, что возвращаются DOM-узлы, при передаче их в компонент, тот не способен определить, какой компонент и с какими свойствами их породил. Это приводит к некоторым проблемам в случае, если компонент ожидает получения лишь элементов конкретного типа. Но и для этого есть решение, просто придется немного обманывать TypeScript. Автору библиотеки про эту проблему известно, но он уведомил, что из-за бедного функционала JSX в TypeScript, решить её без обмана транспилятора не выйдет.
Проблема может выглядеть вот так:
В этом случае компоненту
Да, этот кейс не самый приятный, но решается единожды, а подход далее переиспользуется. На стримах я дал ему рабочее название — "JSX Boxing".
В этой секции вот что скажу напоследок — в Solid компоненты используются для описания шаблона (template) приложения. Иными словами, компоненты описывают скелет приложения и не более того. Каждый компонент никогда не перерисовывается, в мире Solid просто не существует такого процесса, как ре-рендер компонента, как в React. В отдельном посте я расскажу как устроены реактивность и рендеринг в Solid, и тогда этот параграф станет более понятен.
Ну и говоря о чистых (
Компоненты в Solid объявляются аналогично React и являются теми же самыми сущностями — функциями. Код базового компонента идентичный:
И там и там, компонент возвращает JSX-элемент, который в случае обеих технологий имеет совсем разный тип.
Если мы говорим о React, то в качестве результата, компонент вернет так называемый React Element, который является обычным JS-объектом, содержащим мета-информацию об отрисовываемом элементе. В нем указываются тип элемента (в данном случае строка
p
), а также переданные свойства (тут это объект {'data-title':'Test'}
). Таким образом, React работает с каким-то абстрактным представлением элемента, что также позволяет на вход получить таковые от родителя, и понять, какого типа эти элементы, и с какими свойствами их собираются отрисовать.В Solid-же всё немного интереснее. Компоненты в случае этой замечательной технологии возвращают DOM-узлы. Да, буквально те узлы, которые мы создаем через вызов
document.createElement
. Это ли не здорово? Тут, наверное, могли получить экстаз Vanilla JS-разработчики, но не спешите радоваться. Ввиду того, что возвращаются DOM-узлы, при передаче их в компонент, тот не способен определить, какой компонент и с какими свойствами их породил. Это приводит к некоторым проблемам в случае, если компонент ожидает получения лишь элементов конкретного типа. Но и для этого есть решение, просто придется немного обманывать TypeScript. Автору библиотеки про эту проблему известно, но он уведомил, что из-за бедного функционала JSX в TypeScript, решить её без обмана транспилятора не выйдет.
Проблема может выглядеть вот так:
В этом случае компоненту
Chip
будет невозможно проверить, что в свойство children
ему передали именно экземпляры компонента Chip.Item
. Решение есть — Chip.Item
, вместо JSX, должен возвращать JS-объект типа {type: Chip.Item, props: { … }}
. Тогда Chip
получит именно этот объект и сможет корректно решить, чего с этим делать.Да, этот кейс не самый приятный, но решается единожды, а подход далее переиспользуется. На стримах я дал ему рабочее название — "JSX Boxing".
В этой секции вот что скажу напоследок — в Solid компоненты используются для описания шаблона (template) приложения. Иными словами, компоненты описывают скелет приложения и не более того. Каждый компонент никогда не перерисовывается, в мире Solid просто не существует такого процесса, как ре-рендер компонента, как в React. В отдельном посте я расскажу как устроены реактивность и рендеринг в Solid, и тогда этот параграф станет более понятен.
Ну и говоря о чистых (
PureComponent
, memo
) компонентах, можно сказать, что в Solid такой шелупони нет, потому что там нет такого понятия как "свойства компонента изменились, надо перерисовать компонент". Все компоненты в Solid.js — обычные функции, и термин чистоты в понимании React к ним просто не применим.19.04.202511:07
Трансляция запущена!
Разработка Android UI в Platformer-е / Solid.js
— Software and Game Development
— twitch.tv/qbnk
Разработка Android UI в Platformer-е / Solid.js
— Software and Game Development
— twitch.tv/qbnk
24.03.202515:49
Трансляция запущена!
29 лет. Запомните меня таким
— Just Chatting
— twitch.tv/qbnk
29 лет. Запомните меня таким
— Just Chatting
— twitch.tv/qbnk
17.03.202507:25
😏 Я нашел идеальное решение
Идеального решения не существует, это кликбейт, но я нашел отличное решение. Речь, конечно же, о том, чем мы занимаемся на трансляциях — Telegram UI Kit for Solid.js.
На прошлом стриме я рассказывал о потенциальной не столь значительной проблеме как сложная структура компонентов. Ловите пример списка с одним элементом:
Толстовато выглядит, неправда-ли? Тогда я сказал, что в этом ничего плохого нет (в этом и правда ничего плохого нет), потому как в моем понимании задача разрабатываемой мной библиотеки — дать максимально гибкий и простой набор компонентов не выходящий за то, что есть в UI Kit-е. Пользователь уже сам решает как эту гибкость использовать, и если она не нужна, то он может написать переиспользуемые компоненты, состоящие из вот этих непростых структур.
В данном примере каждый из компонентов отвечает за определенную часть структуры более сложного вышестоящего компонента. У ListIosItem может быть только 2 элемента — ListIosItemLeft и ListIosItemBody. У ListIosItemBody только ListIosItemBodyLeft и ListIosItemBodyRight. Каждый из этих компонентов описывает определенный элемент в родительском компоненте, и двинуться в сторону от этой структуры не выйдет, можно лишь повлиять на сами элементы, их атрибуты и события.
Прелесть этого подхода заключается в том, что каждый элемент компонента можно гибко настроить. Это отлично вписывается в случай, когда автор библиотеки упустил для тебя что-то важное, но при этом не переиспользуемое, то есть ты не пойдешь создавать PR с этими изменениями потому как другим разработчикам твои изменения не будут нужны.
Ну а вот если говорить о минусах — то это громоздкость. Для описания элемента списка с одним лэйблом придется использовать 5 компонентов, что не очень удобно.
Ну и знаете что? Я случайным образом пришел к решению, которое всё так же сохраняет гибкость, но избавляет разработчика от обязательности использовать структуру выше. Теперь можно обойтись вот таким кодом, вместо того, что был до этого:
Идея получается достаточно проста — ты используешь только те суб-компоненты большого компонента, которые хочешь модифицировать. Все остальные остаются со своими стандартными настройками. То есть если я хочу подкрутить ListIosItemBody, то код будет уже такой:
Есть ощущение, что я переизобрел слоты, но исходя из тех реализаций этого подхода, что я видел, общего он имеет только идею. В любом случае здорово, что это получилось абсолютно случайно, и при этом решает проблему.
UI Платформера сделаем до конца месяца, бета будет открытой 🫰
Всем хорошей рабочей недели!
Идеального решения не существует, это кликбейт, но я нашел отличное решение. Речь, конечно же, о том, чем мы занимаемся на трансляциях — Telegram UI Kit for Solid.js.
На прошлом стриме я рассказывал о потенциальной не столь значительной проблеме как сложная структура компонентов. Ловите пример списка с одним элементом:
Толстовато выглядит, неправда-ли? Тогда я сказал, что в этом ничего плохого нет (в этом и правда ничего плохого нет), потому как в моем понимании задача разрабатываемой мной библиотеки — дать максимально гибкий и простой набор компонентов не выходящий за то, что есть в UI Kit-е. Пользователь уже сам решает как эту гибкость использовать, и если она не нужна, то он может написать переиспользуемые компоненты, состоящие из вот этих непростых структур.
В данном примере каждый из компонентов отвечает за определенную часть структуры более сложного вышестоящего компонента. У ListIosItem может быть только 2 элемента — ListIosItemLeft и ListIosItemBody. У ListIosItemBody только ListIosItemBodyLeft и ListIosItemBodyRight. Каждый из этих компонентов описывает определенный элемент в родительском компоненте, и двинуться в сторону от этой структуры не выйдет, можно лишь повлиять на сами элементы, их атрибуты и события.
Прелесть этого подхода заключается в том, что каждый элемент компонента можно гибко настроить. Это отлично вписывается в случай, когда автор библиотеки упустил для тебя что-то важное, но при этом не переиспользуемое, то есть ты не пойдешь создавать PR с этими изменениями потому как другим разработчикам твои изменения не будут нужны.
Ну а вот если говорить о минусах — то это громоздкость. Для описания элемента списка с одним лэйблом придется использовать 5 компонентов, что не очень удобно.
Ну и знаете что? Я случайным образом пришел к решению, которое всё так же сохраняет гибкость, но избавляет разработчика от обязательности использовать структуру выше. Теперь можно обойтись вот таким кодом, вместо того, что был до этого:
Идея получается достаточно проста — ты используешь только те суб-компоненты большого компонента, которые хочешь модифицировать. Все остальные остаются со своими стандартными настройками. То есть если я хочу подкрутить ListIosItemBody, то код будет уже такой:
Есть ощущение, что я переизобрел слоты, но исходя из тех реализаций этого подхода, что я видел, общего он имеет только идею. В любом случае здорово, что это получилось абсолютно случайно, и при этом решает проблему.
UI Платформера сделаем до конца месяца, бета будет открытой 🫰
Всем хорошей рабочей недели!
29.04.202514:19
Что будет выводиться в консоль при клике на кнопку? Неопытный разработчик скажет, что значение
Чтобы этот код работал как ожидается, необходимо добавить переменную
...но это ведь тупость? Почему я не могу пользоваться стандартным функционалом JS и ссылаться на актуальное значение переменной? Потому что система реактивности в React крайне тупая, неэффективная и неповоротливая. С хуками в React очень много "веселых" приколов, которые усложняют разработку. Взять хотя бы тот факт, что количество вызовов хуков и их порядок всегда должны быть одинаковыми от рендера к рендеру. Таким образом, вы не можете сделать ранний выход из функции-компонента при необходимости, и вынуждены вызывать даже те хуки, которые точно не пригодятся. Для этого есть workaround-ы, но в данном случае они просто выступают очень сомнительным решением проблемы реактивности технологии.
Я не буду вдаваться в другие, порочащие честь React кейсы, связанные с его хуками, но поверьте мне, ограничений там столько, что после Solid смотреть на это с серьезным лицом просто невозможно.
Напоследок упомянем то, как значения атрибутов просачиваются в сам HTML-элемент. В отрыве от сравнения c Solid это не сказать, что прямо-таки полезная информация, но так как в Solid это работает немного по-другому, это стоит упомянуть. Допустим, есть вот такой компонент:
После сборки такой код превратится вот, например, в такой:
Тут обратим внимание на то, что
Таким образом, в React мы всегда передаем полный набор полей, который может быть даже не использован, но аллокации памяти под них (например, под 10 000 элементов в
Далее я расскажу, как Solid решает эти проблемы.
// В Solid 👩💻
В Solid реактивность и рендеринг устроены категорически по-другому. Работая с Solid, я люблю представлять, что без реактивных примитивов это просто бездушный, серый скелет, который можно заставить что-то делать сугубо при помощи тех самых реактивных примитивов. Фантазируя на их тему, можно представить реактивные примитивы как светящиеся шарики, помещающиеся в ладонь, которые необходимо вложить в какую-то часть скелета, чтобы он приобрел какие-то двигательные способности. Каждый раз, когда шарик пульсирует, скелет на это реагирует. Давайте в рамках этой статьи называть такие шарики Фиксиками.
count
, которое на 1 больше предыдущего. Опытный-же скажет, что всегда будет выводиться 0, несмотря на то, что мы при клике повышаем count
, и он будет прав. Почему? Потому что функция log
в данном коде не имеет зависимостей, а это значит, что она будет инициализирована единожды при первом вызове функции App
и будет ссылаться на значение count
, которое было на момент инициализации функции log
. Все последующие вызовы функции App
будут приводить к инициализации новых переменных count
, не имеющих ничего общего с их предыдущим значением, а значит это никак не будет влиять на то, что log
собирается выводить. Чтобы этот код работал как ожидается, необходимо добавить переменную
count
в список зависимостей useCallback
, что приведет к возвращению нового значения-функции в log
. ...но это ведь тупость? Почему я не могу пользоваться стандартным функционалом JS и ссылаться на актуальное значение переменной? Потому что система реактивности в React крайне тупая, неэффективная и неповоротливая. С хуками в React очень много "веселых" приколов, которые усложняют разработку. Взять хотя бы тот факт, что количество вызовов хуков и их порядок всегда должны быть одинаковыми от рендера к рендеру. Таким образом, вы не можете сделать ранний выход из функции-компонента при необходимости, и вынуждены вызывать даже те хуки, которые точно не пригодятся. Для этого есть workaround-ы, но в данном случае они просто выступают очень сомнительным решением проблемы реактивности технологии.
Я не буду вдаваться в другие, порочащие честь React кейсы, связанные с его хуками, но поверьте мне, ограничений там столько, что после Solid смотреть на это с серьезным лицом просто невозможно.
Напоследок упомянем то, как значения атрибутов просачиваются в сам HTML-элемент. В отрыве от сравнения c Solid это не сказать, что прямо-таки полезная информация, но так как в Solid это работает немного по-другому, это стоит упомянуть. Допустим, есть вот такой компонент:
После сборки такой код превратится вот, например, в такой:
Тут обратим внимание на то, что
bigArray
будет гарантированно вычислен и мы создадим массив из 10 000 элементов, а далее передадим его в SomeComponent
. Также, мы гарантированно передадим через поле subitems
значение props.subitems
, которое нам передали сверху. Таким образом, в React мы всегда передаем полный набор полей, который может быть даже не использован, но аллокации памяти под них (например, под 10 000 элементов в
bigArray
) мы все равно произведем. Понятно, что в реальных проектах создание 10 000 элементов — это скорее редкость, но важно понимать, что чем больше проект, тем больше более мелких схожих ситуаций будет, а значит влияние может оказаться точно таким же большим.Далее я расскажу, как Solid решает эти проблемы.
// В Solid 👩💻
В Solid реактивность и рендеринг устроены категорически по-другому. Работая с Solid, я люблю представлять, что без реактивных примитивов это просто бездушный, серый скелет, который можно заставить что-то делать сугубо при помощи тех самых реактивных примитивов. Фантазируя на их тему, можно представить реактивные примитивы как светящиеся шарики, помещающиеся в ладонь, которые необходимо вложить в какую-то часть скелета, чтобы он приобрел какие-то двигательные способности. Каждый раз, когда шарик пульсирует, скелет на это реагирует. Давайте в рамках этой статьи называть такие шарики Фиксиками.
29.04.202514:19
Простите, я пытался
25.04.202517:30
👩💻 Почему Solid.js — это чудо / Инициализация и компоненты
Уже какое-то время пользуясь Solid.js, открываю всё новые и новые чудные преимущества этой технологий, и просто не перестаю удивляться, насколько Solid.js — это чудо.
Ну и вот, наконец, в самолете у меня появилось немного времени написать небольшую обзорную статью по этой технологии с какими-то абстракциями, пояснениями, и прочим. Как вы уже могли понять по предыдущему моему посту, одним постом тут не обойтись, поэтому у нас будет так называемый цикл постов про такую замечательную технологию, как Solid.
Я очень надеюсь, что кто-то, читая мои наработки, вдохновится на изучение Solid и откроет для себя совсем новый дивный мир эффективной разработки.
Ввиду того, что раннее я был (да и всё ещё являюсь им по долгу службы) преимущественно React-разработчиком, в этой статье я буду вести сравнительную характеристику Solid именно с этой технологией. Просто потому, что в React у меня есть внушительный опыт, и уже какое-то сформировавшееся мнение.
// Инициализация
Визуально, инициализация приложения в Solid не сказать, что сильно отличается от React. На входе нас встречает практически одинаковый код:
Тут, особенно, говорить нечего, кроме того, что в корне приложения на React имеется компонент, именуемый
В Solid таких "приколов" нет — каждый эффект вызывается только тогда, когда должен. У вас нет возможности включить какой-то "строгий режим" при котором эффекты начнут вызываться N раз (хотя при желании вы и это сделать можете).
Уже какое-то время пользуясь Solid.js, открываю всё новые и новые чудные преимущества этой технологий, и просто не перестаю удивляться, насколько Solid.js — это чудо.
Ну и вот, наконец, в самолете у меня появилось немного времени написать небольшую обзорную статью по этой технологии с какими-то абстракциями, пояснениями, и прочим. Как вы уже могли понять по предыдущему моему посту, одним постом тут не обойтись, поэтому у нас будет так называемый цикл постов про такую замечательную технологию, как Solid.
Я очень надеюсь, что кто-то, читая мои наработки, вдохновится на изучение Solid и откроет для себя совсем новый дивный мир эффективной разработки.
Ввиду того, что раннее я был (да и всё ещё являюсь им по долгу службы) преимущественно React-разработчиком, в этой статье я буду вести сравнительную характеристику Solid именно с этой технологией. Просто потому, что в React у меня есть внушительный опыт, и уже какое-то сформировавшееся мнение.
// Инициализация
Визуально, инициализация приложения в Solid не сказать, что сильно отличается от React. На входе нас встречает практически одинаковый код:
Тут, особенно, говорить нечего, кроме того, что в корне приложения на React имеется компонент, именуемый
StrictMode
. Он ответственнен за то, чтобы помочь разработчику найти некорректное поведение, связанное с использованием хуков React и ре-рендерингом. Как по мне, это компонент вызывает больше проблем, нежели чем помогает их решать. Да, он заставляет разработчиков делать свою работу правильно, но заставляет при этом решать какие-то невозможные кейсы, и в каких-то случаях по ощущениям, ведет себя некорректно. Двойной вызов эффектов (useEffect) с моей точки зрения - крайне странный способ проверять, а правильно ли реализован эффект.В Solid таких "приколов" нет — каждый эффект вызывается только тогда, когда должен. У вас нет возможности включить какой-то "строгий режим" при котором эффекты начнут вызываться N раз (хотя при желании вы и это сделать можете).


16.04.202515:00
🫵 We Need You, Developer
Это не учебная тревога. Вчера Павел согласился принять нашу помощь, поэтому приглашаю всех, кому не безразлична судьба Telegram Mini Apps, принять участие вгрупповом сексе волонтерском событии для разработчиков.
Задача заключается в следующем — необходимо собрать документ, в котором мы распишем все насущные баги, которые очень хотелось бы закрыть. Речи о запросе на какие-то новые фичи нет, мы не рискуем, не входим в азарт, поставили — забрали. От нас требуется доложить только о самых важных багах, которые ломают опыт разработчиков и пользователей, формализовать это, и в уже пережёванном виде передать Павлу.
У меня на памяти много важных проблем, на которые стоило бы обратить внимание, но я приглашаю вас, разработчиков, подсобить мне в этом деле. Просто как минимум потому, что я мог про что-то забыть. Принимаю заявки в чате @devs_cis.
Если хотите участвовать, то следуйте правилам:
— Полностью описывайте кейс воспроизведения. Указывайте платформу и пошагово расписывайте, что нужно сделать для воспроизведения проблемы. Всегда проверяйте, что используете актуальную версию клиента.
— Опционально. Описывайте причины возникновения проблемы и возможные способы её решения.
Я буду перепроверять все репорты, приводить их к необходимому формату, приоритизировать, и добавлять в документ. Публичный дашборд будет в Notion, его мы, вероятно, и передадим Павлу: ссылка на дашборд.
Это не учебная тревога. Вчера Павел согласился принять нашу помощь, поэтому приглашаю всех, кому не безразлична судьба Telegram Mini Apps, принять участие в
Задача заключается в следующем — необходимо собрать документ, в котором мы распишем все насущные баги, которые очень хотелось бы закрыть. Речи о запросе на какие-то новые фичи нет, мы не рискуем, не входим в азарт, поставили — забрали. От нас требуется доложить только о самых важных багах, которые ломают опыт разработчиков и пользователей, формализовать это, и в уже пережёванном виде передать Павлу.
У меня на памяти много важных проблем, на которые стоило бы обратить внимание, но я приглашаю вас, разработчиков, подсобить мне в этом деле. Просто как минимум потому, что я мог про что-то забыть. Принимаю заявки в чате @devs_cis.
Если хотите участвовать, то следуйте правилам:
— Полностью описывайте кейс воспроизведения. Указывайте платформу и пошагово расписывайте, что нужно сделать для воспроизведения проблемы. Всегда проверяйте, что используете актуальную версию клиента.
— Опционально. Описывайте причины возникновения проблемы и возможные способы её решения.
Я буду перепроверять все репорты, приводить их к необходимому формату, приоритизировать, и добавлять в документ. Публичный дашборд будет в Notion, его мы, вероятно, и передадим Павлу: ссылка на дашборд.
24.03.202509:12
🥳 Вот и 29 мне уже
Очередная достигнутая вершина в жизни любого живого организма — прожить год и не помереть. Этого, в целом, достаточно 😀
Если быть серьезным, то и в этом году были достаточно примечательные события — мы перебрались обратно в Тюмень, я ушел из Яндекса и устроился в организацию в TON, ездил на конференции с выступлениями, и наконец довел проект до состояния, которым уже кое-как можно пользоваться. Это был насыщенный воспоминаниями год, и я надеюсь, что таких будет еще больше впереди.
Как я уже когда-то говорил, День Рождения — это один из немногих дней в моей жизни, который буквально ощущается по-другому. Он будто бы улыбается тебе. Воздух пропитан какой-то атмосферой, которая говорит тебе, что это твой день. Жаль, конечно, что выпал он на рабочий день, но что уж тут поделаешь? ☹️
В общем, расписывать тут шибко не буду, остановлюсь на этом. Запомните меня таким в 29 — со смешными усиками, улыбкой и мимическими морщинами 😎
P.S. Сегодня с определенной долей вероятности включу трансляцию в 18:30. Работать не будем, поболтаем по душам, посмотрим видео, обсудим будущее канала на твиче.
Очередная достигнутая вершина в жизни любого живого организма — прожить год и не помереть. Этого, в целом, достаточно 😀
Если быть серьезным, то и в этом году были достаточно примечательные события — мы перебрались обратно в Тюмень, я ушел из Яндекса и устроился в организацию в TON, ездил на конференции с выступлениями, и наконец довел проект до состояния, которым уже кое-как можно пользоваться. Это был насыщенный воспоминаниями год, и я надеюсь, что таких будет еще больше впереди.
Как я уже когда-то говорил, День Рождения — это один из немногих дней в моей жизни, который буквально ощущается по-другому. Он будто бы улыбается тебе. Воздух пропитан какой-то атмосферой, которая говорит тебе, что это твой день. Жаль, конечно, что выпал он на рабочий день, но что уж тут поделаешь? ☹️
В общем, расписывать тут шибко не буду, остановлюсь на этом. Запомните меня таким в 29 — со смешными усиками, улыбкой и мимическими морщинами 😎
P.S. Сегодня с определенной долей вероятности включу трансляцию в 18:30. Работать не будем, поболтаем по душам, посмотрим видео, обсудим будущее канала на твиче.
14.03.202515:22
Трансляция запущена!
Developing Platformer UI and Telegram UI Kit using Solid.js!
— Software and Game Development
— twitch.tv/qbnk
Developing Platformer UI and Telegram UI Kit using Solid.js!
— Software and Game Development
— twitch.tv/qbnk
29.04.202514:19
👩💻 Почему Solid.js — это чудо / Реактивность и рендеринг
Наконец, мы подобрались к самому интересному — реактивности и рендерингу. Это как раз именно то, чем Solid удивителен, восхитителен, прекрасен и силён.
// В React.js 👩💻
Давайте вспомним, как работает реактивность и рендеринг в React. Чтобы в React создать некий реактивный юнит, используются такие примитивы как
Под перерисовкой здесь стоит понимать процесс, при котором React пытается выяснить, какие изменения произошли путем построения Virtual DOM и сравнения его с предыдущей его версией. Когда разница была обнаружена, React применяет изменения уже к обычному DOM. Собственно, вот эти сравнения Virtual DOM — одно из узких горлышек производительности React.
Вот простейший пример компонента с реактивными примитивами:
Здесь мы видим, что значение
В React вы обязаны всегда сами указывать этот список, потому как технология не способна вычислить его самостоятельно. Соответственно, если где-то зависимость вы упустили, либо же добавили новую — быть беде. Также, в React нельзя использовать вариативный список зависимостей. Количество зависимостей должно быть всегда строго одним, и это не сказать, что минус технологии. Скорее — пространство для улучшения.
В данном примере при вызове
Кроме того, что это приводит к абсолютно бесполезным аллокациям памяти, это так же порождает и проблемы, при которых функция, создаваемая в рамках компонента, используя замыкание, ссылается на конкретное значение, порожденное в рамках текущей итерации отрисовки. Ну и всегда важно помнить про DX — более сложный код с асинхронными операциями и логическими реакциями на выполнение в таких условиях писать достаточно тяжело, допустить ошибку не составит труда.
Вот пример с не совсем ожидаемым поведением функции:
Наконец, мы подобрались к самому интересному — реактивности и рендерингу. Это как раз именно то, чем Solid удивителен, восхитителен, прекрасен и силён.
// В React.js 👩💻
Давайте вспомним, как работает реактивность и рендеринг в React. Чтобы в React создать некий реактивный юнит, используются такие примитивы как
useState
, useMemo
и useEffect
. Первый создает изменяемое значение, второй — неизменяемое, но вычисляемое, третий ничего не создает, но вызывается в случае, если какая-то зависимость изменилась. Как только реактивный юнит изменился, React вызывает перерисовку компонента, который породил этот самый реактивный юнит, что приводит к перерисовке и всех дочерних элементов.Под перерисовкой здесь стоит понимать процесс, при котором React пытается выяснить, какие изменения произошли путем построения Virtual DOM и сравнения его с предыдущей его версией. Когда разница была обнаружена, React применяет изменения уже к обычному DOM. Собственно, вот эти сравнения Virtual DOM — одно из узких горлышек производительности React.
Вот простейший пример компонента с реактивными примитивами:
Здесь мы видим, что значение
squared
зависит от значения count
, и не потому, что внутри computation-функции используется значение count
, а лишь потому, что мы явно указали это значение в списке зависимостей. Это же относится и к последующему вызову хука useEffect
— там функция будет вызываться каждый раз, когда что-то из списка зависимостей меняется.В React вы обязаны всегда сами указывать этот список, потому как технология не способна вычислить его самостоятельно. Соответственно, если где-то зависимость вы упустили, либо же добавили новую — быть беде. Также, в React нельзя использовать вариативный список зависимостей. Количество зависимостей должно быть всегда строго одним, и это не сказать, что минус технологии. Скорее — пространство для улучшения.
В данном примере при вызове
setCount
, функция App
будет вызываться каждый раз, снова аллоцируя память под все переменные и вызывая уже функцию (компонент) Layout
. Как можно понять, тут начинается самое веселье, потому что надо всегда учитывать, что код компонента может вызываться N раз просто потому, что он по тем или иным причинам перерисовывается, будь то его личные изменения в реактивных юнитах, либо же изменение его родительского компонента. Кроме того, что это приводит к абсолютно бесполезным аллокациям памяти, это так же порождает и проблемы, при которых функция, создаваемая в рамках компонента, используя замыкание, ссылается на конкретное значение, порожденное в рамках текущей итерации отрисовки. Ну и всегда важно помнить про DX — более сложный код с асинхронными операциями и логическими реакциями на выполнение в таких условиях писать достаточно тяжело, допустить ошибку не составит труда.
Вот пример с не совсем ожидаемым поведением функции:
28.04.202514:17
Трансляция запущена!
Разработка Android UI в Platformer-е / Solid.js
— Software and Game Development
— twitch.tv/qbnk
Разработка Android UI в Platformer-е / Solid.js
— Software and Game Development
— twitch.tv/qbnk


25.04.202506:07
Привет.
Пока в путешествии, хотел вам тут кратко рассказать, какой Solid.js чудесный, но результаты вот примерно такие. А ведь я даже и половины не написал того, что хотел.
Чтобы вас не мучать, разобью, наверное, этот гигантский текст на кучку постов, и буду постепенно рассказывать интересности.
Свадьба закончилась, сегодня улетаем в Питер. Схожу на встречи, отдохнем, и в воскресенье двигаю обратно. Поэтому увидимся где-то в понедельник.
Ждите постов по Solid, хорошего дня 🙂
Пока в путешествии, хотел вам тут кратко рассказать, какой Solid.js чудесный, но результаты вот примерно такие. А ведь я даже и половины не написал того, что хотел.
Чтобы вас не мучать, разобью, наверное, этот гигантский текст на кучку постов, и буду постепенно рассказывать интересности.
Свадьба закончилась, сегодня улетаем в Питер. Схожу на встречи, отдохнем, и в воскресенье двигаю обратно. Поэтому увидимся где-то в понедельник.
Ждите постов по Solid, хорошего дня 🙂
15.04.202517:02
Павел ответил. Работаем.
23.03.202511:22
Трансляция запущена!
Заканчиваем работу над Платформером
— Software and Game Development
— twitch.tv/qbnk
Заканчиваем работу над Платформером
— Software and Game Development
— twitch.tv/qbnk
14.03.202511:09
Sup, lads! 👋
Сегодня включимся примерно к 6 часам, может чуть раньше, может чуть позже. На трансляции будем подпиливать интерфейса Платформера, я вам покажу его текущее состояние и то, что в интерфейсе уже работает. Не опаздывайте, интро шибко долгим не будет.
Хорошего дня и до встречи!
Сегодня включимся примерно к 6 часам, может чуть раньше, может чуть позже. На трансляции будем подпиливать интерфейса Платформера, я вам покажу его текущее состояние и то, что в интерфейсе уже работает. Не опаздывайте, интро шибко долгим не будет.
Хорошего дня и до встречи!
29.04.202514:19
Начнем с того, что в Solid компоненты вызываются единожды, то есть понятия ре-рендеринга тут нет. Каждый раз компонент если и вызывается, то это его первый вызов необходимый для того, чтобы отрисовать компонент, но не перерисовать. Запомним — функция-компонент никогда не вызывается по новой, она вызывается лишь в случае, когда компонент хотят примонтировать к DOM.
Для простоты понимания, я люблю говорить, что в Solid есть так называемые "реактивные области". Под ними следует понимать те участки кода, в которых будет работать реактивность Solid. Абстрактно говоря, это те места, куда можно положить Фиксиков, и их работа будет приводить к какой-то реакции приложения.
Примитивами для создания реактивных юнитов, именуемых сигналами, являются функции
Сигналы - это функции, вызов которых приводит к получению текущего значения, инкапсулированного внутри сигнала. Вообще, можно считать их указателями на значения. Таким образом, они не имеют ничего общего с результатом выполнения
Вот как выглядит переписанный c React компонент:
Обратите внимание, что мы явно не указали зависимости в
Если одна из зависимостей изменилась, Solid вызывает реактивную область по новой и вычисляет новый список зависимостей (так как он может меняться от вызова к вызову). Тем не менее, при желании, список зависимостей можно указать явно, можно в каких-то вызовах не отслеживать какие-то сигналы, и так далее. Технология в этом плане очень гибкая.
Важно помнить про еще один вид сигналов, который также играет очень важную роль в становлении Solid производительной технологией — все свойства компонентов реактивны. Ближе к концу статьи мы вернемся к теме о том, как атрибуты просачиваются в реальные DOM-узлы, и вам станет понятно, почему так. На текущем этапе достаточно понимать, что к свойствам компонента (например какому-нибудь
Теперь же давайте посмотрим, как будет выглядеть решение проблемы с замыканием переменной в функции:
Для простоты понимания, я люблю говорить, что в Solid есть так называемые "реактивные области". Под ними следует понимать те участки кода, в которых будет работать реактивность Solid. Абстрактно говоря, это те места, куда можно положить Фиксиков, и их работа будет приводить к какой-то реакции приложения.
Примитивами для создания реактивных юнитов, именуемых сигналами, являются функции
createSignal
и createMemo
. createSignal
порождает реактивное значение, а createMemo
делает то же самое, но при этом значение является вычисляемым на основе какой-то описанной реактивной области. createEffect
-же как будто является createMemo
, просто ничего не возвращает. Есть еще и иные, но этих для начала достаточно, они — базовые. Сигналы - это функции, вызов которых приводит к получению текущего значения, инкапсулированного внутри сигнала. Вообще, можно считать их указателями на значения. Таким образом, они не имеют ничего общего с результатом выполнения
useState
из React, потому как там возвращаются голые значения, а не указатели на них.Вот как выглядит переписанный c React компонент:
Обратите внимание, что мы явно не указали зависимости в
createMemo
и createEffect
. Solid сам понимает, от чего зависит реактивная область. Логику вычисления таких зависимостей понять достаточно просто - список зависимостей определяется списком тех сигналов, доступ к которым был получен в рамках текущего вызова реактивной области. Если одна из зависимостей изменилась, Solid вызывает реактивную область по новой и вычисляет новый список зависимостей (так как он может меняться от вызова к вызову). Тем не менее, при желании, список зависимостей можно указать явно, можно в каких-то вызовах не отслеживать какие-то сигналы, и так далее. Технология в этом плане очень гибкая.
Важно помнить про еще один вид сигналов, который также играет очень важную роль в становлении Solid производительной технологией — все свойства компонентов реактивны. Ближе к концу статьи мы вернемся к теме о том, как атрибуты просачиваются в реальные DOM-узлы, и вам станет понятно, почему так. На текущем этапе достаточно понимать, что к свойствам компонента (например какому-нибудь
props.myProp
) мы относимся как к сигналам — если хотим, чтобы их изменения извне приводили к реакции, то обращаемся к ним в рамках реактивных областей.Теперь же давайте посмотрим, как будет выглядеть решение проблемы с замыканием переменной в функции:
27.04.202516:57
21.04.202505:20
Напоследок покажу пример. У нас наверняка в каждом приложении будет какой-нибудь файлик (или компонент), который описывает стили для текущей платформы. Например, для iOS у нас один шрифт, для Android — другой.
Чтобы корректно использовать плагин, нужно завести вот такие файлы:
Ну и сам блок (из методологии BEM) GlobalStyles:
При сборке под iOS, импорты GlobalStyles.common.scss и GlobalStyles.android.scss будут порезаны 🔪 и в итоге в бандл их CSS-код не попадет.
Плагин расписывать не буду, вы можете найти исходники в отдельном репозитории, который я под всю эту идею выделил — conditional-substitution-example (сам плагин). С позавчерашней трансляции я его подпилил, чтобы учесть больше кейсов и срезать больше ненужного кода. В каких-то местах пришлось отказаться от регулярных выражений в пользу парсинга в AST (начинается вот тут), так как их стало совсем недостаточно.
// Заключение
Какой итог? Мы сделали так, что имея одно приложение, мы генерируем N отдельных бандлов, которые загружаются пользователями без overhead-а. Клиент берет только тот бандл, который специфичен для его платформы.
Теперь знаете где это использовать еще эффективнее? В Платформере. Он позволяет указывать разные ссылки для разных платформ. Вы собираете приложение, получаете N бандлов, выгружаете в Mate, а Платформеру под каждую платформу отдаете ссылку на index-файл специфичный для этой платформы. И всё.
Вот так вот можно значительно улучшить жизнь не только разработчикам, но и пользователям. Надеюсь, что эта идея пойдет в народ и разработчики смогут сделать приятно всем.
Не бойтесь писать полезные плагины, не бойтесь писать эффективные решения. Это не всегда так сложно, как кажется. На этом у меня всё, пользуйтесь на здоровье, и продуктивной недели! 😇
Чтобы корректно использовать плагин, нужно завести вот такие файлы:
Ну и сам блок (из методологии BEM) GlobalStyles:
При сборке под iOS, импорты GlobalStyles.common.scss и GlobalStyles.android.scss будут порезаны 🔪 и в итоге в бандл их CSS-код не попадет.
Плагин расписывать не буду, вы можете найти исходники в отдельном репозитории, который я под всю эту идею выделил — conditional-substitution-example (сам плагин). С позавчерашней трансляции я его подпилил, чтобы учесть больше кейсов и срезать больше ненужного кода. В каких-то местах пришлось отказаться от регулярных выражений в пользу парсинга в AST (начинается вот тут), так как их стало совсем недостаточно.
// Заключение
Какой итог? Мы сделали так, что имея одно приложение, мы генерируем N отдельных бандлов, которые загружаются пользователями без overhead-а. Клиент берет только тот бандл, который специфичен для его платформы.
Теперь знаете где это использовать еще эффективнее? В Платформере. Он позволяет указывать разные ссылки для разных платформ. Вы собираете приложение, получаете N бандлов, выгружаете в Mate, а Платформеру под каждую платформу отдаете ссылку на index-файл специфичный для этой платформы. И всё.
Вот так вот можно значительно улучшить жизнь не только разработчикам, но и пользователям. Надеюсь, что эта идея пойдет в народ и разработчики смогут сделать приятно всем.
Не бойтесь писать полезные плагины, не бойтесь писать эффективные решения. Это не всегда так сложно, как кажется. На этом у меня всё, пользуйтесь на здоровье, и продуктивной недели! 😇


25.03.202516:00
Как порядочный гражданин, купил лицензию на WebStorm и GoLand на год. Обидно было осознать, что я потерял свою скидку из-за того, что получил Open Source лицензию на год. Эх..
Что удивительно, WebStorm перестал показывать уведомление о том, что услуги в России они не предоставляют. То-ли баг, то-ли повезло так.
Что удивительно, WebStorm перестал показывать уведомление о том, что услуги в России они не предоставляют. То-ли баг, то-ли повезло так.
23.03.202510:20
Привет. Сегодня включаемся в 14:30, будем дорабатывать Платформер. Осталось совсем немного. Расскажу интересных вещей, связанных с разработкой и не только.
Не опаздывайте! 🥸
Не опаздывайте! 🥸


12.03.202508:44
Я уже даже не знаю, над чем конкретно тут посмеяться, так много идей.
Давайте поясню, потому что у нас наверняка много новичков-программистов.
Во-первых, факт того, что язык является оберткой над другим языком, не является недостатком. Это просто факт в случае TypeScript, из него ничего не вытащить.
Во-вторых, будучи ИБ-шником по образованию, слышать термин "дешифровка" просто уморительно. Дешифровка — это про взлом алгоритма шифрования, либо же подбор его параметров с попыткой получить исходные данные из зашифрованных. Расшифровка — процесс, обратный шифрованию, то есть преобразование зашифрованных данных к первоначальному виду, имея необходимые для этого данные. Видимо, автор имел ввиду "парсинг" или "валидацию", но как при этом в голову могло прийти слово "дешифровка", вообще непонятно.
В-третьих, строгость типизации не имеет ничего общего с валидацией данных, полученных из третьих источников. Ты хоть на C# пиши, данные валидировать все равно придется, и это проблема абсолютно любого языка. То что кто-то используя TypeScript пишет "response as MyType" — не проблема TypeScript-а, а разработчика с руками из попы.
В общем, кек. Или как там принято? Ауф?
Давайте поясню, потому что у нас наверняка много новичков-программистов.
Во-первых, факт того, что язык является оберткой над другим языком, не является недостатком. Это просто факт в случае TypeScript, из него ничего не вытащить.
Во-вторых, будучи ИБ-шником по образованию, слышать термин "дешифровка" просто уморительно. Дешифровка — это про взлом алгоритма шифрования, либо же подбор его параметров с попыткой получить исходные данные из зашифрованных. Расшифровка — процесс, обратный шифрованию, то есть преобразование зашифрованных данных к первоначальному виду, имея необходимые для этого данные. Видимо, автор имел ввиду "парсинг" или "валидацию", но как при этом в голову могло прийти слово "дешифровка", вообще непонятно.
В-третьих, строгость типизации не имеет ничего общего с валидацией данных, полученных из третьих источников. Ты хоть на C# пиши, данные валидировать все равно придется, и это проблема абсолютно любого языка. То что кто-то используя TypeScript пишет "response as MyType" — не проблема TypeScript-а, а разработчика с руками из попы.
В общем, кек. Или как там принято? Ауф?
Көрсөтүлдү 1 - 24 ичинде 30
Көбүрөөк функцияларды ачуу үчүн кириңиз.