<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Веб-платформа</title><description>О том, как всё устроено в веб-платформе и что происходит в индустрии фронтенда. Новости, полезные выжимки, находки и напоминания</description><link>https://juwain.github.io/</link><item><title>Метрики Web Vitals</title><link>https://juwain.github.io/web-platform/blog/2021-02-24/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-24/</guid><description>На ранжирование страниц в в Гугл-поиске влияет не только качество контента, но и хороший UX</description><pubDate>Wed, 24 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;На ранжирование страниц в в Гугл-поиске влияет не только качество контента, но и хороший UX. По мнению Гугла его можно оценить по трём метрикам:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;время загрузки сайта;&lt;/li&gt;
&lt;li&gt;время до возможности взаимодействовать с интерактивнымм элементами на сайте;&lt;/li&gt;
&lt;li&gt;визуальная «стабильность» интерфейса сайта.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Эти метрики объединили под общим названием Web Vitals. Теперь про каждую подробнее.&lt;/p&gt;
&lt;h3&gt;Время загрузки сайта (LCP, Largest Contentful Paint)&lt;/h3&gt;
&lt;p&gt;Дословно — время до отрисовки самого большого видимого контентного куска. Это может быть картинка, видео или текст. То есть это время с момента перехода на страницу и до &lt;em&gt;ощущения&lt;/em&gt;, что всё загрузилось и до возможности начать взаимодействие со страницей.&lt;/p&gt;
&lt;p&gt;Хорошо, когда это время 2,5 секунды или меньше; 2,5-4 секунды — норм, но надо улучшать; больше 4 секунд — плохо, пользователь не дождётся и уйдёт.&lt;/p&gt;
&lt;p&gt;На эту метрику влияют:&lt;/p&gt;
&lt;p&gt;➡️ Размер загружаемых ресурсов&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;нужно сжимать картинки и остальную статику саму по себе (минификация) и на сервере (gzip, brotli);&lt;/li&gt;
&lt;li&gt;нужно уменьшать размер блочащих рендер ресурсов — JS и CSS — разделять их на мелкие бандлы по страницам, а реиспользуемый код выносить в небольшие отдельные модули.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;➡️ Способ загрузки ресурсов&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;картинки нужно загружать «лениво», то есть только в момент, когда они становятся непосредственно видимы;&lt;/li&gt;
&lt;li&gt;сторонние скрипты (аналитика, реклама, виджеты) нужно загружать асинхронно, вне основного потока.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Время до интерактивности (FID, First Input Delay)&lt;/h3&gt;
&lt;p&gt;Это когда при взаимодействии с интерактивными элементами сайта не возникает большой задержки. Например, при клике на элементы формы, ссылки, выпадашки.&lt;/p&gt;
&lt;p&gt;Если задержки меньше 100 милисекунд, то человеком это воспринимается нормально; 100-300мс — может казаться тормознутым; больше 300мс — явно тормозит, плохо.&lt;/p&gt;
&lt;p&gt;На эту метрику влияет всё, что может «забивать» основной поток работы браузерного движка:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;долгие таски в JS-коде;&lt;/li&gt;
&lt;li&gt;неоптимальное использование операций, вызывающие перерасчёт лейаута страницы (&lt;a href=&quot;https://gist.github.com/paulirish/5d52fb081b3570c81e3a&quot;&gt;список операций&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;большое количество DOM-нод на странице.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Визуальная «стабильность» интерфейса (CLS, Cumulative Layout Shift)&lt;/h3&gt;
&lt;p&gt;Дословно — сдвиги лейаута при загрузке. Если при загрузке страница «прыгает», элементы перескакивают с места не место, загружающиеся элементы сдвигают контент, то это плохо влияет на пользовательский опыт.&lt;/p&gt;
&lt;p&gt;➡️ Чаще всего сдвиги могут вызывать подгружающиеся картинки, видео, реклама. Фиксится заданием фиксированных размеров картинкам и контейнерам, в которые вставляет реклама.&lt;/p&gt;
&lt;p&gt;➡️ Если сдвиги происходят после отрабатывания скриптов, то тоже можно поставить «подпорки» в CSS, которые не допустят сдвигов.&lt;/p&gt;
&lt;p&gt;➡️ Если контент сдвигается при подгрузке и применении кастомного шрифта, то можно изменить способ показа шрифта на &lt;code&gt;font-display: optional&lt;/code&gt;, то есть скрывать текст и задерживать «мигание» до 100мс, пока не загрузится шрифт. Также можно использовать формат шрифтов woff2, вырезать ненужные символы и предзагружать шрифты.&lt;/p&gt;
&lt;h3&gt;⚡️ Как измерять в продакшене&lt;/h3&gt;
&lt;p&gt;В сервисе &lt;a href=&quot;https://developers.google.com/speed/pagespeed/insights/&quot;&gt;PageSpeed Insight&lt;/a&gt; или &lt;a href=&quot;https://www.webpagetest.org/&quot;&gt;webpagetest&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;💻 Как измерять при разработке&lt;/h3&gt;
&lt;p&gt;Локально можно воспользоваться сервисом &lt;a href=&quot;https://developers.google.com/web/tools/lighthouse?hl=ru&quot;&gt;Lighthouse&lt;/a&gt; или расширением &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma&quot;&gt;Web Vitals&lt;/a&gt; для Хрома. Также посдсветка Web Vitals появилась во вкладке &quot;Performance&quot; в Dev Tools 88-й версии Хрома.&lt;/p&gt;
&lt;p&gt;Так как метрика &lt;strong&gt;First Input Delay (FID)&lt;/strong&gt; не может быть достоверно измерена локально, то её можно «проксировать» другой метрикой — &lt;strong&gt;Total Blocking Time (TBT)&lt;/strong&gt;. Это время с начала отрисовки страницы до момента её полной готовности к взаимодействию. Улучшение &lt;strong&gt;TBT&lt;/strong&gt; приведёт к улучшению реальной пользовательской &lt;strong&gt;FID&lt;/strong&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Скриншоты в Dev Tools</title><link>https://juwain.github.io/web-platform/blog/2021-02-25/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-25/</guid><description>Из средств разработчика DevTools в Chrome и Firefox можно делать скриншоты</description><pubDate>Thu, 25 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Из средств разработчика DevTools в Chrome и Firefox можно делать скриншоты.&lt;/p&gt;
&lt;h3&gt;📸 Отдельная DOM-нода страницы&lt;/h3&gt;
&lt;p&gt;Для этого нужно просто вызвать контекстное меню на ноде в инспекторе и выбрать нужный пункт:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;в Chrome — вкладка Elements, в меню на ноде пункт &lt;em&gt;Capture node screenshot&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;в Firefox — вкладка Inspector, в меню на ноде пункт &lt;em&gt;Screenshot Node&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;📸 Выделенная область или весь сайт&lt;/h3&gt;
&lt;p&gt;Для этого нужно перейти в режим «адаптивности» и оттуда уже сделать скриншот:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;в Chrome нужно нажать кнопку &lt;em&gt;Toggle device toolbar&lt;/em&gt; в левом верхнем углу окошка средств разработчика (или нажать &lt;strong&gt;Cmd/Ctrl + Shift + M&lt;/strong&gt;), затем в появившейся верхней панели в её правом углу нажать три точки, чтобы выпало меню, и там выбрать &lt;em&gt;Capture screenshot&lt;/em&gt; (для снимка видимой области) или &lt;em&gt;Capture full size screenshot&lt;/em&gt; (для снимка всего экрана). Также эти команды можно вызвать текстом из командного меню по &lt;strong&gt;Cmd/Ctrl + Shift + P&lt;/strong&gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;в Firefox нужно перейти в режим &lt;em&gt;Responsive Design Mode&lt;/em&gt; кнопкой в правом верхнем углу окошка средств разработчика (или нажать &lt;strong&gt;Cmd/Ctrl + Opt/Alt + M&lt;/strong&gt;), затем в появившейся верхней панели нажать на иконку с фотоаппаратом. Чтобы заскриншотить всю страницу, то сначала нужно включить эту фичу в настройках DevTools: открыть настройки и там поставиьт галочку &lt;em&gt;Take a screenshot of the entire page&lt;/em&gt;. После этого рядом с иконкой &lt;em&gt;Responsive Design Mode&lt;/em&gt; появится иконка с фотоаппаратом, которая делает полноразмерный скриншот страницы.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Прикольно, что в таком скриншоте через браузер можно имитировать высокую плотность пикселей, даже если на вашем девайсе неретиновый экран.&lt;/p&gt;
&lt;p&gt;💡 Заодно в настройках FF нашёл встроенную в DevTools линейку.&lt;/p&gt;
</content:encoded></item><item><title>Event loop и рендер в браузере, часть 1</title><link>https://juwain.github.io/web-platform/blog/2021-03-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-03-16/</guid><description>В браузере есть «исполнитель», который на сайте постоянно ждёт задачи на исполнение — такой бесконечный цикл, который называется Event Loop</description><pubDate>Tue, 16 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Представьте себе, что вы работаете в компании, и ваша работа — общаться и информировать клиентов. Вы появляетесь на рабочем месте, включаете компьютер и начинаете ждать. Вы в компании единственный, кто общается с клиентами, поэтому все входящие заявки приходят вам.&lt;/p&gt;
&lt;p&gt;К вам сразу же клиенты начинают звонить по телефону. Ваша задача:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Ответить им, пообщаться, понять их вопрос;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Затем внести клиента в ваш список, найти ответ на вопрос и сообщить клиенту ответ, завершить разговор;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;От некоторых клиентов (не от всех) нужно отправить полученную информацию по почте внутрь компании, чтобы с ней проложили работать коллеги.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Таким образом у вас есть всегда некая очередь входящих звонков и очередь писем на отправку. Если звонит телефон, то вы отвлекаетесь от почты, и отвечаете по телефону. Если телефон молчит, то вы переходите к отправке почты. Соответсвенно, если телефонные звонки длинные, то очередь звонков копится, и вы не успеваете отправлять почту. Или наоборот, если вам нужно отправлять письма очень часто или они большие, то вы будете с задержками отвечать по телефону.&lt;/p&gt;
&lt;h3&gt;Event Loop&lt;/h3&gt;
&lt;p&gt;А теперь представьте, что в браузере есть тоже некий «исполнитель», который на сайте постоянно ждёт задачи на исполнение — такой бесконечный цикл, который называется Event Loop. Он делает все задачи по исполнению JS-кода (Task) и отрисовке сайта (Render). Этот исполнитель один, и работает он в одном «потоке», так как задачи по исполнению JS-кода и отрисовке DOM взаимосвязаны и их проблематично разделять. Event loop связан с обновлением экрана — в нём рассчитываются кадры страницы.&lt;/p&gt;
&lt;p&gt;Все JS-задачи, которые поступают на исполнение, ставятся в очередь — TaskQueue. Задачи по рендеру тоже записываются в очередь — RenderQueue. Вспомните пример со звонками и почтой. Исполнитель делает поступающие JS-задачи (это очередь телефонных звонков), а когда освобождается от них, переходит к задачам по отрисовке интерфейса (отправка почты).&lt;/p&gt;
&lt;p&gt;В приоритете — работа с JS-задачами, а когда приходит необходимость отрисовать следующий кадр для обновления экрана, Event Loop переходит к задачам отрисовки.&lt;/p&gt;
&lt;p&gt;Как определяется эта необходимость? Современные устройства работают с частотой отрисовки 60 кадров в секунду (FPS). Это значит, что каждые 16.6мс (1/60 секунды) браузеру нужно перерисовывать следующий кадр.&lt;/p&gt;
&lt;p&gt;В случае с общением нашего менеджера с клиентами по телефону, длинные звонки «задерживают» отправку почты. Так же и длинные JS-задачи (&amp;gt;16.6мс) заставляют браузер откладывать отрисовку. Поэтому в момент, когда отрисовка уже была нужна, браузер может «пропустить» кадр. То есть частота обновления кадров станет уже &amp;lt;60FPS. Визуально интерфейс начнёт «подтормаживать» или вообще «фризиться».&lt;/p&gt;
&lt;p&gt;Аналогично и со случаем, когда много писем в очереди могут помешать менеджеру вовремя отвечать на звонки. Если в RenderQueue задач по отрисовке много или они сложные, то исполнение JS-задач в TaskQueue тоже может задерживаться, что проявляется в «тормозах».&lt;/p&gt;
&lt;h3&gt;Микротаски&lt;/h3&gt;
&lt;p&gt;Есть ещё одна разновидность задач — микротаски (MicroTask). Это такие особенные JS-задачи — колбеки для Promise или mutationObserver. Микротаски собираются в отдельную очередь — MicroTaskQueue. Чем микротаски отличаются от обычных тасков? Они исполняются сразу же, когда дорабатывает текущий таск или микротаск, то есть вне очереди TaskQueue и RenderQueue. Эта особенность может быть критична в случае, когда микротаски циклично вызывают следующие микротаски, откладывая рендер и обычные JS-таски, так как до них просто не доходит очередь.&lt;/p&gt;
</content:encoded></item><item><title>Event loop и рендер в браузере, часть 2</title><link>https://juwain.github.io/web-platform/blog/2021-03-18/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-03-18/</guid><description>В момент, когда браузер освобождается от JS-тасок и микротасок, он готов выполнять рендер</description><pubDate>Thu, 18 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Что происходит в RenderQueue?&lt;/h3&gt;
&lt;p&gt;Вот в такой последовательности исполняется рендер:&lt;/p&gt;
&lt;p&gt;JS (RequestAnimationFrame) &amp;gt; Style &amp;gt; Layout &amp;gt; Paint &amp;gt; Composite&lt;/p&gt;
&lt;h4&gt;Этап JS (RequestAnimationFrame)&lt;/h4&gt;
&lt;p&gt;В момент, когда браузер освобождается от JS-тасок и микротасок, он готов выполнять рендер. С помощью колбека &lt;em&gt;requestAnimationFrame&lt;/em&gt; можно «подписаться на свободный момент» в общей очереди исполнения задач. Так как браузер гарантированно будет «не занят» чем-то другим, то это удобный момент, чтобы отрисовать анимацию, посчитать что-то или изменить кадр до его отрисовки.&lt;/p&gt;
&lt;h4&gt;Этап Style&lt;/h4&gt;
&lt;p&gt;На этом этапе выясняется, какие CSS-правила применяются к элементам на странице и затем вычисляются (computed) значения CSS-свойств всех необходимых правил. Также если из JS напрямую изменяются значения CSS-свойств или на элементы навешиваются CSS-классы, то тоже запускается этот этап.&lt;/p&gt;
&lt;h4&gt;Этап Layout&lt;/h4&gt;
&lt;p&gt;Браузер определяет слои с элементами, вычисляет, какого размера элементы, и где они находятся в слое. Так как элементы в слое влияют друг на друга в потоке, то изменение размеров одного элемента может повлечь сдвиг и повторный layout дочерних или последующих элементов. При изменении размеров элементов в JS или даже при считывании информации о размерах, браузер форсирует исполнение layout — выполняет force layout — что приводит к остановке исполнения JS-тасок или микротасок и экстренной перерисовке.
&lt;a href=&quot;https://gist.github.com/paulirish/5d52fb081b3570c81e3a&quot;&gt;Список операций, форсирующих layout&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Этап Paint&lt;/h4&gt;
&lt;p&gt;Браузер отрисовывает текст, цвета, изображения, рамки и весь остальной внешний вид элементов.&lt;/p&gt;
&lt;h4&gt;Этап Composite&lt;/h4&gt;
&lt;p&gt;Браузер разбирается с наложением слоёв друг на друга, с их «композицией». Слои должны отображаться в нужном порядке. В результате этого этапа получается готовый отрисованный кадр с наслоёнными элементами.&lt;/p&gt;
&lt;p&gt;Особенные CSS-свойства для этого этапа — &lt;code&gt;transform&lt;/code&gt; и &lt;code&gt;will-change&lt;/code&gt;. Для элементов с заданным &lt;code&gt;transform&lt;/code&gt; браузер задействует процесс composition. В случае с &lt;code&gt;will-change&lt;/code&gt; — это подсказка для браузера, что для элемента нужно использовать composition-процесс.&lt;/p&gt;
</content:encoded></item><item><title>Стрелочная функция и new</title><link>https://juwain.github.io/web-platform/blog/2021-02-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-16/</guid><description>Стрелочная функция не может использоваться как конструктор</description><pubDate>Tue, 16 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Обычная функция &lt;code&gt;function&lt;/code&gt; может использоваться в качестве конструктора:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Dog(color) {
  this.color = color;
}

const blackDog = new Dog(&quot;black&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Стрелочная функция не может использоваться как конструктор. При попытке использования выбросится ошибка TypeError.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const Dog = (color) =&amp;gt; {
  this.color = color;
};

const blackDog = new Dog(&quot;black&quot;);
// TypeError: Dog is not a constructor
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>DOM и JS-фреймворки</title><link>https://juwain.github.io/web-platform/blog/2021-02-19/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-19/</guid><description>В фреймворках React и Vue используется концепт «Virtual DOM»</description><pubDate>Fri, 19 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В фреймворках React и Vue используется концепт «Virtual DOM». Это представление «реального» UI, то есть DOM-а в браузере пользователя, в виде объекта в JS. Этот объект хранится в памяти браузера и представляет собой такую же иерархическую структуру, что и настоящее DOM-дерево. Упрощённо говоря — так:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;box&quot;&amp;gt;
  &amp;lt;h1&amp;gt;Title&amp;lt;/h1&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;const virtualNode = {
  type: &quot;div&quot;,
  props: {
    className: &quot;box&quot;,
    children: [
      {
        type: &quot;h1&quot;,
        props: {
          children: [&quot;Title&quot;],
        },
      },
    ],
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Зачем делать такую копию DOM-а в памяти? Это нужно для оптимизации работы с настоящим DOM-ом в браузере. Возьмём пример: в браузере отрисовано 1000 DOM-нод, среди них нужно заменить одну ноду. Брать и заменять всё содержимое родительской ноды — неоптимально.&lt;/p&gt;
&lt;p&gt;Лучше будет:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Хранить предыдущее и новое состояние (в памяти, виртуальном DOM-е).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;По специальному алгоритму найти различия между двумя состояниями.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;И затем синхронизировать реальное и виртуальное представление DOM-а, обновив точечно только нужные части дерева.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Этот процесс «сверки» нод в React называется &lt;em&gt;reconciliation&lt;/em&gt; (в русском уже адаптировалось «реконсиляция»). Полное сравнение двух DOM-деревьев может быть довольно «дорогим» по ресурсам, особенно когда нод в них много. Поэтому во фреймворках в алгоритмах сверки и обновления заложены допущения, позволяющие избежать трат слишком больших ресурсов компьютера.&lt;/p&gt;
&lt;p&gt;Например:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;В повторяющихся наборах (списках, листингах) каждая нода помечается уникальным «ключом» — атрибутом key. По таким «подсказкам от разработчика» (уникальным идентификаторам, хэшам) фреймворку легче сравнивать ноды в DOM-деревьях: можно распознать изменение, не залезая внутрь ноды и не ориентируясь на её очерёдность в списке. Задача сводится к работе с «набором ключей» (HashMap): фреймворк определяет появление элементов с новыми ключами или изменение порядка элементов по их ключам.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Если меняется тип DOM-ноды, например, с &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; на &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, то фреймворк заменит саму ноду и все её дочерние элементы целиком.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Плавный скролл в CSS</title><link>https://juwain.github.io/web-platform/blog/2021-02-22/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-22/</guid><description>Переход по якорным ссылкам внутри страницы мгновенно «перебрасывает» к нужному месту</description><pubDate>Mon, 22 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Переход по якорным ссылкам внутри страницы мгновенно «перебрасывает» к нужному месту:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;a class=&quot;back-to-top&quot; href=&quot;#top&quot;&amp;gt;Scroll to Top&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Такое моментальное перемещение может вызвать непонимание, что именно произошло, а это плохой UX. Именно поэтому такой скролл лучше делать плавным, чтобы было видно явно, откуда скролл «выехал» и где остановился.&lt;/p&gt;
&lt;p&gt;Нативное решение можно сделать и на JS, и на CSS.&lt;/p&gt;
&lt;h3&gt;JS-решение&lt;/h3&gt;
&lt;p&gt;В метод &lt;code&gt;scroll&lt;/code&gt; или &lt;code&gt;scrollIntoView&lt;/code&gt; передаётся настройка &lt;code&gt;behavior: &apos;smooth&apos;&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const backLink = document.querySelector(&quot;.back-to-top&quot;);

backLink.addEventListener(&quot;click&quot;, (e) =&amp;gt; {
  // отключаем «перескок» по умолчанию
  e.preventDefault();

  // плавно скроллим к самому верху страницы
  window.scroll({ top: 0, behavior: &quot;smooth&quot; });

  // или скроллим к элементу с id=&quot;top&quot;
  document.querySelector(&quot;#top&quot;).scrollIntoView({ behavior: &quot;smooth&quot; });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CSS-решение&lt;/h3&gt;
&lt;p&gt;Контейнеру со скроллом задаётся свойство &lt;code&gt;scroll-behavior&lt;/code&gt;. Это может быть и вся страница, то есть контейнер самого верхнего уровня — &lt;code&gt;html&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;html {
  scroll-behavior: smooth;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Когда скролл к элементу произошёл, то верхняя
часть экрана «упрётся» прямо в блок, к которому произошёл скролл. Чтобы такого
«прилипания» не произошло, можно воспользоваться свойством &lt;code&gt;scroll-margin&lt;/code&gt;,
которое задаст элементу внешние отступы, учитывающиеся только при скролле.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#top {
  scroll-margin-top: 20px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Таким образом от верхнего края экрана до
блока, к которому произошёл скролл, останется «зазор» в 20 пикселей.&lt;/p&gt;
</content:encoded></item><item><title>Зачем нужен Symbol?</title><link>https://juwain.github.io/web-platform/blog/2021-02-23/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-23/</guid><description>Symbol — это встроенный в язык инструмент для создания гарантированно уникальных и неизменных значений, идентификаторов</description><pubDate>Tue, 23 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В JS есть тип данных — &lt;code&gt;Symbol&lt;/code&gt;. Название не говорящее само за себя сходу, и непонятно зачем он нужен. Давайте разбираться.&lt;/p&gt;
&lt;p&gt;Вообще &lt;code&gt;Symbol&lt;/code&gt; — это встроенный в язык инструмент для создания гарантированно уникальных и неизменных значений, идентификаторов.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const mySymbol = Symbol();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В переменной &lt;code&gt;mySymbol&lt;/code&gt; в примере кода выше будет храниться «нечто», что уникально и что нельзя никак изменить, похожее и на объект, и на примитив.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Symbol&lt;/code&gt; появился в стандарте ES2015, когда язык сильно менялся и в нём появлялись новые методы. При появлении новых фич нужно было не «сломать» старые.&lt;/p&gt;
&lt;p&gt;В частности нужна была возможность добавлять в объекты новые свойства, но чтобы:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Все методы для «перебора», например, &lt;code&gt;for-in&lt;/code&gt; или &lt;code&gt;Object.keys()&lt;/code&gt;, продолжили работать как раньше;&lt;/li&gt;
&lt;li&gt;Не было риска «пересечения» названий новых и уже существующих свойств.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Про перебор&lt;/h3&gt;
&lt;p&gt;Например, у объекта есть условно три свойства:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = { first: &quot;1&quot;, second: &quot;2&quot;, third: &quot;3&quot; };
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Предположим, что некая программа рассчитывает, что у объекта есть ровно три свойства, к примеру, при переборе в цикле &lt;code&gt;for-in&lt;/code&gt;. И если комитет разработки языка вдруг решит, что у всех объектов в JS должно просто появиться новое четвёртое свойство, например, &lt;code&gt;coolNewProperty&lt;/code&gt;, то программа сломается.&lt;/p&gt;
&lt;p&gt;А вот если создать новое свойство объекта как символ, то оно не появится в списке всех свойств при итерации.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const myObject = { first: &quot;1&quot;, second: &quot;2&quot;, third: &quot;3&quot; };
const coolNewProperty = Symbol();

myObject[coolNewProperty] = &quot;coolNewValue&quot;;

for (let property in myObject) {
  console.log(property);
  // Выведется first second third
}

console.log(myObject[coolNewProperty]);
// Выведется coolNewValue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Про «пересечение» имён&lt;/p&gt;
&lt;p&gt;С помощью символа можно «безопасно» создать новое свойство в объекте, не боясь, что в будущих версиях языка или сторонних библиотеках появится свойство с таким же названием.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let myArray = [1, 2, 3];

const reverse = Symbol();

Array.prototype[reverse] = () =&amp;gt; console.log(&quot;custom reverse&quot;);

console.log(myArray.reverse());
// Выведется [3, 2, 1]

console.log(myArray[reverse]());
// Выведется custom reverse
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Реактивность в CSS</title><link>https://juwain.github.io/web-platform/blog/2021-02-15/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-15/</guid><description>Реактивность — это когда изменение состояния одной штуки приводит к реакции</description><pubDate>Mon, 15 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Реактивность — это когда изменение состояния одной штуки приводит к реакции — изменению состояния других штук. К примеру, если температура воздуха опустилась ниже 0°C, вода замёрзнет и сожмётся.&lt;/p&gt;
&lt;p&gt;Реактивность в программировании тоже про реакцию на изменение состояния. Пример:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let number = 2;
let doubled = number * 2;
// doubled равно 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Число &lt;code&gt;number&lt;/code&gt; — это переменная состояния. Удвоенное число &lt;code&gt;doubled&lt;/code&gt; «выводится» из этой переменной. Если число меняется, то удвоенное число по умолчанию не «обновится», нужно явно вычислить его ещё раз:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let number = 2;
let doubled = number * 2;
// doubled равно 4

number = 5;
doubled = number * 2;
// doubled равно 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Такая «ручная реактивность» неоптимальна. Современные JS-фреймворки, например Svelte, умеют в автоматическую реактивность. Для этого «реактивное» значение нужно явно определить, а фреймворк будет автоматически следить за изменением «источников» и пересчитывать состояние:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let number = 2;
$: doubled = number * 2;
// doubled равно 4

number = 5;
// doubled стало 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Нативные переменные в CSS — сразу реактивные «из коробки». Браузер будет следить за их изменением и пересчитывать все зависящие от них значения.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;block&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;block modified&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;.block {
  --number: 20px;
  --doubled: calc(var(--number) * 2);

  width: var(--doubled);
  /* width равно 40px */
}

.block.modified {
  --number: 50px;
  /* width стало 100px */
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Hot Module Replacement на нативных ES-модулях</title><link>https://juwain.github.io/web-platform/blog/2021-02-26/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-02-26/</guid><description>HMR — это способ точечного обновления в браузере только изменившихся JS-модулей приложения вместо полной перезагрузки страницы</description><pubDate>Fri, 26 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Представьте, что вы начинаете разрабатывать JS-приложение. При разработке вы используете локальный сервер, запускаете проект, далее собирается JS-бандл и приложение открывается в браузере. В вашем проекте пока что немного модулей, и приложение «собирается» быстро. Правда в процессе разработки вам приходится полностью обновлять страницу, чтобы увидеть, как работают ваши написанные скрипты, и состояние приложения теряется при перезагрузке. Со временем также модулей в приложении становится много и полная «пересборка» теперь длится долго.&lt;/p&gt;
&lt;p&gt;Решение этой проблемы — инкрементальная пересборка. То есть билд только тех модулей, которые вы только что изменили, вместо пересборки бандла всего приложения целиком.&lt;/p&gt;
&lt;p&gt;Ок, сделали. Перебилд теперь проиcходит быстрее, но страницу всё ещё приходится полностью перезагружать для обновления. Теперь задача в том, чтобы точечно обновить загруженный код в вашем браузере с запущенным сервером. Как это сделать «на горячую», без перезагрузки всей страницы целиком? Для этого придуман подход Hot Module Replacement (HMR).&lt;/p&gt;
&lt;p&gt;HMR — это способ точечного обновления в браузере только изменившихся JS-модулей приложения вместо полной перезагрузки страницы. Дальше я рассмотрю, как HMR реализован в сборщиках на нативных ES-модулях — например, в &lt;a href=&quot;https://www.snowpack.dev/&quot;&gt;Snowpack&lt;/a&gt; или &lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;В HMR-движке на нативных ES-модулях есть две части: серверная и клиентская.&lt;/p&gt;
&lt;p&gt;На сервере из всех модулей и их зависимостей (import и export) строится дерево: в корне — «главный» модуль (что-то типа app.js), от него расходится древовидная цепочка подключаемых JS-модулей, от которых модуль зависит.&lt;/p&gt;
&lt;p&gt;Также на сервере стороне подготавливаются все файлы модулей и запускается WebSocket Server, который будет ждать сообщения от клиента, с запросом на пересборку дерева или на перезагрузку страницы целиком.&lt;/p&gt;
&lt;p&gt;Клиент подключается к серверу по WebSocket. Когда изменяется один из файлов JS-модулей, от клиента на сервер отправляется сообщение, какой именно модуль изменился.&lt;/p&gt;
&lt;p&gt;Когда сервер получает сообщение от клиента, он начинает анализировать зависимости этого модуля. Сервер идёт вверх по цепочке родительских зависимостей и инвалидирует их до тех пор, пока не дойдёт до «граничного» модуля — это последний элемент в цепочке, который явно помечен как принимающий HMR-обновления. Именно этот файл и все его зависимости сервер «перебилдит», а клиент запросит на обновление. В случае, если этим «граничным» модулем окажется корневой модуль app.js, то приложение перезагрузится целиком.&lt;/p&gt;
&lt;p&gt;Так как в движке используется механизм нативных ES-модулей найти «граничный» родительский модуль и заменить его — достаточно. Все дочерние зависимости модуля уже обработаются и загрузятся автоматически самим браузером.&lt;/p&gt;
&lt;p&gt;Итоговый найденный «граничный» модуль теперь нужно «подменить», а затем перестроить дерево зависимостей (убрать старые связи и добавить новые), ведь во внесённых изменениях могли быть подключены новые модули.&lt;/p&gt;
&lt;p&gt;Как же именно «подменяется» модуль со старого на новый?&lt;/p&gt;
&lt;p&gt;В случае, если используются нативные ES-модули, выполняется динамический &lt;code&gt;import&lt;/code&gt; интересующего модуля. А если преварительно изменившиеся файлы ещё нужно «сбилдить», то перед импортом ещё выполняется этот этап билда.&lt;/p&gt;
&lt;p&gt;Чтобы импортировать свежий файл (не кешированную браузером версию), то к импорту можно добавить уникальную метку, например, текущий timestamp:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const updateID = Date.now();
import(muduleName + `?time=${updateID}`);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Остаётся решить вопрос, как при такой «подмене» передать в новый модуль состояние из старого модуля.&lt;/p&gt;
&lt;p&gt;Для этого на колбеке динамического импорта нового модуля нужно забрать интересущие данные из старого модуля и записать данные в новый.&lt;/p&gt;
&lt;p&gt;Посмотрим детали реализации.&lt;/p&gt;
&lt;p&gt;Всю служебную инфу о модуле будем записывать в специальном объекте &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import.meta&quot;&gt;import.meta&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Самое первое, что нужно, это пометка, участвует ли модуль в HMR-процессе. Это объект &lt;code&gt;import.meta.hot&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// тут идёт код модуля
let test = 1;

//...

if (import.meta.hot) {
  // в этот условии записывается вся начинка HMR
  // нужная только для режима разработки
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Всё, что сборщик встретит внутри таких условий в модулях, он будет использовать только в режиме разработки. При билде для продашкена все эти места будут выпилены.&lt;/p&gt;
&lt;p&gt;Внутри &lt;code&gt;import.meta.hot&lt;/code&gt; есть несколько методов, которые будут вызываться на этапах «жизни» HMR-модуля и свойств.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import.meta.hot.accept&lt;/code&gt; — этот метод, который в старом модуле принимает подменённый новый модуль.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export let value = 1;

import.meta.hot.accept(({ module }) =&amp;gt; {
  // module – новый импортированный модуль
  value = module.value;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;При замене нужно сменить переменные в экспортирующих частях модуля со старого на новый модуль.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import.meta.hot.dispose&lt;/code&gt; — этот метод, который в старом модуле запускается перед подключением нового модуля, чтобы подчистить в старом необходимые штуки (отключить стили, снять обработчики событий).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;document.head.appendChild(style);

import.meta.hot.dispose(() =&amp;gt; {
  document.head.removeChild(style);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import.meta.hot.decline&lt;/code&gt; — это метод для того, чтобы модуль мог безусловно отклонить HMR-обновление. Этот метод триггерит полную перезагрузку страницы. Он нужнен, например, в случае, если модуль вносит в состояние приложения какие-то непоправимые сайд-эффекты.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// HMR безусловно отклоняется
import.meta.hot.decline();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import.meta.hot.invalidate&lt;/code&gt; — это метод для того, чтобы по условию пометить модуль как нуждающийся в обновлении и стриггерить перезагрузку страницы.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Если something, то модуль инвалидируется
import.meta.hot.accept(({ module }) =&amp;gt; {
  if (something) {
    import.meta.hot.invalidate();
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import.meta.hot.data&lt;/code&gt; — «буфер» для передачи данных между обновлением модулей (к нему можно обращаться между &lt;code&gt;dispose()&lt;/code&gt; и &lt;code&gt;accept()&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export let value = 1;

if (import.meta.hot) {
  // Приём данных от прошлого dispose
  import.meta.hot.accept(({ module }) =&amp;gt; {
    value = import.meta.hot.data.value || module.value;
  });

  // Отправка данных будущему accept
  import.meta.hot.dispose(() =&amp;gt; {
    import.meta.hot.data = { value };
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Важное дополнение про ES-модули. Так как ES-модули не поддерживают неотносительные пути при подключении — &lt;code&gt;import {init} from &apos;module&apos;&lt;/code&gt;, то на первом этапе «сборки» нужно для дев-режима автоматически пройтись по всем файлам и заменить пути импортов на относительные &lt;code&gt;import {init} from &apos;/node_modules/module&apos;&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Event loop и рендер в браузере, часть 3</title><link>https://juwain.github.io/web-platform/blog/2021-03-20/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-03-20/</guid><description>Чем меньше операций производится браузером, тем лучше производительность</description><pubDate>Sat, 20 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Как оптимизировать Render&lt;/h3&gt;
&lt;p&gt;Чем меньше операций производится браузером, тем лучше производительность. При первоначальной загрузке сайта браузер выполяет все этапы RequestAnimationFrame &amp;gt; Style &amp;gt; Layout &amp;gt; Paint &amp;gt; Composite.&lt;/p&gt;
&lt;h4&gt;Минимизировать количество layout&lt;/h4&gt;
&lt;p&gt;После загрузки страницы уже не каждая операция в JS обязательно проходит по всему циклу рендера.&lt;/p&gt;
&lt;p&gt;Например, если изменить что-то из свойств, затрагивающих лейаут страницы (размеры, отступы, позиционирование) или считать их в JS, то сработает layout, а за ним нужно будет снова перерисовать элементы в paint и сложить в слои в composition.&lt;/p&gt;
&lt;p&gt;Получается довольно затратная по производительности цепочка операций.&lt;/p&gt;
&lt;p&gt;А если, к примеру, для перепозиционирования элементов изменять свойство &lt;code&gt;transform&lt;/code&gt;, то браузеру не требуется перестраивать сетку страницы и делать перерисовку элементов, и поэтому этап layout и paint не запускается повторно. Работа идёт только на этапе composite, поэтому операций становится существенно меньше, и они уже не такие тяжёлые.&lt;/p&gt;
&lt;p&gt;Также «тяжёлый» этап layout пропускается, если изменяетя только внешний вид элемента, например, фоновое изображение, цвет текста или тень, а не его размеры. В этом случае выполняется только paint и composite.&lt;/p&gt;
&lt;h4&gt;Использовать requestAnimationFrame&lt;/h4&gt;
&lt;p&gt;Если приходить к браузеру в нужный момент, когда он готов начинать отрисовку следующего кадра, то тем самым мы не прерываем форсированно работу JS-тасок или микротасок.&lt;/p&gt;
&lt;h4&gt;Использовать CSS-анимации&lt;/h4&gt;
&lt;p&gt;Анимации, сделанные на JS, вдобавок к исполнению JS-таски будут в лучшем случае прождать процесс composition (в худшем ещё и style, layout, paint). Поэтому если делать анимации в CSS, количество тасок для Event Loop будет меньше, так как мы не создаём JS-таски.&lt;/p&gt;
&lt;p&gt;Кроме того, все CSS-анимации и процесс composition браузер выполняет с задействованием GPU, а не только с помощью CPU. Если браузер выясняет, что изменяемые свойства не влияют на layout и paint, то он отрисовывает слои в картинки (делает ещё раз repaint) и вместе с информацией о слоях передаёт их в GPU. Процессинг в GPU не зависит от CPU, и поэтому разгружает основной поток исполнения задач. Преимущетсво именно в параллельности, так как когда, например, слоёв мало или нет драйвера для видеокарты, то браузер не включает GPU, а запускает composition в отдельном CPU-треде и получается прирост произовдительности.&lt;/p&gt;
&lt;p&gt;Также отдельные composition-слои могут создаваться неявно, если анимируемый элемент находится «под» другими слоями. Так для каждого вышележащего слоя будет создаваться отдельный composition-слой.&lt;/p&gt;
&lt;p&gt;У CSS-анимаций есть ограничения.&lt;/p&gt;
&lt;p&gt;Чем больше composition-слоёв формируются и чем они больше по размеру, тем дольше происходит передача слоёв с CPU на GPU и может появиться «мигание».&lt;/p&gt;
&lt;p&gt;Кроме того, каждый слой в GPU занимает место в памяти видеокарты. Размер памяти тоже ограничен, как и вычислительное время процессора.&lt;/p&gt;
&lt;h4&gt;Использовать will-change&lt;/h4&gt;
&lt;p&gt;Использование этого свойства может подсказать браузеру сделать необходимую подготовку, например, заранее создать отдельный слой для процесса composition. Когда дело дойдёт до изменения указанных в &lt;code&gt;will-change&lt;/code&gt; свойств, браузеру не нужно будет делать подготовку, так как он её произвёл заранее, в свободный момент.&lt;/p&gt;
&lt;p&gt;Отдельный composition-слой будет создаваться браузером, если задавать &lt;code&gt;will-change&lt;/code&gt; для &lt;code&gt;opacity&lt;/code&gt;, &lt;code&gt;transform&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;left&lt;/code&gt;, &lt;code&gt;bottom&lt;/code&gt;, &lt;code&gt;right&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Но задавать &lt;code&gt;will-change&lt;/code&gt; для всего сразу тоже вредно, так как это может создать нагрузку на GPU:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;на обработку GPU будут передаваться слишком большие картинки, что будет тратить время на передачу и загружать память видеокарты (на мобильных девайсах это особенно критично, так как этой памяти немного);&lt;/li&gt;
&lt;li&gt;картинок будет слишком много, что тоже скажется на скорости процесса передачи и на количестве потраченной памяти.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Поэтому &lt;code&gt;will-change&lt;/code&gt; лучше применять точечно для улучшение плохой ситуации с перфомансом непосредственно перед грядущей перерисовкой, и по возможности его выключать после отрисовки. Помимо количества слоёв, можно снижать размеры слоёв. Чем меньше, тем лучше.&lt;/p&gt;
</content:encoded></item><item><title>Когда overflow: hidden не работает</title><link>https://juwain.github.io/web-platform/blog/2021-06-10/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-06-10/</guid><description>overflow: hidden не всегда обрезает выходящее за пределы содержимое бокса</description><pubDate>Thu, 10 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Есть несколько причин, по которым дочерние боксы элементов, могут «вываливаться» из родительских.&lt;/p&gt;
&lt;p&gt;Например, когда в дочернем боксе есть длинное неразрывое слово типа &lt;code&gt;Тунгнафедльсйёкюдль&lt;/code&gt;, «вырывающееся» за пределы контейнера.&lt;/p&gt;
&lt;p&gt;Или когда дочернему боксу задана ширина или высота явно больше, чем у родительского бокса.&lt;/p&gt;
&lt;p&gt;Также если дочернему боксу заданы отрицательное значение &lt;code&gt;margin&lt;/code&gt; или элемент абсолютно спозиционирован так, что он выходит за пределы родителя.&lt;/p&gt;
&lt;p&gt;И известный способ ликвидировать эффект «вываливания» — применить свойство &lt;code&gt;overflow: hidden&lt;/code&gt;. В таком случае части бокса, вышедшие за пределы родительского элемента обрежутся без возможности доскроллить до них вручную.&lt;/p&gt;
&lt;p&gt;Но &lt;code&gt;overflow: hidden&lt;/code&gt; не всегда обрезает выходящее за пределы содержимое бокса. Есть исключение: абсолютно спозиционированный элемент не будет обрезаться родительским элементом с &lt;code&gt;overflow: hidden&lt;/code&gt;, если родитель не является &lt;em&gt;содержащим блоком&lt;/em&gt; (containing block), то есть ему не заданы &lt;code&gt;position&lt;/code&gt; со значением &lt;code&gt;absolute&lt;/code&gt;, &lt;code&gt;relative&lt;/code&gt; или &lt;code&gt;fixed&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Пример:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;parent&quot;&amp;gt;
  &amp;lt;div class=&quot;overflow&quot;&amp;gt;
    &amp;lt;div class=&quot;absolute-child&quot;&amp;gt;LonglonglonglonglongAbsolute&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;static-child&quot;&amp;gt;LonglonglonglonglongStatic&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;.parent {
  position: relative;
}
.overflow {
  overflow: hidden;
}
.absolute-child {
  position: absolute;
}
.static-child {
  position: static;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В примере бокс &lt;code&gt;.absolute-child&lt;/code&gt; не обрезается по границам бокса &lt;code&gt;.overflow&lt;/code&gt;, а
при этом &lt;code&gt;.static-child&lt;/code&gt; — обрезается, так как он имеет обычное
позиционирование. &lt;a href=&quot;https://codepen.io/juwain/pen/OJpwYrw&quot;&gt;Пример в codepen&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Статистика использования фич на сайтах</title><link>https://juwain.github.io/web-platform/blog/2021-06-26/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-06-26/</guid><description>Как узнать, как часто та или иная HTML-, CSS- или JS-фича используются на сайтах в интернете?</description><pubDate>Sat, 26 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Как узнать, как часто та или иная HTML-, CSS- или JS-фича используются на сайтах в интернете? Окей, на &lt;a href=&quot;http://caniuse.com/&quot;&gt;Can I Use&lt;/a&gt; можно узнать, как фичи поддерживаются браузерами. Но как узнать часто ли фичи используются разработчиками?&lt;/p&gt;
&lt;p&gt;К примеру, нужно узнать про сайты:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;как часто в стилевых файлах используется &lt;code&gt;Grid Layout&lt;/code&gt; или &lt;code&gt;@import&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;много ли где в HTML встречается атрибут &lt;code&gt;placeholder&lt;/code&gt; или &lt;code&gt;required&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;насколько в JS-файлах распространён &lt;code&gt;fetch&lt;/code&gt; или &lt;code&gt;ResizeObserver&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Собрать статистику во всём интернете сложно, но возможно: есть два решения, которые в тандеме приближаются близко к решению задачи.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Сервис статистики Chrome Stats&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Каждый браузер Chrome собирает анонимную статистику. Разработчики Chrome добавляют в код браузера «счётчики» использования фич. Если пользоваль открывает в своём браузере сайт с определённой фичей, то «счётчик» увеличивается. В итоге получается такая статистика: сколько процентов страниц, загруженных через Chrome, было с интересующей фичей (фича встретилась в коде хотя бы один раз).&lt;/p&gt;
&lt;p&gt;Посмотреть статистику можно &lt;a href=&quot;https://chromestatus.com/metrics/feature/popularity&quot;&gt;тут&lt;/a&gt;. На 1 июня 2021 года:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;по &lt;code&gt;Grid Layout&lt;/code&gt; — стили 9-10% всех загруженных пользователями страниц содержит гриды (&lt;a href=&quot;https://chromestatus.com/metrics/feature/timeline/popularity/1693&quot;&gt;источник&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;по &lt;code&gt;@import&lt;/code&gt; — в CSS-коде почти 15% всех загруженных страниц используются директива &lt;code&gt;@import&lt;/code&gt; (&lt;a href=&quot;https://chromestatus.com/metrics/feature/timeline/popularity/971&quot;&gt;источник&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;атрибут &lt;code&gt;placeholder&lt;/code&gt; встретился в HTML-коде 52% сайтов (&lt;a href=&quot;https://chromestatus.com/metrics/feature/timeline/popularity/45&quot;&gt;источник&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;атрибут &lt;code&gt;required&lt;/code&gt; появился на 9% сайтов (&lt;a href=&quot;https://chromestatus.com/metrics/feature/timeline/popularity/49&quot;&gt;источник&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch&lt;/code&gt; использовался на 38% сайтах (&lt;a href=&quot;https://chromestatus.com/metrics/feature/timeline/popularity/675&quot;&gt;источник&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ResizeObserver&lt;/code&gt; был замечен на 17% загруженных сайтов (&lt;a href=&quot;https://chromestatus.com/metrics/feature/timeline/popularity/2592&quot;&gt;источник&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В &lt;a href=&quot;https://chromestatus.com/metrics/css/popularity&quot;&gt;отдельном разделе&lt;/a&gt; живёт детальная статистика по использованию в коде CSS-свойств.&lt;/p&gt;
&lt;p&gt;Самое клёвое, что есть не только текущая статистика, но и график её «адаптации» на сайтах со временем (период в несколько лет).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Статистика HTTP Archive&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;«Счётчики» в Chrome Stats анонимные, то есть не показывают конкретные адреса сайтов и абсолютное количество проанализированных страниц. А вот у &lt;a href=&quot;https://httparchive.org/&quot;&gt;HTTP Archive&lt;/a&gt;, где собирается и анализируется «архив сайтов», есть &lt;a href=&quot;https://console.cloud.google.com/bigquery?p=httparchive&amp;amp;d=httparchive&amp;amp;page=dataset&quot;&gt;публичный датасет в сервисе BigQuery&lt;/a&gt;. Превью этих данных есть также на &lt;a href=&quot;https://www.chromestatus.com/metrics/feature/timeline/popularity/972&quot;&gt;самой странице&lt;/a&gt; Chrome Stats.&lt;/p&gt;
&lt;p&gt;К примеру, в таблице за 1 июня 2021 года сохранено 6435567 десктопных и 7452047 мобильных страниц. По этим страницам собрана информация:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;по тем же «счётчикам», что и в Chrome Stats, только с привязкой к конкретному сайту;&lt;/li&gt;
&lt;li&gt;лог работы движка V8 на странице;&lt;/li&gt;
&lt;li&gt;метрики Web Vitals;&lt;/li&gt;
&lt;li&gt;количество HTML-элементов и доступность страницы;&lt;/li&gt;
&lt;li&gt;картинки и другой медиа-контент на странице;&lt;/li&gt;
&lt;li&gt;использованные сторонние приложения и библиотеки (jQuery, React, Google Analytics…).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Чтобы отобразить эту информацию, нужно знать SQL. В прочем, в HTTP Archive есть и уже &lt;a href=&quot;https://httparchive.org/reports&quot;&gt;готовые отчёты о состоянии веба&lt;/a&gt;, которые просто открываются в браузере.&lt;/p&gt;
</content:encoded></item><item><title>var(--) валидно?</title><link>https://juwain.github.io/web-platform/blog/2021-07-04/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-07-04/</guid><description>Как вы думаете, сработает ли такой код в браузерах, и валидно ли имя кастомного свойства  `--`</description><pubDate>Sun, 04 Jul 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Представьте себе CSS-код:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  --: honeydew;
  background-color: var(--);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Как вы думаете, сработает ли такой код в браузерах, и валидно ли имя кастомного свойства &lt;code&gt;--&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Ответ: да, в июне 2021 код работает в Chrome, Firefox и Safari. Но имя переменной &lt;code&gt;--&lt;/code&gt; формально невалидно.&lt;/p&gt;
&lt;p&gt;Текущий &lt;a href=&quot;https://drafts.csswg.org/css-variables/#defining-variables&quot;&gt;черновик спеки о кастомных свойствах&lt;/a&gt; зарезервировал кастомное свойство &lt;code&gt;--&lt;/code&gt; для будущего использования в CSS.&lt;/p&gt;
&lt;p&gt;Объясню идею авторов спеки.&lt;/p&gt;
&lt;p&gt;В CSS есть наследование: значения некоторых свойств (например, &lt;code&gt;color&lt;/code&gt; или &lt;code&gt;font-size&lt;/code&gt;), а также кастомных свойств передаются от родителя к детям:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  color: rgb(51, 51, 51);
  --gap-size: 10px;
}

p {
  /* color тоже будет rgb(51, 51, 51) */
  padding: var(--gap-size); /* 10px */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Если эффект наследования нежелателен, его можно отменить ключевым словом &lt;code&gt;initial&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  color: rgb(51, 51, 51);
  --gap-size: 10px;
}

p {
  color: initial; /* значение rgb(0, 0, 0) */
  --gap-size: initial; /* значение «пустое» */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Если же хочется отменить &lt;strong&gt;все&lt;/strong&gt; наследуемые свойства, но при этом не хочется их все перечислять, есть свойство &lt;code&gt;all&lt;/code&gt;, которое обращается сразу ко всем возможным CSS-свойствам сразу:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  color: rgb(51, 51, 51);
  font-size: 20px;
}

p {
  all: initial;
  /*
  color: initial, то есть rgb(0, 0, 0)
  font-size: initial, то есть 16px
  */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;У свойства &lt;code&gt;all&lt;/code&gt; есть пара исключений: одно из них — оно не затрагивает кастомные свойства, для сброса их придётся перечислять все до единого:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  --prop-1: 123;
  --prop-2: red;
  --prop-3: 10px;
}

p {
  --prop-1: initial;
  --prop-2: initial;
  --prop-3: initial;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Так вот идея авторов спеки — сделать свойство с именем &lt;code&gt;--&lt;/code&gt; аналогом &lt;code&gt;all&lt;/code&gt; только для кастомных свойств. Чтобы можно было написать:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  --prop-1: 123;
  --prop-2: red;
  --prop-3: 10px;
}

p {
  --: initial;
  /*
  --prop-1: initial, то есть значение «пустое»
  --prop-2: initial, то есть значение «пустое»
  --prop-3: initial, то есть значение «пустое»
  */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Несмотря на то, что это пока черновик спеки, решение было уже &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/2692#issuecomment-395247646&quot;&gt;обсуждено&lt;/a&gt; рабочей группой, то есть скорее всего будет зафиксировано и в будущей рекомендации.&lt;/p&gt;
&lt;p&gt;А пока что не используйте &lt;code&gt;var(--)&lt;/code&gt;, если вдруг эта мысль вам приходила в голову, так как оно вероятно перестанет работать.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://phabricator.services.mozilla.com/D116456&quot;&gt;Баг&lt;/a&gt; уже починен в Firefox Nightly, а в Chrome &lt;a href=&quot;https://crbug.com/1220145&quot;&gt;багрепорт&lt;/a&gt; пока только заведён.&lt;/p&gt;
</content:encoded></item><item><title>Декларативность и сотрудничество в HTML</title><link>https://juwain.github.io/web-platform/blog/2021-10-07/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2021-10-07/</guid><description>Есть некоторые клёвые API в HTML/CSS, которые прям доставляют. Чтоб решить задачу, вместо императивщины сообщаешь браузеру нужную инфу, а он делает всю остальную работу</description><pubDate>Thu, 07 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Есть некоторые клёвые API в HTML/CSS, которые прям доставляют. Чтоб решить задачу, вместо императивщины сообщаешь браузеру нужную инфу, а он делает всю остальную работу.&lt;/p&gt;
&lt;p&gt;Хочу рассказать про &lt;code&gt;srcset&lt;/code&gt; и &lt;code&gt;sizes&lt;/code&gt; у &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;. Для чего они нужны? Прежде всего — подсказать браузеру, какую версию картинки начать загружать, когда только парсится HTML, и браузеру ещё ничего неизвестно о лейауте страницы. Браузер будет полагаться на подсказки, оставленные разработчиком, и исходя из них начинать сразу же загружать нужную картинку, не дожидаясь полного окончания парсинга страницы и применения стилей.&lt;/p&gt;
&lt;p&gt;Частый кейс — указание обычной или ретиновой версии картинки. Браузер на этапе загрузки картинки ещё не знает какого она будет размера. Зато при загрузке картинки у браузера уже есть информация, что за экран у устройства: обычный или ретиновый. Поэтому разработчик подсказывает ему: вот эта картинка поменьше — для обычной плотности пикселей (1x), а вот эта картинка побольше — для большей (2x):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;img src=&quot;picture1.jpg&quot; srcset=&quot;picture1.jpg 1x, picture2.jpg 2x&quot; alt=&quot;&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Браузер получает подсказку от разработчика, какая картинка для какого экрана
подходит, и сам делает выбор: если экран ретиновый, грузит 2x-версию, а иначе —
1x. Более сложная логика описания &lt;code&gt;srcset&lt;/code&gt; нужна, если разработчик хочет
предусмотреть, что на разных разрешениях экрана должны загружаться картинки
разного размера. При загрузке картинки у браузера уже есть информация, какой
размер вьюпорта на устройстве. А у разработчика есть инфа, какая картинка какому
размеру соответствует. То есть разработчик заранее подказывает браузеру: вот эта
картинка шириной 100px, вот эта — 500px, а вот эта — 1000px.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;img
  src=&quot;default.jpg&quot;
  srcset=&quot;small.jpg 100w, medium.jpg 300w, large.jpg 1000w&quot;
  alt=&quot;&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Браузер руководствуется подсказкой разработчика и делает выбор: ага, сейчас
вьюпорт десктопный &lt;code&gt;&amp;gt;1000px&lt;/code&gt;, поэтому беру &lt;code&gt;large.jpg&lt;/code&gt; и загружаю. Если бы
вьюпорт был поменьше, то была бы загружена соответствующая более мелкая версия
картинки. Но картинки не всегда показываются на всю ширину вьюпорта! Ок, браузер
выбрал картинку &lt;code&gt;large.jpg&lt;/code&gt;, так как вьюпорт был &lt;code&gt;&amp;gt;1000px&lt;/code&gt;. А на самом деле
картинка после загрузки стилей будет показана не на всю ширину вьюпорта, а
вписана в блок шириной &lt;code&gt;300px&lt;/code&gt;. Об этом браузер не мог знать заранее, на этапе,
когда он встретил при парсинге разметки тег &lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt;, и поэтому сделал неверное
предположение и загрузил слишком большую картинку. Поэтому браузеру нужна ещё и
инфа, которую заранее знает разработчик: какую часть вьюпорта будет занимать
картинка, когда страница полностью загрузится. Например, на мобильном разрешении
картинка будет на весь экран, а на более широком разрешении три картинки
выстроятся в ряд и будут занимать каждая 1/3 размера вьюпорта. Эту инфу и
сообщаем браузеру в атрибуте &lt;code&gt;sizes&lt;/code&gt;: начиная с 1000px картинка будет занимать
треть размера вьюпорта &lt;code&gt;33.3vw&lt;/code&gt;, а в остальных случаях — весь вьюпорт &lt;code&gt;100vw&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;img sizes=&quot;(min-width: 1000px) 33.3vw, 100vw&quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Таким образом у браузера есть все вводные для принятия решения: размер вьюпорта и плотность экрана (браузер знает сам), собственные размеры картинок и их размер на экране (разработчик сообщил в &lt;code&gt;srcset&lt;/code&gt; и &lt;code&gt;sizes&lt;/code&gt;). И дальше браузер сам принимает
решение, какую картинку выбрать. А разработчику не нужно плясать с императивными
конструкциями &lt;code&gt;picture&lt;/code&gt;, что именно и когда именно браузеру показывать. Вроде
всё классно, если разобраться, как это работает. Только вот если не разобраться,
то выходит не очень: у &lt;code&gt;sizes&lt;/code&gt; по умолчанию значение &lt;code&gt;100vw&lt;/code&gt;. То есть если не
указать &lt;code&gt;sizes&lt;/code&gt;, а указать только &lt;code&gt;srcset&lt;/code&gt;, то браузер будет думать, что
картинки всегда на всю ширину вьюпорта, а это часто не так. Выходит так, что
фича классная, но если не въехать, как она работает, то толку нет — пользователь
будет получать слишком большие картинки там, где мог получить меньшие.&lt;/p&gt;
</content:encoded></item><item><title>Сборник примеров условных конструкций в CSS</title><link>https://juwain.github.io/web-platform/blog/2023-01-10/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-01-10/</guid><description>«Встроенные умности» в синтаксисе для реализации типовых интерфейсных паттернов, которые CSS «додумывает сам» без необходимости добавления этой логики в JS</description><pubDate>Sun, 01 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Сборник примеров условных конструкций в CSS. «Встроенные умности» в синтаксисе для реализации типовых интерфейсных паттернов, которые CSS «додумывает сам» без необходимости добавления этой логики в JS.&lt;/p&gt;
&lt;p&gt;Из побочных инсайтов: относительно Container Queries уже настолько привычно стало думать, что оно доедет до всех браузеров «когда-нибудь потом», что оказалось внезапно они уже легально есть и в Chrome, и в Safari, а в FF появятся в следующей версии. 🧙‍♂️&lt;/p&gt;
&lt;p&gt;То же самое и про селектор &lt;code&gt;:has&lt;/code&gt;, но в FF пока непонятно когда доедет до стабильной версии.&lt;/p&gt;
&lt;p&gt;https://ishadeed.com/article/conditional-css/&lt;/p&gt;
</content:encoded></item><item><title>Numeric Separators</title><link>https://juwain.github.io/web-platform/blog/2023-01-12/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-01-12/</guid><description>В JS есть Numeric Separators для более удобного визуального разделения цифр в числах</description><pubDate>Thu, 12 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В JS есть &lt;a href=&quot;https://github.com/tc39/proposal-numeric-separator&quot;&gt;Numeric Separators&lt;/a&gt; для более удобного визуального разделения цифр в числах. Разделитель — это символ нижнего подчёркивания _ (U+005F).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1_000_000_000; // миллиард
101_475_938.38; // сотни миллионов

const fee = 123_00; // 12300
const fee = 12_300; // тоже 12300

const amount = 12345_00; // 1234500
const amount = 123_4500; // тоже 1234500
const amount = 1_234_500; // тоже 1234500
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Начинаться и заканчиваться подчёркиванием числа не могут, будут ошибки.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const a = 00_; // SyntaxError: No identifiers allowed directly after numeric literal

const b = _00; // ReferenceError: Can&apos;t find variable: _00
// ```
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Нативный скоупинг в CSS</title><link>https://juwain.github.io/web-platform/blog/2023-01-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-01-16/</guid><description>В Chrome начали пилить реализацию нативного скоупинга в CSS</description><pubDate>Mon, 16 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В Chrome &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/3547#issuecomment-1381262259&quot;&gt;начали пилить&lt;/a&gt; реализацию нативного скоупинга в CSS 🎉&lt;/p&gt;
&lt;p&gt;Это чтобы можно было делать, например, вот так:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@scope (.light-theme) { a { color: purple; } }
@scope (.dark-theme) { a { color: plum; } }

&amp;lt;div class=&quot;dark-theme&quot;&amp;gt;
  &amp;lt;a href=&quot;#&quot;&amp;gt;plum&amp;lt;/a&amp;gt;
  &amp;lt;div class=&quot;light-theme&quot;&amp;gt;
    &amp;lt;a href=&quot;#&quot;&amp;gt;purple&amp;lt;/a&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;На самом деле &lt;a href=&quot;https://drafts.csswg.org/css-cascade-6/#scoped-styles&quot;&gt;спека&lt;/a&gt;, как это обычно бывает в CSS, довольно много всего предусматривает «с запасом», а не только показанное в примере.&lt;/p&gt;
&lt;p&gt;Фича важная для CSS-in-JS и подобных «инкапсулирующих» решений, поэтому если фичу реализуют в этом году в Chrome, вангую, что остальные вендоры тоже быстро подтянутся.&lt;/p&gt;
</content:encoded></item><item><title>Фича-флаги в CSS</title><link>https://juwain.github.io/web-platform/blog/2023-01-23/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-01-23/</guid><description>Look Ma, это я в 2025 пишу фича-флаги прямо в CSS</description><pubDate>Mon, 23 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Look Ma, это я в 2025 пишу фича-флаги прямо в CSS!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.component {
  /* обычные стили */
  /* ... */

  @container style(--wow-such-a-feature: true) {
    /* стили за фича-флагом */
    /* ... */
  }

  @container style(--wow-such-an-another-feature: true) {
    /* стили за фича-флагом */
    /* ... */
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://una.im/style-queries/&quot;&gt;реф&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пропоузал с недеструктивными методами изменения массивов</title><link>https://juwain.github.io/web-platform/blog/2023-01-25/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-01-25/</guid><description>Суть методов toReversed, toSorted и toSpliced сходу понятна: это просто те же обычные reverse, sort и splice, которые возвращают новый массив вместо изменения старого</description><pubDate>Wed, 25 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В конце января – начале февраля 2023 будет проходить &lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2023/01.md&quot;&gt;митинг TC39&lt;/a&gt;, на котором, среди прочего, stage 4 будет брать &lt;a href=&quot;https://github.com/tc39/proposal-change-array-by-copy&quot;&gt;пропоузал&lt;/a&gt; с недеструктивными методами изменения массивов:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Array.prototype.toReversed();
Array.prototype.toSorted(compareFn);
Array.prototype.toSpliced(start, deleteCount, ...items);
Array.prototype.with(index, value);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Суть методов &lt;code&gt;toReversed&lt;/code&gt;, &lt;code&gt;toSorted&lt;/code&gt; и &lt;code&gt;toSpliced&lt;/code&gt; сходу понятна: это просто те же обычные &lt;code&gt;reverse&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt; и &lt;code&gt;splice&lt;/code&gt;, которые возвращают новый массив вместо изменения старого:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[3, 10, 1].toReversed();
// [1, 10, 3]

[3, 10, 1].toSorted();
// [1, 10, 3]

[3, 10, 1].toSpliced(1, 2, 5, 6);
// [3, 5, 6]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;А вот метод &lt;code&gt;with&lt;/code&gt; уже сходу не очень понятен. Он про точечную замену: меняет один элемент массива на указанном индексе на другой:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[3, 10, 1].with(2, 0);
// [3, 10, 0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Интересно ещё то, что эти методы уже доступны в бетке Chrome 110 без флага, то есть вероятно после встречи TC39, когда пропоузал выдет на stage 4, скоро выкатится и стабильный Chrome.&lt;/p&gt;
</content:encoded></item><item><title>Алиасы в именованных CSS-цветах</title><link>https://juwain.github.io/web-platform/blog/2023-01-27/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-01-27/</guid><description>Алиасы в именованных CSS-цветах</description><pubDate>Fri, 27 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В именованных CSS-цветах &lt;code&gt;red&lt;/code&gt; — это алиас для &lt;code&gt;#ff0000&lt;/code&gt;, а &lt;code&gt;blue&lt;/code&gt; — это &lt;code&gt;#0000ff&lt;/code&gt;.
Но &lt;code&gt;green&lt;/code&gt; — это не &lt;code&gt;#00ff00&lt;/code&gt;, что кажется логичным. На самом деле &lt;code&gt;green&lt;/code&gt; — это &lt;code&gt;#008800&lt;/code&gt;. А за цвет &lt;code&gt;#00ff00&lt;/code&gt; отвечает алиас &lt;code&gt;lime&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://austingil.com/css-named-colors/&quot;&gt;реф&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Новые версии черновиков CSS Box Alignment Module Level 3 и CSS Positioned Layout Module Level 3</title><link>https://juwain.github.io/web-platform/blog/2023-02-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-02-16/</guid><description>Новости веб-платформы</description><pubDate>Thu, 16 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Фреймворки фремворками, а махина CSS медленно, но верно движется вперёд.&lt;/p&gt;
&lt;p&gt;Вчера были опубликованы две новых версии черновиков &lt;a href=&quot;https://www.w3.org/TR/css-align-3/#changes&quot;&gt;CSS Box Alignment Module Level 3&lt;/a&gt; и &lt;a href=&quot;https://www.w3.org/TR/css-position-3/#changes&quot;&gt;CSS Positioned Layout Module Level 3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;В Position 3 с прошлой публикации:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;уточнили концептуально, что такое &lt;code&gt;static position&lt;/code&gt; и &lt;code&gt;static position rectangle&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;а также явно прописали, что &lt;code&gt;position: absolute&lt;/code&gt; вынуждает бокс получить &lt;a href=&quot;https://www.w3.org/TR/css-display-3/#independent-formatting-context&quot;&gt;independent formatting context&lt;/a&gt; (то есть если этот блок внутри грида и ему задали &lt;code&gt;pos:abs&lt;/code&gt;, то субгрид внутри него выключится).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В Align 3 с прошлой публикации:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;добавлены технические правки, связанные с baseline и особенностями выравнивания по ней,&lt;/li&gt;
&lt;li&gt;также выравнивание при значениях &lt;code&gt;space-around&lt;/code&gt; и &lt;code&gt;space-evenly&lt;/code&gt; стало по умолчанию «безопасно» (то есть если такое выравнивание переполняет контейнер и приводит к обрезанию контента, то это выравнивание будет вести себя так, чтоб контент не обрезался, например, будет становиться как &lt;code&gt;start&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;уточнено, что для замещаемых элементов (например, &lt;code&gt;img&lt;/code&gt;) не будет работать внутреннее выравнивание, так как внутри таких элементов не могу содержаться другие элементы.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Также несколько дней назад был обновлён &lt;a href=&quot;https://www.w3.org/TR/css-2023/&quot;&gt;CSS Snapshot 2023&lt;/a&gt;, к котором в раздел «Modules with Rough Interoperability» внесли три новых спецификации:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/css-conditional-4/&quot;&gt;CSS Conditional Rules Module Level 4&lt;/a&gt;
@-правила, например, @supports и @media — сейчас лучше всего поддерживаются в Firefox, в отстающих Safari.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/css-cascade-5/&quot;&gt;CSS Cascading and Inheritance Level&lt;/a&gt;&lt;a href=&quot;https://www.w3.org/TR/css-scroll-snap-1/&quot;&gt;5&lt;/a&gt;
Каскадные слои @layer — тут в лидерах по имплементации Chrome, а Firefox отстаёт.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/TR/css-scroll-snap-1/&quot;&gt;CSS Scroll Snap Module Level 1&lt;/a&gt;
Пристыковка к скроллу — ситуация примерно одинаковая во всех браузерах.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;И ещё на очереди публикация первых версий черновиков &lt;a href=&quot;https://drafts.csswg.org/web-animations-2/&quot;&gt;Web Animations Level 2&lt;/a&gt; и &lt;a href=&quot;https://drafts.csswg.org/css-animations-2/&quot;&gt;CSS Animations Level 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Также в раздел «Safe to Release pre-CR Exceptions» был добавлен &lt;a href=&quot;https://www.w3.org/TR/css-color-5/#relative-color&quot;&gt;relative color&lt;/a&gt; syntax.&lt;/p&gt;
</content:encoded></item><item><title>Container Queries доехали везде</title><link>https://juwain.github.io/web-platform/blog/2023-02-17/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-02-17/</guid><description>Container Queries доехали везде, теперь можно</description><pubDate>Fri, 17 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Короч, FF 110 вышел, Container Queries доехали везде, теперь можно! 💫&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
  &amp;lt;div class=&quot;grid&quot;&amp;gt;
    &amp;lt;div&amp;gt;1&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;2&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;3&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;.container {
  container-type: size;
  width: 500px;
}

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

@container (max-width: 500px) {
  .grid {
    grid-template-columns: 1fr;
  }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Как «прокачать» объект, чтобы он был итерируемым?</title><link>https://juwain.github.io/web-platform/blog/2023-02-20/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-02-20/</guid><description>Использовать один из Well-known Symbols, а именно Symbol.iterator</description><pubDate>Mon, 20 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Как «прокачать» объект, чтобы он был итерируемым?&lt;/p&gt;
&lt;p&gt;Использовать один из Well-known Symbols, а именно &lt;code&gt;Symbol.iterator&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const obj = { a: 1, b: 2, c: 3 };

obj[Symbol.iterator] = function* () {
  for (const key of Object.keys(this)) {
    yield [key, this[key]];
  }
};

for (const [key, value] of obj) {
  console.log(`${key}: ${value}`);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Также есть вариант для асинхронного итерирования посредством &lt;code&gt;Symbol.asyncIterator&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://h3manth.com/posts/Well-known-symbols/&quot;&gt;реф&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Обновления box-shadow в CSS Backgrounds and Borders Module Level 4</title><link>https://juwain.github.io/web-platform/blog/2023-03-14/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-03-14/</guid><description>Новости веб-платформы</description><pubDate>Tue, 14 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В &lt;a href=&quot;https://drafts.csswg.org/css-backgrounds-4/#misc&quot;&gt;черновик&lt;/a&gt; спеки &lt;strong&gt;CSS Backgrounds and Borders Module Level 4&lt;/strong&gt; &lt;a href=&quot;https://github.com/w3c/csswg-drafts/pull/6083&quot;&gt;смерджили&lt;/a&gt; изменение, делающее свойство &lt;code&gt;box-shadow&lt;/code&gt; полноценным longhand-свойством!&lt;/p&gt;
&lt;p&gt;Теперь управлять отдельными параметрами тени можно будет не повторным переопределением всего значения &lt;code&gt;box-shadow&lt;/code&gt;, а задавая параметры shorthand-ами:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;box-shadow-color&lt;/code&gt;: &lt;code&gt;&amp;lt;color&amp;gt;&lt;/code&gt;, initial: currentColor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;box-shadow-offset&lt;/code&gt;: none | &lt;code&gt;&amp;lt;length&amp;gt;{2}, initial: none&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;box-shadow-blur&lt;/code&gt;: &lt;code&gt;&amp;lt;length [0,∞]&amp;gt;, initial: 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;box-shadow-spread&lt;/code&gt;: &lt;code&gt;&amp;lt;length&amp;gt;, initial: 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;box-shadow-position&lt;/code&gt;: &lt;code&gt;[ outset &amp;lt;u&amp;gt;|&amp;lt;/u&amp;gt; inset ]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Аналогичные правки ожидаются и для «текстовой» тени &lt;code&gt;text-shadow&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 03.11.2023</title><link>https://juwain.github.io/web-platform/blog/2023-11-03/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-11-03/</guid><description>Новости веб-платформы</description><pubDate>Fri, 03 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://yarnpkg.com/blog/release/4.0&quot;&gt;Yarn 4.0&lt;/a&gt;, интересного особо ничего нет, пофиксили баги, обновили ноду, причисали синтаксис&lt;/li&gt;
&lt;li&gt;обновилась &lt;a href=&quot;https://nodejs.org/en/blog/release/v21.1.0&quot;&gt;Node v21.1.0&lt;/a&gt;, из интересного появился флаг &lt;code&gt;--experimental-detect-module&lt;/code&gt;, по которому Нода сама распознает &lt;code&gt;.js&lt;/code&gt; файлы как ES-модули, даже если для них не указан &lt;code&gt;type&lt;/code&gt; в &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;все ишью для выпуска &lt;a href=&quot;https://github.com/jquery/jquery&quot;&gt;jquery 4.0.0&lt;/a&gt; пофикшены (наверняка вы очень сильно ждали этого и вот, наконец, свершилось 🎉)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/xenova/transformers.js&quot;&gt;transformers.js&lt;/a&gt; — это самые известные модели ML в одном флаконе в виде JS, который работает даже прямо в браузере, теперь умеют ещё и &lt;a href=&quot;https://github.com/xenova/transformers.js/releases/tag/2.7.0&quot;&gt;конвертацию text to speech/audio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.epicweb.dev/why-i-wont-use-nextjs&quot;&gt;почему Next.js нехороший&lt;/a&gt;: после маркетинговой компании в поддержку Next 14, на волну запрыгивает Remix и в сравнении получается истина (Next не про платформу, несёт зависимости, нестабилен, слишком магический и комплексный)&lt;/li&gt;
&lt;li&gt;зато Remix больше не отдельная тула, а идёт в сторону становления &lt;a href=&quot;https://remix.run/blog/remix-heart-vite&quot;&gt;плагином для Vite&lt;/a&gt; (и это хорошо)&lt;/li&gt;
&lt;li&gt;топ идея включать веб-компоненты в Markdown как &lt;a href=&quot;https://jakelazaroff.com/words/web-components-will-outlive-your-javascript-framework/&quot;&gt;валидный HTML на примере CRDT-компонента&lt;/a&gt; в блог-посте&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zachleat.com/web/browser-window/&quot;&gt;ещё один веб-компонент&lt;/a&gt; в виде мокового окна браузера для презентация&lt;/li&gt;
&lt;li&gt;Синдре Сорхус (тот самый) &lt;a href=&quot;https://sindresorhus.com/blog/goodbye-nodejs-buffer&quot;&gt;выпиливает из своих пакетов&lt;/a&gt;… 🥁 Node.js &lt;code&gt;Buffer&lt;/code&gt; и меняет на &lt;code&gt;Uint8Array&lt;/code&gt;, а также делится пошаговой инструкцией, если вам захочется сделать так же&lt;/li&gt;
&lt;li&gt;опрос &lt;a href=&quot;https://survey.devographics.com/en-US/survey/state-of-react/2023&quot;&gt;State of React 2023&lt;/a&gt; как обычно интересен не только будущими результатами, но и содержимым, где можно узнать названия новых хуков и реактовских API-шек&lt;/li&gt;
&lt;li&gt;неплохой свежеиспечённый &lt;a href=&quot;https://sveltebyexample.com/&quot;&gt;туториал по Svelte&lt;/a&gt; в добавок к также недавно испечённому &lt;a href=&quot;https://nextjs.org/learn&quot;&gt;туториалу Next&lt;/a&gt;-а&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/what1s1ove/ecmascript-decorators-the-ones-that-are-real-g96&quot;&gt;история разработки ECMAScript Decorators&lt;/a&gt; с самым внятным объяснением, что это такое (tldr, например, функции высшего порядка типа &lt;code&gt;debounce&lt;/code&gt; или HOC-и типа &lt;code&gt;withModal&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;новые CSS-функции &lt;a href=&quot;https://danielcwilson.com/posts/mathematicss-rem-mod/&quot;&gt;&lt;code&gt;rem()&lt;/code&gt; и &lt;code&gt;mod()&lt;/code&gt;&lt;/a&gt; и где они обитают&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://herman.bearblog.dev/how-bear-does-analytics-with-css/&quot;&gt;аналитика на CSS-коленке&lt;/a&gt;, беспощадная и неуязвимая&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefers-reduced-transparency&lt;/code&gt; в копилку директив для тюнинга CSS-мелочей, &lt;a href=&quot;https://developer.chrome.com/blog/css-prefers-reduced-transparency/&quot;&gt;которые почти никто не заметит&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;съешь ещё этих мягких французских CSS-функций (&lt;a href=&quot;https://chriscoyier.net/2023/10/17/a-couple-of-new-css-functions-id-never-heard-of/&quot;&gt;&lt;code&gt;light-dark&lt;/code&gt;, &lt;code&gt;xywh&lt;/code&gt;, &lt;code&gt;round&lt;/code&gt;, &lt;code&gt;perspective&lt;/code&gt;&lt;/a&gt;) от Криса Койера&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fffuel.co/css-selectors/&quot;&gt;визуальный гайд по селекторам&lt;/a&gt; от fffuel&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;0 из топ-100 самых больших мировых сайтов &lt;a href=&quot;https://meiert.com/en/blog/html-conformance-2023/&quot;&gt;используют валидный HTML&lt;/a&gt; (и всем это ок)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 10.11.2023</title><link>https://juwain.github.io/web-platform/blog/2023-11-10/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-11-10/</guid><description>Новости веб-платформы</description><pubDate>Fri, 10 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;астрологи объявили неделю AI, поэтому в &lt;a href=&quot;https://github.blog/2023-11-08-universe-2023-copilot-transforms-github-into-the-ai-powered-developer-platform/&quot;&gt;Гитхабе объявили начало новой реальности&lt;/a&gt;, GitHub Copilot теперь будет в виде чата подсказывать код, посвечивать ошибки и уязвимости, а также улучшать код, писать тесты, план работы и всё это прямо на &lt;a href=&quot;http://github.com/&quot;&gt;github.com&lt;/a&gt; 🧙‍♂️ (отделить маркетинг от реальности правда пока ещё предстоит в декабре этого года)&lt;/li&gt;
&lt;li&gt;Дуглас Крокфорд (после того, как отговаривал всех писать на JS) написал &lt;a href=&quot;https://www.crockford.com/misty/&quot;&gt;новый язык Misty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;как метрики Web Vitals помогли улучшить интернет (главным образом за счёт &lt;a href=&quot;https://blog.chromium.org/2023/11/how-core-web-vitals-saved-users-10000.html&quot;&gt;улучшения WordPress&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react/pull/26446&quot;&gt;сорсмапы теперь будут генериться&lt;/a&gt; для прод-реакт-бандлов&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://reactflow.dev/&quot;&gt;библиотека для создания схем React Flow&lt;/a&gt; теперь есть и для Svelte — &lt;a href=&quot;https://svelteflow.dev/examples&quot;&gt;meet Svelte Flow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;versel выпустили &lt;a href=&quot;https://vercel.com/font/mono&quot;&gt;свой шрифт&lt;/a&gt; — &lt;a href=&quot;https://github.com/vercel/geist-font&quot;&gt;Geist&lt;/a&gt; (да, это именно для того, чтобы о них ещё раз упомянули в новостях)&lt;/li&gt;
&lt;li&gt;ещё одна попытка сделать &lt;a href=&quot;https://github.com/dflex-js/dflex&quot;&gt;норм DragNDrop либу&lt;/a&gt; (без привязки к фреймворку)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloud.google.com/blog/products/maps-platform/introducing-react-components-for-the-maps-javascript-api/&quot;&gt;новенькие React-компоненты для Goggle Maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.buttons.cool/buttons&quot;&gt;больше кнопок богу кнопок&lt;/a&gt; (гигантская коллекция разнообразных кнопок, а также генератор кнопок на Tailwind)&lt;/li&gt;
&lt;li&gt;тула для &lt;a href=&quot;https://evanw.github.io/source-map-visualization/&quot;&gt;визуализации сорсмапов&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/headless-component.html&quot;&gt;паттерн проектирования Headless Component&lt;/a&gt; для React UI-ев&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/blog/compressionstreams&quot;&gt;Compression Streams API&lt;/a&gt; — что это и зачем нужно (доступно во всех свежих браузерах)&lt;/li&gt;
&lt;li&gt;хорошая ли идея собрать React Server Components без фреймворка (автор попробовал и &lt;a href=&quot;https://timtech.blog/posts/react-server-components-rsc-no-framework/&quot;&gt;так не думает&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;немного обновившаяся &lt;a href=&quot;https://react.dev/reference/react/use-server&quot;&gt;оф дока по &apos;use server&apos;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tkdodo.eu/blog/why-you-want-react-query&quot;&gt;психологическая статья про React Query&lt;/a&gt;, которая заставит вас захотеть использовать либу из-за легких угрызений совести&lt;/li&gt;
&lt;li&gt;оказывается двойной запуск useEffect в дев-режиме — это &lt;a href=&quot;https://react.dev/reference/react/StrictMode#fixing-bugs-found-by-re-running-effects-in-development&quot;&gt;не баг, а фича&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;только два слова — &lt;a href=&quot;https://github.com/ascorbic/use-php&quot;&gt;use-php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/blog/introducing-learn-performance?hl=en&quot;&gt;небольшой учебный курс&lt;/a&gt; по браузерному перфомансу&lt;/li&gt;
&lt;li&gt;построение &lt;a href=&quot;https://emilkowal.ski/ui/building-a-drawer-component&quot;&gt;UI-элемента шторки&lt;/a&gt; (a la iOS, но на веб-технологиях)&lt;/li&gt;
&lt;li&gt;как более корректно &lt;a href=&quot;https://gomakethings.com/dont-disable-buttons/&quot;&gt;«выключать» кнопки при сабмите форм&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;и ещё немного про разделители в &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;: &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;optgroup&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; + &lt;code&gt;&amp;lt;optgroup&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-irl.info/messing-about-with-css-gradients&quot;&gt;CSS-градиенты&lt;/a&gt; в реальной (или всё таки фэнтезийной?) жизни&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://keithjgrant.com/posts/2023/11/problematic-color-gradients-and-workarounds/&quot;&gt;как обойти «серые» зоны в градиентах&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexcodle.com/&quot;&gt;угадайка про HEX-цвета&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/JohnPhamous/pen/MWLeJVd&quot;&gt;демка&lt;/a&gt; про анимацию вариативных шрифтов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/using-css-content-visibility-boost-rendering-performance/&quot;&gt;на что способно&lt;/a&gt; CSS-свойство &lt;code&gt;content-visibility&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 17.11.2023</title><link>https://juwain.github.io/web-platform/blog/2023-11-17/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-11-17/</guid><description>Новости веб-платформы</description><pubDate>Fri, 17 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ESLint обновляется до 9 версии и &lt;a href=&quot;https://eslint.org/blog/2023/11/whats-coming-in-eslint-9.0.0/&quot;&gt;там будет много изменений,&lt;/a&gt; в том числе breaking&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-3-rc&quot;&gt;появился TypeScript 5.3 RC,&lt;/a&gt; из интересного: поддержка &lt;a href=&quot;https://github.com/tc39/proposal-import-attributes&quot;&gt;Import Attributes,&lt;/a&gt; &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-3-rc/#switch-true-narrowing&quot;&gt;улучшенный narrowing&lt;/a&gt; для некоторых случаев, &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-3-rc/#interactive-inlay-hints-for-types&quot;&gt;Interactive Inlay Hints,&lt;/a&gt; настройка для VSCode, чтобы автоимпорт типов писался так &lt;code&gt;import { type Person } from &quot;./types&quot;&lt;/code&gt;, а не так &lt;code&gt;import { Person } from &quot;./types&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;либа компонентов React Aria Components переходит из &lt;a href=&quot;https://react-spectrum.adobe.com/releases/2023-11-8.html&quot;&gt;Beta в RC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rviscomi.dev/2023/11/a-faster-web-in-2024/&quot;&gt;главной метрикой в Core Web Vitals,&lt;/a&gt; отвечающей за отзывчивость интерфейса, становится &lt;a href=&quot;https://web.dev/articles/inp&quot;&gt;INP,&lt;/a&gt; а также другие интересности по перфомансу от HTTP Archive на 2024&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/astoilkov/main-thread-scheduling&quot;&gt;либа&lt;/a&gt; для того, чтобы управлять приоритетом выпоннения тасок к основном потоке, а также бонусом &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Prioritized_Task_Scheduling_API&quot;&gt;Prioritized Task Scheduling API,&lt;/a&gt; который уже сейчас в Хроме может управлять приоритетом исполняемых тасок&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/okonet/react-scroll-sync&quot;&gt;управление синхронным скроллом&lt;/a&gt; в нескольких скроллящихся элементах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://typpo.github.io/spacekit/&quot;&gt;либа&lt;/a&gt; для создания 3d-космических сцен 🪐&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://phuoc.ng/collection/html-dom/&quot;&gt;набор простеньких, но полезных, демок&lt;/a&gt; небольших DOM-манипуляцей&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v5.chriskrycho.com/journal/how-to-do-a-typescript-conversion/&quot;&gt;какую выбрать стратегию&lt;/a&gt; перевода кодовой базы на TS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://daily.dev/blog/moving-back-to-react&quot;&gt;сага&lt;/a&gt; о том, как разработчики обратно на React с Preact переходили (Или туда и обратно)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/refine/react-design-patterns-230o&quot;&gt;React Design Patterns:&lt;/a&gt; общеизвестные типа HOC, а также малоизвестные типа Compound Components&lt;/li&gt;
&lt;li&gt;как марсиане писали плагин для фигмы или &lt;a href=&quot;https://evilmartians.com/chronicles/figma-plugin-api-dive-into-advanced-algorithms-and-data-structures&quot;&gt;Зачем фронтендерам обход деревьев&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;страсти вокруг Barrel-импортов в файлах не утихают, &lt;a href=&quot;https://blog.vramana.com/posts/barrel_files_slow_build/&quot;&gt;очередной наброс&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;невероятные трюки и возможности &lt;a href=&quot;https://alan.norbauer.com/articles/browser-debugging-tricks&quot;&gt;дебаггера в браузере&lt;/a&gt; (без шуток)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ещё один &lt;a href=&quot;https://cloudfour.com/thinks/surprising-facts-about-new-css-selectors/&quot;&gt;годный разбор&lt;/a&gt; псевдоселекторов (&lt;code&gt;:has&lt;/code&gt;, &lt;code&gt;:not&lt;/code&gt;, &lt;code&gt;:is&lt;/code&gt;, &lt;code&gt;:where&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;свойство gap может быть полезно и в &lt;a href=&quot;https://css-irl.info/dont-mind-the-gap/&quot;&gt;многострочных флексбоксах&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ещё один костыльный (но нормальных пока нет) &lt;a href=&quot;https://til.simonwillison.net/css/resizing-textarea&quot;&gt;вариант&lt;/a&gt; автоувеличивающейся textarea&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.matuzo.at/blog/2023/how-browsers-zoom-text&quot;&gt;как браузеры зумят текст&lt;/a&gt; (tldr: неконситентно)&lt;/li&gt;
&lt;li&gt;если убрать &lt;code&gt;list-style: none&lt;/code&gt; у списка, то &lt;a href=&quot;https://gomakethings.com/semantic-inline-lists/&quot;&gt;Safari перестанет считать его списком&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://flowingdata.com/2023/11/08/fonts-for-rendering-lines-and-bars-from-data/&quot;&gt;гугл-шрифты,&lt;/a&gt; рендерящие волны и линии&lt;/li&gt;
&lt;li&gt;вариативный моноширинный шрифт &lt;a href=&quot;https://monaspace.githubnext.com/&quot;&gt;Monaspace&lt;/a&gt; от Github&lt;/li&gt;
&lt;li&gt;HTML Web Components — не React-компоненты, &lt;a href=&quot;https://blog.jim-nielsen.com/2023/html-web-components/&quot;&gt;меняем майндсет&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;подход &lt;a href=&quot;https://htmx.org/essays/locality-of-behaviour/&quot;&gt;HTML First&lt;/a&gt; или Скрытая реклама htmx&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ittavern.com/url-explained-the-fundamentals/&quot;&gt;что такое URL&lt;/a&gt; и чем он отличается от URI, URN и URC (даже под закат фронтендерской карьеры не поздно освоить азы 👴)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 24.11.2023</title><link>https://juwain.github.io/web-platform/blog/2023-11-24/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-11-24/</guid><description>Новости веб-платформы</description><pubDate>Fri, 24 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://vitejs.dev/blog/announcing-vite5&quot;&gt;Vite 5.0&lt;/a&gt;: прибрались, дропнули поддержку старых версий Node, задепрекейтили CommonJS-модули, обновили Rollup до 4&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/blog/2023/11/13/3.1.0&quot;&gt;Prettier 3.1&lt;/a&gt; теперь умеет форматировать вложенные тернарники лесенкой&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://www.mozilla.org/en-US/firefox/121.0beta/releasenotes/&quot;&gt;Firefox 121.0beta&lt;/a&gt; и там долгожданная поддержка &lt;code&gt;:has&lt;/code&gt; без флага, а также менее долгожданные Lazy loading iframes и поддержка &lt;code&gt;text-wrap: balance&lt;/code&gt;, ждём в стабильного релиза в качестве новогоднего подарка 🎁&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://github.com/reduxjs/redux-toolkit/releases/tag/v2.0.0-rc.0&quot;&gt;redux-toolkit v2.0.0-rc.0&lt;/a&gt;, есть breaking changes&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-3/&quot;&gt;TypeScript 5.3&lt;/a&gt;, отличий по сравнению с RC-версией нет&lt;/li&gt;
&lt;li&gt;контрьбьюторам Node не понравилось выпиливание форматирования из ESLint и появилось &lt;a href=&quot;https://github.com/nodejs/node/pull/50672&quot;&gt;предложение использовать Biome&lt;/a&gt; в качестве форматтера (это же была нативная реклама в PR, да?)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://survey.devographics.com/en-US/survey/state-of-js/2023&quot;&gt;State of JavaScript 2023&lt;/a&gt; начался: как обычно мне больше всего интересна первая страница с примерами кода, но посмотреть на итоги голосования тоже будет интересно (чтоб узнать, всё ли React или ещё нет)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/loro-dev/&quot;&gt;Loro&lt;/a&gt; — либа для реализации offline-first и CRDT-приложений&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-datasheet-grid.netlify.app/&quot;&gt;React Datasheet Grid&lt;/a&gt; — либа для реализации редактируемых таблиц типа Notion и Airtable&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/alexanderson1993/svg-icons-cli&quot;&gt;svg-icons-cli&lt;/a&gt; — тулза для генерации SVG-спрайтов (тк использование SVG напрямую в бандлах удобно, но дорого и медленно)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thewebshowcase.withgoogle.com/&quot;&gt;рекламный лендос возможностей веб-платформы&lt;/a&gt; (оч крутой) от разрабов Chrome&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thevalleyofcode.com/&quot;&gt;обучалка основам веб-разработки&lt;/a&gt; (если у вас спросят, как стать разработчиком, это неплохой свежий гайд на английском)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://iliazeus.github.io/articles/js-explicit-resource-management-en/&quot;&gt;Explicit Resource Management&lt;/a&gt; — изучение новой фичи TS и платформы &lt;code&gt;using&lt;/code&gt;, которая может указывать движку, чтоб прибрал подвисшие в памяти процессы&lt;/li&gt;
&lt;li&gt;обзор легковесных JS-фремворков за пределами React-пузыря (да, &lt;a href=&quot;https://saashammer.com/blog/lightweight-javascript-framework-review-for-django-developers/&quot;&gt;там тоже есть жизнь&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;как собрать и использовать &lt;a href=&quot;https://neon.tech/blog/using-npm-packages-outside-node&quot;&gt;NPM-пакет вне Node&lt;/a&gt;, например, в браузере (олды сразу вспомнят &lt;a href=&quot;https://browserify.org/&quot;&gt;browserify&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.benwiley.org/audio-plugins/&quot;&gt;инсайты разработчика аудио-приложения в браузере&lt;/a&gt;: интересный тейк — обработку iframe с разными доменами Chromium-браузеры могут выполнять не в основном потоке (такой &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Prioritized_Task_Scheduling_API&quot;&gt;Prioritized Task Scheduling API&lt;/a&gt; из айфреймов и палок)&lt;/li&gt;
&lt;li&gt;оказывается Next.js умеет обрабатывать &lt;a href=&quot;https://dev.to/nathan_tarbert/the-zebras-guide-to-showcase-your-images-in-light-dark-17f5&quot;&gt;md-файлы со встроенными React-компонентами&lt;/a&gt; (у меня до сих пор к этому подходу есть вопросики, намного лучше выглядит &lt;a href=&quot;https://jakelazaroff.com/words/web-components-will-outlive-your-javascript-framework/&quot;&gt;включение веб-компонентов в md&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;никогда не будет лишним прочитать &lt;a href=&quot;https://dev.to/what1s1ove/javascript-naming-conventions-are-important-45n&quot;&gt;гайд&lt;/a&gt; по именованию разных штук в JS-коде&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zachleat.com/web/a-taxonomy-of-web-component-types/&quot;&gt;разные подходы на написания веб-компонентов&lt;/a&gt; на примерах: улучшающие код, дополняющие код и генерирующие код&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;качественный &lt;a href=&quot;https://ishadeed.com/article/css-nesting&quot;&gt;гайд&lt;/a&gt; по CSS Nesting&lt;/li&gt;
&lt;li&gt;качественный &lt;a href=&quot;https://www.joshwcomeau.com/css/interactive-guide-to-grid/&quot;&gt;гайд&lt;/a&gt; по CSS Grid&lt;/li&gt;
&lt;li&gt;качественный &lt;a href=&quot;https://developer.mozilla.org/en-US/blog/getting-started-with-css-container-queries/&quot;&gt;гайд&lt;/a&gt; по CSS Container queries&lt;/li&gt;
&lt;li&gt;и всё же, &lt;a href=&quot;https://gomakethings.com/modular-css-and-different-ways-to-structure-your-stylesheets/&quot;&gt;как лучше собирать CSS-файлы&lt;/a&gt;: в бандл, отдельными файлами или использовать &lt;code&gt;@import&lt;/code&gt; внутри?&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://utilitybend.com/blog/elevate-your-css-debugging-skills-with-these-chrome-devtools-tricks-in-2024/&quot;&gt;возможности dev-tools&lt;/a&gt; для дебага разных CSS-вещей&lt;/li&gt;
&lt;li&gt;и почему же всё таки &lt;code&gt;height&lt;/code&gt; в CSS &lt;a href=&quot;https://blog.jim-nielsen.com/2023/width-and-height-in-css/&quot;&gt;так странно работает&lt;/a&gt; (не как &lt;code&gt;width&lt;/code&gt;)?&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>URL Pattern API</title><link>https://juwain.github.io/web-platform/blog/2023-11-28/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-11-28/</guid><description>Это инструмент для сопоставления URL на основе шаблонов</description><pubDate>Tue, 28 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Это инструмент для сопоставления URL на основе шаблонов. Допустим, есть URL &lt;code&gt;https://example.com/products/123&lt;/code&gt;. И нужно сопоставить его с шаблоном &lt;code&gt;https://example.com/products/:id&lt;/code&gt;. Это можно сделать так:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const urlPattern = new URLPattern({ pathname: &quot;/products/:id&quot; });
const url = new URL(&quot;https://example.com/products/123&quot;);
console.log(urlPattern.test(url)); // true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Кроме теста соответствия урла шаблону, можно ещё и извлечь соответствующие параметры:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const urlPattern = new URLPattern({ pathname: &quot;/products/:id&quot; });
const url = new URL(&quot;https://example.com/products/123&quot;);
const result = urlPattern.exec(url);
console.log(result.pathname.groups.id); // &quot;123&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Самый очевидный юзкейс &lt;code&gt;URLPattern&lt;/code&gt; — клиентский роутер, который проверяет соответствие текущего урла паттерну, по которому показывается нужный контент. Пример в React:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;Router&amp;gt;
  &amp;lt;Route path=&quot;/&quot;&amp;gt;
    &amp;lt;Home /&amp;gt;
  &amp;lt;/Route&amp;gt;
  &amp;lt;Route path=&quot;/about&quot;&amp;gt;
    &amp;lt;About /&amp;gt;
  &amp;lt;/Route&amp;gt;
  &amp;lt;Route path=&quot;/messages/:id&quot;&amp;gt;
    &amp;lt;Messages /&amp;gt;
  &amp;lt;/Route&amp;gt;
&amp;lt;/Router&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;function Route({ path, children }) {
  const baseURL = window.location.origin;
  const pattern = new URLPattern({ pathname: path, baseURL });
  const match = pattern.test(currentPath);

  if (!match) {
    return null;
  }

  return children;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Помимо &lt;code&gt;pathname&lt;/code&gt; &lt;code&gt;URLPattern&lt;/code&gt; умеет определять все остальные части урла: &lt;code&gt;hash&lt;/code&gt;, &lt;code&gt;hostname&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;protocol&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, &lt;code&gt;username&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Работает пока что &lt;a href=&quot;https://caniuse.com/mdn-api_urlpattern&quot;&gt;только в Chromium,&lt;/a&gt; но &lt;a href=&quot;https://github.com/kenchris/urlpattern-polyfill&quot;&gt;полифиллится.&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 01.12.2023</title><link>https://juwain.github.io/web-platform/blog/2023-12-01/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-01/</guid><description>Новости веб-платформы</description><pubDate>Fri, 01 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://github.blog/2023-11-20-highlights-from-git-2-43/&quot;&gt;Git 2.43&lt;/a&gt; (да, такое тоже бывает): появилась возможность лучше прибираться с помощью &lt;code&gt;git repack&lt;/code&gt;, клонировать репозитории в режиме &lt;code&gt;tree-less&lt;/code&gt;, более гуманные сообщения при повторном &lt;code&gt;revert&lt;/code&gt;-е, возможность отмены текущих запусков CI при новых push в CI-ветку и ещё немного ништяков&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://nodejs.org/en/blog/release/v20.10.0&quot;&gt;Node v20.10.0 (LTS)&lt;/a&gt; забэкпортили некоторые хорошие вещи: к примеру, режим работы с флагами &lt;code&gt;--experimental-default-type&lt;/code&gt;, &lt;code&gt;--experimental-wasm-modules&lt;/code&gt; и &lt;code&gt;--experimental-websocket&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;обновился &lt;a href=&quot;https://rsms.me/inter/&quot;&gt;шрифт Inter&lt;/a&gt; до версии &lt;a href=&quot;https://github.com/rsms/inter/releases/tag/v4.0&quot;&gt;4.0&lt;/a&gt;: вариативность, переработанные и новые глифы (есть, в том числе, кириллица), доп OpenType-фичи (и это оперсорс и бесплатно, если что)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;опенсорсная десктопная плиложуха для теста API &lt;a href=&quot;https://www.usebruno.com/&quot;&gt;bruno&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sindresorhus/request-animation-frames&quot;&gt;requestAnimationFrame&lt;/a&gt; как асинхронный итератор для любых сред исполнения JS&lt;/li&gt;
&lt;li&gt;крутое приложение для визуального создания анимаций &lt;a href=&quot;https://www.viget.com/articles/create-rive-animations/&quot;&gt;Rive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/henriqueinonhe/promises-training/&quot;&gt;репозиторий для тренировки работы с промисами&lt;/a&gt; путём их имплементации&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;как создать одно приложение с использованием нескольких фреймворков (а точнее как &lt;a href=&quot;https://jakelazaroff.com/words/web-components-eliminate-javascript-framework-lock-in/&quot;&gt;использовать веб-компоненты для уменьшения связности&lt;/a&gt;, которую несут JS-фреймворки)&lt;/li&gt;
&lt;li&gt;обзор, &lt;a href=&quot;https://pqvst.com/2023/11/21/web-push-notifications/&quot;&gt;как работает Web Push&lt;/a&gt; (оказалось, что очень завязанно на браузерных вендоров)&lt;/li&gt;
&lt;li&gt;как добавить немного AI для &lt;a href=&quot;https://labs.pineview.io/using-openai-platform-to-analyse-automated-test-failures/&quot;&gt;расшифровки результатов выполнения тестов&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;как опубликовать реакт-компонент как &lt;a href=&quot;https://blog.coderspirit.xyz/blog/2023/09/15/create-a-react-component-lib/&quot;&gt;ESM+CJS библиотеку с типами&lt;/a&gt;, а также два интересных инструмента: &lt;a href=&quot;https://arethetypeswrong.github.io/&quot;&gt;Are The Types Wrong?&lt;/a&gt; для проверки типов в опубликованной библиотеке и &lt;a href=&quot;https://www.npmjs.com/package/publint&quot;&gt;publint&lt;/a&gt; для проверки корректности &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ещё &lt;a href=&quot;https://dev.to/francescovetere/css-trick-transition-from-height-0-to-auto-21de&quot;&gt;один трюк&lt;/a&gt; плавного перехода для &lt;code&gt;height&lt;/code&gt; с &lt;code&gt;0&lt;/code&gt; до &lt;code&gt;auto&lt;/code&gt; (tldr, на гридах с &lt;code&gt;0fr&lt;/code&gt; до &lt;code&gt;1fr&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;много мелких, но приятных &lt;a href=&quot;https://www.smashingmagazine.com/2023/11/few-ways-css-easier-write-2023/&quot;&gt;CSS-полезностей&lt;/a&gt;, которые так и ждут, чтобы их использовали&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hanging-punctuation&lt;/code&gt; — или как &lt;a href=&quot;https://chriscoyier.net/2023/11/27/the-hanging-punctuation-property-in-css/&quot;&gt;вынести висящие знаки препинания за пределы строки&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amitmerchant.com/hollow-text-hover-effect-with-only-three-lines-of-css/&quot;&gt;как сделать текст прозрачным внутри&lt;/a&gt; (с помощью небольшой -webkit-магии)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/francescovetere/the-css-property-you-didnt-know-you-needed-3fk0&quot;&gt;как вытащить элемент из stacking context-а&lt;/a&gt; без задания ему &lt;code&gt;transform&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt; или &lt;code&gt;opacity&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-irl.info/preventing-overscroll-bounce-with-css/&quot;&gt;лок скролла&lt;/a&gt; с помощью &lt;code&gt;overscroll-behavior&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tsev.dev/posts/2023-11-10-should-avif-be-the-dominant-image-format/&quot;&gt;пора ли уже переходить на формат изображений AVIF&lt;/a&gt;? Если сжимаете картинки сильно, и не нужна поддержка в Edge — да!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/web-dot-dev/pen/vYbadaJ&quot;&gt;бургер-менюшка без JS&lt;/a&gt; на Popover API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tedium.co/2023/11/24/weird-html-hacks-history/&quot;&gt;пост&lt;/a&gt; для фронтендеров «кому за…» со сборником ностальгических хаков (даже есть упоминание &lt;a href=&quot;https://www.w3.org/submissions/1996/1/WD-jsss-960822&quot;&gt;спеки JSSS&lt;/a&gt;, которая однажды проиграла в браузерных войнах, и где мы сейчас?)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wattenberger.com/thoughts/evolving-the-infinite-canvas&quot;&gt;красивая статья-размышление&lt;/a&gt; о многомерном пространстве в сайтах&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Роутер с помощью URL Pattern API</title><link>https://juwain.github.io/web-platform/blog/2023-12-06/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-06/</guid><description>Обещанный видос по URL Pattern API и пример роутера с его использованием</description><pubDate>Wed, 06 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Обещанный видос по URL Pattern API и пример роутера с его использованием.&lt;/p&gt;
&lt;p&gt;Код тут &lt;a href=&quot;https://codesandbox.io/p/sandbox/holy-feather-7m4ftd&quot;&gt;https://codesandbox.io/p/sandbox/holy-feather-7m4ftd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ютуб &lt;a href=&quot;https://youtu.be/LHAjrvfej4U?si=xuW6UdFNMSkChgZP&quot;&gt;https://youtu.be/LHAjrvfej4U?si=xuW6UdFNMSkChgZP&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 08.12.2023</title><link>https://juwain.github.io/web-platform/blog/2023-12-08/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-08/</guid><description>Новости веб-платформы</description><pubDate>Fri, 08 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://www.electronjs.org/blog/electron-28-0&quot;&gt;Electron 28.0.0&lt;/a&gt;: добавлена поддержка ES-модулей и там всё оч интересно: главный процесс Electron-а запускается в ноде и соответственно &lt;a href=&quot;https://www.electronjs.org/docs/latest/tutorial/esm&quot;&gt;использует имплементацию ESM ноды&lt;/a&gt;, а рендерится всё в хромиуме и там уже другая имплементация, Electron выбирает, как быть, в зависимости от контекста&lt;/li&gt;
&lt;li&gt;вышла библиотека &lt;a href=&quot;https://github.com/facebook/stylex&quot;&gt;StyleX от фб&lt;/a&gt;: из плюсов — типизация, генерация в билд-тайме, из минусов — непонятно зачем это нужно сейчас кому-то, кроме фб&lt;/li&gt;
&lt;li&gt;Remix &lt;a href=&quot;https://github.com/orgs/remix-run/projects/5/views/1&quot;&gt;запланировал реализацию&lt;/a&gt; React Server Components (видимо, вынужденно)&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://github.com/vitest-dev/vitest/releases/tag/v1.0.0&quot;&gt;Vitest v1.0.0&lt;/a&gt;: кажется уже устаканилось настолько, чтобы внедрять (1.0.0 внушает доверие)&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://htmlcssjavascript.com/web/html5-boilerplate-v9-0-0-released/&quot;&gt;новый HTML5 Boilerplate&lt;/a&gt; (да, это не шутка! внимание, может вызвать ностальгические чувства)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;как вам стейт-менеджер веб-приложений в виде SQL-бд (чудны дела твои, эволюция)? такое есть в &lt;a href=&quot;https://github.com/orbitinghail/sqlsync&quot;&gt;SQLSync&lt;/a&gt; (а для выборки из стора можно пользовать SQL, yay)&lt;/li&gt;
&lt;li&gt;симпатичная либа компонентов на тейлвинде &lt;a href=&quot;https://github.com/MarsX-dev/floatui&quot;&gt;floatui&lt;/a&gt; (проект настолько свежий, что не успели ещё поправить ридми)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/3rd/tsdiagram&quot;&gt;tsdiagram&lt;/a&gt; сгенерит для вас на лету красивую диаграмму из хитросплетений типов&lt;/li&gt;
&lt;li&gt;just another либа для манипуляций с цветом &lt;a href=&quot;https://github.com/Evercoder/culori&quot;&gt;culori&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Zizzamia/perfume.js&quot;&gt;тул для сбора перфоманс-метрик&lt;/a&gt; (в том числе Web Vitals) на пользовательских устройствах и отсыла их обратно через google-аналитику либо другие аналитические тулы (главное чтобы браузеры не блочили аналитические тулы)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;как улучшить &lt;a href=&quot;https://calendar.perfplanet.com/2023/yielding-main-thread-breaking-up-tasks-fix-inp/&quot;&gt;перфоманс-метрику INP&lt;/a&gt;: предсказуемые способы разгрузить основной поток &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;requestAnimationFrame&lt;/code&gt;, &lt;code&gt;requestIdleCallback&lt;/code&gt;, а также неведомый &lt;code&gt;scheduler.yield()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;как плохой INP может &lt;a href=&quot;https://www.speedcurve.com/blog/INP-user-experience-correlation/&quot;&gt;уронить бизнес-метрики&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gomakethings.com/the-elevator-pitch-for-web-components/&quot;&gt;ещё одна попытка&lt;/a&gt; заинтересовать в веб-компонентах: в них можно бесплатно инкапсулировать логику, есть встроенные колбеки на добавление и удаление из DOM-а и изменение «пропсов»&lt;/li&gt;
&lt;li&gt;как &lt;a href=&quot;https://pawelgrzybek.com/i-replaced-npm-yarn-and-nvm-with-pnpm/&quot;&gt;заменить&lt;/a&gt; npm, yarn и nvm на pnpm (правда не очень понятно зачем)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://proxiesapi.com/articles/the-complete-puppeteer-cheatsheet&quot;&gt;сборник рецептов для Puppeteer&lt;/a&gt; (от простого волшебства к сложным заклинаниям)&lt;/li&gt;
&lt;li&gt;как &lt;a href=&quot;https://lirantal.com/blog/advanced-usage-patterns-for-taking-page-element-screenshots-with-playwright/&quot;&gt;сделать скриншот фрагмента страницы&lt;/a&gt; с помощью Playwright&lt;/li&gt;
&lt;li&gt;old but gold: что такое и с чем едят &lt;a href=&quot;https://spidermonkey.dev/blog/2023/02/23/javascript-import-maps-part-1-introduction.html&quot;&gt;JavaScript Import maps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;паттерны проектирования реакт-компонентов: &lt;a href=&quot;https://www.bekk.christmas/post/2023/1/polymorphism-in-react&quot;&gt;as и asChild&lt;/a&gt; (is this a полиморфизм?)&lt;/li&gt;
&lt;li&gt;история того, как в JS появилось &lt;a href=&quot;https://www.smashingmagazine.com/2023/12/marketing-changed-oop-javascript/&quot;&gt;именно такое ООП&lt;/a&gt;, какое есть сейчас (читать с кофе, в кресле, укрывшись пледом)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nolanlawson.com/2023/12/02/lets-learn-how-modern-javascript-frameworks-work-by-building-one/&quot;&gt;реактивный JS-фреймворк на коленке&lt;/a&gt;, откуда можно узнать: юзкейс для &lt;code&gt;Proxy&lt;/code&gt;, незаслуженно неизвестное API &lt;code&gt;queueMicrotask&lt;/code&gt;, ликбез по &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates&quot;&gt;tagged template literals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://timjohns.ca/typescripts-hidden-feature-subtypes.html&quot;&gt;хитрая магия&lt;/a&gt;, чтобы делать «подтипы» в TS (после использования сжечь проект!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.classyfont.com/&quot;&gt;тулза для генерации CSS&lt;/a&gt; для подключения шрифтов&lt;/li&gt;
&lt;li&gt;дешёвый и сердитый способ сделать &lt;a href=&quot;https://chriscoyier.net/2023/12/04/html-css-for-a-one-time-password-input/&quot;&gt;инпут для one-time-пароля&lt;/a&gt; (без JS!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.jim-nielsen.com/2023/examples-of-great-urls/&quot;&gt;примеры классного дизайна… URL&lt;/a&gt; (от stackoverflow, slack, github, npm и unpkg)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Новая версия CSS Snapshot 2023</title><link>https://juwain.github.io/web-platform/blog/2023-12-12/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-12/</guid><description>Новости веб-платформы</description><pubDate>Tue, 12 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Финально в этом году обновился &lt;a href=&quot;https://www.w3.org/TR/css-2023/&quot;&gt;CSS Snapshot 2023&lt;/a&gt;! 🥁&lt;/p&gt;
&lt;p&gt;В финальной редакции спека &lt;a href=&quot;https://www.w3.org/TR/css-view-transitions-1/&quot;&gt;CSS View Transitions Module Level 1&lt;/a&gt; перешла в &lt;a href=&quot;https://www.w3.org/TR/css-2023/#fairly-stable&quot;&gt;FairlyStable-раздел&lt;/a&gt;. Это значит, что основная работа над спекой завершена и полученный результат довольно стабилен.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://caniuse.com/view-transitions&quot;&gt;Поддержка&lt;/a&gt; View Transitions API пока что есть только в Хромиуме. Но вангую, что переход спеки в стабильный раздел должен дать сигнал в Мозиллу и Эпл, чтобы поддержка побыстрее появилась и в Firefox с Safari. Ждём в 2024. 🤞&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 15.12.2023</title><link>https://juwain.github.io/web-platform/blog/2023-12-15/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-15/</guid><description>Новости веб-платформы</description><pubDate>Fri, 15 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://webkit.org/blog/14787/webkit-features-in-safari-17-2/&quot;&gt;Safari 17.2,&lt;/a&gt; много мелких и классных обновлений в уходящий год, чтобы подбить статистику Interop 2023:
&lt;ul&gt;
&lt;li&gt;аккордеон на &lt;code&gt;&amp;lt;details&amp;gt; + &amp;lt;summary&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onetimecode&lt;/code&gt; для инпутов&lt;/li&gt;
&lt;li&gt;«расслабленный» CSS-nesting&lt;/li&gt;
&lt;li&gt;обновления &lt;a href=&quot;https://drafts.fxtf.org/motion-1/&quot;&gt;CSS Motion Path&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;функция &lt;code&gt;linear()&lt;/code&gt; для создания «нелинейных» анимаций&lt;/li&gt;
&lt;li&gt;математические функции &lt;code&gt;rem()&lt;/code&gt;, &lt;code&gt;mod()&lt;/code&gt;, &lt;code&gt;round()&lt;/code&gt; в CSS&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display: list-item&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mask-border&lt;/code&gt; без префиксов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API&quot;&gt;Custom Highlights API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;link rel=&quot;preload&quot;&amp;gt;&lt;/code&gt; с атрибутами &lt;code&gt;imagesrcset&lt;/code&gt; и &lt;code&gt;imagesizes&lt;/code&gt; для подгрузки адаптивных изображений&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import&lt;/code&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import&quot;&gt;attributes&lt;/a&gt; в JS&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetchpriority&lt;/code&gt; для загрузки ресурсов&lt;/li&gt;
&lt;li&gt;улучшение нативной валидации форм и ещё много других плюшек&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://million.dev/blog/million-3&quot;&gt;анонсирован&lt;/a&gt; выход Million 3.0 — альтернативного VDOM для Реакта &lt;a href=&quot;https://million.dev/blog/virtual-dom&quot;&gt;(подробно о его работе):&lt;/a&gt; вкратце, он берёт для реконсиляции только динамически заполняемые DOM-ноды, а на статические не обращает внимания, а затем сравнивает не сами DOM-ноды, а их состояние (что существенно быстрее); годится для случаев, когда в приложении не слишком много динамических кусков, и часть приложения в ходе работы остаётся неизменной (значит её не нужно учитывать в пересчёте)&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://github.com/svg/svgo/releases/tag/v3.1.0&quot;&gt;SVGO v3.1.0,&lt;/a&gt; улучшено всё, без маркетиноговых уловок сообщаю, что это просто классный проект, cli-тулза для чистки SVG от мусора&lt;/li&gt;
&lt;li&gt;Storybook с &lt;a href=&quot;https://storybook.js.org/blog/storybook-react-server-components/&quot;&gt;8.0 версии&lt;/a&gt; будет поддерживать React Server Components: минус — Next.js съест и Storybook, плюс — Storybook не будет медленно рендериться на клиенте&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://primer.style/react/&quot;&gt;Primer React&lt;/a&gt; — библиотека Реакт-компонентов Гитхаба: круто, что такие проекты выкладываются в opensource, поэтому можно почитать исходники: из интересного, у них используются &lt;code&gt;styled-components&lt;/code&gt; и чтобы компоненты писать вот так красиво &lt;code&gt;&amp;lt;Header.Item&amp;gt;&lt;/code&gt; делается &lt;code&gt;Object.assign(Header, {Link: HeaderLink, Item: HeaderItem})&lt;/code&gt; &lt;a href=&quot;https://github.com/primer/react/blob/8a8973cd23e6810a15da5f0113395369d8bc3cd0/src/Header/Header.tsx#L73&quot;&gt;(реф)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liriliri/eruda&quot;&gt;eruda&lt;/a&gt; — эмулятор браузерной консоли и девтулзов для мобильных браузеров&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stellate.co/blog/announcing-fuse-js&quot;&gt;Fuse.js&lt;/a&gt; — фреймворк для создания типобезопасного слоя данных между бэком и фронтом, работает поверх Ноды и gql&lt;/li&gt;
&lt;li&gt;простой и честный респонсив компонент пагинации для Реакта — &lt;a href=&quot;https://github.com/jonelantha/react-responsive-pagination&quot;&gt;React Responsive Pagination&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amrdeveloper.github.io/GQL/&quot;&gt;GQL (Git Query Language)&lt;/a&gt; — а как вам такое: можно делать выборки по истории гита с помощью SQL!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://enhance.dev/&quot;&gt;enhance&lt;/a&gt; — HTML-first full-stack веб-фреймворк на веб-компонентах, выглядит очень симпатично, так и тянутся руки глотнуть свежего воздуха&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://giacomocerquone.com/keep-input-cursor-still/&quot;&gt;интересная детективная история,&lt;/a&gt; которая начинается с того, что при изменении содержимого инпута курсор переносится в конец строки, а заканчивается кишками событийной модели Реакта и методом &lt;code&gt;flushSync&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-irl.info/nan-or-not-a-number/&quot;&gt;статья&lt;/a&gt; о том, чем &lt;code&gt;isNaN&lt;/code&gt; отличается от &lt;code&gt;Number.isNaN()&lt;/code&gt;, а также почему &lt;code&gt;typeof NaN&lt;/code&gt; это &lt;code&gt;&apos;number&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sinja.io/blog/guide-to-react-suspense&quot;&gt;как устроен React Suspense:&lt;/a&gt; tldr, Реакт под капотом использует новый компонент &lt;a href=&quot;https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#offscreen-rendering&quot;&gt;Offscreen,&lt;/a&gt; который как бы есть, но его как бы нет, то есть туда можно заблаговременно рендерить контент, но его не будет сразу видно (он условно скрыт&lt;code&gt;style=&quot;display: none !important;&quot;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/nguyenhongphat0/react-state-management-in-2024-5e7l&quot;&gt;подборка текущих актуальных стейт-менеджеров:&lt;/a&gt; построенные на редьюсинге, атомах либо мутации, а также их плюсы, минусы и подводные камни (хотя в 90% случаев можно было бы обойтись простой useReducer + контекст)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://molefrog.com/notes/react-tricks&quot;&gt;хитрости в работе с Реактом&lt;/a&gt; от автора &lt;a href=&quot;https://github.com/molefrog/wouter&quot;&gt;Wouter:&lt;/a&gt; патчим компоненты с &lt;code&gt;cloneElement&lt;/code&gt;; &lt;code&gt;useState&lt;/code&gt;, который никогда не обновляется &lt;code&gt;const [value] = useState(() =&amp;gt; { /* initializer */ });&lt;/code&gt; неизменная ссылка на функцию с помощью &lt;code&gt;useEvent&lt;/code&gt; и кое-что ещё&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://overreacted.io/a-chain-reaction/&quot;&gt;статья от Дэна Абрамова&lt;/a&gt; от том, как обрабатывается JSX (feels like мемуары о тех временах, когда деревья были большие и зелёные, а рендеринг был только клиентский)&lt;/li&gt;
&lt;li&gt;супер-гигантская и супер-полезная статья про всё, что вам может понадобиться при &lt;a href=&quot;https://blog.xnim.me/indexeddb-guide&quot;&gt;работе с IndexedDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;использование кастомных &lt;a href=&quot;https://tbeseda.com/blog/super-helpful-server-timing-http-response-headers&quot;&gt;Server-Timing HTTP-заголовков&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;кодим &lt;a href=&quot;https://fffuel.co/svg-spinner/&quot;&gt;SVG-спиннер&lt;/a&gt; голыми руками без сторонней помощи (и без страховки)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/css-wrapped-2023&quot;&gt;что из CSS зарелизилось в браузерах в 2023&lt;/a&gt; (огромное количество класных фич, на 2024 уже даже столько интересного не осталось): тригонометрические функции, микросинтаксис селекторов &lt;code&gt;An+B&lt;/code&gt;, &lt;code&gt;scope&lt;/code&gt;, &lt;code&gt;nesting&lt;/code&gt;, &lt;code&gt;subgrid&lt;/code&gt;, &lt;code&gt;initial-letter&lt;/code&gt;, &lt;code&gt;text-wrap&lt;/code&gt;, &lt;code&gt;color-mix()&lt;/code&gt;, relative color syntax, &lt;code&gt;@container&lt;/code&gt; и &lt;code&gt;@container style()&lt;/code&gt;, &lt;code&gt;:has()&lt;/code&gt;, новые возможности медиа-выражений, View Transitions API, &lt;code&gt;linear()&lt;/code&gt;, событие &lt;code&gt;scrollend&lt;/code&gt;, скролл-анимации с ViewTimeline, анимация дискретных свойств типа &lt;code&gt;display: none&lt;/code&gt;, &lt;code&gt;@starting-style&lt;/code&gt;, Popover API, &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; в &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;, псевдоклассы &lt;code&gt;:user-valid&lt;/code&gt; и &lt;code&gt;:user-invalid&lt;/code&gt;, аккордеон на &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/fine-ill-use-a-super-basic-css-processing-setup/&quot;&gt;минималистическая сборка CSS&lt;/a&gt; с помощью &lt;a href=&quot;https://lightningcss.dev/&quot;&gt;Lightning CSS&lt;/a&gt; (немного свело олдскулы)&lt;/li&gt;
&lt;li&gt;будущие нативные &lt;a href=&quot;https://css.oddbird.net/sasslike/mixins-functions/&quot;&gt;функции и миксины в CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://svg-tutorial.com/&quot;&gt;SVG-адвент&lt;/a&gt;-календарь&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scottjehl.com//posts/using-responsive-video/&quot;&gt;использование респонсив &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;&lt;/a&gt; (аля &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;) теперь кроссбраузерно (а также зачем-то респонсив &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.pope.tech/2023/11/27/how-to-use-chromes-accessibility-tree/&quot;&gt;инспекция дерева доступности&lt;/a&gt; страницы теперь доступно в Хроме&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/timeweb/articles/751338/&quot;&gt;разбор HTTP/2 по байтам&lt;/a&gt;: очень дотошно, душно и исчерпывающе&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://inclusion.yandex.ru/settingsresearch&quot;&gt;исследование Яндекса&lt;/a&gt; о частоте использования тех или иных фич доступности на смартфонах: оказывается очень много людей используют системное увеличение шрифта и тёмную тему&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2023/12/preparing-interaction-next-paint-web-core-vital/&quot;&gt;подготовка к мониторингу метрики INP&lt;/a&gt;: в целом, рекомендации те же — не допускать долгих блокирующих тасок всеми возможными способами&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Селектор :has() в FF 121</title><link>https://juwain.github.io/web-platform/blog/2023-12-21/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-21/</guid><description>FF 121 вышел, селектор :has() доехал везде, теперь можно</description><pubDate>Thu, 21 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Короч, FF 121 вышел, селектор &lt;code&gt;:has()&lt;/code&gt; доехал везде, теперь можно! 💫&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;body&amp;gt;
  &amp;lt;div class=&quot;one&quot;&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class=&quot;two&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;.one {
  background-color: green;
}

.two {
  background-color: orange;
}

body:has(.two:hover) .one {
  background-color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/juwain/pen/MWxgMRY&quot;&gt;демо&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 22.12.2023</title><link>https://juwain.github.io/web-platform/blog/2023-12-22/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-22/</guid><description>Новости веб-платформы</description><pubDate>Fri, 22 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;появился новый линтер &lt;a href=&quot;https://oxc-project.github.io/blog/2023-12-12-announcing-oxlint.html&quot;&gt;oxlint&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;написан на Rust&lt;/li&gt;
&lt;li&gt;можно не настраивать (convention over configuration)&lt;/li&gt;
&lt;li&gt;плагинов пока нет, но обещают, что можно будет писать их без использования JS или Rust&lt;/li&gt;
&lt;li&gt;быстр, но в том числе потому что проверяемых правил мало&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://svelte.dev/blog/sveltekit-2&quot;&gt;SvelteKit 2&lt;/a&gt;: &lt;a href=&quot;https://vitejs.dev/blog/announcing-vite5&quot;&gt;Vite 5&lt;/a&gt; под капотом, подготовка к будущему Svelte 5, &lt;a href=&quot;https://kit.svelte.dev/docs/shallow-routing&quot;&gt;shallow routing&lt;/a&gt;; tldr: Svetle продолжает прорастать в экосистему&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.vuejs.org/posts/vue-2-eol&quot;&gt;Vue 2 станет deprecated&lt;/a&gt; 31 декабря 2023&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://www.mozilla.org/en-US/firefox/121.0/releasenotes/&quot;&gt;Firefox 121&lt;/a&gt;: главное поддержан &lt;code&gt;:has()&lt;/code&gt;!&lt;/li&gt;
&lt;li&gt;вышла &lt;a href=&quot;https://blog.date-fns.org/v3-is-out/&quot;&gt;библиотека date-fns v3&lt;/a&gt;: теперь 100% типизирована, уменьшен размер бандла, функции экспортируются через named exports и кое-что ещё&lt;/li&gt;
&lt;li&gt;обновился &lt;a href=&quot;https://tailwindcss.com/blog/tailwindcss-v3-4&quot;&gt;Tailwind CSS v3.4&lt;/a&gt;: динамические viewport units, поддержка &lt;code&gt;:has()&lt;/code&gt;, &lt;code&gt;text-wrap: balance&lt;/code&gt;, субгриды и многое другое&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dai-shi/waku&quot;&gt;waku&lt;/a&gt; — минималистичный React-фреймворк с поддержкой ServerComponents: включает клиент, сервер и роутер&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/diegohaz/constate&quot;&gt;constate&lt;/a&gt;: библиотека для решения проблемы плодящихся контекстов в Реакте&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/terreng/simple-web-server&quot;&gt;simple-web-server&lt;/a&gt;: простая декстопная аппка для настройки и запуска дев-сервера&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/guest271314/bd292fc33e1b30dede0643a283fadc6a&quot;&gt;список&lt;/a&gt; всех известных (и неизвестных) JS рантаймов и движков на все случаи жизни (даже чтобы выполнять JS в с/с++)&lt;/li&gt;
&lt;li&gt;если промис ушёл и не вернулся, он попал в чёрную дыру: чтобы это исправить нужно &lt;a href=&quot;https://frontside.com/blog/2023-12-11-await-event-horizon/&quot;&gt;отказаться от асинхронных функций в угоду генераторов&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://calendar.perfplanet.com/2023/benchmarking-profiling-and-optimizing-javascript-libraries/&quot;&gt;профилируя приложение для локализации&lt;/a&gt; автор пришёл к тому, что &lt;code&gt;node --prof&lt;/code&gt; и инструмент &lt;a href=&quot;https://www.npmjs.com/package/speedscope&quot;&gt;speedscope&lt;/a&gt; — хорошая отправная точка для анализа перфоманса&lt;/li&gt;
&lt;li&gt;члены tc39 устали отвечать на одни и те же вопросы в ишью, и &lt;a href=&quot;https://github.com/tc39/faq/&quot;&gt;создали faq&lt;/a&gt;, в котором можно узнать, почему &lt;a href=&quot;https://github.com/tc39/faq/#can-we-change-json&quot;&gt;JSX не появится в ES&lt;/a&gt;, почему &lt;a href=&quot;https://github.com/tc39/faq/#can-we-change-json&quot;&gt;JSON никогда не поменяется&lt;/a&gt;, а также &lt;a href=&quot;https://github.com/tc39/faq/&quot;&gt;почему числа в JS такие странные&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://calendar.perfplanet.com/2023/fastest-way-passing-state-javascript-revisited/&quot;&gt;конкурсе&lt;/a&gt; на самый быстрый способ проброса состояния с сервера на клиент победил &lt;code&gt;&amp;lt;script type=&quot;mime/invalid&quot; id=&quot;myState&quot;&amp;gt;{&quot;foo&quot;:&quot;bar&quot;}&amp;lt;/script&amp;gt; window.__STATE__ = JSON.parse(window.myState.innerHTML)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bekk.christmas/post/2023/13/react-fights-you-can-have-with-your-team&quot;&gt;темы для холиваров&lt;/a&gt; в вашей команде, если вы работатете с Реактом: как писать экспорты, как называть файлы и пропсы, нужны ли стрелочные функции, а также тернарники vs early return&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@hamsterhomka/typescript-features-that-will-significantly-upgrade-your-skills-e40a3424fa50&quot;&gt;TS-фичи&lt;/a&gt; «следующего» уровня: satisfies, infer, exhaustive type checking&lt;/li&gt;
&lt;li&gt;эволюция &lt;a href=&quot;https://gist.github.com/kethinov/6658166&quot;&gt;синхронного рекурсивного обхода папок в ноде&lt;/a&gt; достигла вершины — &lt;code&gt;await fs.readdir(dir, { recursive: true })&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dmitripavlutin.com/what-every-javascript-developer-should-know-about-unicode/&quot;&gt;всё про Unicode для разработчиков&lt;/a&gt;: символы, их объединение, эскейп в JS, сравнение строк и регекспы&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/quantity-queries-are-very-easy-with-css-has/&quot;&gt;смена стилей в зависимости от количества элементов&lt;/a&gt; с помощью &lt;code&gt;element:has(&amp;gt; :nth-child(10))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://robbowen.digital/wrote-about/locking-scroll-with-has/&quot;&gt;лок скролла из глубины DOM-а&lt;/a&gt; с помощью &lt;code&gt;body:has(.lock-scroll) { overflow: hidden} &amp;lt;dialog class=&quot;lock-scroll&quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bejamas.io/blog/css-animated-gradient-border/&quot;&gt;четыре способа&lt;/a&gt; создать анимированные градиентные рамки&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://12daysofweb.dev/2023/animation-composition/&quot;&gt;свойство&lt;/a&gt; &lt;code&gt;animation-composition&lt;/code&gt;, позволяет начать анимацию с нуля либо с того значения свойства, которое уже задано на момент начала анимации (удивительно, но &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-composition#browser_compatibility&quot;&gt;поддерживается везде&lt;/a&gt;!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://csswizardry.com/2023/12/correctly-configure-preconnections/&quot;&gt;в каких случаях&lt;/a&gt; подходит использование &lt;code&gt;&amp;lt;link rel=preconnect&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;при использовании атрибута &lt;code&gt;sizes=&quot;auto&quot;&lt;/code&gt; у &lt;a href=&quot;https://ericportis.com/posts/2023/auto-sizes-pretty-much-requires-width-and-height/&quot;&gt;img нужно указывать&lt;/a&gt; также &lt;code&gt;width&lt;/code&gt; и &lt;code&gt;height&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://daniel.do/article/making-noisy-svgs/&quot;&gt;создание шумной текстуры в SVG&lt;/a&gt; (секрет в применении SVG-фильтров)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.htmhell.dev/adventcalendar/2023/3/&quot;&gt;древнее знание&lt;/a&gt;: атрибут &lt;code&gt;form&lt;/code&gt; у кнопки позволяет сабмитить форму, даже если кнопка снаружи неё&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>View Transitions API в SPA</title><link>https://juwain.github.io/web-platform/blog/2023-12-28/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2023-12-28/</guid><description>А вот и демо с применением View Transitions API в SPA</description><pubDate>Thu, 28 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;А вот и демо с применением View Transitions API в SPA.&lt;/p&gt;
&lt;p&gt;Код тут &lt;a href=&quot;https://codesandbox.io/p/sandbox/vigilant-bell-8tglkp&quot;&gt;https://codesandbox.io/p/sandbox/vigilant-bell-8tglkp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ютуб &lt;a href=&quot;https://youtu.be/nT1VC6_DDS8&quot;&gt;https://youtu.be/nT1VC6_DDS8&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Таймер без фриза с помощью Web Worker</title><link>https://juwain.github.io/web-platform/blog/2024-01-04/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-04/</guid><description>Если в JS запустить таймер с помощью setInterval, который срабатывает довольно часто, например, раз в 100мс, а затем уйти из таба на некоторое время, то окажется, что браузер остановит таймер на время «неактивности» таба</description><pubDate>Thu, 04 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Если в JS запустить таймер с помощью setInterval, который срабатывает довольно часто, например, раз в 100мс, а затем уйти из таба на некоторое время, то окажется, что браузер остановит таймер на время «неактивности» таба. «Фриз» таймера в неактивном табе можно посмотреть тут &lt;a href=&quot;https://codesandbox.io/p/sandbox/dreamy-bartik-vkkmjr&quot;&gt;https://codesandbox.io/p/sandbox/dreamy-bartik-vkkmjr&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Это не баг, а фича: с целью экономии ресурсов браузеры троттлят фоновую активность тех табов, которые сейчас не открыты.&lt;/p&gt;
&lt;p&gt;Но как быть, если нужно, чтобы таймер в фоновом табе гарантированно работал без замедления и остановки? На помощь приходит веб воркер, который работает в браузере отдельном потоке и поэтому на его работу оптимизации основного потока не распространяются.&lt;/p&gt;
&lt;p&gt;Вот пример таймера в отдельном файле воркера, к примеру, timerWorker.ts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let timerId: number | null = null;

self.onmessage = (event: MessageEvent) =&amp;gt; {
  const { data } = event;

  switch (data) {
    case &quot;start&quot;:
      timerId = self.setInterval(() =&amp;gt; {
        self.postMessage(&quot;tick&quot;);
      }, 100);
      break;
    case &quot;stop&quot;:
      if (timerId) {
        clearInterval(timerId);
        timerId = null;
      }
      break;
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В воркере нет объекта window, но есть self, местный аналог &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/self&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/self&lt;/a&gt;. С основным приложением воркер общается с помощью команды postMessage. При этом из приложения также можно дёргать postMessage воркера и подписываться на событие onmessage:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function App() {
  const [time, setTime] = useState&amp;lt;number&amp;gt;(0);
  const workerRef = useRef&amp;lt;Worker | null&amp;gt;(null);

  useEffect(() =&amp;gt; {
    workerRef.current = new Worker(&quot;/timerWorker.ts&quot;);

    workerRef.current.postMessage(&quot;start&quot;);

    workerRef.current.onmessage = (event) =&amp;gt; {
      if (event.data === &quot;tick&quot;) {
        setTime((prevTime) =&amp;gt; prevTime + 1);
      }
    };

    return () =&amp;gt; {
      workerRef.current?.postMessage(&quot;stop&quot;);
    };
  }, []);

  return &amp;lt;div&amp;gt;{time}&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В воркере, к сожалению, нет доступа к DOM-у, но зато доступны разные API, например, Fetch или Canvas, так что выгружать в воркер что-то тяжёлое или важное — вполне себе рабочая тема, о которой не стоит забывать.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 05.01.2024</title><link>https://juwain.github.io/web-platform/blog/2024-01-05/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-05/</guid><description>Новости веб-платформы</description><pubDate>Fri, 05 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tanstack.com/router/v1/docs/overview&quot;&gt;вышел TanStack Router&lt;/a&gt; — полностью типизированный (не только на TS, но и сами роуты защищены от ошибок типами) роутер от известного в узких кругах разработчика&lt;/li&gt;
&lt;li&gt;подведены &lt;a href=&quot;https://risingstars.js.org/2023/&quot;&gt;итоги 2023 года в экосистеме JS&lt;/a&gt; по версии Rising Stars: победители — shadcn/ui, Bun и Excalidraw&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wooorm/refractor&quot;&gt;refractror&lt;/a&gt; — хайлайтер синтаксиса, основанный на Prism, но отдающий на выходе не строку HTML, а объекты AST&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/salesforce/observable-membrane&quot;&gt;observable-membrane&lt;/a&gt; — создание обсервабл-объектов на основе Proxy&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tokenami/tokenami&quot;&gt;tokenami&lt;/a&gt; — ещё одна CSS-in-JS либа на Тейлвинде + custom properties, типизация из коробки&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/blog/introducing-catalyst&quot;&gt;catalyst&lt;/a&gt; — первая демка UI-кита для Реакта на Тейлвинде, от создателей Тейлвинда&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://microsoft.github.io/devicescript/&quot;&gt;devicescript&lt;/a&gt; — среда в VS Code, эмулятор и компилятор TS для программирования IoT-девайсов, контроллеров и прочего хардверного стафа&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rough-stuff/rough-notation&quot;&gt;оживление текста&lt;/a&gt; анимациями «ручных» обводок и подчёркиваний&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;оказывается цикл &lt;code&gt;forEach&lt;/code&gt; &lt;a href=&quot;https://dev.to/polakshahar/interview-can-you-stop-foreach-in-javascript-57h0&quot;&gt;всё таки можно остановить&lt;/a&gt; (но вряд ли нужно) с помощью &lt;code&gt;throw&lt;/code&gt; внутри &lt;code&gt;try&lt;/code&gt; с переходом в &lt;code&gt;catch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://julesblom.com/writing/flushsync&quot;&gt;в каких случаях нужен &lt;code&gt;flushSync&lt;/code&gt; в Реакте:&lt;/a&gt; по умолчанию изменения UI батчатся и затем применяются асинхронно, что не всегда подходит (Реакт иногда обновляет UI позже, чем нужно); если нужно гарантировано обновить UI «здесь и сейчас», то flushSync — подходящй инструмент (например, чтобы корректно установить фокус или позицию скролла)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/topefasasi/js-design-patterns-a-comprehensive-guide-h3m&quot;&gt;гайд по паттернам проектирования в JS&lt;/a&gt; с простыми примерами&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://betterprogramming.pub/all-javascript-and-typescript-features-of-the-last-3-years-629c57e73e42&quot;&gt;все JS и TS фичи за последние 3 года:&lt;/a&gt; чтиво на ночь для лёгкого засыпания либо для постновогоднего рефлексивного настроения&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/sportmaster_lab/articles/782822/&quot;&gt;кодогенерация и парсинг TS с помощью TS&lt;/a&gt; (конкурс на лучший юзкейс объявляется открытым!)&lt;/li&gt;
&lt;li&gt;если для работы с датами не хочется тащить библиотеку, то можно &lt;a href=&quot;https://habr.com/ru/articles/783236/&quot;&gt;воспользоваться встроенным Intl.DateTimeFormat,&lt;/a&gt; который довольно много умеет сам по себе&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fullystacked.net/vertical-alignment/&quot;&gt;свойство &lt;code&gt;align-content&lt;/code&gt; выравнивает&lt;/a&gt; элементы не только внутри флексбокса, но также и display: table-cell и list-item&lt;/li&gt;
&lt;li&gt;как происходит &lt;a href=&quot;https://www.phpied.com/image-requests-in-hidden-content/&quot;&gt;загрузка «невидимых» картинок:&lt;/a&gt; картинки без &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; грузятся всегда (даже в скрытом виде), а вот с &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; грузятся внутри &lt;code&gt;visibility: hidden&lt;/code&gt; и не грузятся внутри &lt;code&gt;display: none&lt;/code&gt; или &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;как выполнить невозможное &lt;code&gt;calc(100vw / 5px)&lt;/code&gt; с &lt;a href=&quot;https://dev.to/janeori/css-type-casting-to-numeric-tanatan2-scalars-582j&quot;&gt;помощью тригонометрических функций&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML, SVG&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nan.fyi/svg-paths&quot;&gt;интерактивный гайд по &lt;code&gt;path&lt;/code&gt;&lt;/a&gt; (залипательный)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Платформа&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tonsky.me/blog/unicode/&quot;&gt;абсолютный минимум о Unicode,&lt;/a&gt; который должен знать каждый уважающий себя разработчик в 2023 (и 2024, всё ещё никаких отговорок!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/articles/782608/&quot;&gt;сложность алгоритмов. Разбор Big O:&lt;/a&gt; для освежения в памяти после новогодних каникул&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Proxy и мемоизация функции</title><link>https://juwain.github.io/web-platform/blog/2024-01-10/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-10/</guid><description>Есть такая платформенная штука — Proxy. Это когда берёшь обычный объект в JS, создаёшь для него прокси и получаешь возможность перехватывать и переопределять основные операции, которые с объектом можно совершить: get, set, delete</description><pubDate>Wed, 10 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Есть такая платформенная штука — Proxy. Это когда берёшь обычный объект в JS, создаёшь для него прокси и получаешь возможность перехватывать и переопределять основные операции, которые с объектом можно совершить: get, set, delete… Внутри перехватчиков можно, например, логировать, валидировать или дополнять значения. Например:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const target = {
  message1: &quot;hello&quot;,
  message2: &quot;everyone&quot;,
};

const handler = {
  get(target, prop, receiver) {
    console.log(`Свойство ${prop} считалось`);
    return target[prop];
  },
  set(target, prop, value) {
    console.log(`Свойству ${prop} задано значение ${value}`);
    target[prop] = value;
    return true;
  },
};

const proxiedObj = new Proxy(target, handler);

proxiedObj.message1;
// log: Свойство message1 считалось

proxiedObj.message2 = &quot;nobody&quot;;
// log: Свойству message2 задано значение nobody
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Так вот, проксировать можно не только объекты, но и функции. В случае функций через прокси можно перехватывать момент вызова функции (перехватчик apply) и, например, манипулировать аргументами до вызова.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const a = () =&amp;gt; {
  // функция
};

const b = new Proxy(a, {
  apply: (target, thisArg, argumentsList) =&amp;gt; {
    // перехватчик вызова
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;До вызова функции мы получаем референс на саму функцию, контекст и массив агрументов и можем с ними делать что угодно перед тем, как непосредственно вызвать (или даже не вызвать) функцию. К примеру, можно организовать кэш, чтобы по переданному набору аргументов запомнить вычисленное значение и при повторном вызове брать его из кэша.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function memoize(target) {
  const cache = new Map();

  return new Proxy(target, {
    apply: (target, thisArg, argumentsList) =&amp;gt; {
      const key = JSON.stringify(argumentsList);
      if (cache.has(key)) {
        console.log(`Результат для ${argumentsList} взят из кэша`);
        return cache.get(key);
      } else {
        const result = target.apply(thisArg, argumentsList);
        cache.set(key, result);
        return result;
      }
    },
  });

  const add = (a, b) =&amp;gt; a + b;
  const memoizedAdd = memoize(add);

  memoizedAdd(3, 7); // Вычисляет и записывает в кэш
  memoizedAdd(3, 7); // Берёт результат из кэша
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Аргументами функции, то есть и ключами в кэше могут быть не только примитивы, но и объекты, за счёт того, что ключ формируется с помощью &lt;code&gt;JSON.stringify&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Таким образом, с помощью &lt;code&gt;Proxy&lt;/code&gt; можно на коленке собрать «мидлвари» для объектов, массивов и функций, в общем-то, с любыми целями.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 12.01.2024</title><link>https://juwain.github.io/web-platform/blog/2024-01-12/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-12/</guid><description>Новости веб-платформы</description><pubDate>Fri, 12 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://blog.vuejs.org/posts/vue-3-4&quot;&gt;Vue 3.4&lt;/a&gt;: переписан парсер шаблонов на &lt;a href=&quot;https://github.com/fb55/htmlparser2&quot;&gt;htmlparser2&lt;/a&gt; (стало 2x быстрее), улучшена система реактивности и добавлен шортхэнд для дублирующих значений атрибутов (&lt;code&gt;&amp;lt;img :id=&quot;id&quot; :src=&quot;src&quot; :alt=&quot;alt&quot;&amp;gt;&lt;/code&gt; 👉 &lt;code&gt;&amp;lt;img :id :src :alt&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;круг замкнулся: &lt;a href=&quot;https://github.com/remix-run/remix/pull/8338&quot;&gt;в Remix появится&lt;/a&gt; классический SPA-режим работы, с возможностью опционально включить SSR (сейчас в Remix приложениях вся загрузка данных происходит на сервере)&lt;/li&gt;
&lt;li&gt;в Chrome &lt;a href=&quot;https://chromestatus.com/feature/5133113939722240&quot;&gt;начали выпиливать&lt;/a&gt; сторонние (3-party) куки (у 1% пользователей)&lt;/li&gt;
&lt;li&gt;в React &lt;a href=&quot;https://github.com/reactjs/react.dev/pull/6459&quot;&gt;появятся&lt;/a&gt; API для прелоадинга ресурсов: &lt;a href=&quot;https://react-dev-git-fork-davidmccabe-float2-fbopensource.vercel.app/reference/react-dom/preload&quot;&gt;&lt;code&gt;preload&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://react-dev-git-fork-davidmccabe-float2-fbopensource.vercel.app/reference/react-dom/preconnect&quot;&gt;&lt;code&gt;preconnect&lt;/code&gt;&lt;/a&gt; и другие&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://whatpwacando.today/&quot;&gt;PWA-приложение&lt;/a&gt;, показывающее все возможности PWA-приложений&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zed.dev/&quot;&gt;zed&lt;/a&gt; — быстрый мультиплеерный редактор кода (почему, зачем, за что?)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fontsource/fontsource&quot;&gt;fontsource&lt;/a&gt; — опенсорсные шрифты в npm-пакете (для установки шрифтов как контроллируемых зависимостей вместо гугл-фонтс)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/humanwhocodes/fsx&quot;&gt;fsx&lt;/a&gt; — либа для работы с файловой системой в ноде, дено и памяти (в том числе браузерах) от создателя eslint&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;напоминание, что во всех браузерах доступны немутирующие аналоги &lt;code&gt;reverse()&lt;/code&gt;, &lt;code&gt;splice()&lt;/code&gt;, &lt;code&gt;sort()&lt;/code&gt; – &lt;a href=&quot;https://12daysofweb.dev/2023/new-js-array-methods/&quot;&gt;&lt;code&gt;toReversed()&lt;/code&gt;, &lt;code&gt;toSplice()&lt;/code&gt;, &lt;code&gt;toSorted()&lt;/code&gt; и &lt;code&gt;with()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;в JS-движке JavaScriptCore (в Safari), в отличие от V8 (в Chrome) реализован механизм оптимизации хвостовой рекурсии (Tail Call Optimization), позволяющий вызывать рекурсивно функцию сколько угодно раз без переполнения стека и &lt;a href=&quot;https://www.onsclom.net/posts/javascript-tco&quot;&gt;код можно сделать таким же быстрым&lt;/a&gt;, как и в цикле for&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2023/12/making-sense-of-senseless-javascript-features/&quot;&gt;разбор классических «странностей JS»&lt;/a&gt;: &lt;code&gt;0.2 + 0.1 = 0.300000001.&lt;/code&gt;, преобразование типов, автодобавление &lt;code&gt;;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://uncenter.dev/posts/npm-install-everything/&quot;&gt;история&lt;/a&gt;, как создали npm-пакет &lt;code&gt;everything&lt;/code&gt;, который включает ВСЕ пакеты npm, включая себя; из-за политики, что нельзя снять с публикации пакет, от которого зависит любой другой пакет, стало невозможно убрать из npm ВСЕ пакеты&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bekk.christmas/post/2023/20/jotai-build-your-state-with-atom-precision&quot;&gt;туториал по стейт-менеджеру Jotai&lt;/a&gt;, &lt;em&gt;состоящему из атомов&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;в Next.js теперь можно будет &lt;a href=&quot;https://twitter.com/leeerob/status/1743709145386131906&quot;&gt;запускать проект на https локально&lt;/a&gt; с помощью &lt;code&gt;next dev --experimental-https&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;здравый смысл восторжествовал и в &lt;a href=&quot;https://twitter.com/leeerob/status/1733154383410684148&quot;&gt;Next.js не будут больше патчить fetch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;document.getAnimations()&lt;/code&gt; &lt;a href=&quot;https://twitter.com/jh3yy/status/1712498013401235596&quot;&gt;возвращает в виде промисов&lt;/a&gt; все текущие CSS-анимации&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/timeweb/articles/781346/&quot;&gt;анатомия shadcn/ui&lt;/a&gt;: безголовые компоненты с отдельным слоем стилей, для установки разных состояний используется &lt;a href=&quot;https://cva.style/&quot;&gt;cva&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/samokat_tech/articles/766978/&quot;&gt;гайд по микрофронтендам на single-spa&lt;/a&gt;: такие штуки кажутся с первого взгляда сложными, но стоит попасть в ситуацию больших проектов, когда нужно шарить данные между разными приложениями, и уже становится понятно, зачем вся эта сложность&lt;/li&gt;
&lt;li&gt;чтоб не заморачиваться с выводом &lt;a href=&quot;https://habr.com/ru/articles/783858/&quot;&gt;типа события TS в React&lt;/a&gt;, можно воспользоваться общим «доставатором» типа &lt;code&gt;React.ComponentProps&amp;lt;&quot;input&quot;&amp;gt;[&quot;onChange&quot;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/nlmk/articles/770974/&quot;&gt;особенности использования enum в TS&lt;/a&gt;: например, const &lt;code&gt;enum Name {}&lt;/code&gt; полностью удалит этот фрагмент из скомпилированного кода, &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/enums.html#const-enum-pitfalls&quot;&gt;но есть нюансы&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/container-queries-and-units/&quot;&gt;гайд по container queries&lt;/a&gt; (с живыми примерами)&lt;/li&gt;
&lt;li&gt;как написать &lt;a href=&quot;https://component-odyssey.com/articles/05-using-heaps-of-cutting-edge-css-to-build-a-progress-indicator&quot;&gt;круглый индикатор прогресса&lt;/a&gt; со скролл-анимацией&lt;/li&gt;
&lt;li&gt;в Chome 120 появилось &lt;a href=&quot;https://blog.stephaniestimac.com/posts/2023/12/css-media-query-scripting/&quot;&gt;&lt;code&gt;@media (scripting: none)&lt;/code&gt;&lt;/a&gt; для определения выключенных скриптов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://utilitybend.com/blog/taking-a-closer-look-at-property-in-css/&quot;&gt;директива &lt;code&gt;@property&lt;/code&gt;&lt;/a&gt;: создание, дебаг, юзкейсы&lt;/li&gt;
&lt;li&gt;кликабельную область вокруг интерактивных элементов лучше увеличить (удобно для мобилок), &lt;a href=&quot;https://ishadeed.com/article/target-size/&quot;&gt;как это лучше сделать&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rauno.me/craft/vercel&quot;&gt;трюки и находки&lt;/a&gt; при создании нового сайта vercel: SVG-лучи, пиксельные логотипы на гридах, CSS-счётчики, круговая анимация&lt;a href=&quot;https://utilitybend.com/blog/taking-a-closer-look-at-property-in-css/&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML, SVG&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tpgi.com/the-top-accessibility-errors-found-in-2023/&quot;&gt;топ-10 ошибок в доступности&lt;/a&gt; на сайтах в 2023: пустые ссылки, некорректный tabindex, отсутствие alt и другое&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/the-popular-vote-of-interop-2024/&quot;&gt;победители&lt;/a&gt; в народном голосовании за фичи в Interop 2024: &lt;a href=&quot;https://github.com/web-platform-tests/interop/issues/430&quot;&gt;JPEG XL image format&lt;/a&gt;, &lt;a href=&quot;https://github.com/web-platform-tests/interop/issues/437&quot;&gt;View Transitions Level 1&lt;/a&gt;, &lt;a href=&quot;https://github.com/web-platform-tests/interop/issues/439&quot;&gt;Scroll-driven Animations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Настоящее айкидо</title><link>https://juwain.github.io/web-platform/blog/2024-01-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-16/</guid><description>Фикшн веб-платформы</description><pubDate>Tue, 16 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;Сейчас уже нет Настоящего Айкидо. В наше время айкидо называется, когда два чудака лупят друг друга пятками в челюсть или ломают друг другу суставы, или не знаю, чем они там ещё занимаются, не видел никогда.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;А Настоящее Айкидо — оно было совсем другое. Оно заключалось в том, чтобы победить Неприятеля так, чтобы самому не сильно напрягаться. Для этого даже не обязательно с этим Неприятелем встречаться.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Вот скажем принесли вам в разработку макеты с Неведомой Фичей. Как её сделать — хз, нет понимания.&lt;/p&gt;
&lt;p&gt;Приходит вам в голову мысль, как реализовать эту фичу с помощью Костылей. «Что поделать, инженерия — она такая», — думаете вы и берётесь за работу. В процессе к одному Костылю приходится прилепить ещё парочку и скрепить это для прочности подручными материалами. В общем, вы по ходу встречаете всё большие сложности и затем героически с ними боретесь. Получившееся решение громоздкое, хрупкое, но время на него уже потрачено, выкинуть жалко, да и в целом оно работает (почти всегда), так что что уж тут, оставляем.&lt;/p&gt;
&lt;p&gt;Вроде бы вы и победили, но гаденько как-то, нет этого приятного ощущения, ради которого вы когда-то давно вообще этим всем начали заниматься. Это не Настоящее Айкидо.&lt;/p&gt;
&lt;p&gt;Либо же вы ищете похожую задачу на Стэковерфлоу или спрашиваете у Чат-бота. И таким образом вы находите «Либу, которая решит все ваши проблемы». Правда помимо вашей задачи она решает ещё и парочку других проблем по пути, ну и тянет набор зависимостей на 500кб. Но это ладно, думаете вы, фичу-то надо сделать ещё вчера. «Ок, для временного решения сойдёт», — решаете вы и используете либу.&lt;/p&gt;
&lt;p&gt;А потом, спустя год-другой нужно вам зависимости проекта обновить и вы находите эту либу, вспоминаете что к чему, хотите версию этой либы заодно поднять. Но либа уже заброшена владельцем и вообще новым Реактом не поддерживается. «Что поделать, надо выпиливать», — думаете вы и снова оказываетесь в самом начале.&lt;/p&gt;
&lt;p&gt;Это не победа, Неприятель вас обхитрил, притворился побеждённым и вам снова нужно с ним сражаться. Это тоже не путь Настоящего Айкидо.&lt;/p&gt;
&lt;p&gt;А как бы поступил Мастер Настоящего Айкидо? Он бы сел, подумал и вспомнил, что Браузер, для которого он пишет программу, уже и сам умеет в нужную фичу. И вот Мастер на митинге скажет «Это умеет Платформа», а потом возьмёт и напишет несколько строк кода, чтобы дёрнуть нужный браузерный API, закроет задачу и пойдёт пить чай. И его решение никогда не протухнет, ведь Платформа всегда обратно совместима.&lt;/p&gt;
&lt;p&gt;Мастер Настоящего Айкидо прилагает большего всего сил, чтобы освоить базу, и затем стремится к применению усвоенных принципов. А когда ему приходит мысль, что ему всё ясно, то он говорит себе: «Этого недостаточно», и идёт дальше копать Базу. 🥷&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 19.01.2024</title><link>https://juwain.github.io/web-platform/blog/2024-01-19/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-19/</guid><description>Новости веб-платформы</description><pubDate>Fri, 19 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в &lt;a href=&quot;https://webkit.org/blog/14916/release-notes-for-safari-technology-preview-186/&quot;&gt;Safari TP 186&lt;/a&gt; допиливают &lt;code&gt;@scope&lt;/code&gt;, добавили &lt;code&gt;align-content&lt;/code&gt; для табличных ячеек и сделали анимируемым свойство &lt;code&gt;content-visibility&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;обновилась &lt;a href=&quot;https://nodejs.org/en/blog/release/v20.11.0&quot;&gt;Node v20.11.0 (LTS)&lt;/a&gt;: появились esm &lt;code&gt;import.meta.dirname&lt;/code&gt; и &lt;code&gt;import.meta.filename&lt;/code&gt; на замену CommonJS &lt;code&gt;filename&lt;/code&gt; и &lt;code&gt;dirname&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://prettier.io/blog/2024/01/12/3.2.0.html&quot;&gt;Prettier 3.2&lt;/a&gt;: поддержан формат файлов jsonc (если вы, также как и я не знали, что это такое, — это творение Microsoft, &lt;a href=&quot;https://code.visualstudio.com/docs/languages/json#_json-with-comments&quot;&gt;json с комментами&lt;/a&gt; &lt;code&gt;//&lt;/code&gt; и &lt;code&gt;/**/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://nextjs.org/blog/next-14-1&quot;&gt;Next.js 14.1&lt;/a&gt; — ускорен стартап и Turbopack, улучшен вывод ошибок, добавлена поддержка нативных &lt;code&gt;window.history.pushState&lt;/code&gt; и &lt;code&gt;window.history.replaceState&lt;/code&gt;, логирование использования кэша, расширены возможности работы с картинками&lt;/li&gt;
&lt;li&gt;в TS 5.4 появится новый тип &lt;a href=&quot;https://github.com/microsoft/TypeScript/pull/56794&quot;&gt;&lt;code&gt;NoInfer&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;, чтобы блокировать инфер пришедшего типа&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ahastack.dev/&quot;&gt;The AHA Stack&lt;/a&gt; — всем панкрок! или Astro, htmx и Alpine.js объединились в банду, шатают SPA-мир и хотят вернуть веб-разработке простые ментальные модели и воркфлоу (интересно, доколе ещё ждать наступления прекрасного будущего?!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FrigadeHQ/remote-storage&quot;&gt;remote-storage&lt;/a&gt; — &lt;code&gt;localStorage&lt;/code&gt; с сохранением на удалённый сервер (даже бесплатный, чтобы вы туда насохраняли инфы, а потом душили жабку за подписку, которая вскоре появится)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://templ.guide/syntax-and-usage/using-react-with-templ&quot;&gt;templ&lt;/a&gt; — серверный рендеринг HTML на Go (внутри можно &lt;a href=&quot;https://templ.guide/syntax-and-usage/using-react-with-templ/&quot;&gt;редерить и React-компоненты&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/chrisguttandin/worker-timers&quot;&gt;worker-timers&lt;/a&gt; — таймеры, которые не фризятся при неактивном окне за счёт выноса в worker&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gabotechs/dep-tree&quot;&gt;dep-tree&lt;/a&gt; — 3d визуализация внутренних связей проекта&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://symbiotejs.org/&quot;&gt;symbiotejs&lt;/a&gt; — а что если вы завтра проснётесь и React окажется дурным сном, а все приложения вокруг будут написаны близко к нативным API, без прятания за абстракциями и «магических ящиков»&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;новомодные написанные на Rust линтеры (oxlint, biome…) быстры в том числе потому, что &lt;a href=&quot;https://www.joshuakgoldberg.com/blog/rust-based-javascript-linters-fast-but-no-typed-linting-right-now/&quot;&gt;не интегрированы с TS type checking API&lt;/a&gt;, которое, увы, довольно медленное, но зато фичёвое&lt;/li&gt;
&lt;li&gt;ещё одно напоминание, что в Google Chrome во второй половине 2024 будут отключены сторонние (3d-party) куки, что поломает Google же Analytics, Google Pixel, инструменты ретаргетинга…, но в целом останутся ещё другие безкукисовые инструменты, чтобы показать вам баннер с рекламой кредитной карты — &lt;a href=&quot;https://blog.sentry.io/we-removed-advertising-cookies-heres-what-happened/&quot;&gt;опыт команды Sentry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/dan_abramov2/status/1745795274977493317&quot;&gt;React Server Components не требует наличия сервера&lt;/a&gt; или Анонс курса Дэна Абрамова «Нейминг от бога» (а Astro, кстати, требует)&lt;/li&gt;
&lt;li&gt;с помощью Clipboad API можно копипастить не только текст, но и картинки в PNG, &lt;a href=&quot;https://spacejelly.dev/posts/how-to-copy-to-clipboard-in-react/&quot;&gt;гайд как это сделать на React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;как с помощью современных JS-рантаймов (bun, deno, node) &lt;a href=&quot;https://gist.github.com/guest271314/9b1adad3db3deba64e118f844a77bad6&quot;&gt;собрать самодостаточный выполняемый файл&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.epicweb.dev/the-golden-rule-of-assertions&quot;&gt;золотое правило написания тестов&lt;/a&gt;: «Тест должен не проходить, тогда и только тогда, когда цель системы не выполнена.», то есть в тесте не стоит вдаваться в детали имплементации, а сфокусировать один тест только на одной цели&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mwskwong.com/blog/migrating-from-zod-to-valibot-a-comparative-experience&quot;&gt;сравнение либ&lt;/a&gt; типизированной проверки данных: Zod vs Valibot&lt;/li&gt;
&lt;li&gt;&lt;code&gt;querySelector&lt;/code&gt; отличается от &lt;code&gt;getElementById&lt;/code&gt; тем, что &lt;a href=&quot;https://kiru.io/til/entries/2024-01-16-javaScript-difference-querySelector-and-getElementById/&quot;&gt;не признаёт id начинающиеся с цифры&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sparkbox.com/foundry/internationalization_css_html&quot;&gt;набор молодого интернационалиста&lt;/a&gt;: &lt;code&gt;margin-inline&lt;/code&gt;, &lt;code&gt;dir&lt;/code&gt;, &lt;code&gt;:lang()&lt;/code&gt; и &lt;code&gt;writing-mode&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2024/01/css-border-image-property/&quot;&gt;на что способно свойство &lt;code&gt;border-image&lt;/code&gt;&lt;/a&gt;: полупрозрачный фейд, скошенный фон на весь экран, градиентные бордеры&lt;/li&gt;
&lt;li&gt;ещё один &lt;a href=&quot;https://bejamas.io/blog/centering-elements-without-wrapper-in-css/&quot;&gt;способ центровки контента без обёртки&lt;/a&gt; — &lt;code&gt;max-width: max-content; margin-inline: auto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tympanus.net/codrops/2024/01/17/a-practical-introduction-to-scroll-driven-animations-with-css-scroll-and-view/&quot;&gt;юзкейсы скролл-анимации&lt;/a&gt; с помощью &lt;code&gt;animation-timeline&lt;/code&gt; (пока только в Chrome)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2024/01/12/waapi-custom-easing-function/&quot;&gt;способы описания кастомных easing-функций&lt;/a&gt; в JS для Web Animations API: предвычисление массива &lt;code&gt;keyframes&lt;/code&gt;, новая функция &lt;code&gt;linear()&lt;/code&gt;, а также &lt;a href=&quot;https://github.com/w3c/csswg-drafts/issues/1012&quot;&gt;предложение&lt;/a&gt; добавить встроенную функцию &lt;code&gt;document.registerTimingFunction&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;чтобы убрать элемент от показа в описании сайта в гугл-поиске нужно добавить тегу &lt;a href=&quot;https://www.gsqi.com/marketing-blog/how-to-use-data-nosnippet/&quot;&gt;атрибут &lt;code&gt;data-nosnippet&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/2023-npm-retrospective&quot;&gt;прошедший год у npm&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;184 миллиарда скачиваний пакетов в месяц&lt;/li&gt;
&lt;li&gt;март самый активный месяц по публикации версий пакетов&lt;/li&gt;
&lt;li&gt;топ зависимостей — TS, react, eslint, @types/node, react-dom, jest, prettier&lt;/li&gt;
&lt;li&gt;самое длинное возможное название пакета из 214 символов&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/console-delight/&quot;&gt;как выводить в консоль браузера&lt;/a&gt; анимированные 3D-SVG картинки и стилизованный текст, а также бонусом &lt;a href=&quot;https://github.com/sindresorhus/devtools-detect&quot;&gt;либа для определения открытости консоли&lt;/a&gt; и факт, что &lt;code&gt;console.table([&apos;foo&apos;])&lt;/code&gt; &lt;a href=&quot;https://frontendmasters.com/blog/console-delight/#responsive-sizing&quot;&gt;растягивается на всю ширину консоли&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>API window.matchMedia</title><link>https://juwain.github.io/web-platform/blog/2024-01-23/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-23/</guid><description>Триггерить только срабатывание определённого условия ширины можно… теми же mediaQuery, только в JS. Для этого существет API window.matchMedia, который принимает строку с медиавыражением и возвращает объект MediaQueryList, содержащий информацию о медиавыражении, применённом к документу</description><pubDate>Tue, 23 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Окей, когда что-то нужно перестроить в интерфейсе при изменении разрешения экрана, используется media query в CSS.&lt;/p&gt;
&lt;p&gt;Но бывают случаи, когда просто что-то изменить в стилях недостаточно. Например, нужно перемонтировать компонент, запрос отправить на сервер за дополнительными данными или ещё что-то в этом духе.&lt;/p&gt;
&lt;p&gt;Первая мысль, как поступить в этой ситуации — подписаться на resize окна и смотреть в хендлере, нужная сейчас ширина окна или нет.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function handleResize() {
  if (window.innerWidth &amp;gt;= width) {
    // setIsGreaterThanOrEqual whatever
  }
}

window.addEventListener(&quot;resize&quot;, handleResize);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Проблема такого подхода в том, что резайз будет срабатывать на каждом изменившемся пикселе размера окна, и триггерить перерисовку. Что не есть хорошо если нужно отследить только факт условного «сейчас мобилка или нет?».&lt;/p&gt;
&lt;p&gt;Триггерить только срабатывание определённого условия ширины можно… теми же mediaQuery, только в JS. Для этого существет API window.matchMedia &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia&lt;/a&gt;, который принимает строку с медиавыражением и возвращает объект MediaQueryList, содержащий информацию о медиавыражении, применённом к документу.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;const matchQueryList = window.matchMedia(&quot;(max-width: 600px)&quot;)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Для разовой проверки соответствия используется свойство matches:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;matchQueryList.matches // true or false&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;А для постоянного отслеживания соответствия, есть подписка на событие change:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function handleChange(e) {
  // e.matches whatever
}

matchQueryList.addEventListener(&quot;change&quot;, handleChange);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Для Реакта всё это заворачивается в хук и получается удобное отслеживание медиавыражений в JS:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function App() {
  const isMobile = useMatchMedia(&quot;(max-width: 768px)&quot;);

  return &amp;lt;h1&amp;gt;Browsing with {isMobile ? &quot;mobile&quot; : &quot;desktop&quot;}&amp;lt;/h1&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Код тут &lt;a href=&quot;https://codesandbox.io/p/devbox/frosty-mcclintock-93ghzg&quot;&gt;https://codesandbox.io/p/devbox/frosty-mcclintock-93ghzg&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 26.01.2024</title><link>https://juwain.github.io/web-platform/blog/2024-01-26/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-26/</guid><description>Новости веб-платформы</description><pubDate>Fri, 26 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eisenbergeffect.medium.com/web-components-2024-winter-update-445f27e7613a&quot;&gt;состоялось заседание&lt;/a&gt; рабочей группы по веб-компонентам W3C, результаты:
&lt;ul&gt;
&lt;li&gt;Declarative Shadow DOM появится в Firefox 123 в конце февраля (эта фича, позволяющая использовать Shadow DOM напрямую в HTML без вызова attachShadow() из JS)&lt;/li&gt;
&lt;li&gt;начнёт разрабатываться Scoped Element Registries, позволяющий создавать элементы с одинаковым именем в рамках одной страницы&lt;/li&gt;
&lt;li&gt;Container Style Queries быть во всех движках в ближайшем будущем 🎉&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/rickhanlonii/status/1747333798323261882&quot;&gt;грядущие нововведения в «клиентском» Реакте&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;use(Promise)&lt;/code&gt; — саспендинг на клиенте&lt;/li&gt;
&lt;li&gt;&lt;code&gt;use(Context)&lt;/code&gt; — такой же, как &lt;code&gt;useContext&lt;/code&gt;, но можно вызывать в условиях&lt;/li&gt;
&lt;li&gt;хуки и апи для работы с формами Form Actions, &lt;code&gt;useFormState&lt;/code&gt;, &lt;code&gt;useFormStatus&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;а также &lt;code&gt;useOptimistic&lt;/code&gt; — специальный хук, чтобы смотреть на «классический» Реакт с оптимизмом&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;обновления в Chrome 121:
&lt;ul&gt;
&lt;li&gt;появились свойства &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/scrollbar-color&quot;&gt;&lt;code&gt;scrollbar-color&lt;/code&gt;&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/scrollbar-width&quot;&gt;&lt;code&gt;scrollbar-width&lt;/code&gt;&lt;/a&gt; (раньше работало только в FF, так что если у вас были стили только для FF в Хроме тоже внезапно включится!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-palette&lt;/code&gt; для управления &lt;a href=&quot;https://developer.chrome.com/blog/colrv1-fonts&quot;&gt;цветовыми шрифтами&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;псевдоэлементы &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/::spelling-error&quot;&gt;&lt;code&gt;::spelling-error&lt;/code&gt;&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/::grammar-error&quot;&gt;&lt;code&gt;::grammar-error&lt;/code&gt;&lt;/a&gt; для стилизации ошибок&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Speculation_Rules_API&quot;&gt;Speculation Rules API&lt;/a&gt; для программного префетча и пререндера страниц в классических MPA&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLSelectElement/showPicker&quot;&gt;&lt;code&gt;showPicker()&lt;/code&gt;&lt;/a&gt; для программного выпадения &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; (кажется, я когда-то ждал этого, но так давно, что уже забыл)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://webkit.org/blog/14919/webkit-features-in-safari-17-3/&quot;&gt;Safari 17.3:&lt;/a&gt; пофикшен &lt;code&gt;@supports&lt;/code&gt; и цвет каретки на iOS, закольцовывание медиа с нулевой длиной и другие мелочи&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/the-bun-shell&quot;&gt;bun shell&lt;/a&gt; — возможность запускать shell-скрипты в JS (с помощью и во славу Bun)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/josdejong/workerpool&quot;&gt;workerpool&lt;/a&gt; — централизованный способ выгрузить воркеры (если у вас их много разных) в отдельный пул с очередью выполнения&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://partytown.builder.io/&quot;&gt;partytown&lt;/a&gt; — запуск 3d-party скриптов в воркере (для выгрузки Google Tag Manager, Google Analytics, Amplitude из основного потока)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-irl.info/handling-null-undefined-and-zero-values-in-javascript/&quot;&gt;как отделить 0 от null и undefined:&lt;/a&gt; напоминание про разницу операторов &lt;code&gt;||&lt;/code&gt; и &lt;code&gt;??&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;c &lt;code&gt;AbortController.abort()&lt;/code&gt; &lt;a href=&quot;https://www.codewithshripal.com/playground/js/abort-multiple-events-at-once&quot;&gt;удаляет разом несколько обработчиков событий&lt;/a&gt; (не нужно писать множество &lt;code&gt;removeListener&lt;/code&gt;, yay!)&lt;/li&gt;
&lt;li&gt;если вы захотите обновиться на 18 Реакт, возможно вам тоже придётся сделать что-то из того, что уже &lt;a href=&quot;https://www.sonarsource.com/blog/upgrading-react-18-sonarqube/&quot;&gt;сделали в команде SonarQube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.robinwieruch.de/react-starter/&quot;&gt;Реакт-стартеры в 2024:&lt;/a&gt; Vite, Next или Astro?&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexsidorenko.com/blog/react-prop-drilling-composition/&quot;&gt;возможная замена проп-дриллингу&lt;/a&gt; — &lt;code&gt;{children}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs-app-router-training.vercel.app/&quot;&gt;туториал по Next.js App Router&lt;/a&gt; от мейнтейнера Node.js и webpack: минималистично и интерактивно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/articles/788656/&quot;&gt;как уменьшить размер бандла&lt;/a&gt; — рецепты с разных сторон:
&lt;ul&gt;
&lt;li&gt;мониторинг через Lighhouse, Sentry&lt;/li&gt;
&lt;li&gt;анализ с помощью Webpack Bundle Analyzer, Statoscope, bundlephobia&lt;/li&gt;
&lt;li&gt;распространённые приёмы — отключить сорсмапы, оптимизировать импорты библиотек типа lodash, выделение чанков, динамические импорты и фреймворкоспецифичные подходы типа &lt;code&gt;React.lazy&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://polypane.app/blog/my-take-on-fading-content-using-transparent-gradients-in-css/&quot;&gt;частичный фейд текста с помощью градиентов&lt;/a&gt; (именно текста, а не покрывающий слой!): способы с &lt;code&gt;mask-image&lt;/code&gt; и &lt;code&gt;background-clip: text&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;сборник мелких, точных (и злых) «CSS-однострочников», которые &lt;a href=&quot;https://moderncss.dev/12-modern-css-one-line-upgrades/&quot;&gt;уже можно заносить в проекты&lt;/a&gt; (и за это не придётся оправдываться): &lt;code&gt;aspect-ratio&lt;/code&gt;, &lt;code&gt;object-fit&lt;/code&gt;, &lt;code&gt;margin-inline&lt;/code&gt;, &lt;code&gt;text-underline-offset&lt;/code&gt;…&lt;/li&gt;
&lt;li&gt;ещё одна &lt;a href=&quot;https://bejamas.io/blog/learn-css-has-selector-by-examples-top-use-cases/&quot;&gt;подборка юзкесов селектора :has():&lt;/a&gt; делаем выборку родителя, предыдущего сиблинга, по количеству элементов, в любом месте или всё, кроме меня&lt;/li&gt;
&lt;li&gt;в догонку к предыдущему пункту &lt;a href=&quot;https://twitter.com/jonkantner/status/1745861950821777771&quot;&gt;демка с плавным переходом между радио-кнопками,&lt;/a&gt; которая стала возможна в CSS благодаря &lt;code&gt;:has()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://chromestatus.com/feature/5176596826161152&quot;&gt;в 123 Chrome появится&lt;/a&gt; свойство &lt;code&gt;field-sizing&lt;/code&gt;, &lt;a href=&quot;https://blog.stephaniestimac.com/posts/2024/01/css-field-sizing/&quot;&gt;авторасширяющее инпуты и текстареа&lt;/a&gt; при вводе длинного текста (неужели это когда-нибудь свершится, боже)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;SVG&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://garden.bradwoods.io/notes/svg/draw-on-scroll&quot;&gt;эффект движущейся линии по скроллу&lt;/a&gt; на SVG элементах &lt;code&gt;&amp;lt;linearGradient&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;clip-path&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://davidwalsh.name/fixing-cumulative-layout-shift-problems-on-davidwalshblog&quot;&gt;чтобы улучшить метрику CLS&lt;/a&gt; достаточно просто один раз в день… задавать размеры &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; в атрибутах &lt;code&gt;width&lt;/code&gt; и &lt;code&gt;height&lt;/code&gt; (и без px)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/ruvds/articles/784542/&quot;&gt;aria-hidden в жизни:&lt;/a&gt; для сокрытия визуальных декоративных элементов, скрывает интерактивные элементы не всегда, &lt;code&gt;aria-hidden !== aria-hidden=&quot;true&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;рецепты как &lt;a href=&quot;https://cristian.sulea.net/blog/disable-browser-caching-with-meta-html-tags/&quot;&gt;выключить браузерное кеширование&lt;/a&gt; в серверных заголовках, HTML, htaccess, PHP и других бэкендах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://designsystems.surf/&quot;&gt;каталог&lt;/a&gt; известных (и не очень) дизайн-систем на случай, если вам понадобится впечатлить коллег проведённым обширным ресёрчем&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Обратная совместимость веб-платформы</title><link>https://juwain.github.io/web-platform/blog/2024-01-30/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-01-30/</guid><description>Веб-платформа регламентирована как backwards и forwards совместимая. То есть всё новое, что появляется в платформе не ломает уже имеющееся, и гарантированно должно быть совместимо с будущими изменениями. На деле это вроде как так и есть, но не всегда и не совсем.</description><pubDate>Tue, 30 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Веб-платформа регламентирована как backwards и forwards совместимая.&lt;/p&gt;
&lt;p&gt;То есть всё новое, что появляется в платформе не ломает уже имеющееся, и гарантированно должно быть совместимо с будущими изменениями. На деле это вроде как так и есть, но не всегда и не совсем.&lt;/p&gt;
&lt;p&gt;Работает это так. Вам вдруг приходит задача, что что-то поломалось в коде. Причём в старом коде, который уже давно не менялся и был написан прото-программистами, которые уже давно уволились. Казалось бы, что может пойти не так? А дело в том, что сами браузеры обновляются и в них что-то вдруг начинает работать по-другому. В том числе код, который вам предстоит исправить. Самые «любимые» баги.&lt;/p&gt;
&lt;p&gt;Как это такое происходит, ведь платформа должна быть обратно совместима? Главным образом так: далеко не всегда сначала появляются стандарты, а потом браузеры пилят фичи по этим каноническим стандартам. Иногда фичи просто пропушиваются вендорами (яркий пример — префиксы -webkit-feature, -moz-feature), а потом уже под них подгоняются стандарты или же они адоптятся стандартами и… всё это обратной волной докатывается до браузеров. Браузеры немного меняют имплементацию и ваш код, который просто работал, становится как бы сломанным.&lt;/p&gt;
&lt;p&gt;Что поделать, ваш код признан устаревшим и приговаривается к утилизации, приговор обжалованию не подлежит!&lt;/p&gt;
&lt;p&gt;Но ок, вендорные префиксы были всеми явно признаны как фейл. Есть и более прозаические примеры.&lt;/p&gt;
&lt;p&gt;Есть такой метод play() у аудио и видео HTML-элементов. Он появился ещё в Chrome 3. Он просто работал и включал медиа. То есть можно было запустить, например, видео и тут же его поставить на паузу, чтобы оно сразу прогрузилось.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  video.play();
  video.pause();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Потом в Chrome 32 появились Promise. Затем обновились стандарты. И уже в Chrome 50 метод play() стал возвращать промис вместо того, чтобы синхронно выполнить запуск медиа. То есть ваш код сломался и выдаёт эксепшн, который даже даёт ссылку на специальную страничку &lt;a href=&quot;https://developer.chrome.com/blog/play-request-was-interrupted&quot;&gt;https://developer.chrome.com/blog/play-request-was-interrupted&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ещё один пример, немного с другого бока подсвечивает эту же проблему. Люди издревле желали стилизовать скроллбары. Поэтому в Chrome появился целое семейство свойств для стилизации (::-webkit-scrollbar, ::-webkit-scrollbar-track…), в которых можно было задавать ширину или высоту скроллабара (в пикселях!), его цвет фона. Потом это дело ушло вариться в стандарты, ранние черновики были реализованы в Firefox: это были свойства scrollbar-width и scrollbar-color. Причём в scrollbar-width уже нельзя было задавать значения в пикселях (только thin или auto), а scrollbar-color принимал два цвета через пробел (для фонового цвета трека и «таскалки»). И вот так оно и жило где-то с 64 версии FF до наших дней: для стилизации в FF использовался «правильный» вариант с scrollbar-width/scrollbar-color, а в Chrome работали вендорные префиксы.&lt;/p&gt;
&lt;p&gt;Что же могло пойти не так? В Chrome 121 завезли (&lt;a href=&quot;https://developer.chrome.com/docs/css-ui/scrollbar-styling&quot;&gt;https://developer.chrome.com/docs/css-ui/scrollbar-styling&lt;/a&gt;) так же стандартные scrollbar-width и scrollbar-color! И ваш код, хоть и не упал, но начал работать по-другому, так как скроллбары стали другими, и хорошо, если просто стали другими. В целом не то чтобы критично. Но возможно сегодня где-то в далёком офисе одинокий разработчик сдувает пыль с давнего проекта и добавляет хак, чтобы всё оставалось как раньше, и в Chrome по-прежнему применялась только стилизация через вендорные префиксы:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media screen and (min--moz-device-pixel-ratio: 0) {
  .scrollable_styled {
    scrollbar-width: thin;
    scrollbar-color: gray transparent;
  }
}

.scrollable_styled::-webkit-scrollbar {
  width: 8px;
}

.scrollable_content::-webkit-scrollbar-thumb {
  background-color: gray;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Directed by robert b weide 🥁&lt;/p&gt;
&lt;p&gt;А для тех, кто дочитал до конца, приятный бонус: список задепрекейченых и выпиленных платформенных API: &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features&quot;&gt;JS&lt;/a&gt;, &lt;a href=&quot;https://html.spec.whatwg.org/multipage/obsolete.html&quot;&gt;HTML&lt;/a&gt;, &lt;a href=&quot;https://stackoverflow.com/a/74980459&quot;&gt;CSS&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 02.02.2024</title><link>https://juwain.github.io/web-platform/blog/2024-02-02/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-02-02/</guid><description>Новости веб-платформы</description><pubDate>Fri, 02 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в React 19 &lt;a href=&quot;https://github.com/facebook/react/issues/11347#issuecomment-1899140345&quot;&gt;появятся нативные custom elements&lt;/a&gt; (мама, неужели они решили задепрекейтить jsx?!)&lt;/li&gt;
&lt;li&gt;что в последнее время &lt;a href=&quot;https://web.dev/blog/web-platform-01-2024&quot;&gt;появилось нового в браузерах&lt;/a&gt;: &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; в &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;, &lt;code&gt;HTMLSelectElement.showPicker&lt;/code&gt;, стилизация скроллбаров, анимация &lt;code&gt;font-palette&lt;/code&gt;, &lt;code&gt;transfer()&lt;/code&gt; и &lt;code&gt;transferToFixedLength()&lt;/code&gt; у &lt;code&gt;ArrayBuffer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-beta/&quot;&gt;анонсирован Typescript 5.4 beta&lt;/a&gt;: улучшение сужениях типов в замыканиях, новый утилитарный тип NoInfer для запрета вывода типов, &lt;code&gt;Object.groupBy&lt;/code&gt; и &lt;code&gt;Map.groupBy&lt;/code&gt;, улучшение quick-fix, а также анонс грядущих депрекетов в TypeScript 5.0&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/vulnerability/february-2024-security-releases&quot;&gt;минорно обновлены&lt;/a&gt; версии Node 18, 20, 21 для фиксов безопасности&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://v8.dev/features/import-attributes&quot;&gt;V8 v9.1&lt;/a&gt; выпущена поддержка import assertions (это такое &lt;code&gt;import json from &apos;./foo.json&apos; with { type: &apos;json&apos; }&lt;/code&gt;, для того, чтобы не запустить зловредное ПО, маскирующееся под JSON)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://expressive-code.com/installation/&quot;&gt;expressive-code&lt;/a&gt; — решение для интеграции блоков кода в контенте сайта (для astro, next)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/johannschopplich/unlazy&quot;&gt;unlazy&lt;/a&gt; — универсальная либа для ленивой загрузки картинок (с плейсхолдерами)&lt;/li&gt;
&lt;li&gt;веб-компонент &lt;a href=&quot;https://github.com/andrico1234/autosize-textarea&quot;&gt;авторастягивающейся textarea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://sparkbox.github.io/bouncy-ball/&quot;&gt;анимация прыгающего мяча&lt;/a&gt; кучей возможных способов (без JS, на чистом JS, с либами, на canvas, видео и гифка)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/plantain-00/type-coverage&quot;&gt;type-coverage&lt;/a&gt; — мониторинг и зачистка (от any) типов в проекте&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://johan.hal.se/wrote/2024/01/24/concatenating-text/&quot;&gt;мнение&lt;/a&gt;, что вся React-движуха завела часть индустрии не туда, отзывается: неестественный для браузера DX, в который двигаются React, Next и иже с ними, оказывают медвежью услугу (и, конечно, зарабатывают на этом), и, в целом, во многих случаях не нужны, так как являются легаси из 2013, когда в
браузерах не было шаблонных строк и BFCache&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://begin.com/blog/posts/2024-01-26-removing-react-is-just-weakness-leaving-your-codebase&quot;&gt;ещё одно мнение&lt;/a&gt;, что система, которая вынуждает переписывать кодовую базу каждые 2-3 года — слабая, и напоминание о «правиле минимальной мощности», когда для решения задачи следует выбирать минимально необходимый по мощности язык/систему/технологию&lt;/li&gt;
&lt;li&gt;не поверите, ещё одно мнение о том, что стоит попробовать &lt;a href=&quot;https://thenewstack.io/take-a-qwik-break-from-react-with-astro/&quot;&gt;Qwik вместо React&lt;/a&gt; (по мне так шило на мыло, нужны другие ментальные модели для написания кода для платформы)&lt;/li&gt;
&lt;li&gt;сначала придумывается SSR, потом решается, как же быть, когда нужно узнать что-то из клиентского браузера, а потом &lt;a href=&quot;https://blog.6nok.org/server-side-rendering-local-dates-without-fouc/&quot;&gt;придумываются костыли&lt;/a&gt; — надёжный план!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/web-platform/soft-navigations-experiment&quot;&gt;попытки замерять Core Web Vitals&lt;/a&gt; не только на первой загрузке SPA, но и на последующей клиентской навигации — спец событие soft navigation для PerformanceObserver&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pnpm.io/benchmarks&quot;&gt;pnpm поддерживает страницу&lt;/a&gt; с бенчмарками npm, pnpm, yarn (они поддерживают страницу, потому что pnpm быстрый или следят за быстротой pnpm из-за поддержки страницы 🤔)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://advancedweb.hu/modern-javascript-library-starter/&quot;&gt;современный стартер для либы&lt;/a&gt;: TS, тесты нативные node:test, билд npm-скриптами, конфиг для CI на GitHub Actions в yml, автодеплой в npm, provenance и секреты&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.frontend-almanac.ru/event-loop-myths-and-reality&quot;&gt;event loop – мифы и реальность&lt;/a&gt;: браузерные и небраузерные среды исполнения, почему понятия нет в спеке ECMA-262, макротасков не бывает, а task queue это не очередь, а set&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/alfa/articles/691976/&quot;&gt;улучшаем качество кода React-приложения&lt;/a&gt; с помощью Compound Components&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2024/01/css-blurry-shimmer-effect/&quot;&gt;блюрная backdrop-тень&lt;/a&gt; с помощью &lt;code&gt;mask&lt;/code&gt;, &lt;code&gt;backdrop-filter&lt;/code&gt; и &lt;code&gt;box-shadow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если вы всё ещё убираете обводку (&lt;code&gt;outline: 0&lt;/code&gt;), то это можно уже не делать, так как &lt;a href=&quot;https://daverupert.com/2024/01/focus-visible-love/&quot;&gt;есть &lt;code&gt;:focus-visible&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;попытка объять &amp;lt;s&amp;gt;необъятное&amp;lt;/s&amp;gt; &lt;a href=&quot;https://techhub.iodigital.com/articles/going-beyond-pixels-and-rems-in-css/relative-length-units-based-on-font&quot;&gt;шрифтовые единицы измерения длины&lt;/a&gt;: &lt;code&gt;cap&lt;/code&gt;, &lt;code&gt;ch&lt;/code&gt;, &lt;code&gt;em&lt;/code&gt;, &lt;code&gt;ex&lt;/code&gt;, &lt;code&gt;ic&lt;/code&gt;, &lt;code&gt;lh&lt;/code&gt;, а также из «рутовые» аналоги &lt;code&gt;rem&lt;/code&gt;, &lt;code&gt;rlh&lt;/code&gt;, &lt;code&gt;rex&lt;/code&gt;, &lt;code&gt;rch&lt;/code&gt;, &lt;code&gt;ric&lt;/code&gt; и другая магия&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/highlight-text-when-a-user-scrolls-down-to-that-piece-of-text/&quot;&gt;выделение текста с помощью скролл-анимации&lt;/a&gt;: &lt;code&gt;animation-timeline&lt;/code&gt; и &lt;code&gt;background-size&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://piccalil.li/blog/a-highly-configurable-switch-component-using-modern-css/&quot;&gt;строим тоггл&lt;/a&gt;: с &lt;code&gt;:has()&lt;/code&gt;, адаптивно, доступно, с «ручками» для кастомизации стилей&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://textlab.dev/posts/animating-font-palette&quot;&gt;анимация цветовых шрифтов font-palette&lt;/a&gt; (жаль, что самих шрифтов мало)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.letsbuildui.dev/articles/what-is-css-motion-path/&quot;&gt;анимация движения по линии&lt;/a&gt; в SVG с &lt;code&gt;offset-path&lt;/code&gt; и &lt;code&gt;offset-distance&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;свежий взгляд на старую как мир &lt;a href=&quot;https://dev.to/madsstoumann/a-guide-to-styling-tables-28d2&quot;&gt;стилизацию &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML, SVG&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://adrianroselli.com/2024/01/using-abbr-element-with-title-attribute.html&quot;&gt;про тег &lt;code&gt;&amp;lt;abbr&amp;gt;&lt;/code&gt; и атрибут &lt;code&gt;title&lt;/code&gt;&lt;/a&gt;: лучше не использовать и с &lt;code&gt;title&lt;/code&gt;, и без него&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/articles/790230/&quot;&gt;плохие стороны HTML&lt;/a&gt;: лучше НЕ использовать &lt;code&gt;&amp;lt;select multiple&amp;gt;&lt;/code&gt;, атрибут &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;&amp;lt;datalist&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input type=number&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;input type=date&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;menu&amp;gt;&lt;/code&gt; во избежание проблем&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/codeparrot/jwt-vs-session-authentication-1mol&quot;&gt;базовые различия&lt;/a&gt; jwt и session-вариантов аутентификации: jwt более модное, но сложнее в реализации, сессия попроще и понадёжнее&lt;/li&gt;
&lt;li&gt;что намечается в рамках &lt;a href=&quot;https://webkit.org/blog/14955/the-web-just-gets-better-with-interop/&quot;&gt;Interop 2024&lt;/a&gt;: хотеть custom properties, declarative shadow DOM, relative color syntax, &lt;code&gt;@starting-style&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 09.02.2024</title><link>https://juwain.github.io/web-platform/blog/2024-02-09/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-02-09/</guid><description>Новости веб-платформы</description><pubDate>Fri, 09 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://million.dev/blog/million-3&quot;&gt;вышел Million 3&lt;/a&gt; (кастомный компилятор для React): авторы обещают, что просто выполнив &lt;code&gt;npx million@latest&lt;/code&gt; можно добиться ускорения работы Реакта с O(n) до O(1)&lt;/li&gt;
&lt;li&gt;вышла &lt;a href=&quot;https://blog.jquery.com/2024/02/06/jquery-4-0-0-beta/&quot;&gt;jQuery 4.0.0 BETA&lt;/a&gt;: без шуток внушительный чейнджлог, в который разве что не влез отказ от IE11&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://vitejs.dev/blog/announcing-vite5-1.html&quot;&gt;Vite 5.1&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появился экспериментальный режим Vite Runtime API, который позволяет сделать прослойку между сервером и рантаймом и делать там что-то своё, такая мидлваря, но мощная, и отвязанная от сервера&lt;/li&gt;
&lt;li&gt;поддержка запуска CSS-препроцессоров в отдельных потоках (перф улушается)&lt;/li&gt;
&lt;li&gt;более быстрый холодный старт&lt;/li&gt;
&lt;li&gt;улучшенная поддержка &lt;code&gt;.css?url&lt;/code&gt; и другие фишки&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;вышел биндинг GSAP для React &lt;a href=&quot;https://www.npmjs.com/package/@gsap/react&quot;&gt;@gsap/react&lt;/a&gt;, включает удобный хук &lt;code&gt;useGASP()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://remix.run/docs/en/main/start/changelog#v260&quot;&gt;Remix v2.6.0&lt;/a&gt;, который однажды утром проснулся и обнаружил, что он превратился в Vite-плагин&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://drab.robino.dev/&quot;&gt;drab&lt;/a&gt; — коллекция headless кастомных элементов (для расширения кругозора, что кастомные элементы можно использовать как обёртку как для ui-элемента, так и для процесса, например, prefetch)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://svgfm.chriskirknielsen.com/&quot;&gt;svgfm&lt;/a&gt; — визуальный конструктор SVG-фильтров, позволяющий собирать фильтры в цепочки (написано на JS!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Trendyol/baklava&quot;&gt;baklava&lt;/a&gt; — приятная дизайн-система и ui на нативных веб-компонентах без примудростей&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/puppeteer/replay&quot;&gt;replay&lt;/a&gt; — «проигрывание» действий в интерфейсе puppetier-ом с помощью Chrome DevTools Recorder (попробуйте, это вкладка есть в девтулзах Хрома)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://knip.dev/blog/knip-v4&quot;&gt;knip&lt;/a&gt; — либа для нахождения неиспользуемых файлов, зависимостей и экспортов в проекте&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/toplenboren/simple-git-hooks&quot;&gt;simple-git-hooks&lt;/a&gt; — суперлайтовые и простые гит-хуки, если не нужно сложности и нужна быстрота и простота&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://npmgraph.js.org/&quot;&gt;npmgraph&lt;/a&gt; — визуальное отображение зависимостей проекта в виде интерактивного графа&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kravchyk.com/adding-type-safety-to-object-ids-typescript/&quot;&gt;типобезопасные id в TS&lt;/a&gt; с помощью template literal types (&lt;code&gt;node_${string}&lt;/code&gt;): в комментариях приводят более общее решение через branded types&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/deno-in-2023&quot;&gt;как Deno изменился за 2023 год&lt;/a&gt;, а также кое-что под названием &lt;a href=&quot;https://jsr.io/&quot;&gt;JSR&lt;/a&gt; (JavaScript Registry), «смутно напоминающий npm», но с нативной интеграция TS и ESM-only пакетами, автоматически генерируемой документацией&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.devjobsscanner.com/blog/the-most-demanded-frontend-frameworks/&quot;&gt;стата о самом востребованном JS-фреймворке&lt;/a&gt;: конечно, это React по количеству вакансий; в Бельгии больше всего востребован Vue, а в Швейцарии — Ангуляр (интересно, а отсутствие JS-фреймворка это хоть сколько-нибудь востребовано?)&lt;/li&gt;
&lt;li&gt;оказывается есть не только &lt;code&gt;&amp;lt;input type=&quot;color&quot;&amp;gt;&lt;/code&gt; (везде), но и &lt;a href=&quot;https://frontendmasters.com/blog/the-color-input-the-color-picker/&quot;&gt;цветовой пикер&lt;/a&gt; &lt;code&gt;new EyeDropper()&lt;/code&gt; (в Хроме)&lt;/li&gt;
&lt;li&gt;очередной герой самоотверженно бросается в пучину настройки фронтовой монорепы и выясняет, что для него лучшим оказалось &lt;a href=&quot;https://www.aha.io/engineering/articles/monorepo&quot;&gt;сочетание инструментов Turborepo + pnpm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;бестпрактисы и юзкейсы &lt;a href=&quot;https://expo.dev/blog/what-are-environment-variables&quot;&gt;переменных окружения .env&lt;/a&gt;: можно задавать при запуске ноды, в .env-файлах можно задавать фича-тогглы, переменные для разных окружений и хранить секреты&lt;/li&gt;
&lt;li&gt;попытка ещё раз взять и запомнить различия между типами &lt;a href=&quot;https://twitter.com/sulco/status/1214541115602472960&quot;&gt;&lt;code&gt;ReactElement&lt;/code&gt;, &lt;code&gt;ReactChild&lt;/code&gt; и &lt;code&gt;ReactNode&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;когда может пригодиться &lt;a href=&quot;https://www.totaltypescript.com/as-never&quot;&gt;&lt;code&gt;as never&lt;/code&gt; в TS&lt;/a&gt; (спойлер: в этом кейсе не поможет даже &lt;code&gt;as any&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;шоукейс про микрофронты от команды Dodo: в &lt;a href=&quot;https://habr.com/ru/companies/dododev/articles/712320/&quot;&gt;1&lt;/a&gt; и &lt;a href=&quot;https://habr.com/ru/companies/dododev/articles/715988/&quot;&gt;2&lt;/a&gt; рассказано, как переходили на SingleSPA + SystemJS, а заодно и на Vite и Vitest&lt;/li&gt;
&lt;li&gt;а может и не нужны эти ваши микрофронты и достаточно ограничиться &lt;a href=&quot;https://habr.com/ru/companies/sportmaster_lab/articles/724314/&quot;&gt;npm modules или даже git submodules&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;организация кэша в JS с помощью &lt;a href=&quot;https://habr.com/ru/articles/788786/&quot;&gt;Cache Storage API&lt;/a&gt; и его преимущества перед local storage и indexed db&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mayank.co/blog/revert-layer/&quot;&gt;юзкейсы &lt;code&gt;all: revert-layer&lt;/code&gt;&lt;/a&gt;: более лайтовый ресет, чем &lt;code&gt;all: revert&lt;/code&gt;, точечное восстановление ранее сброшенных значений, а также антихрупкие дефолты для переменных &lt;code&gt;var(--size, revert-layer)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benfrain.com/how-to-create-rounded-gradient-borders-with-any-background-in-css/&quot;&gt;градиентная рамка&lt;/a&gt; с помощью &lt;code&gt;linear-gradient&lt;/code&gt; и &lt;code&gt;mask&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/build-off-canvas-menu-web-components/&quot;&gt;боковая шторка на &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;&lt;/a&gt; (не обошлось без заворачивания в веб-компонент)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/alinaki/pen/YzBNyEz&quot;&gt;CSS-анимация SVG-элементов&lt;/a&gt; и тонкости настройки &lt;code&gt;transform-box&lt;/code&gt; и &lt;code&gt;transform-origin&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML, SVG&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.htmhell.dev/adventcalendar/2023/4/&quot;&gt;пятёрка атрибутов&lt;/a&gt;, улучшающих UX: &lt;code&gt;hreflang&lt;/code&gt;, &lt;code&gt;translate&lt;/code&gt;, &lt;code&gt;reversed&lt;/code&gt;, &lt;code&gt;controls&lt;/code&gt; и &lt;code&gt;autocomplete&lt;/code&gt; (в порядке возрастания полезности)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tonsky.me/blog/checkbox/&quot;&gt;история&lt;/a&gt; о том, как веб нарушил конвенцию квадратных чекбоксов и круглых радиокнопок&lt;/li&gt;
&lt;li&gt;дзен и искусство &lt;a href=&quot;https://www.robinwieruch.de/mac-setup-web-development/&quot;&gt;ухода за маком в 2024&lt;/a&gt;: чеклист от и до&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.meain.io/2024/just-enough-cors/&quot;&gt;кто такой и зачем нужен CORS&lt;/a&gt; с бонусным списком как не нужно его обходить (принимать всё отовсюду, выключать preflight checks плагинами в браузере и устанавливать mode в no-cors)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Состояние в битовых картах</title><link>https://juwain.github.io/web-platform/blog/2024-02-13/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-02-13/</guid><description>В повседневном коде с недесятичными форматами чисел сталкиваться приходится редко. Но есть кейс, когда двоичный формат приходится в тему — это битовые карты.</description><pubDate>Tue, 13 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В повседневном коде с недесятичными форматами чисел сталкиваться приходится редко. Но есть кейс, когда двоичный формат приходится в тему — это битовые карты. То есть можно решить, что определённое число — это не просто число, а обозначение какого-то состояния. Например, у нас есть три слота, они могут быть заполнены или нет. Тогда битовые карты будут выглядеть так:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// все три слота свободны
000;

// первый слот занят, остальные свободны
100;

// первый и третий слоты заняты, второй свободен
101;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ок, идём дальше. То, что состояния теперь заданы в виде двоичных чисел, даёт возможность применять к ним двоичные операции! Например, это могут быть двоичные И и ИЛИ. Обозначаются они операторами &amp;amp; и |. Двоичные числа сравниваются побитово (первый бит одного числа с первым битом другого, второй бит одного числа со вторым битом другого…).&lt;/p&gt;
&lt;p&gt;В случае логического И оба бита должны быть равными 1, чтобы в результате получить 1, в остальных случаях будет 0:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 &amp;amp; (0 === 0);
0 &amp;amp; (1 === 0);
1 &amp;amp; (0 === 0);
1 &amp;amp; (1 === 1);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В случае логического ИЛИ любой из битов может быть равен 1, чтобы получить в результате 1:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 | (0 === 0);
0 | (1 === 1);
1 | (0 === 1);
1 | (1 === 1);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;И теперь, если вернуться к примеру со слотами, мы можем «складывать» два состояния с помощью побитового ИЛИ: 100 | 001 === 101 (первый занятый слот ИЛИ третий занятый слот — это занятые 1 и 3 слот). А из «суммы» двух состояний можно убрать все состояния, кроме определённого, с помощью побитового И: 101 &amp;amp; 100 === 100 (первый с третьим занятые слоты И первый занятый слот — это первый занятый слот).&lt;/p&gt;
&lt;p&gt;Теперь к юзкейсу. Вся мякотка маппинга состояний на битовые карты раскрывается в кейсе, когда побитовое ИЛИ используется для создания композиции нескольких отдельных состояний. Представьте, что у нас есть некие состояния:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const MOBILE = 0b0001;
const TABLET = 0b0010;
const LAPTOP = 0b0100;
const DESKTOP = 0b1000;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Можно использовать как просто отдельное состояние, например, MOBILE, так и композицию нескольких состояний, к примеру, MOBILE | LAPTOP (что буквально так и считывается мобайл ИЛИ лаптоп, спасибо TS👋).&lt;/p&gt;
&lt;p&gt;Это можно использовать для задания динамических ключей объектов:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const objectMap = {
  [MOBILE]: &quot;mobile stuff&quot;,
  [LAPTOP]: &quot;laptop stuff&quot;,
  [MOBILE | LAPTOP]: &quot;mobile or laptop stuff&quot;,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Как вы уже, возможно, догадались, распаковать этот ключ можно с помощью логического И (&amp;amp;), обратной операции. Предположим, что нужно отфильтровать только те ключи, в которых есть MOBILE, то есть нужно ко всем ключам применить &amp;amp; MOBILE:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MOBILE &amp;amp; (MOBILE === MOBILE);
// у 0b0001 и 0b0001 есть общая 1, получаем 0b0001

LAPTOP &amp;amp;
  (MOBILE ===
    0(
      // у 0b0100 и 0b0001 нет общей 1, получаем 0b0000

      MOBILE | LAPTOP
    )) &amp;amp;
  (MOBILE === MOBILE);
// у 0b0101 и 0b0001 есть общая 1, получаем 0b0001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Дальше отфильтровываем те значения, ключи которых выдали нули и готово!&lt;/p&gt;
&lt;p&gt;Вот как выглядит функция-фильтровщик:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function getFilteredValues(objectMap, filterKey) {
  return Object.entries(objectMap)
    .map(([key, value]) =&amp;gt; {
      const shouldInclude =
        (key &amp;amp; MOBILE) === filterKey ||
        (key &amp;amp; TABLET) === filterKey ||
        (key &amp;amp; LAPTOP) === filterKey ||
        (key &amp;amp; DESKTOP) === filterKey;
      return shouldInclude ? value : null;
    })
    .filter(Boolean);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Полный код примера тут &lt;a href=&quot;https://codepen.io/juwain/pen/KKEGRrB?editors=0011&quot;&gt;https://codepen.io/juwain/pen/KKEGRrB?editors=0011&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Кстати, небольшой оффтоп: обратите внимание на ссылку. Codepen тоже использует битовую карту, чтобы обозначить, какие редакторы по умолчанию скрыть (0), а какие показать (1) 👾&lt;/p&gt;
&lt;p&gt;Я использовал такой подход для динамического создания стилей для каждого типа девайса. Иногда стили для соседних девайсов повторялись, не хотелось их дублировать и получилось сгруппировать по типу MOBILE | LAPTOP.&lt;/p&gt;
&lt;p&gt;Пример (это Styled Components):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;${setResponsiveStyles({
  [MOBILE]: css`
    // some only mobile styles
  `,
  [MOBILE | TABLET]: css`
    // some mobile or tablet styles
  `,
  [LAPTOP]: css`
    // some only laptop styles
  `,
  [DESKTOP]: css`
    // some only desktop styles
  `
})}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Пульс веб-платформы 16.02.2024</title><link>https://juwain.github.io/web-platform/blog/2024-02-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-02-16/</guid><description>Новости веб-платформы</description><pubDate>Fri, 16 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://webkit.org/blog/15026/release-notes-for-safari-technology-preview-188/&quot;&gt;Safari TP 188&lt;/a&gt;: добавлена поддержка альтернативного синтаксиса свойства &lt;code&gt;content&lt;/code&gt;, поддержка &lt;code&gt;supports&lt;/code&gt; внутри директивы &lt;code&gt;@import&lt;/code&gt;, выпилена поддержка нестандартного &lt;code&gt;resize: auto&lt;/code&gt; и много всего мелкого пофикшено&lt;/li&gt;
&lt;li&gt;из-за противостояния бюрократии и бигтехов в iOS &lt;a href=&quot;https://www.theregister.com/2024/02/08/apple_web_apps_eu/&quot;&gt;в Европе перестанут работать PWA&lt;/a&gt;, как работают сейчас (по сути останется возможность только создать «закладку» со ссылкой 🤷‍♂️)&lt;/li&gt;
&lt;li&gt;мейнтейнер Express решил взбодрить проект и запостил &lt;a href=&quot;https://github.com/expressjs/discussions/issues/160&quot;&gt;планы на 5, 6 и 7 версии&lt;/a&gt; (которые подозрительно напоминают план начать с нового года жизнь заново): больше координации с LST-версиями Ноды, меньше манкипатчинга и использования внутрянок Ноды, официально поддерживаемые типы&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/honojs/hono&quot;&gt;hono&lt;/a&gt; — серверный фреймворк для все JS-рантаймов: &lt;a href=&quot;https://github.com/honojs/hono/releases/tag/v4.0.0&quot;&gt;недавно вышла версия 4&lt;/a&gt;, которая во времена Реакта, идущего на сервер, наоборот стала уметь в SSG, клиентские компоненты (c jsx и реактовскими хуками), file-based роутингом и другими плюшками. Безусловно, радует что не next-ом единым!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dnnsjsk/glaze&quot;&gt;glaze&lt;/a&gt; — если вдруг вам нравится tailwind-подход к написанию стилей, этой либой можно так же «декларативно» описывать GSAP-анимации&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/devidw/tabgod&quot;&gt;tabgod&lt;/a&gt; — запуск JS-скрипта одновременно в нескольких табах сразу (для гугления сразу в нескольких гуглах, например)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gilbarbara/react-joyride&quot;&gt;react-joyride&lt;/a&gt; — либа для создания туториалов и онбордингов по сервису&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sindresorhus/type-fest&quot;&gt;type-fest&lt;/a&gt; — набор базовых утилитарных дженерик-типов TS (автор разрешил копипастить код без импорта либы 😊)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tempo.formkit.com/&quot;&gt;tempo&lt;/a&gt; — yet another библиотека для работы с датами от команды Formkit&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;иногда сидишь, думаешь, как пробросить что-то из состояния в DOM или наоборот, и тут, хоба!, &lt;a href=&quot;https://heydonworks.com/article/offloading-javascript-with-custom-properties/&quot;&gt;можно же пробросить значение в кастомном свойстве&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://commerce.nearform.com/blog/2024/tale-of-a-refactor/&quot;&gt;подход к&lt;/a&gt;&lt;a href=&quot;https://commerce.nearform.com/blog/2024/tale-of-a-refactor/&quot;&gt;рефакторингу&lt;/a&gt;&lt;a href=&quot;https://commerce.nearform.com/blog/2024/tale-of-a-refactor/&quot;&gt;кода&lt;/a&gt;, который оброс множественными ветками условий или кейсов: найти общий паттерн, выделить его в интерфейс и причесать ветки кода так, чтобы каждая имплементировала выделенный интерфейс&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spacejelly.dev/posts/how-to-detect-clicks-anywhere-on-a-page-in-react&quot;&gt;как хэндлить события за пределами компонента в Реакте&lt;/a&gt;, из которого я узнал в том числе о нативном методе &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath&quot;&gt;&lt;code&gt;event.composedPath()&lt;/code&gt;&lt;/a&gt;, выдающие массив всех таргетов, через которых пройдёт событие при всплытии&lt;/li&gt;
&lt;li&gt;дружеское напоминание, что &lt;a href=&quot;https://web.dev/blog/array-with&quot;&gt;&lt;code&gt;Array.prototype.with&lt;/code&gt;&lt;/a&gt; работает везде и может «заменять» элементы массива немутабельно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sonarsource.com/blog/union-intersection-difference-javascript-sets/&quot;&gt;новые методы&lt;/a&gt; &lt;code&gt;Set.prototype.union&lt;/code&gt;, &lt;code&gt;Set.prototype.intersection&lt;/code&gt;, &lt;code&gt;Set.prototype.difference&lt;/code&gt; и другие (похожие на SQL) методы доступны в Chrome 122+ и Safari 17+&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;объёмный (я бы даже сказал) &lt;a href=&quot;https://developer.chrome.com/docs/css-ui/high-definition-css-color-guide&quot;&gt;справочник по цветовым пространствам, функциям в CSS&lt;/a&gt; от базовых до современных от гугловцев: &lt;code&gt;color()&lt;/code&gt;, &lt;code&gt;display-p3&lt;/code&gt;, &lt;code&gt;oklch&lt;/code&gt;, градиенты, проверка фич в &lt;code&gt;supports()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;пока мы тут работу работаем, в &lt;a href=&quot;https://css.oddbird.net/sasslike/mixins-functions/&quot;&gt;CSS тихо варятся нативные mixin-ы и функции&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://danielcwilson.com/posts/mathematicss-powers/&quot;&gt;новые функции&lt;/a&gt; возведения в степень pow(), квадратный корень sqrt() и другая математика (даже есть примеры!)&lt;/li&gt;
&lt;li&gt;задание диапазона &amp;lt;s&amp;gt;жирности&amp;lt;/s&amp;gt; насыщенности шрифта с &lt;a href=&quot;https://css-irl.info/how-i-solved-my-font-rendering-problem/&quot;&gt;font-weight для вариативных шрифтов&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;как &lt;a href=&quot;https://frontendmasters.com/blog/how-to-fix-the-invisible-scrollbar-issue-in-ios/&quot;&gt;побороть поведение iOS&lt;/a&gt;, когда неправильно определяется цвет скроллбара, и он оказывается белым на белом фоне&lt;/li&gt;
&lt;li&gt;на три вещи можно смотреть вечно: на огонь, воду и &lt;a href=&quot;https://www.joshwcomeau.com/css/center-a-div/&quot;&gt;центровку блоков в CSS&lt;/a&gt; — современное прочтение без &lt;code&gt;transform: translate(-50%)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если нужно вставить SVG фоном, &lt;a href=&quot;https://www.phpied.com/truth-encoding-svg-data-uris/&quot;&gt;можно встроить его прямо в CSS&lt;/a&gt;, и оказывается, можно даже не энкодить его в base64&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML, SVG&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ещё одно &lt;a href=&quot;https://frontendmasters.com/blog/basic-dialog-usage-and-gotchas-to-watch-for/&quot;&gt;дружеское напоминание&lt;/a&gt;, что элемент &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;: 1) поддерживается везде и 2) из коробки имеет центровку, оверлей, закрывается по esc, а также ловит фокус и возвращает его при закрытии&lt;/li&gt;
&lt;li&gt;дизейблить кнопки ок, но &lt;a href=&quot;https://adrianroselli.com/2024/02/dont-disable-form-controls.html&quot;&gt;не совсем ок дизейблить элементы форм&lt;/a&gt; (особенно кнопки, тк это ридонли-элементы)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ежегодное обновление поста Андрея Ситника о том, &lt;a href=&quot;https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs&quot;&gt;как подключать favicon&lt;/a&gt; (кажется, с каждым годом он всё короче и когда-нибудь схлопнется до 1 строки)&lt;/li&gt;
&lt;li&gt;никогда не будет лишним вспомнить или узнать &lt;a href=&quot;https://blog.gitbutler.com/git-tips-1-theres-a-git-config-for-that/&quot;&gt;хитрости по работе с гитом&lt;/a&gt;: &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;blame&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;, &lt;code&gt;rerere&lt;/code&gt; (не путать с ололо)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 23.02.2024</title><link>https://juwain.github.io/web-platform/blog/2024-02-23/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-02-23/</guid><description>Новости веб-платформы</description><pubDate>Fri, 23 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024&quot;&gt;новости с полей Реакта&lt;/a&gt;: впиливают автомемоизацию (React &amp;lt;s&amp;gt;Forget&amp;lt;/s&amp;gt; Compiler), Actions на клиенте, работа с &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; из коробки, директивы &lt;code&gt;&quot;use client&quot;&lt;/code&gt; и &lt;code&gt;&quot;use server&quot;&lt;/code&gt;, а также API для подгрузки статических файлов; всё это уже упаковано в канареечную версию вместе с докой и поедет в мажорной 19 версии&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/wooorm/status/1759918205928194443&quot;&gt;1 из 5 пакетов&lt;/a&gt; в npm на содержит ESM-модули&lt;/li&gt;
&lt;li&gt;анонсирован &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-rc/&quot;&gt;TypeScript 5.4 RC&lt;/a&gt;: улучшение в выводе типов, утилитарный тип &lt;code&gt;NoInfer&lt;/code&gt;, &lt;code&gt;Object.groupBy&lt;/code&gt; и &lt;code&gt;Map.groupBy&lt;/code&gt; и другое&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lucia-auth/lucia&quot;&gt;lucia&lt;/a&gt; — аутентификация во всех основных JS-рантаймах с адаптерами к БД из коробки&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/petyosi/react-virtuoso&quot;&gt;react-virtuoso&lt;/a&gt; — либа для быстрой работы с большими списками без проблем с перфомансом (включает также «виртуальные» таблицы, сетки, бесконечный скролл, группировку со стики-хедером)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/epicweb-dev/restore-scroll&quot;&gt;restore-scroll&lt;/a&gt; — либа для восстановления позиции скролла после навигации (не только лишь body, но и любого другого элемента со скроллбаром)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react-strict-dom&quot;&gt;react-strict-dom&lt;/a&gt; — экспериментальная встройка StyleX в ReactDOM как часть движения по сближению React Native и React DOM&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.raymondcamden.com/2024/02/12/looking-at-the-javascript-promise-collection-methods&quot;&gt;сравнение методов промисов&lt;/a&gt; &lt;code&gt;all()&lt;/code&gt;, &lt;code&gt;allSettled()&lt;/code&gt;, &lt;code&gt;any()&lt;/code&gt; и &lt;code&gt;race()&lt;/code&gt;, и от меня напоминание, что появлялись они не все сразу: &lt;code&gt;all()&lt;/code&gt; и &lt;code&gt;race()&lt;/code&gt; -&amp;gt; &lt;code&gt;allSettled()&lt;/code&gt; -&amp;gt; &lt;code&gt;any()&lt;/code&gt; в порядке исправления обнаруженных недостатков&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bjornlu.com/blog/hot-module-replacement-is-easy&quot;&gt;как работает Hot Module Replacement&lt;/a&gt; (HMR) в сборщиках типа Vite и почему всё это хорошо легло на ESM-модули благодаря мета-информации об импортах/экспортах (&lt;code&gt;import.meta.&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.robinwieruch.de/react-trends/&quot;&gt;тренды React в 2024&lt;/a&gt; (а скорее саммари событий 2023): Astro — самый быстрый фреймворк, аутентификация — всё ещё горячая тема, React Server Components шатко-валко адоптятся, в мире SPA новый роутер — TanStack Router, Vercel пушит React вперёд, противостояние Turbopack vs Vite и безголовые UI-либы&lt;/li&gt;
&lt;li&gt;и &lt;a href=&quot;https://blog.rafaelgss.dev/nodejs-2023-year-in-review&quot;&gt;саммари результатов разработки Node в 2023&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;дропнули 14, 16 и 19 версии&lt;/li&gt;
&lt;li&gt;добавили в зависимости &lt;a href=&quot;https://github.com/ada-url/ada&quot;&gt;Ada&lt;/a&gt;, &lt;a href=&quot;https://github.com/simdutf/simdutf&quot;&gt;simdutf&lt;/a&gt;, &lt;a href=&quot;https://github.com/simdjson/simdjson&quot;&gt;simdjson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;обновили сайт&lt;/li&gt;
&lt;li&gt;добавили систему пермишенов&lt;/li&gt;
&lt;li&gt;добавили фичи: Single Executable Apps (самодостаточные Nodejs-приложения без необходимости установленной Nodejs в системе), встроенная поддержка .env, WebSocket-клиент и test runner&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/alterebro/random-distribution&quot;&gt;визуализация распределения значений функции random&lt;/a&gt; и других её вариаций&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rxdb.info/articles/localstorage.html&quot;&gt;гайд по использованию localStorage&lt;/a&gt;: синхронный, хранит не больше 5mb, но проще IndexedDB и быстрее куки — годится для малых данных, которые не нужно постоянно читать/писать; узнал про File System API, который работает только через воркер и про Extension Storage API для хранения данных браузерных расширений&lt;/li&gt;
&lt;li&gt;как минимальными силами и зависимостями (только TS) &lt;a href=&quot;https://www.learnwithjason.dev/blog/modern-node-server-typescript-2024&quot;&gt;поднять TS-сервер на Node&lt;/a&gt; c лайв-релоадом и env-переменными&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/netologyru/articles/694660/&quot;&gt;использование&lt;/a&gt; discriminating unions (для более декларативных и разделённых типов) и pattern matching (для укрощения развесистых условий) в TS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.frontend-almanac.ru/iterators&quot;&gt;анатомия итераторов в JS&lt;/a&gt;: встроенные и собственные, синхронные, асинхронные, прокачка объектов, чтобы сделать их итерируемыми&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;наброс №1 (на серьёзных щщах) на &lt;a href=&quot;https://nuejs.org/blog/tailwind-misinformation-engine/&quot;&gt;Tailwind как маркетинговый проект&lt;/a&gt;, в котором идея «независимых от контента названий классов» была извращена, онбордя пользователей, а затем загоняя в vendor lock-in и заставляя привлекать в экосистему новых адептов&lt;/li&gt;
&lt;li&gt;наброс №2 (смешной, слово «fuck» встречается 5 раз) &lt;a href=&quot;https://heydonworks.com/article/what-is-utility-first-css/&quot;&gt;на Tailwind с тем же посылом&lt;/a&gt;: если бы в мире был только HTML и Tailwind, а потом бы появился грамотно проданный CSS(!), то все бы начали писать кипятком по концептам, которые в него встроены&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/&quot;&gt;Custom Highlight API&lt;/a&gt; уже есть в Chrome, Safari 17.2 и даже ночном Firefox, а это значит, что выделять элементы на странице станет проще&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/vk/articles/794160/&quot;&gt;работа с анимациями в UI&lt;/a&gt;: используем доп потоки, выносим разумно в композитные слои (они потребляют доп память)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;попытка объять в одном тексте &amp;lt;s&amp;gt;необъятное&amp;lt;/s&amp;gt; &lt;a href=&quot;https://daverupert.com/2024/02/ui-states/&quot;&gt;все виды состояний&lt;/a&gt;, которые влияют на конечный UI: состояние приложения, данных, страницы, UI-компонентов и элементов самого браузера, параметры и настройки девайсов и состояния самого пользователя 🤯&lt;/li&gt;
&lt;li&gt;если вы уже оптимизировали в ассетах, что могли, можно ещё попробовать &lt;a href=&quot;https://paulcalvano.com/2024-02-16-identifying-font-subsetting-opportunities/&quot;&gt;подрезать кастомные шрифты&lt;/a&gt;, чтобы убрать оттуда неиспользуемые символы (есть ссылки на инструменты анализа и модификации подключенных шрифтов)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Укрощение режимов наложения в CSS</title><link>https://juwain.github.io/web-platform/blog/2024-02-27/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-02-27/</guid><pubDate>Tue, 27 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Как-то раз мне пришла в голову идея воссоздать такой эффект выборочного обесцвечивания на CSS:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/9d0f1666185d68a75a3c9.jpg&quot; alt=&quot;Кадр из фильма «Город грехов»&quot; /&gt;&lt;/p&gt;
&lt;p&gt;С художественной точки зрения такой эффект уже давно заезжен, но мне была интересна именно техническая сторона вопроса. То есть задача — обесцветить всю картинку, при этом оставив нетронутым красный цвет.&lt;/p&gt;
&lt;p&gt;Вот что получилось в результате экспериментов:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/3ea4bad3bb6489477e114.jpg&quot; alt=&quot;Оригинал фотографии взят здесь https://unsplash.com/@luiskcortes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Демо тут https://codepen.io/juwain/pen/mxLJYj.&lt;/p&gt;
&lt;p&gt;Как это работает. Сразу стало понятно, что для решения нужно изготовить под конкретную картинку SVG-маску, затем наложить поверх цветной картинки чёрно-белую с вырезанной частью. В итоге, через дырку в чёрно-белом изображении будет просвечивать цветная. Решение с изготовлением маски вручную было отброшено из-за неуниверсальности.&lt;/p&gt;
&lt;p&gt;В поисках универсального способа я решил попробовать сделать «маску на лету» из самого же оригинального изображения с помощью режимов наложения (blend modes).&lt;/p&gt;
&lt;p&gt;Вкратце про режимы наложения. По умолчанию слои в CSS располагаются друг поверх друга и не «просвечивают»:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/862a21ecdfae359baefa2.png&quot; alt=&quot;Нормальный режим наложения&quot; /&gt;&lt;/p&gt;
&lt;p&gt;А можно сделать так, чтобы слои не просто показывались один над другим, а «смешивались» по определённому алгоритму:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/18d30ec9e974bf4a591ec.png&quot; alt=&quot;Умножающий режим наложения&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Режимы наложения пришли в CSS из Фотошопа благодаря сотрудникам компании Adobe. Но не все фотошоповские режимы наложения переехали в CSS — всего в CSS есть 16 вариантов смешивания слоёв. Не буду вдаваться в подробности, с режимами наложения можно поиграть тут.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ок, к &lt;em&gt;селективному обесцвечиванию&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Сверху на изображение накладывается его же копия с помощью псевдоэлемента:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.photo {
  --source: url(some-url-string);
  /* это нижний слой */
  background-image: var(--source);
}

.photo::after {
  /* это верхний слой */
  background-image: var(--source);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;./assets/ef11e3cafbcb8529133a5.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Дальше у верхнего слоя режим наложения меняется на lighten. При таком режиме тёмные участки начинают «просвечивать», а светлые — наоборот остаются непрозрачными:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/1bab7eb884ebb1e5d4ab9.png&quot; alt=&quot;Режим наложения lighten&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Режим наложения между слоями включается свойством &lt;code&gt;mix-blend-mode&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.photo::after {
  mix-blend-mode: lighten;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Получилось то, что нужно: тёмный фон верхнего слоя стал прозрачным, а светлые участки — нет:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/80fbbfee065bd49e617dc.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Далее верхний слой обесцвечивается с помощью CSS-фильтра:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.photo::after {
  filter: grayscale(1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Теперь верхний слой накладывается светлыми обесцвеченными участками на нижнюю цветную фотографию:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/e819b22b942e08d09a70a.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Уже почти то, что нужно. Надо теперь сделать светлые участки верхнего слоя более непрозрачными.&lt;/p&gt;
&lt;p&gt;В этом снова помогут режимы наложения. Помимо свойства &lt;code&gt;mix-blend-mode&lt;/code&gt;, «смешивающее» два разных слоя, есть ещё одно свойство, меняющее режим наложения — это &lt;code&gt;background-blend-mode&lt;/code&gt;. Оно задаёт режим смешивания фоновых элементов одного слоя: изображения, фонового цвета, градиента.&lt;/p&gt;
&lt;p&gt;Итак, верхнему слою задаётся серый фоновый цвет и режим смешивания картинки с ним &lt;code&gt;hard-light&lt;/code&gt;. Это комбинированный режим, он чем-то похож на режим умножения — если коротко, он делает цвета ярче. Применительно в чёрно-белому изображению, этот режим сделает его светлые части более контрастными.&lt;/p&gt;
&lt;p&gt;В итоге получается желаемый результат:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/ebe987a6b8ed53613fb44.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Остаётся разобраться, какие именно цвета в таком сочетании режимов наложения делаются прозрачными, а какие нет.&lt;/p&gt;
&lt;p&gt;Для этого я сделал демо со слоями с полосатыми линейными градиентами, и вот что получилось:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/8ee0238b1edf3808b3eff.png&quot; alt=&quot;Вживую можно посмотреть в https://codepen.io/juwain/pen/vRjaQb&quot; /&gt;&lt;/p&gt;
&lt;p&gt;То есть при рассмотренной в этой статье комбинации режимов наложения прозрачными становятся области красного, синего и фиолетового оттенков, а желто-оранжевые, зелёные и голубые оттенки остаются непрозрачными.&lt;/p&gt;
&lt;p&gt;Довольно крейзи-фича, которую вряд ли где-то можно заиспользовать, но кайфовая и трюковая, как я люблю.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 01.03.2024</title><link>https://juwain.github.io/web-platform/blog/2024-03-01/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-01/</guid><description>Новости веб-платформы</description><pubDate>Fri, 01 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/123&quot;&gt;вышел Firefox 123:&lt;/a&gt; поддерживает Declarative Shadow DOM (теперь поддерживается всеми!), пофикшен &lt;code&gt;Date.parse()&lt;/code&gt;, улучшены SVG-градиенты, добавлена поддержка кода &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103&quot;&gt;103 Early Hints&lt;/a&gt; HTTP для предзагрузки ресурсов&lt;/li&gt;
&lt;li&gt;в Mozilla выпустили &lt;a href=&quot;https://developer.mozilla.org/en-US/curriculum/&quot;&gt;MDN curriculum&lt;/a&gt; — учебный план для разработчиков, чтобы подтянуть базу по фронту: HTML, CSS, JS, доступность, контроль версий, перфоманс, тестирование, фреймворки, тулинг&lt;/li&gt;
&lt;li&gt;в Firefox 125 &lt;a href=&quot;https://twitter.com/Una/status/1762451966389575720&quot;&gt;будет доступен&lt;/a&gt; Popover API&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://github.com/vuejs/core/pull/10397&quot;&gt;Vue отрефакторили систему реактивности&lt;/a&gt; и заменили структуры данных, чем уменьшили использование памяти на 56% и улучшили перф на 100-200% (а что, так можно было?)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2024-02-23-highlights-from-git-2-44/&quot;&gt;вышел Git 2.44:&lt;/a&gt; более лучшие ребейзы командой git replay, опция --autosquash для сквоша коммитов при обычном, неинтерактивном ребейзе, настройка хинтов и другое&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nuejs/nue&quot;&gt;nue&lt;/a&gt; — генератор статических сайтов и аппликух, дерзкий, но честный аналог Astro и Next.js&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://functional-ui-kit.com/&quot;&gt;functional-ui-kit&lt;/a&gt; — есть много разных UI-китов, но мало из них классно реализовано и в коде, и в Figma: этот кит из таких&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shoelace.style/&quot;&gt;shoelace&lt;/a&gt; — ещё один UI-кит, но на этот раз на веб-компонентах (аккуратный, с возможностью использовать совместно с фреймворками)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://picocss.com/&quot;&gt;picocss&lt;/a&gt; — минималистичный CSS-фреймворк для стилизации (практически) голого HTML&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ai/keyux&quot;&gt;keyux&lt;/a&gt; — либа для добавления управления с клавиатуры к сайту, интегрируется с aria- и role-атрибутами в HTML&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;подраскрывается &lt;a href=&quot;https://dev.to/abbeyperini/slots-slots-slots-everybody-4p5i&quot;&gt;концепт slot-ов:&lt;/a&gt; в веб-компонентах, Vue и Angular: даже если не использовать их напрямую, иногда полезно иметь в голове такую ментальную модель&lt;/li&gt;
&lt;li&gt;оказывается, в &lt;a href=&quot;https://alexharri.com/blog/jsdoc-as-an-alternative-typescript-syntax&quot;&gt;JSDoc есть даже продвинутые конструкции&lt;/a&gt; типа дженериков, каста типов и implements класса (правда становится нечитаемо быстрее, чем в TS)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tonsky.me/blog/js-bloat/&quot;&gt;как мы докатились до жизни такой:&lt;/a&gt; для того, что показать статический лендос нужно 10+ mb JS-кода (а для чата 50+ mb) 🤯&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.saeloun.com/2024/02/21/next.js-vs-remix/&quot;&gt;сравнительный разбор Next.js и Remix,&lt;/a&gt; что же выбрать? (не забываем об опции, что можно не выбирать)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semaphoreci.com/blog/htmx-react&quot;&gt;сравнительный разбор HTMX и React,&lt;/a&gt; что же выбрать? (опять же, можно и не выбирать 😏)&lt;/li&gt;
&lt;li&gt;как, упрощенно, &lt;a href=&quot;https://www.recompiled.dev/blog/ssa/&quot;&gt;работает React Compiler,&lt;/a&gt; а также в целом подход к компиляции Static Single Assignment&lt;/li&gt;
&lt;li&gt;а что, если не присылать на клиент JSON и строить DOM, а стримить готовый HTML? &lt;a href=&quot;https://aralroca.com/blog/html-node-streaming&quot;&gt;Такое сложно, но возможно&lt;/a&gt; не только для стрима при первой загрузке страницы, но и в рантайме при переходе в View Transitions API&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;как &lt;a href=&quot;https://jakearchibald.com/2024/view-transitions-handling-aspect-ratio-changes/&quot;&gt;подогнать стили при использовании View Transitions,&lt;/a&gt; чтобы две картинки «бесшовно переходили» одна в другую&lt;/li&gt;
&lt;li&gt;в CSS есть &lt;a href=&quot;https://codersblock.com/blog/playing-with-infinity-in-css/&quot;&gt;константное значение infinity,&lt;/a&gt; и с его помощью, наконец-то, можно завершить эту битву раз и навсегда — &lt;code&gt;z-index: calc(infinity)&lt;/code&gt;, только нужно иметь в виду, что это число зависит от контекста&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/css-backdrop-inheritance&quot;&gt;псевдоэлемент &lt;code&gt;::backdrop&lt;/code&gt;&lt;/a&gt; (подложка элемента &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;) теперь может наследовать все наследуемые свойства родителей, и кастомные тоже (странно, что раньше не могло)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/css-has-guide/&quot;&gt;исчерпывающий гайд по селектору &lt;code&gt;:has&lt;/code&gt;&lt;/a&gt;: такая читерская неявная связь элементов одновременно и привлекает, и отпугивает своей неявностью&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.ungra.dev/how-to-know-whether-to-use-data-urls&quot;&gt;когда нужно использовать data URL-ы:&lt;/a&gt; как обычно, it depends, надо сравнить насколько передача файла по сети добавляет больше байтов (заголовки, обмен сообщениями…), чем строка, закодированная в CSS&lt;/li&gt;
&lt;li&gt;когда в кастомном свойстве CSS находится невалидное значение (20px задаётся для цвета, например), то срабатывает &lt;a href=&quot;https://www.bram.us/2024/02/26/css-what-is-iacvt/&quot;&gt;механизм Invalid At Computed Value Time&lt;/a&gt; (IACVT), который приводит к откату значения до unset&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;декларативный shadow DOM пришёл, &lt;a href=&quot;https://www.mayank.co/blog/declarative-shadow-dom-guide/&quot;&gt;для чего же он может пригодиться:&lt;/a&gt; это некий «ковёр», куда можно замести детали имплементации интерфейсных частей (сомнительно, но окэй)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jvns.ca/blog/2024/02/16/popular-git-config-options/&quot;&gt;полезные настройки Git:&lt;/a&gt; автосквош и автостэш при ребейзе, автосоздание ветки на сервере при пуше, изменение алгоритма диффов, авторебейз при пулле, автосоздание ветки main вместо master и другое&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 08.03.2024</title><link>https://juwain.github.io/web-platform/blog/2024-03-08/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-08/</guid><description>Новости веб-платформы</description><pubDate>Fri, 08 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/&quot;&gt;вышел TypeScript 5.4:&lt;/a&gt; нового с RC версии почти ничего не подвезли, но там было много всего хорошего, можно обновляться&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://parceljs.org/blog/v2-12-0/&quot;&gt;вышел Parcel v2.12.0:&lt;/a&gt; теперь умеет прекомпилировать JS-функции в билд-тайме вместо включения в общий бандл (вдохновлено макросами из Bun); на сайте появился &lt;a href=&quot;https://repl.parceljs.org/&quot;&gt;REPL&lt;/a&gt; (интерактивный редактор с отображением результата); теперь под капотом Lightning CSS бандлит CSS-файлы; возможность вручную сконфигурировать &lt;a href=&quot;https://parceljs.org/features/code-splitting/#shared-bundles&quot;&gt;shared-бандлы&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://babeljs.io/blog/2024/02/28/7.24.0&quot;&gt;вышел Babel 7.24.0:&lt;/a&gt; теперь поддерживает JSON modules imports, а также последнюю актуальную версию декораторов&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://webkit.org/blog/15054/an-html-switch-control/&quot;&gt;Safari 17.4 появится поддержка&lt;/a&gt; нового «пропатченного» чекбокса — переключателя (&lt;code&gt;&amp;lt;input type=checkbox switch checked&amp;gt;&lt;/code&gt; с псевдоэлементами &lt;code&gt;::thumb&lt;/code&gt; и &lt;code&gt;::track&lt;/code&gt;), также &lt;a href=&quot;https://webkit.org/blog/15063/webkit-features-in-safari-17-4/&quot;&gt;появились&lt;/a&gt; вертикальные контролы форм, &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt; в &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;, обновление движка Inline Layout, работающий &lt;code&gt;align-content&lt;/code&gt; для таблиц и блоков (не только гридов и флексбоксов), &lt;code&gt;@scope&lt;/code&gt; и &lt;code&gt;:scope&lt;/code&gt;, &lt;code&gt;Promise.withResolvers&lt;/code&gt;, &lt;code&gt;Object.groupBy&lt;/code&gt; и &lt;code&gt;Map.groupBy&lt;/code&gt; и &lt;a href=&quot;https://webkit.org/blog/15063/webkit-features-in-safari-17-4/&quot;&gt;кое-что ещё&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pixijs.com/blog/pixi-v8-launches&quot;&gt;вышла PixiJS v8:&lt;/a&gt; либа для 2d анимации с десятилетней историей хорошо бустанулась по перфу, подружилась с WebGPU, изменила структуру пакета, получила обновления в графических, векторных и текстовых API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://million.dev/blog/lint&quot;&gt;вышла бета Million Lint:&lt;/a&gt; интересный концепт линтера перфоманса React-приложения, который в реалтайме показывает в коде на манер eslint количество ререндеров и время&lt;/li&gt;
&lt;li&gt;React Compiler aka Forget (автомемоизатор) &lt;a href=&quot;https://twitter.com/en_JS/status/1760433969118769654&quot;&gt;не будет включён в релиз React 19&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mozilla/readability&quot;&gt;readability&lt;/a&gt; — JS-версия браузерного режима для чтения из Firefox: это когда остаётся только текст, а стили и оформление с баннерами уходит&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/davidjerleke/embla-carousel&quot;&gt;embla-carousel&lt;/a&gt; — минималистичная JS-карусель, без зависимостей, для доп функциональности подключаются плагины&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pkgx.sh/&quot;&gt;pkgx&lt;/a&gt; — запускальщик &lt;em&gt;всего&lt;/em&gt; здесь и сейчас без установки &amp;lt;s&amp;gt;и смс&amp;lt;/s&amp;gt;, что не умеет npx, например, мождно запустить ноду pkgx node@16 или бан pkgx bun run&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://turbo.build/repo/&quot;&gt;turbo repo&lt;/a&gt; — тула для организации более быстрой работы команд запуска и сборки в монорепах (yarn/npm/pnpm устанавливает пакеты, turbo запускает с кешированием)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rviscomi.github.io/capo.js/&quot;&gt;capo.js&lt;/a&gt; — инструмент для анализа правильности в порядке тегов в &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;: покажет, в какой последовательности расставить теги будет правильнее&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;4 издание прекрасной книги про JS — &lt;a href=&quot;https://eloquentjavascript.net/&quot;&gt;Eloquent JavaScript&lt;/a&gt; — для программистов любых возрастов и вероисповедания&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/jsr-new-javascript-package-registry&quot;&gt;первые отзывы о JSR&lt;/a&gt; — альтернативному npm пакетному менеджеру от создателей deno: пока очень нишево, привязано к deno и немного чем отличается (TS-first, only ESM-модули), но, тем не менее, конкуренция — всегда хорошо&lt;/li&gt;
&lt;li&gt;если вы, как и &lt;a href=&quot;https://shubhamjain.co/2024/02/29/why-is-number-package-have-59m-downloads/&quot;&gt;автор статьи,&lt;/a&gt; удивляетесь, почему у однострочных пакетов типа is-number столько скачиваний на npm, то бывает это сам автор раздувает использование своей либы через другие пакеты (naturally, пакеты с пакетами)&lt;/li&gt;
&lt;li&gt;как на Performance API собрать (на коленке) &lt;a href=&quot;https://www.smashingmagazine.com/2024/02/reporting-core-web-vitals-performance-api/&quot;&gt;основные пользовательские метрики перфа:&lt;/a&gt; Largest Contentful Paint, First Contentful Paint, Cumulative Layout Shift, Interaction To Next Paint, Long Animation Frames&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;реакт реактом, а &lt;a href=&quot;https://adrianroselli.com/2024/02/techniques-to-break-words.html&quot;&gt;переносить текст со строчки на строчку&lt;/a&gt; всё равно нужно — гайд по &lt;code&gt;word-break&lt;/code&gt;, &lt;code&gt;oveflow-wrap&lt;/code&gt;, &lt;code&gt;hyphens&lt;/code&gt;, &lt;code&gt;&amp;lt;wbr&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;amp;shy&lt;/code&gt; (с последней парочкой нужно быть аккуратными)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ryanmulligan.dev/blog/scroll-triggered-animations-style-queries/&quot;&gt;скролл-анимация триггерит&lt;/a&gt; смену кастомного свойства &lt;code&gt;--animate: true&lt;/code&gt;, а по нему применяется Style Query &lt;code&gt;@container style(--animate: true)&lt;/code&gt;, который анимирует появившийся во вьюпорте элемент — самый блидинг из возможных эджей&lt;/li&gt;
&lt;li&gt;хочешь не хочешь, а рано или поздно придёт она — задача на стилизацию печатных страниц, в этом случае пригодится &lt;a href=&quot;https://voussoir.net/writing/css_for_printing&quot;&gt;детальный гайд&lt;/a&gt; по &lt;code&gt;@page&lt;/code&gt; и &lt;code&gt;@media print&lt;/code&gt; в разных вариациях&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;обширный &lt;a href=&quot;https://www.browsercat.com/post/ultimate-guide-visual-testing-playwright&quot;&gt;гайд по скриншотному тестированию с Playwright:&lt;/a&gt; самое ценное, пожалуй, что есть рецепт по запуску таких тестов в CI/CD, так как локально, как правило, скриншоты будут немного отличаться в зависимости от ОС&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/samolet/articles/788288/&quot;&gt;опыт команды Самолёта по оптимизации перфа:&lt;/a&gt; есть довольно полный чеклист кандидатов на оптимизацию&lt;/li&gt;
&lt;li&gt;из серии «не боги горшки обжигают»: понаблюдать за редизайном сайта nodejs можно тут: &lt;a href=&quot;https://beta-node-js-org.vercel.app/en&quot;&gt;новый сайт,&lt;/a&gt; &lt;a href=&quot;https://www.figma.com/file/pu1vZPqNIM7BePd6W8APA5/Node.js&quot;&gt;макет,&lt;/a&gt; &lt;a href=&quot;https://github.com/nodejs/nodejs.org/discussions/5131&quot;&gt;обсуждение&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Анимация без стереотипов</title><link>https://juwain.github.io/web-platform/blog/2024-03-06/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-06/</guid><description>Хоть анимация и понимается прежде всего как «оживление», в CSS кроме обычной плавной анимации, есть ещё пара типов — дискретная и никакая (свойство не анимируется)</description><pubDate>Wed, 06 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Хоть анимация и понимается прежде всего как «оживление», в CSS кроме обычной плавной анимации, есть ещё пара типов — дискретная и никакая (свойство не анимируется).&lt;/p&gt;
&lt;p&gt;Про неанимируемые свойства понятно из названия. А что за дискретная анимация? В отличие от плавной анимации, когда одно значение может быть &lt;a href=&quot;https://drafts.csswg.org/css-values/#combining-values&quot;&gt;интерполировано, суммировано или аккумулировано&lt;/a&gt; к другому, в дискретном варианте значение сменяется, но без плавности, а просто в середине кейфрейма становится другим.&lt;/p&gt;
&lt;p&gt;Свойства с плавной анимацией — это цвета, размеры, отступы и прочие свойства, к которым можно применить плавные переходы.&lt;/p&gt;
&lt;p&gt;Свойства с дискретнной анимацией — (внезапно) почти все остальные свойства, за некоторым исключением.&lt;/p&gt;
&lt;p&gt;Ок, как это можно использовать. В этом кейсе я воспринимаю анимацию как механизм переключения значения свойства из одного в другое (с опциональным таймером и повторением N-раз). То есть некий setInterval(() =&amp;gt; fn(value)), только в мире CSS.&lt;/p&gt;
&lt;p&gt;Я полистал список всех CSS-свойств и выбрал несколько, об анимации которых я раньше не задумывался. Например, свойство content. Можно сделать &lt;a href=&quot;https://codepen.io/juwain/pen/NWmPgrJ&quot;&gt;«мигающий курсор»&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;div::after {
  animation: blink 1s infinite;
}

@keyframes blink {
  from {
    content: &quot;&quot;;
  }
  to {
    content: &quot;|&quot;;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;А учитывая, что content в качестве значения поддерживает текст, картинки, кавычки, счётчики, то можно сделать хоть &lt;a href=&quot;https://codepen.io/juwain/pen/MVYVrj&quot;&gt;целое слайдшоу&lt;/a&gt; 😁&lt;/p&gt;
&lt;p&gt;Окей, ещё с помощью дискретной анимации можно собрать свою gif-ку на коленке. Это буквально быстрая смена «кадров» с картинками, как в кино. Если в секунду сменять 10 «кадров», то скорость будет достаточная для создания иллюзии непрерывного движения:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.frame {
  animation: movie 1s infinite;
}

@keyframes movie {
  0% {
    background-image: var(--image-1);
  }

  10% {
    background-image: var(--image-2);
  }

  …
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Демо собрано &lt;a href=&quot;https://codepen.io/juwain/pen/GxgdQo&quot;&gt;тут&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Дальше я решил развить тему кинематографа и следующим попробовать анимировать лейаут гридов. Для построения отдельных «кадров» я решил использовать свойство grid-template-areas. Это свойство описывает раскладку грида в декларативном виде. Вот так, к примеру, будет выглядеть начальный «кадр» будущего фильма:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grid-template-areas:
  &quot;. . . . a a a a a . . . .&quot;
  &quot;. . . . . . . . b . . . .&quot;
  &quot;. . . . . . . . b . . . .&quot;
  &quot;. . . . . . . . b . . . .&quot;
  &quot;. . . . c c c c c . . . .&quot;
  &quot;. . . . . . . . d . . . .&quot;
  &quot;. . . . . . . . d . . . .&quot;
  &quot;. . . . . . . . d . . . .&quot;
  &quot;. . . . . . . . d . . . .&quot;
  &quot;. . . . e e e e e . . . .&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Точками в значении grid-template-areas обозначены те области грида, которые не будут закрашены белым, а буквами — те, которые закрашиваются. По ходу «фильма» значение grid-template-areas будет принимать разные значения. А вот подменять эти значения раскладки грида будет CSS-анимация. Для этого нужно прописать раскадровку «фильма» в кейфреймах:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@keyframes movie {
  0% {
    grid-template-areas: …;
  }
  10% {
    grid-template-areas: …;
  }

  … 100% {
    grid-template-areas: …;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;И затем задать получившуюся анимацию для грид-контейнера .field:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.field {
  animation-name: movie;
  animation-duration: 10s;
  animation-play-state: paused;
  animation-timing-function: step-end;
  animation-iteration-count: 1;
  animation-fill-mode: both;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Получившийся триллер можно найти &lt;a href=&quot;https://codepen.io/juwain/pen/aqxyxY&quot;&gt;тут&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;И ещё одна деталь про неанимируемые свойства. А что будет, если в кейфреймы положить display: none? Оно применится в конце, начале или середине анимации?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.fade-out {
  animation: fade-out 1s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Спецификация говорит, что свойство display — &lt;a href=&quot;https://drafts.csswg.org/css-display/#the-display-properties&quot;&gt;not animatable&lt;/a&gt;. И для display: none с относительно недавних пор действует особое правило: если анимация «появляет» элемент, то display включается в самом начале, а если анимация элемент скрывает, то display: none применяется в самом конце, после всех остальных транзишнов (&lt;a href=&quot;https://codepen.io/juwain/pen/dyLYbwG&quot;&gt;демо тут&lt;/a&gt;, работает везде)!&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 22.03.2024</title><link>https://juwain.github.io/web-platform/blog/2024-03-22/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-22/</guid><description>Новости веб-платформы</description><pubDate>Fri, 22 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-450/&quot;&gt;вышел Astro 4.5&lt;/a&gt;: новая встроенная панель аудита сайта, по View Transitions теперь можно перерендерить интерактивные части сайта, обновлён хайлайтер синтаксиса для блоков кода Shiki, поддержка отдельных CDN для разных типов файлов (и заодно ребята отпраздновали 3 года проекта)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/124.0/releasenotes/&quot;&gt;вышел Firefox 124&lt;/a&gt;: добавлена поддержка &lt;code&gt;AbortSignal.any&lt;/code&gt;, &lt;code&gt;::first-letter&lt;/code&gt; и &lt;code&gt;::first-line&lt;/code&gt; теперь работают для SVG &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt;, &lt;code&gt;content-visibility: auto&lt;/code&gt; включено по умолчанию (скорость отрисовки сайтов станет быстрее)&lt;/li&gt;
&lt;li&gt;что будет, если вместе соберутся создатель и бывший CEO npm, инжиниринг-менеджер из Github и npm и разработчик из Google? Они попробуют &lt;a href=&quot;https://blog.vlt.sh/blog/the-team&quot;&gt;создать более лучший пакетный менеджер&lt;/a&gt; (JSR был только началом)!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vuejs/vitepress&quot;&gt;выпущен vitepress&lt;/a&gt; — генератор статических сайтов из md на vue и vite: изначально генерится статика SSG, а после загрузки инициализируется SPA для дальнейшей навигации по сайту&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pahen/madge&quot;&gt;madge&lt;/a&gt; — анализ и нахождение циклических зависимостей в проекте, а также постройка визуального графа зависимостей&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shiki.style/&quot;&gt;shiki&lt;/a&gt; — стильный хайлайтер кода в браузере + если вы читали документацию по TS на сайте TS, то наверняка запомнили примеры кода с тултипами-аннотациями, в которых показываются «скомпиленные» подсказки: это реализовано с помощью &lt;a href=&quot;https://github.com/twoslashes/twoslash&quot;&gt;twoslash&lt;/a&gt;, который &lt;a href=&quot;https://shiki.style/packages/twoslash&quot;&gt;работает в тандеме с shiki&lt;/a&gt;, а также бонусом библиотека анимирования кода из одного состояния в другой &lt;a href=&quot;https://antfu.me/posts/shiki-magic-move&quot;&gt;shiki-magic-move&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/downshift-js/downshift&quot;&gt;downshift&lt;/a&gt; — базовые примитивы, заложенные в хуки, для создания доступных выпадашек на React&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FormidableLabs/spectacle&quot;&gt;spectacle&lt;/a&gt; — либа для создания презентаций с помощью React и JSX&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://modernfontstacks.com/&quot;&gt;modernfontstacks&lt;/a&gt; — наборы шрифтов (включая системные): показывается, какие шрифты используются сейчас в браузере, какие доступны и недоступны&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.recompiled.dev/blog/type-system/&quot;&gt;автомемоизация React Compiler&lt;/a&gt; строится на том, чтобы при выводе типов понять какие значения — примитивы и не момойзить их; собственно, и без React Compiler примитивные значения мемойзить иногда вредно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sitepoint.com/react-spring-interactive-animations/&quot;&gt;гайд по созданию анимаций с react spring&lt;/a&gt;: есть примеры с простыми и сложными анимациями, впрочем простые анимации можно собрать и на коленке на CSS, разве что в либе есть встроенные «пружинные» изинги&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://runtime-compat.unjs.io/&quot;&gt;сравнительная таблица&lt;/a&gt; наличия API в разных JS-рантаймах (кроме браузера): заодно освещён рантайм &lt;a href=&quot;https://wasmer.io/posts/winterjs-v1&quot;&gt;WinterJS&lt;/a&gt;, использующий для JS движок SpiderMonkey из FF&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://romgrk.com/posts/optimizing-javascript&quot;&gt;мастеркласс по экономии на спичках&lt;/a&gt; в JS-коде, если всё остальное уже оптимизировано&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.totaltypescript.com/typescript-and-node&quot;&gt;как настроить среду и TS&lt;/a&gt; для разработки Node-приложения&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-typescript-cheatsheet.netlify.app/&quot;&gt;шпаргалка&lt;/a&gt; по типизации в React-е: если вы когда-нибудь натыкались на заковыристую типизацию, она наверняка раскрыта в этой доке&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;напоминание, что &lt;a href=&quot;https://kyleshevlin.com/no-outer-margin/&quot;&gt;отступы &lt;code&gt;margin&lt;/code&gt; и &lt;code&gt;padding&lt;/code&gt; недопустимы&lt;/a&gt; в стилях агностик-UI-компонентов, вместо них нужно использовать &lt;code&gt;gap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;свойство &lt;code&gt;contain&lt;/code&gt;, которое привносит новизну в &lt;a href=&quot;https://ryanmulligan.dev/blog/50-50-overflow&quot;&gt;вёрстку двухколоночного лейаута&lt;/a&gt;: с &lt;code&gt;contain: size&lt;/code&gt; можно «изолировать» лейаут одного элемента от всех остальных (как будто &lt;code&gt;position: absolute&lt;/code&gt; только в потоке), а также с помощью &lt;code&gt;contain: layout&lt;/code&gt; можно &lt;a href=&quot;https://codepen.io/juwain/pen/gOymQOe&quot;&gt;спозиционировать fixed элемент относительно родителя&lt;/a&gt; (но он перестанет быть &lt;code&gt;fixed&lt;/code&gt;!)&lt;/li&gt;
&lt;li&gt;вместо &lt;code&gt;border: 0&lt;/code&gt; лучше писать &lt;code&gt;border-color: transparent&lt;/code&gt;, чтобы &lt;a href=&quot;https://frontendmasters.com/blog/you-want-border-color-transparent-not-border-none/&quot;&gt;не отрубать рамки для контрастного режима&lt;/a&gt; браузера (такое стоит делать хотя бы для &lt;code&gt;@media (forced-colors: active)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dbushell.com/2024/03/10/css-button-styles-you-might-not-know/&quot;&gt;неочевидные стили для кнопок&lt;/a&gt;: &lt;code&gt;touch-action: manipulation&lt;/code&gt; для отключения зума по двойному тапу, &lt;code&gt;user-select: none&lt;/code&gt; для выключение выделения текста, &lt;code&gt;::file-selector-button&lt;/code&gt; для стилизации кнопки input file, аутлайн для фокуса не по клику с &lt;code&gt;:focus-visible&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;значение &lt;code&gt;align-items: safe center&lt;/code&gt; &lt;a href=&quot;https://frontendmasters.com/blog/what-is-safe-alignment-in-css/&quot;&gt;для выравнивания элементов без риска обрезать их&lt;/a&gt; в случае появления скролла в контейнере&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://piccalil.li/blog/the-box-model-and-box-sizing/&quot;&gt;ликбез по боксовой модели CSS&lt;/a&gt;, а также сброс неудобной дефолтной настройки &lt;code&gt;box-sizing: content-box&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jameshfisher.com/2024/03/12/a-formula-for-responsive-font-size/&quot;&gt;удобный дефолт для респонсив-размера шрифта&lt;/a&gt; &lt;code&gt;font-size: calc(1rem + 0.25vw)&lt;/code&gt; вместо дурацкого переключения по разрешениям&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;если ваша монорепа разрастётся до миллиона файлов, то скорее всего в ней начнёт тормозить git; если такое произошло, выхода два: распилить монорепу или &lt;a href=&quot;https://graphite.dev/blog/why-facebook-doesnt-use-git&quot;&gt;перейти на Mercurial&lt;/a&gt; (как сделали ребята из компании на букву F)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 15.03.2024</title><link>https://juwain.github.io/web-platform/blog/2024-03-15/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-15/</guid><description>Новости веб-платформы</description><pubDate>Fri, 15 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в опенсорс &lt;a href=&quot;https://rolldown.rs/&quot;&gt;выложен Rolldown,&lt;/a&gt; замена Rollup на Rust для Vite: радует, что обратно совместим с Rollup, но пока ещё в активной разработке, не для продакшена&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v21.7.0&quot;&gt;вышла Node v21.7.0:&lt;/a&gt; встроенная стилизация текста &lt;code&gt;console.log(util.styleText(&apos;bold&apos;, &apos;text&apos;))&lt;/code&gt;, загрузка и парсинг переменных окружения &lt;code&gt;process.loadEnvFile(path)&lt;/code&gt; и &lt;code&gt;util.parseEnv(content)&lt;/code&gt;, поддержка многострочных значений в &lt;code&gt;.env&lt;/code&gt; файлах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://biomejs.dev/blog/biome-v1-6/&quot;&gt;вышел Biome v1.6&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддержка расширений файлов vue, astro, svelte&lt;/li&gt;
&lt;li&gt;новые настройки форматтера&lt;/li&gt;
&lt;li&gt;лёгкая миграция с Prettier&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://storybook.js.org/blog/storybook-8/&quot;&gt;вышел Storybook 8:&lt;/a&gt; встроенные визуальные тесты, поддержка React Server Components, обновления интерфейса и ускорение работы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/blog/inp-cwv-launch&quot;&gt;INP теперь официальная метрика Core Web Vitals,&lt;/a&gt; FID будет задепрекейчена в сентябре 2024&lt;/li&gt;
&lt;li&gt;Astro выпустили &lt;a href=&quot;https://astro.build/db/&quot;&gt;Astro DB,&lt;/a&gt; адаптированную SQL-бд на основе &lt;a href=&quot;https://github.com/tursodatabase/libsql&quot;&gt;libsql&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://utopia.fyi/&quot;&gt;utopia&lt;/a&gt; — система «резиновой» типографики, отступов, сетки: позволяет задать минимальное и максимальное разрешение интерфейса, а также количество промежуточных шагов между ними и получить готовые CSS-переменные для использования&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://device-simulator.vercel.app/&quot;&gt;device-simulator&lt;/a&gt; — симуляция девайсов в браузере для тестирования интерфейсов: не browserstack, скорее переосмысление стандартных браузерных дев-тулзов (device toolbar), помощнее, есть возможность показа нескольких устройств одновременно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gravity-ui/uikit&quot;&gt;gravity-ui&lt;/a&gt; — каждое поколение яндексоидов создаёт собственный UI-кит, и этот выглядит очень даже прилично: есть дизайн-система, Figma и токены, позаботилились о доступности, свои иконки; остаётся только понять, какой из двух Яндексов будет его дальше овнить&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kristiandupont/react-geiger&quot;&gt;react-geiger&lt;/a&gt; — счётчик Гейгера для React-приложения: если что-то рендерится долго и часто, то вы это услышите&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jsoncanvas.org/?ref=sidebar&quot;&gt;jsoncanvas&lt;/a&gt; — спецификация и формат файлов JSON Canvas для имплементации бесконечных досок аля Miro, Obsidian и тд&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если долго сидеть у реки, то рано или поздно по ней проплывёт заброшенный JS-проект, так как его купили крупняки, уволили сотрудников и забили &lt;a href=&quot;https://www.smashingmagazine.com/2024/03/end-of-gatsby-journey/&quot;&gt;(речь о Gatsby,&lt;/a&gt; если что)&lt;/li&gt;
&lt;li&gt;работа с относительными datetime-ами с помощью &lt;a href=&quot;https://www.raymondcamden.com/2024/03/07/using-intlrelativetimeformat-for-localized-relative-timings&quot;&gt;&lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt;&lt;/a&gt; (давно поддерживаемая в браузерах)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://claritydev.net/blog/creating-accessible-form-components-with-react&quot;&gt;создание доступных компонентов форм на React:&lt;/a&gt; кнопки, лейблы, филдсет, плейстхолдеры, фокус и навигация с клавиаутры, отображение ошибок&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://claritydev.net/blog/improving-react-testing-library-tests&quot;&gt;лучшие практики по использованию React Testing Library:&lt;/a&gt; тестирование доступности компонентов, реализация смоук-тестов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/devongovett/unplugin-parcel-macros&quot;&gt;make macros great again:&lt;/a&gt; теперь подход с прекомпилированными в билд-тайме кусочками JS-кода доступен не только в parcel, но и в webpack, vite и остальных&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;статьи про новые CSS-фичи читаются как научная фантастика: красиво, интересно, когда-то это будет, но пока полностью не работает; вот и в этом материале рассказывается, &lt;a href=&quot;https://frontendmasters.com/blog/menus-toasts-and-more/&quot;&gt;как собрать ванильные модалки и «тосты»:&lt;/a&gt; &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; для модальных всплывашек, popover — для немодальных всплывашек, нативная стилизация элементов и показ/сокрытие, стартовая анимация &lt;code&gt;@starting-style&lt;/code&gt; и даже anchor positioning для показа в определённом месте интерфейса&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.logrocket.com/5-ways-style-text-css-inspired-spider-verse/&quot;&gt;стилизация текста:&lt;/a&gt; глитч-эффект, множественные тени и SVG-фильтры (осторожно, можно случайно стать КМС по &lt;code&gt;text-shadow&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://piccalil.li/blog/some-little-ways-im-using-css-has-in-the-real-world/&quot;&gt;небольшие рецепты из жизни&lt;/a&gt; по использованию &lt;code&gt;:has()&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;изменение лейаута, если в контейнере есть определённый элемент&lt;/li&gt;
&lt;li&gt;подсветка контейнера, если внутри есть &lt;code&gt;:target&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;затемнение соседей при ховере на элементе&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lea.verou.me/docs/var-groups/&quot;&gt;предложение от Ли Веру сделать&lt;/a&gt; из кастомных свойств своего рода «объекты»: &lt;code&gt;--color-green: { base: red; 100: green; 200: blue};&lt;/code&gt; зная, что благодаря Ли в CSS уже появилось много ништяков, глядишь и этот тоже затащат&lt;/li&gt;
&lt;li&gt;использование &lt;a href=&quot;https://developer.mozilla.org/en-US/blog/color-palettes-css-color-mix/&quot;&gt;&lt;code&gt;color-mix()&lt;/code&gt; для создания палитр:&lt;/a&gt; ещё один кусок платформа откусила от sass&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cdpn.io/pen/debug/XWQWgrj&quot;&gt;для записи кавычек в тексте alt&lt;/a&gt; используйте одинарные кавычки &lt;code&gt;&apos;&lt;/code&gt; или &lt;code&gt;&amp;amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в Chrome 122 &lt;a href=&quot;https://developer.chrome.com/blog/speculation-rules-improvements&quot;&gt;появилась улучшенная поддержка Speculation Rules API:&lt;/a&gt; это переосмысленный, более выразительный и автоматизированный последователь &lt;code&gt;link=&quot;prerender&quot;&lt;/code&gt; с исчерпывающим описанием, какие ресурсы и в какой очерёдности прелоадить и пререндерить&lt;/li&gt;
&lt;li&gt;35 лет назад Тим Бернес Ли описал «спецификацию интернета» — &lt;a href=&quot;https://www.w3.org/History/1989/proposal.html&quot;&gt;Information Management: A Proposal&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Зависимости</title><link>https://juwain.github.io/web-platform/blog/2024-03-26/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-26/</guid><description>Как правильно подобрать зависимость</description><pubDate>Tue, 26 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Окей, вам нужно сделать фичу и вы решаете добавить в проект зависимость. Лучше было бы, конечно, &lt;a href=&quot;https://t.me/web_platform/75&quot;&gt;этого не делать&lt;/a&gt;, но иногда бывает нужно срочно-кипяточно или наговнякать для проверки гипотезы. Как сделать выбор более осознанно и уменьшить риски, что зависимость в будущем создаст проблем?&lt;/p&gt;
&lt;p&gt;Признаю: будущее никто не знает, может случиться что угодно и риски есть всегда. Так что, как осознанно не подходи к выбору, всё равно что-то может пойти не так. Но что можно сделать, так это собрать более-менее полную эвристику и вывести наименее рискованный вариант.&lt;/p&gt;
&lt;p&gt;Обычно проекты и большие, и маленькие, проходят примерно один и тот же жизненный цикл: рождение, бурное развитие со сломом обратной совместимости, стабилизация, стагнация, уход в поддержку/неподдержку.&lt;/p&gt;
&lt;p&gt;Причём проект может проходить цикл повторно. Например, если изменилась прикладная цель или пришёл новый овнер, проект может пойти на новый круг по спирали.&lt;/p&gt;
&lt;p&gt;Сам цикл может проходить быстро, если проект — это mvp со сроком жизни в месяц, или долго, когда проект долгоиграющий (Linux 👋).&lt;/p&gt;
&lt;p&gt;Так вот, к зависимостям.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Гвард 1&lt;/em&gt;. О качестве зависимости можно не задумываться, если срок жизни вашего проекта будет &lt;strong&gt;короче&lt;/strong&gt;, чем срок жизни зависимости. И, наоборот, качество зависимости очень важно, если ваш проект — долгий: зависимости нужно будет обслуживать и утилизировать в случае заброшенности, либо дорабатывать форк. Чем зависимостей больше, тем больше времени будет уходить на обслуживание.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Гвард 2&lt;/em&gt;. Нестабильные зависимости в стабилизировавшийся проект лучше не добавлять, иногда становится трудно/накладно обновлять зависимости и в проекте может появиться дырка, которая будет висеть месяцами.&lt;/p&gt;
&lt;p&gt;Окей, если гварды вас не остановили, то дальше нужно определиться, из чего складывается качество зависимости.&lt;/p&gt;
&lt;p&gt;🍿 Часто бывает, что зависимость выбирается по популярности. Типа «миллионы юзеров не могут ошибаться».Да, у популярного проекта большее сообщество, больше контрибьюторов, но бывает, что что-то становится модным, а затем мода на это проходит. Тут можно смотреть на количество звёзд, форков, подписчиков, контрибьюторов, скачиваний (а также тренд скачиваний).&lt;/p&gt;
&lt;p&gt;👥 Мейнтейнер(ы) и мейнтейн. Если мейнтейнер один, то вероятность стать заброшенным у проекта больше, так как &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%BA%D1%82%D0%BE%D1%80_%D0%B0%D0%B2%D1%82%D0%BE%D0%B1%D1%83%D1%81%D0%B0&quot;&gt;бас фактор&lt;/a&gt;. Мейнтейн можно оценить по соотношению открытых/закрытых ишью, времени закрытия ишью, времени последнего обновления и частоте релизов.&lt;/p&gt;
&lt;p&gt;🛠️ Качество инфраструктуры. Документация, настроенный линтер, тесты, внятное версионирование. Тут всё ясно.&lt;/p&gt;
&lt;p&gt;⛓️ Зависимость от других зависимостей. Чем больше зависимостей, тем хуже. Энтропия увеличивается, всё остальное падает. Одиночные пакеты лучше, но есть исключение, когда речь идёт о целой экосистеме, например, ui-ките, который вы целиком используете.&lt;/p&gt;
&lt;p&gt;🏋️ Размер. Часто даже у популярного проекта могут быть более компактные аналоги. Размер одиночных пакетов часто кореллирует с количеством зависимостей. Меньше зависимостей — меньше размер.&lt;/p&gt;
&lt;p&gt;🧭 DX. Если проект будет минимального размера и без внешних зависимостей, но при этом него будет неудобный API, то не стоит брать его. Нервы дороже.&lt;/p&gt;
&lt;p&gt;💸 Финансирование. Если у проекта есть платная версия или же за ним стоит зарабатывающая компания, то вероятность более длинной жизни проекта больше. Без поддержки энтузиазм быстрее заканчивается.&lt;/p&gt;
&lt;p&gt;Как теперь это всё отслеживать, спросите вы. Для этого есть инструменты.&lt;/p&gt;
&lt;p&gt;Оценить размер бандла, увидеть вложенные зависимости и сравнить с аналогами можно на &lt;a href=&quot;https://bundlephobia.com/&quot;&gt;bundlephobia&lt;/a&gt; (&lt;a href=&quot;https://bundlephobia.com/package/react-joyride&quot;&gt;пример&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Увидеть «рейтинг» пакета можно на &lt;a href=&quot;https://npms.io/&quot;&gt;npms&lt;/a&gt; (&lt;a href=&quot;https://npms.io/search?q=react-joyride&quot;&gt;пример&lt;/a&gt;). Там оценивается «качество», «популярность» и «мейнтейн». Так же можно сравнить с аналогами.&lt;/p&gt;
&lt;p&gt;Более детально проанализировать зависимости можно на &lt;a href=&quot;https://npmgraph.js.org/&quot;&gt;npmgraph&lt;/a&gt;. Например, можно оценить &lt;a href=&quot;https://npmgraph.js.org/?q=react-joyride#color=bus&quot;&gt;количество мейнтейнеров в дочерних зависимостях&lt;/a&gt;, &lt;a href=&quot;https://npmgraph.js.org/?q=react-joyride#color=outdated&quot;&gt;актуальность зависимостей&lt;/a&gt;, &lt;a href=&quot;https://npmgraph.js.org/?q=react-joyride#color=overall&quot;&gt;оценку npms&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Повторюсь: даже проанализировав все параметры, что-то в будущем всё равно может пойти не так. Но этого никто не знает, а здесь и сейчас у вас будет инструмент для более осознанного выбора зависимостей и обоснования этого выбора для коллег и менеджеров.&lt;/p&gt;
</content:encoded></item><item><title>Конечные автоматы</title><link>https://juwain.github.io/web-platform/blog/2024-03-19/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-19/</guid><description>В этом случае приходит на помощь проектирование системы исходя из её состояний и переходов между ними, а не из выполняемых функций. Такая система и есть конечный автомат, то есть система с конечным числом состояний.</description><pubDate>Tue, 19 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Когда создаётся некая система, обычно естественно думать о том, что эта система будет делать, какие выполнять действия, что она поможет достичь. То есть продумываются целевые действия пользователя, что он он будет делать, куда переходить, какие кнопки нажимать.&lt;/p&gt;
&lt;p&gt;В целом, это ок подход. Он хорошо работает на прямолинейных сценариях с несложной логикой. В случае системы со сложным поведением, если её спроектировать исходя из действий, то тогда в программе начнут появляться «режимы работы», «флаги» isSomething… и хитроспетения условий с комбинациями значений этих флагов.&lt;/p&gt;
&lt;p&gt;Если ветвлений и состояний более 8-10, то тогда сложно создать и держать в голове ментальную модель, код на флагах и ифах превращается в плохо структурированную кашу, в которой легко допустить ошибку или логическую дыру.&lt;/p&gt;
&lt;p&gt;В этом случае приходит на помощь проектирование системы исходя из её состояний и переходов между ними, а не из выполняемых функций. Такая система и есть конечный автомат, то есть система с конечным числом состояний.&lt;/p&gt;
&lt;p&gt;Самый простой автомат состоит из двух состояний: выключено → включено. Чтобы перейти из одного состояний в другое вызывается action. Например, человек «спит» → вызывается action «пробудиться» → человек «бодрствует».&lt;/p&gt;
&lt;p&gt;Ключевая фишка такого подхода к описанию работы системы — можно на одной схеме изобразить все состояния и переходы между ними в виде такого «пошагового визарда», в котором видно всё одновременно.&lt;/p&gt;
&lt;p&gt;На фронте для реализации конечных автоматов есть классная либа &lt;a href=&quot;https://stately.ai/docs/xstate&quot;&gt;xState&lt;/a&gt;. Автор либы из Microsoft, и она появилась, чтобы было проще поддерживать редактор workflows в Azure. На самом деле такое случается сплошь и рядом, когда появляется некая развесистая система, в которой могут разобраться только её авторы, так как в неё сложно въехать, объять умом целиком. И если есть общая диаграмма работы, то больше шансов, что человек с улицы сможет её раскурить.&lt;/p&gt;
&lt;p&gt;Например, посмотрите на &lt;a href=&quot;https://stately.ai/registry/editor/f62ce536-4dc1-4f88-89bd-92be0fd5be49&quot;&gt;вот эту схему&lt;/a&gt;, попробуйте нажать «Simulate» в правом верхнем углу и прогоните программу от начала до конца. Так уже сходу и стало более-менее понятно, что в ней происходит?&lt;/p&gt;
&lt;p&gt;А теперь если добавить, что из этой схемы сразу же генерится и код автомата, который можно скопировать в проект, допилить напильником и он будет работать, то получается прям бомба-пушка. Кстати, для VS Code есть визуализация прям внутри редактора, оч удобно прочекать, где куда и что идёт, это «живая документация».&lt;/p&gt;
&lt;p&gt;Что ещё интересного есть в xState. Между состояниями могут быть guards, которые в зависимости от результата поведут в одну сторону или в другую. Поддерживается TS и асинхронная логика. Есть интеграция с React, Vue, Svelte. Также авторы стали развивать либу в сторону actor-ов: это такой архитектурный паттерн, когда система представляется неким действующим лицом, актором, которое выполняет действия, может взаимодействовать с другими акторами и тд.&lt;/p&gt;
&lt;p&gt;В общем, если у вас уже запутанная система или вы собираетесь заниматься системой с множественными состояниями, советую приглядеться к xState ✌️.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 29.03.2024</title><link>https://juwain.github.io/web-platform/blog/2024-03-29/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-03-29/</guid><description>Новости веб-платформы</description><pubDate>Fri, 29 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/safari-technology-preview-release-notes/stp-release-190&quot;&gt;вышел Safari TP 190&lt;/a&gt;: поддерживается style container queries, ключевое слово &lt;code&gt;safe&lt;/code&gt; во флексбоксах, &lt;code&gt;getComputedStyle()&lt;/code&gt; теперь работает с &lt;code&gt;::highlight()&lt;/code&gt;, атрибут &lt;code&gt;shadowrootclonable&lt;/code&gt; для разрешения кловирования shadow root&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://turbo.build/blog/turbo-1-13-0&quot;&gt;вышла Turborepo 1.13&lt;/a&gt;: новый ui-терминал, команда scan для определения подходящих настроек на вашей машине, улучшенное логирование на CI&lt;/li&gt;
&lt;li&gt;веб-компонентный ui-кит &lt;a href=&quot;https://www.kickstarter.com/projects/fontawesome/web-awesome&quot;&gt;Shoelace теперь называется Web Awesome&lt;/a&gt; (так как их купил Font Awesome): хорошая новость — у кита будет финансовая поддержка, плохая — полностью бесплатным кит не будет&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v8.dev/features/iterator-helpers&quot;&gt;в V8 у итераторов появились новые методы&lt;/a&gt; &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;drop&lt;/code&gt;, &lt;code&gt;flatMap&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt;, &lt;code&gt;toArray&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt;, &lt;code&gt;some&lt;/code&gt;, &lt;code&gt;every&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, позволяющие, например, не приводить к массиву коллекцию &lt;code&gt;Nodelist&lt;/code&gt;, чтобы её обойти &lt;code&gt;const posts = document.querySelectorAll(&apos;a&apos;).values().find()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-123&quot;&gt;обновился Chrome до версии 123&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;функция &lt;code&gt;light-dark()&lt;/code&gt; для упрощённого задания цветовой темы&lt;/li&gt;
&lt;li&gt;Long Animation Frames API для отслеживания избыточных перерисовок в &lt;code&gt;PerformanceObserver&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Service worker Static Routing API для указания, какие ресурсы через Service worker гонять не нужно, а всегда брать из сети&lt;/li&gt;
&lt;li&gt;стили для picture-in-picture версии сайта &lt;code&gt;@media (display-mode: picture-in-picture)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/EqualMa/gitpkg&quot;&gt;gitpkg&lt;/a&gt; — тула, чтобы сделать папку github-репозитория отдельной npm-зависимостью&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vvo/tzdb/&quot;&gt;tzdb&lt;/a&gt; — либа с всегда актуальными мировыми таймзонами (данные берутся с &lt;a href=&quot;https://www.geonames.org/&quot;&gt;geonames.org&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/changesets/changesets&quot;&gt;changesets&lt;/a&gt; — тула для составления чейнджлогов в репах и монорепах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/AsyncBanana/microdiff&quot;&gt;microdiff&lt;/a&gt; — мини-либа без зависимостей для сравнения объектов в JS, в том числе &lt;code&gt;new Date()&lt;/code&gt; и &lt;code&gt;new RegExp()&lt;/code&gt;, а также объектов с циклическими ссылками&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LB8KwiiUGy0&quot;&gt;документалка о истории Node.js&lt;/a&gt;: не смотрел, но одобряю&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://humanwhocodes.com/blog/2024/03/javascript-engines-runtimes/&quot;&gt;чем отличаются JS движок и JS рантайм&lt;/a&gt;: движок (V8, SpiderMonkey, JavaScriptCore) имплементит спецификацию ECMAScript, а рантайм (браузеры, Node, Deno, Bun) — это хост, в котором запускается движок + дополнительная инфраструктура для работы (DOM для браузеров, доступ в файловой системе в Node, event loop)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rxdb.info/articles/websockets-sse-polling-webrtc-webtransport.html&quot;&gt;походы для двустороннего и одностороннего общения сервер-клиент&lt;/a&gt; с WebSockets, Server-Sent-Events, Long-Polling, WebRTC и WebTransport: WebSockets ок, но сложны в реализации, SSE — только в направлении сервер-&amp;gt;клиент, WebTransport работает на протоколе HTTP/3 QUIC и пока не везде поддерживается, WebRTC больше для клиент-клиент соединений, Long-Polling ок, но хак&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dyte.io/blog/package-json/&quot;&gt;обзор всех полей package.json&lt;/a&gt;: скорее всего они уже описаны в доке npm, но тут как-то приятно собрано и описано всё вместе&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/chill-scroll-snapping-article-headers/&quot;&gt;идея использовать scroll-snap&lt;/a&gt; не в горизонтальной карусели, а для скролл-навигации по заголовкам текста в вертикальном направлении: чем-то напомнило вертикально листающиеся по свайпу «карточки»&lt;/li&gt;
&lt;li&gt;как &lt;a href=&quot;https://thathtml.blog/2024/03/superpowered-container-style-queries/&quot;&gt;создать фича-флаги на CSS&lt;/a&gt; с помощью &lt;code&gt;@container style(--is-mobile: true)&lt;/code&gt;: &lt;a href=&quot;https://t.me/web_platform/35&quot;&gt;я предполагал&lt;/a&gt;, что это станет можно делать в 2025, и кажется прогноз сбудется, так как хоть style container queries и &lt;a href=&quot;https://developer.apple.com/documentation/safari-technology-preview-release-notes/stp-release-190&quot;&gt;появились в Safari TP 190&lt;/a&gt;, но в FF ещё нет&lt;/li&gt;
&lt;li&gt;мастеркласс по приготовлению &lt;a href=&quot;https://piccalil.li/blog/solution-009-progress-indicator/&quot;&gt;веб-компонента круглого прогресс-бара&lt;/a&gt;: в меню инкапсуляции с выделением открытых «ручек» на кастомных свойствах, обзёрвабл атрибутов (реактивность!), на десерт размеры в container unit-ах и гриды&lt;/li&gt;
&lt;li&gt;найдено &lt;a href=&quot;https://www.amitmerchant.com/spicing-up-text-with-text-emphasis-in-css/&quot;&gt;малоизвестное CSS-свойство text-emphasis&lt;/a&gt; для выделения символов в тексте: кажется, может сгодиться, например, для подсветки «неверных» слов в тексте&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.letsbuildui.dev/articles/how-to-animate-borders-in-css/&quot;&gt;5 примеров разной анимации бордеров&lt;/a&gt;: строится на вращении фонового псевдоэлемента с сокрытием лишнего &lt;code&gt;overflow: hidden&lt;/code&gt;, размытии фильтром, &lt;code&gt;outline&lt;/code&gt; или анимации &lt;code&gt;stroke-dashoffset&lt;/code&gt; у SVG&lt;/li&gt;
&lt;li&gt;найден юзкейс единицы измерения &lt;code&gt;turn&lt;/code&gt; — &lt;a href=&quot;https://codepen.io/t_afif/pen/XWQMPqY&quot;&gt;«докрутка» элемента при остановке анимации&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;псевдокласс &lt;code&gt;:empty&lt;/code&gt; не учитывает текстовые ноды, а вот &lt;a href=&quot;https://twitter.com/anatudor/status/1767479639432122512&quot;&gt;&lt;code&gt;:not(:has(*))&lt;/code&gt; чинит это&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;отсюда можно &lt;a href=&quot;https://nerdy.dev/steal-this-popover-starter-kit&quot;&gt;просто взять и скопипастить&lt;/a&gt; popover-модалку&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://martinheinz.dev/blog/109&quot;&gt;незаслуженно неизвестные современные команды git&lt;/a&gt;: &lt;code&gt;switch&lt;/code&gt; для переключения веток, &lt;code&gt;restore&lt;/code&gt; для отката правок в файле, &lt;code&gt;sparse-checkout&lt;/code&gt; для частичного чакаута, &lt;code&gt;worktree&lt;/code&gt; для чекаута одновременно двух веток, &lt;code&gt;bisect&lt;/code&gt; для бинарного поиска проблемного коммита&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Фикс скроллбар-сдвига</title><link>https://juwain.github.io/web-platform/blog/2024-04-02/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-04-02/</guid><description>Бывает кейс, когда интерфейс сайта центрируется, и при появлении и скрытии скроллбара контент начинает сдвигаться чуть в сторону на ширину скроллбара. Особенно актуально в случае модалок, при появлении которых общий скролл «выключается» и интерфейс «прыгает» вправо, а при сокрытии — обратно влево.</description><pubDate>Tue, 02 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Сегодня расскажу про старый-добрый CSS-трюк.&lt;/p&gt;
&lt;p&gt;Бывает кейс, когда интерфейс сайта центрируется, и при появлении и скрытии скроллбара контент начинает сдвигаться чуть в сторону на ширину скроллбара. Особенно актуально в случае модалок, при появлении которых общий скролл «выключается» и интерфейс «прыгает» вправо, а при сокрытии — обратно влево.&lt;/p&gt;
&lt;p&gt;Это можно решить, задав в CSS принудительный показ скроллбара с &lt;code&gt;overflow-y: scroll&lt;/code&gt;. Но тогда скролл будет показываться в том числе, когда в этом нет необходимости.&lt;/p&gt;
&lt;p&gt;Можно также придумать или найти разные варианты решения этой проблемы на JS: высчитывать ширину скроллбара и вычитать её из общей ширины body, либо вычислять разницу между интерфейсом со скроллом и без скролла, а затем компенсировать эту разницу опять же для &lt;code&gt;body&lt;/code&gt;. Но всё это кажется неизящными костылями. Даже если пробросить вычисленное значение в CSS кастомными свойствами.&lt;/p&gt;
&lt;p&gt;Есть более изящный костыль на CSS, который применяется только когда нужно и не нагружает скрипты ненужными махинациями.&lt;/p&gt;
&lt;p&gt;Суть в том, чтобы задать контейнеру, внутри которого располагается центрирующийся контент, компенсирующий отступ слева, если скроллбара нет. А если скроллбар есть, то этот отступ должен убираться.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container {
  margin-left: Npx;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Как вычислить это значение без прибегания к скриптам? На помощь приходит то, чему равняются значения &lt;code&gt;100%&lt;/code&gt; и &lt;code&gt;100vw&lt;/code&gt; для блока со скроллом. В случае &lt;code&gt;vw&lt;/code&gt; — это ширина всего вьюпорта, включая скроллбар, а в случае &lt;code&gt;%&lt;/code&gt; — это ширина блока без скроллбара. То есть разница между этими двумя значениями — это и есть ширина самого скроллбара:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container {
  margin-left: calc(100vw - 100%);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Если скроллбар есть, то отступ будет, так как &lt;code&gt;100vw&lt;/code&gt; будет больше &lt;code&gt;100%&lt;/code&gt;. Если скроллбара нет, то &lt;code&gt;100vw&lt;/code&gt; и &lt;code&gt;100%&lt;/code&gt; будут равны между собой и отступа не будет.&lt;/p&gt;
&lt;p&gt;Демо &lt;a href=&quot;https://codepen.io/juwain/pen/BaEmbyo&quot;&gt;тут&lt;/a&gt;: попробуйте понажимать на кнопку, которая включает и выключает скролл, и увидеть сдвиг, а затем раскомментировать фикс.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 12.04.2024</title><link>https://juwain.github.io/web-platform/blog/2024-04-12/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-04-12/</guid><description>Новости веб-платформы</description><pubDate>Fri, 12 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://opensource.googleblog.com/2024/04/introducing-jpegli-new-jpeg-coding-library.html?ck_subscriber_id=2011909133&quot;&gt;вышел Jpegli&lt;/a&gt; — новая либа для кодирования jpeg, обещают на 35% лучшее &amp;lt;s&amp;gt;зашакаливание&amp;lt;/s&amp;gt; сжатие, казалось бы jpeg сто лет в обед, но до сих пор случаются прорывы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.partykit.io/&quot;&gt;PartyKit&lt;/a&gt;, библиотека для создания мультиплеер-приложений, &lt;a href=&quot;https://blog.cloudflare.com/cloudflare-acquires-partykit&quot;&gt;куплена Cloudflare&lt;/a&gt;: обещают холить и лелеять (но это в пресс-релизах они все так обещают)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v8.dev/blog/sandbox&quot;&gt;V8 Sandbox&lt;/a&gt; — более не эксперимент: уже в Chrome 123 память для V8 будет отделяться в отдельную «резервацию», чтобы предотвратить несанкционированный доступ к ней&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/blog/introducing-learn-javascript&quot;&gt;вышел&lt;/a&gt; новый &lt;a href=&quot;https://web.dev/learn/javascript/control-flow&quot;&gt;учебник по JS&lt;/a&gt; от гугловцев: как обычно, считаю, что только читать материал — мало, квизы в конце статей — тоже мало, надо отрабатывать на практике, вот буквально набивать руку, печатая код&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2024/04/eslint-v9.0.0-released/&quot;&gt;вышел ESLint v9.0.0&lt;/a&gt;, в нём много нововведений и breaking changes:
&lt;ul&gt;
&lt;li&gt;не поддерживается нода &amp;lt; v18.18.0, v19&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eslint.config.js&lt;/code&gt; — теперь дефолт, &lt;code&gt;.eslintrc&lt;/code&gt; —депрекейт&lt;/li&gt;
&lt;li&gt;удалены форматтеры, кроме stylish, html, json и json-with-meta&lt;/li&gt;
&lt;li&gt;обновлен eslint:recommended&lt;/li&gt;
&lt;li&gt;добавлены и изменены многие правила&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://eslint.org/blog/2024/04/eslint-config-inspector/&quot;&gt;ESLint Config Inspector&lt;/a&gt; — инструмент для визуального изучения вашего конфига, к чему он применяется, почему, зачем, за что (работает только с eslint.config.js) — это приятная пилюля для тех, кто страдает, что надо снова всё перелопачивать&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gvergnaud/ts-pattern&quot;&gt;ts-pattern&lt;/a&gt; — либа реализующая pattern matching подход в TS: если у вас есть развесистые условия, то возможно стоит присмотреться к либе&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vinejs.dev/&quot;&gt;vinejs&lt;/a&gt; — если вдруг вы использовали Zod в Node для валидации полей формы с клиента, то вас стоит взглянуть на спец либу для валидации именно HTTP request body&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zheksoon/dioma&quot;&gt;dioma&lt;/a&gt; — либа для реализации dependency injection в JS и TS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/WickyNilliams/cally&quot;&gt;cally&lt;/a&gt; — веб-компонент календаря: фичастый, маленький, доступный, твой&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://previewjs.com/&quot;&gt;previewjs&lt;/a&gt; — таб с превью отрендеренного компонента из текущего файла прямо в редакторе для React, Vue, Svelte, Solid&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;очередное напоминание о существовании Shadow DOM без разглагольствований: &lt;a href=&quot;https://southleft.com/insights/development/adopted-stylesheets/&quot;&gt;бери и копируй базовый веб-компонент кнопки&lt;/a&gt;, который сразу заработает&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/almaju/someone-finally-fixed-javascript-426i&quot;&gt;шоукейс библиотеки Effect&lt;/a&gt;, которая берёт на себя задачу помочь декларативностью и наглядностью побороть неоптимальную конкуренцию в асинхронных приложениях&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/appqui/how-i-optimized-carousel-for-editorjs-2x-in-size-4efa&quot;&gt;оптимизация бандла&lt;/a&gt;, в общем-то, неважно какого приложения: основная мысль — бандл — не бинарник, это высокоуровневый JS, который можно растрепать и посмотреть, что там есть лишнего (webpack-bundle-analyzer в помощь)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/dododev/articles/798519/&quot;&gt;yarn для тех&lt;/a&gt;, кому нужно не только запускать команды из package.json, а: хранить кэш всех пакетов проекта в репозитории; использовать workspaces в монорепе; интерактивно обновлять зависимости проекта; гибко управлять версиями пакетов; использовать «протоколы» для подключения к проекту внешних файлов и папок; патчить пакеты и другое&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://texteffects.dev/&quot;&gt;крутые текстовые эффекты&lt;/a&gt; (ведь всю эту мощь в CSS же принесли для стилей, а не программирования, так?)&lt;/li&gt;
&lt;li&gt;что будет, если соединить &lt;code&gt;:has(:hover)&lt;/code&gt; и сетку на 100500 элементов — &lt;a href=&quot;https://dev.to/warkentien2/curious-geckos-the-most-precise-css-only-position-aware-mini-game-16i2&quot;&gt;позиционирование курсора без использования JS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;а что будет, если соединить &lt;code&gt;:has(input:focus) input:invalid&lt;/code&gt; и пачку инпутов с &lt;code&gt;maxlength=&quot;1&quot;&lt;/code&gt; и &lt;code&gt;pattern=&quot;[tT]&quot;&lt;/code&gt; — &lt;a href=&quot;https://scottjehl.com/posts/wordleish/&quot;&gt;wordle без использования JS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshwcomeau.com/react/folding-the-dom/&quot;&gt;«складывающиеся» элементы&lt;/a&gt; на &lt;code&gt;transform&lt;/code&gt;-ах: особо приятен эффект затенения при более остром угле складывания&lt;/li&gt;
&lt;li&gt;использование CSS как инструмента &lt;a href=&quot;https://heydonworks.com/article/testing-html-with-modern-css/&quot;&gt;для причинения умышленного визуального регресса&lt;/a&gt; для антипаттернов в HTML (например, для выявления забытых пустых ссылок &lt;code&gt;a:not([href]), a[href=&quot;&quot;], a[href$=&quot;#&quot;], a[href^=&quot;javascript&quot;]&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ещё один &lt;a href=&quot;https://danburzo.ro/responsive-images-html/&quot;&gt;гайд по &amp;lt;img&amp;gt;, srcset, sizes и &amp;lt;picture&amp;gt;&lt;/a&gt; с фокусом на последовательное понимание, а зачем оно вообще нужно&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;если что WebP уже не самый топ-формат и повсеместно &lt;a href=&quot;https://blog.sentry.io/low-effort-image-optimization-tips/&quot;&gt;распространён более лучший AVIF&lt;/a&gt;, правда руками настраивать всю машинерию &lt;em&gt;имаджинерии&lt;/em&gt; сложно, поэтому можно воспользоваться инструментами для пребилда картинок в нужном формате или доставкой из CDN&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 05.04.2024</title><link>https://juwain.github.io/web-platform/blog/2024-04-05/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-04-05/</guid><description>Новости веб-платформы</description><pubDate>Fri, 05 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;обновились LST версии Node.js:
&lt;ul&gt;
&lt;li&gt;в &lt;a href=&quot;https://nodejs.org/en/blog/release/v20.12.0&quot;&gt;v20.12.0&lt;/a&gt; бэкпортированы &lt;code&gt;crypto.hash()&lt;/code&gt;, более быстрый, чем &lt;code&gt;createHash()&lt;/code&gt;, загрузка и парсинг переменных окружения с &lt;code&gt;process.loadEnvFile(path)&lt;/code&gt; и &lt;code&gt;util.parseEnv(content)&lt;/code&gt;, стилизация вывода текста &lt;code&gt;util.styleText&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://nodejs.org/en/blog/release/v18.20.0&quot;&gt;v18.20.0&lt;/a&gt; добавлены импорт-атрибуты &lt;code&gt;import &quot;foo&quot; with { ... }&lt;/code&gt;, а также &lt;code&gt;dirent.path&lt;/code&gt; заменён на &lt;code&gt;dirent.parentPath&lt;/code&gt; (следом доехали секьюрные апдейты v20.12.1 и v18.20.1)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-v1.1&quot;&gt;вышел bun v1.1&lt;/a&gt;: теперь поддерживается в Windows 10, также добавлен Bun.Glob для поиска по файловой системе, Bun.Semver для проверки и сортировки версий по semver, новые свойства server.url и server.requestIP() при использовании serve, улучшена совместимость с Node для более бесшовного перехода, много &lt;a href=&quot;https://bun.sh/blog/bun-v1.1#web-apis&quot;&gt;улучшений в работе с Web API&lt;/a&gt; и в целом дофига фиксов и изменений&lt;/li&gt;
&lt;li&gt;вышел (олдскулы свело) &lt;a href=&quot;https://medium.com/gulpjs/announcing-gulp-v5-c67d077dbdb7&quot;&gt;Gulp v5&lt;/a&gt;: разработчикам пришлось отказаться или взять под своё крыло заброшенные зависимости, многое переписать (вызывает чувство уважения с лёгким налётом тщетности бытия)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mattboldt/typed.js/&quot;&gt;typed.js&lt;/a&gt; — либа для анимации печатающегося текста&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JS-DevTools/npm-publish&quot;&gt;npm-publish&lt;/a&gt; — публикация npm-пакетов из GitHub Actions при изменении версии пакета&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://runjs.app/&quot;&gt;runJS&lt;/a&gt; — песочница для написания JS- или TS-кода с одновременным выводом результата рядом (как будто каждая строка выводится в консоль, только прямо рядом с кодом, без переключения контекста)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.lydiahallie.com/blog/promise-execution&quot;&gt;визуальный гайд по работе промисов&lt;/a&gt;, из которого можно узнать, что «колбек» на резолве промисов записывается в поле &lt;code&gt;[[PromiseFulfillReactions]]&lt;/code&gt; и что «макротасков» нет, а есть просто таски&lt;/li&gt;
&lt;li&gt;если вы захотите &lt;a href=&quot;https://dev.to/shreshthgoyal/a-guide-to-building-cli-tools-in-javascript-28nn&quot;&gt;на JS собрать CLI-программу&lt;/a&gt;, то это можно сделать без всяких дополнительных библиотек на коленке с помощью файла &lt;code&gt;index.js&lt;/code&gt; со строкой &lt;code&gt;#!/usr/bin/env node&lt;/code&gt;, а также запуска через поле &lt;code&gt;package.json&lt;/code&gt; &lt;code&gt;&quot;bin&quot;: { &quot;setup-project&quot;: &quot;./index.js&quot; }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;а почему бы нам не добавить реактивности в JS, подумали двое ребят и отправили &lt;a href=&quot;https://github.com/proposal-signals/proposal-signals&quot;&gt;пропоузал сигналов в JS&lt;/a&gt;, чтобы можно было создавать &lt;code&gt;new Signal.State&lt;/code&gt; и &lt;code&gt;Signal.Computed&lt;/code&gt;: внутри рантайма это будет лучше по перфомансу и возможно даже будет интегрировано с DOM (уууу, ну уже тогда проклятому Реакту точно конец!)&lt;/li&gt;
&lt;li&gt;каждая версия Реакта как приход весны: старые хуки перерождаются в новые и жизнь фреймворка выходит на новый круг (&lt;a href=&quot;https://github.com/facebook/react/pull/28491&quot;&gt;useFormState умер, да здравствует useActionState&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;в Реакте &lt;a href=&quot;https://habr.com/ru/articles/804187/&quot;&gt;при задании значений по умолчанию в аргументах&lt;/a&gt; не стоит использовать массивы и объекты, так как каждый раз это будет ссылкой на новый объект, то есть пропсы будут меняться и компонент ререндериться&lt;/li&gt;
&lt;li&gt;попытки ограничить типами передаваемые в &lt;code&gt;children&lt;/code&gt; элементы в Реакте заранее обречены, так как &lt;a href=&quot;https://www.totaltypescript.com/type-safe-children-in-react-and-typescript&quot;&gt;все элементы будут всё равно безликими JSX.Element&lt;/a&gt;, поэтому если нужен контроль за передаваемыми внутрь компонента данными, лучше воспользоваться пропами&lt;/li&gt;
&lt;li&gt;в браузерах &lt;a href=&quot;https://www.sabatino.dev/bfcache-explained/&quot;&gt;есть механизм bfcache&lt;/a&gt;, который позволяет при переходе &lt;strong&gt;b&lt;/strong&gt;ack и &lt;strong&gt;f&lt;/strong&gt;orward загружать страницу не повторно по сети, а из хранящегося снепшота в памяти (чек window pageshow по &lt;code&gt;event.persisted&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;как на &lt;a href=&quot;https://robinrendle.com/the-cascade/017-how-to-kill-the-cascade/&quot;&gt;@scope, :scope и all: revert-layer&lt;/a&gt; собрать инкапсуляцию стилей в компонентах: как обычно в CSS — многословно, но нативно&lt;/li&gt;
&lt;li&gt;как на &lt;code&gt;:root:has(select option[value=&quot;dark&quot;]:checked)&lt;/code&gt; &lt;a href=&quot;https://www.smashingmagazine.com/2024/03/setting-persisting-color-scheme-preferences-css-javascript/&quot;&gt;собрать современный переключатор светлой/тёмной темы сайта&lt;/a&gt; с сохранением в localstorage&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/css-container-query-guide/&quot;&gt;интерактивный гайд по container queries&lt;/a&gt;, в котором приводится много юзкейсов примеров использования единиц измерения от «контейнера», а также перечислены ограничения: если блок объявлен как container, то он не может иметь одновременно лейаут грида/флексбокса; container нельзя использовать в query для самого себя, для этого должен быть отдельный элемент&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;marquee&amp;gt;&lt;/code&gt; хоть и давно задепрекейчен, «бесконечные» движущиеся полосы в дизайнах с нами, думаю, навсегда, поэтому &lt;a href=&quot;https://www.smashingmagazine.com/2024/04/infinite-scrolling-logos-html-css/&quot;&gt;можно научиться их реализовывать&lt;/a&gt; с помощью задержки анимации &lt;code&gt;margin-left&lt;/code&gt; для каждого отдельного элемента&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://performance.shopify.com/blogs/blog/how-to-optimize-cumulative-layout-shift-cls-on-shopify-sites&quot;&gt;как улучшить метрику CLS&lt;/a&gt;: предустанавливать размеры для картинок и для мест с инжектящимся контентом, не загружать лениво CSS в зоне видимого интерфейса, не анимировать &lt;code&gt;top&lt;/code&gt;/&lt;code&gt;left&lt;/code&gt;, подбирать подходящие фолбек-шрифты&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 19.04.2024</title><link>https://juwain.github.io/web-platform/blog/2024-04-19/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-04-19/</guid><description>Новости веб-платформы</description><pubDate>Fri, 19 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/124&quot;&gt;обновления Chrome 124&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;возможность фокусироваться клавиатурой на скроллер&lt;/li&gt;
&lt;li&gt;атрибут &lt;code&gt;writingsuggestions&lt;/code&gt; для включения/отключения браузерных подсказок при запонении полей&lt;/li&gt;
&lt;li&gt;заголовок &lt;code&gt;priority&lt;/code&gt; для HTTP&lt;/li&gt;
&lt;li&gt;блок рендера страницы с помощью &lt;code&gt;rel=expect&lt;/code&gt; у ссылок, пока гарантировано не загрузится нужный элемент&lt;/li&gt;
&lt;li&gt;новый WebSocketStream API, фиксящий недостатки WebSocket API&lt;/li&gt;
&lt;li&gt;методы &lt;code&gt;setHTMLUnsafe&lt;/code&gt; и &lt;code&gt;parseHTMLUnsafe&lt;/code&gt; для доступа к декларативному shadow DOM из JS&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pageswap&lt;/code&gt; эвент для реакции на переход по View Transitions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/15260/release-notes-for-safari-technology-preview-192/&quot;&gt;обновления Safari TP 192&lt;/a&gt;: поддержаны View Transitions API, &lt;code&gt;URL.parse()&lt;/code&gt;, внесены багфиксы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/125&quot;&gt;обновления Firefox 125&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;align-content&lt;/code&gt; в добавок к гридам и флексбоксам теперь работает и с &lt;code&gt;display: block&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержан &lt;code&gt;Intl.Segmenter&lt;/code&gt; и Popover API&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/blog/next-14-2&quot;&gt;обновления Next.js до версии 14.2&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;продолжено впиливание Turbopack&lt;/li&gt;
&lt;li&gt;улучшен тришейкинг и потребление памяти при билде&lt;/li&gt;
&lt;li&gt;CSS-чанки теперь подключатся в порядке импортов (странно, что это было не так)&lt;/li&gt;
&lt;li&gt;появились более явные сообщения об ошибках&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;рендер JSX в следующей версии React &lt;a href=&quot;https://github.com/facebook/react/pull/28768&quot;&gt;обещает быть быстрее&lt;/a&gt; за счёт отказа от клона объекта пропсов в пользу прокидывания его напрямую&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://svgencode.com/&quot;&gt;svgencode&lt;/a&gt; — энкодер SVG в URL, base64 и другие вариации (раньше пользовался &lt;a href=&quot;https://yoksel.github.io/url-encoder/&quot;&gt;энкодером от yoksel&lt;/a&gt;, но этот помощнее)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Hacker0x01/react-datepicker&quot;&gt;react-datepicker&lt;/a&gt; — доступный, фичастый реакт дейтпикер-компонент&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/shuding/next-view-transitions&quot;&gt;next-view-transitions&lt;/a&gt; — View Transitions API для Next.js App Router (в догонку ко всем, кто уже внедрил у себя VT)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://markdowndown.vercel.app/&quot;&gt;markdowndown&lt;/a&gt; — инструмент для скачивания любого сайта в виде md&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshwcomeau.com/react/css-in-rsc/&quot;&gt;как быть со StyledComponents в React Server Components&lt;/a&gt;: на сервере context не поддерживается, поэтому SC не могут работать, в принципе; альтернативно можно перейти на compile-time-библиотеки с похожим API — Linaria, Panda CSS или Pigment CSS (основанный на либе, выросшей из Linaria — &lt;a href=&quot;https://github.com/Anber/wyw-in-js&quot;&gt;wyw-in-js&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jsbin.com/safoqap/6/edit?html,output&quot;&gt;песочница&lt;/a&gt;, чтоб поиграть с предложенным Signal API в JS (поиграл, ощущения приятные)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/officialanurag/javascript-secrets-how-to-implement-retry-logic-like-a-pro-g57&quot;&gt;подходы к написанию логики retry&lt;/a&gt;: можно увеличивать время повторного запроса по экспоненте, линейно, рандомно, просто фиксировать задержку или обойтись вовсе без неё&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mxstbr.com/thoughts/graphql/&quot;&gt;в каких случаях (не) нужен GraphQL&lt;/a&gt;: клиенты ломаются при смене API; долгое время загрузки из-за каскадных запросов; сложность поддержки множественных эндпойнтов; нужна тонкая настройка перфоманса и безопасности&lt;/li&gt;
&lt;li&gt;создатели xState отпилили от него лишнее и получился… &lt;a href=&quot;https://stately.ai/blog/2024-04-10-xstate-store&quot;&gt;новый стейт-менеджер @xstate/store&lt;/a&gt;, основанный на событийной модели&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://csspro.com/css-gradients&quot;&gt;галерея копипаст-градиентов&lt;/a&gt;: линейные, круговые и серобуроказявчатые&lt;/li&gt;
&lt;li&gt;в каких ситуациях &lt;a href=&quot;https://frontendmasters.com/blog/things-that-can-break-aspect-ratio-in-css/&quot;&gt;может не сработать aspect-ratio&lt;/a&gt;: когда заданы явно оба размера, блок растягивает флекс-контейнер, что-то форсит расчёт естественной высоты блока&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.37signals.com/modern-css-patterns-and-techniques-in-campfire/&quot;&gt;современные CSS-фишечки в Campfire&lt;/a&gt;, используются:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;oklch&lt;/code&gt; для высчитывания оттенков цветов&lt;/li&gt;
&lt;li&gt;кастомные свойства в фолбеках кастомных свойств &lt;code&gt;color&lt;/code&gt;: &lt;code&gt;var(--btn-color&lt;/code&gt;, &lt;code&gt;var(--color-text))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:has&lt;/code&gt; для определения наличия внутренних элементов &lt;code&gt;:where(:not([open]):has(.unread))&lt;/code&gt; или их количества &lt;code&gt;:where(:has(&amp;gt; :last-child:nth-child(2))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;единственное медиавыражение &lt;code&gt;@media (max-width: 100ch); any-hover: hover&lt;/code&gt; для определения нетач-девайсов&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;как попап об использовании кукис &lt;a href=&quot;https://www.speedcurve.com/blog/web-performance-cookie-consent/&quot;&gt;может навредить перфомансу&lt;/a&gt;: на самом деле относится к любому попапу или всплывающему элементу: скрипты/стили попапа могут загружать основной поток, хотя это явно должно грузиться асинхронно; поисковой робот может неверно определить LCP-элемент (вместо контента самого сайта — баннер или попап); попап может двигать контент (нехорошо для CLS)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/devtools-tips-tricks/&quot;&gt;подборка фишек дев-тулзов&lt;/a&gt;: обычно в таких списках всё уже известно, но также попадается 1-2 фишки, которые прям вау; так и в этой статье нашлось кое-что новое интересное — эмуляция фокуса на странице (чтобы при переходе в дев-тулзы не закрывался ховер-элемент) и logpoints — &lt;code&gt;console.log&lt;/code&gt;, который можно назначить на строке прям из дебаггера&lt;/li&gt;
&lt;li&gt;оказывается, &lt;a href=&quot;https://textslashplain.com/2024/04/10/browser-security-bugs-that-arent-javascript-in-pdf/&quot;&gt;внутрь PDF можно встраивать JS by design&lt;/a&gt;, который можно использовать, например, для XSS-атаки (к счастью, в браузере можно запретить исполнение JS в PDF)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Про платформу</title><link>https://juwain.github.io/web-platform/blog/2024-04-23/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-04-23/</guid><description>Про платформу</description><pubDate>Tue, 23 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Представьте, что завтра вы проснётесь, а горячо любимый всеми нами telegram перестанет работать или объявят, что он теперь только платный или что-то ещё с ним произойдёт такого, что вы вынуждены будете перестать им пользоваться.&lt;/p&gt;
&lt;p&gt;Например, гендир telegram решит отойти от дел и прикрыть лавочку, так как все доступные средства освоены, а новых не нашли, или уволятся ключевые разработчики.&lt;/p&gt;
&lt;p&gt;Все подписки на блоги, бережно отсортированные папки и сохранёнки больше станут недоступны. Ощущения так себе, куда идти, что читать? Не в Твиттер же 😅&lt;/p&gt;
&lt;p&gt;Мы находимся в большущем вендор-локе, и это само по себе печально. Вдвойне печально, что мы читаем тексты (в том числе рекламные), оформление которых заточено под проприетарное ПО. Часто оформление тестов скудное или неудобное, кроме того случаются баги. Хотя, на минуточку, у нас есть бесплатный веб с его HTML, CSS и JS для абсолютно любой стилизации и добавления интерактивности в контент.&lt;/p&gt;
&lt;p&gt;А представьте, если бы вместо того, чтобы заводить новый канал автор бы создавал свой блог в вебе? И чтобы была такая технология, чтобы можно было в одном приложении собирать посты со всех блогов, которые вам интересны, а также чтобы можно было и комментировать, ставить реакции, вот это всё.&lt;/p&gt;
&lt;p&gt;Беда в том, что у веба самого по себе никогда не было хороших продуктологов. Вот которые бы придумывали новые фичи самого веба. Как мы пользуемся вебом, взаимодействуем с другими пользователями веба, чтобы это было свежо и интересно. Такое ощущение, что веб принадлежит всем, но в то же время никем не овнится. Если речь идёт про взаимодействие, то мы уходим в определённый сервис, но у нас мало или нет фич самого веба хотя бы для взаимодействия друг с другом.&lt;/p&gt;
&lt;p&gt;Окей, частично функцию развития веба выполняют вендоры браузеров, но у них своя повестка и заработок (продажа рекламы вам и ваших данных рекламодателям).&lt;/p&gt;
&lt;p&gt;Окей, есть W3C, какие-то ещё комитеты и члены, которые придумывают протоколы того, как машинам общаться с машинами — это именно технари, они не овнят веб как продукт для людей. Это скорее про техническую составляющую: как технарям хорошо делать так, чтобы машины успешно общались с другими машинами.&lt;/p&gt;
&lt;p&gt;Окей, есть электронная почта, а также когда-то был популярным RSS — это когда контент сайта публиковался в определённом XML-формате и у вас был приёмник, который подсасывал все обновления с интересующих вас сайтов. Это было в целом удобно, но ограничено вашим личным опытом взаимодействия с контентом в вебе (как и сам «веб-сёрфинг»). То есть нельзя было прямо в RSS-ридере пообщаться с другими читателями этой же ленты.&lt;/p&gt;
&lt;p&gt;Может быть бы RSS и развился дальше во что-то такое, но его сначала придушили поисковики (Google выгоднее, чтобы вы гуглили что-то в интернете и переходили на сайты, а не собирали инфу себе в Google Reader) и потом заменили соцсети.&lt;/p&gt;
&lt;p&gt;Гугл, справедливости ради, пытался в эту сторону. Некоторое время просуществовал Google Wave, но, к сожалению, он появился слишком рано, чтобы выстрелить. Но если сейчас на него взглянуть, то можно узнать то, что мы сейчас видим, например, в telegram: мессенджер, треды, комменты. Даже мультиредактирование было. 🙂 Уже не помню, был ли там прикручен RSS, чтобы совместно читать одну ленту с другими пользователями.&lt;/p&gt;
&lt;p&gt;К слову, потом, в эру зарождения соцсетей, Гугл делал заход со своим Google+, но не зашло. Кажется, что тот раз было уже слишком поздно. Да и идеи были заложены вторичные, заливание баблом не помогло.&lt;/p&gt;
&lt;p&gt;В общем, так и живём тут, хотя могли бы огого!&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 03.05.2024</title><link>https://juwain.github.io/web-platform/blog/2024-05-03/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-03/</guid><description>Новости веб-платформы</description><pubDate>Fri, 03 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blogs.windows.com/msedgedev/2024/04/29/deprecating-ms-high-contrast/&quot;&gt;из MS Edge будут выпилилены свойства&lt;/a&gt; &lt;code&gt;-ms-high-contrast media&lt;/code&gt; и &lt;code&gt;-ms-high-contrast-adjust&lt;/code&gt; в угоду стандартным медиа-фичам &lt;code&gt;forced-colors&lt;/code&gt; и &lt;code&gt;prefers-color-scheme&lt;/code&gt;, а также свойству &lt;code&gt;forced-color-adjust&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react/releases/tag/v18.3.0&quot;&gt;вышел React v18.3.0:&lt;/a&gt; добавились ворнинги на задепрекейченые фичи в React и React DOM&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/2024-04-29-github-copilot-workspace/&quot;&gt;анонсирован GitHub Copilot Workspace:&lt;/a&gt; (утопичная) идея сделать некую среду, в которой можно будет на натуральном языке планировать, обсуждать, писать, отлаживать и тестировать программы&lt;/li&gt;
&lt;li&gt;у Bun вышло обновление с &lt;a href=&quot;https://bun.sh/blog/bun-report-is-buns-new-crash-reporter&quot;&gt;новым crash reporter-ом,&lt;/a&gt; из интересного: идея в один 150-байтный URL запихнуть платформу, хэш коммита, стэк трейсы, сообщение и тип ошибки: малочитаемо, но зато очень коротко&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-5-beta/&quot;&gt;TypeScript 5.5 Beta:&lt;/a&gt; TS научился выводить тайпгарды самостоятельно, появился импорт типов JSDoc в js-файлах и встроенная проверка регулярок, упрощен импорт es-модулей из пакета typescript для Ноды, опция &lt;code&gt;isolatedDeclarations&lt;/code&gt; для изолированной компиляции d.ts, задепрекечена часть вещей&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-spectrum.adobe.com/releases/2024-05-01.html&quot;&gt;обновился кит React Spectrum и Aria:&lt;/a&gt; добавлены компоненты вложенного меню, дропзоны, инпут-файла, а также компоненты для работы с цветом (пикер, ареа, слайдер, колесо)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://svelte.dev/blog/svelte-5-release-candidate&quot;&gt;вышел release candidate Svelte 5:&lt;/a&gt; для тех, кто использует Svelte 4, всё будет будет работать быстрее, а для тех, кто использует Svelte 3, сначала рекомендуют обновиться до Svelte 4&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://extension.js.org/&quot;&gt;extension&lt;/a&gt; — либа для разработки браузерных расширений, достаточно простая, чтобы запустить своё расширение командой npx extension &lt;code&gt;create &amp;lt;your-extension-name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react-spring-visualizer.com/&quot;&gt;react-spring-visualizer&lt;/a&gt; — визуализатор анимации либы &lt;a href=&quot;https://www.react-spring.dev/&quot;&gt;react-spring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yaireo.github.io/tagify/&quot;&gt;tagify&lt;/a&gt; — компонент тегов в инпуте и текстарии, умеет в поиск, сортировку, кастомизацию&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;как улучшить читаемость кода, вынеся подробности имплементации API &lt;a href=&quot;https://profy.dev/article/react-architecture-api-layer-and-fetch-functions&quot;&gt;в отдельный архитектурный слой:&lt;/a&gt; было — &lt;code&gt;apiClient.get&amp;lt;UserResponse&amp;gt;(\&lt;/code&gt;/user/${handle}`)&lt;code&gt;, стало — &lt;/code&gt;UserApi.getUser(handle)`&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://javascript.plainenglish.io/react-19-beta-release-a-quick-guide-05678e2ed571&quot;&gt;туториал по новым фичам нового Реакта:&lt;/a&gt; особо хорошо выглядит use&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/05/01/when-to-use-bun-instead-of-nodejs.html&quot;&gt;когда использовать Bun вместо Node:&lt;/a&gt; если важен перф; когда нужен швейцарский нож (раннер, пакетный менеджер, тест-раннер и бандлер в одном); когда не хочется заморачиваться с импортами, а хочется, чтобы просто работало; когда нужна встроенная БД SQLite&lt;/li&gt;
&lt;li&gt;объяснена тайна века, как же всё таки работает &lt;a href=&quot;https://www.jameskerr.blog/posts/javascript-sort-comparators/&quot;&gt;array.sort((a, b) =&amp;gt; b - a):&lt;/a&gt; функция нужна, чтобы понять куда уйдёт a на числовой прямой, вправо и влево&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/devmount/building-a-static-site-generator-in-3-steps-72e&quot;&gt;как собрать на коленке свой шаблонизатор&lt;/a&gt; на HTML и .sh, «потому что могу»&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sitepoint.com/fluid-typography-css-clamp-function/&quot;&gt;респонсив размеры шрифта&lt;/a&gt; с помощью &lt;code&gt;clamp()&lt;/code&gt;: хорошо — &lt;code&gt;clamp(1rem, 2.5vw, 3rem)&lt;/code&gt;, ещё лучше — &lt;code&gt;clamp(1rem, calc(2.5vw + 1rem), 3rem)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;реализация &lt;a href=&quot;https://ishadeed.com/article/tree-view-css-indent/&quot;&gt;боковых отступов в древовидном компоненте:&lt;/a&gt; проще всего добавить пустой элемент-спейсер с динамической шириной &lt;code&gt;--spacer-col: max(8px, var(--level) * 8px)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cruncher.ch/blog/printing-music-with-css-grid/&quot;&gt;отрисовка нот в гридовой сетке:&lt;/a&gt; SVG с data-атрибутами вписывается и раскладывается по рядам и колонкам&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fullystacked.net/prefix/&quot;&gt;вендорные префиксы&lt;/a&gt; для каких свойств ещё остались актуальны (можно пересчитать на пальцах рук)&lt;/li&gt;
&lt;li&gt;оказывается можно управлять порядком отрисовки &lt;code&gt;fill&lt;/code&gt; и &lt;code&gt;stroke&lt;/code&gt; &lt;a href=&quot;https://codepen.io/argyleink/pen/MWoeoKV&quot;&gt;с помощью свойства paint-order: stroke fill&lt;/a&gt; (по умолчанию рисуется &lt;code&gt;fill&lt;/code&gt; → &lt;code&gt;stroke&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;официальное разрешение от Гугла: &lt;a href=&quot;https://web.dev/blog/popover-api&quot;&gt;использовать popover API теперь можно!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;великая проблема компьютерных наук — &lt;a href=&quot;https://habr.com/ru/companies/ruvds/articles/810311/&quot;&gt;центрирование элементов&lt;/a&gt; (если вы думаете, что проблема в CSS или вебе, то это не так: те же проблемы есть и у дизайнеров, и в нативной платформе)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 26.04.2024</title><link>https://juwain.github.io/web-platform/blog/2024-04-26/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-04-26/</guid><description>Новости веб-платформы</description><pubDate>Fri, 26 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pnpm/pnpm/releases/tag/v9.0.0&quot;&gt;обновился pnpm до версии v9.0.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;дропнули поддержку Node.js v16 и 17 (кстати, у pnpm есть standalone-версия с нодой прямо в бандле)&lt;/li&gt;
&lt;li&gt;добавлена совместимость с Corepack&lt;/li&gt;
&lt;li&gt;обновлены параметры конфигов и изменён формат лок-файлов (для более лучшего разрешения git-конфликтов)&lt;/li&gt;
&lt;li&gt;улучшен процесс разрешения вложенных зависимостей&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/announcements/v22-release-announce&quot;&gt;выпущена Node.js 22&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;обновлён V8&lt;/li&gt;
&lt;li&gt;появился синхронный &lt;code&gt;require()&lt;/code&gt; ESM-модулей пока за флагом&lt;/li&gt;
&lt;li&gt;добавлена команда &lt;code&gt;node --run&lt;/code&gt; для запуска скриптов из &lt;code&gt;package.json&lt;/code&gt; в обход npm и встроенный вотчер изменений файлов &lt;code&gt;node --watch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержка WebSocket выведена из-под флага&lt;/li&gt;
&lt;li&gt;в &lt;code&gt;node:fs&lt;/code&gt; добавлены паттерн-матчеры &lt;code&gt;glob&lt;/code&gt; и &lt;code&gt;globSync&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://privacysandbox.com/intl/en_us/news/update-on-the-plan-for-phase-out-of-third-party-cookies-on-chrome/&quot;&gt;обещанная блокировка 3d-party cookies&lt;/a&gt; в Chrome откладывается на конец года: сообщество и британская антимонопольная служба проверяет эту прекрасную затею&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2024/04/eslint-v9.1.0-released/&quot;&gt;первый минорный апдейт в ESLint v9.1.0&lt;/a&gt;: в основном багфиксы, но печаль в том, что плагинная экосистема ещё совсем не готова к новому формату, переход будет долгим&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/blog/2024/04/25/react-19&quot;&gt;вышла React 19 Beta&lt;/a&gt;: всё, что обещали раньше (&lt;code&gt;useTransition&lt;/code&gt;, &lt;code&gt;useActionState&lt;/code&gt;, &lt;code&gt;useFormStatus&lt;/code&gt;, &lt;code&gt;useOptimistic&lt;/code&gt;, &lt;code&gt;use&lt;/code&gt;, ref as a prop, &lt;code&gt;&amp;lt;Context&amp;gt;&lt;/code&gt; as a provider, поддержка &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt;-тегов, API для предзагрузки &lt;code&gt;prefetchDNS&lt;/code&gt;, &lt;code&gt;preconnect&lt;/code&gt;, &lt;code&gt;preload&lt;/code&gt;, &lt;code&gt;preinit&lt;/code&gt;), а также вроде как новое: сleanup functions for refs, &lt;code&gt;useDeferredValue&lt;/code&gt;, атрибут &lt;code&gt;precedence&lt;/code&gt; для &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; (вроде как нестандартный), поддержка асинхронных скриптов и кастомных элементов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://biomejs.dev/blog/biome-v1-7/&quot;&gt;выпущен Biome v1.7&lt;/a&gt; (форматтер и линтер, 2 в 1): включает тулу для миграции с ESLint и Prettier (соблазнительно в момент, когда ESlint в переходном состоянии)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://catamphetamine.gitlab.io/react-phone-number-input/&quot;&gt;react-phone-number-input&lt;/a&gt; — инпут для ввода телефонного номера в различных международных форматах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/uNmAnNeR/imaskjs&quot;&gt;imaskjs&lt;/a&gt; — ещё один «маскировщик» инпутов, но уже более широкого формата: есть даты, адреса, деньги&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/guides/front-end-handbook/2024/&quot;&gt;The Front End Developer/Engineer Handbook 2024&lt;/a&gt; — большой сборник по современным технологиям фронтенда: помню, что в 2018-2019 часто к нему прибегал, когда составлял карты обучения&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/andrewcourtice/ripl&quot;&gt;ripl&lt;/a&gt; — общий API для создания 2d-графики в SVG и canvas&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gemini-testing/testplane&quot;&gt;testplane&lt;/a&gt; (aka Hermione) — браузерное тестирование с mocha и WebdriverIO на борту&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Rich-Harris/devalue&quot;&gt;devalue&lt;/a&gt; — &lt;code&gt;JSON.stringify&lt;/code&gt;, который не ломается на циклических референсах, &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;Infinity&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt;, &lt;code&gt;-0&lt;/code&gt;, датах, &lt;code&gt;Map&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt; и &lt;code&gt;BigInt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jakearchibald.com/2024/attributes-vs-properties/&quot;&gt;атрибуты и свойства DOM-элементов&lt;/a&gt; — разные вещи: атрибуты сериализуются, свойства могут быть любого типа, атрибуты нечувствительны к кейсу; иногда изменения свойств отражаются в атрибуты, иногда нет; в целом, атрибуты — для конфигурации, а свойства — для хранения состояния&lt;/li&gt;
&lt;li&gt;пропоузал &lt;a href=&quot;https://thenewstack.io/did-signals-just-land-in-react/&quot;&gt;TC39 signals завернули в Реакт-хук&lt;/a&gt; и сравнили с &lt;code&gt;useState&lt;/code&gt;: даже сейчас уже выглядит приятно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/orgs/web-infra-dev/discussions/17&quot;&gt;как работает тришейкинг в Webpack&lt;/a&gt;: местами непонятно, но суть улавливается&lt;/li&gt;
&lt;li&gt;Райан Даль настойчиво &lt;a href=&quot;https://deno.com/blog/jsr-is-not-another-package-manager&quot;&gt;зовёт вас воспользоваться JSR&lt;/a&gt;, новым npm-совместимым реестром (esm-only, ts-first), обещает, что не придётся жонглировать package.json и tsconfig, так как всё заработает само&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;для определения включенности скриптов есть &lt;a href=&quot;https://ryanmulligan.dev/blog/detect-js-support-in-css/&quot;&gt;@media (scripting: enabled | none)&lt;/a&gt; (если вы считаете, что такое ещё возможно в современном вебе)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/15269/help-us-invent-masonry-layouts-for-css-grid-level-3/&quot;&gt;плиточная раскладка (masonry)&lt;/a&gt; — это всё же часть гридов или отдельный вариант &lt;code&gt;display&lt;/code&gt;? Вот и разработчики не могут выбрать и просят вас помочь&lt;/li&gt;
&lt;li&gt;с помощью режимов наложения &lt;a href=&quot;https://javier.xyz/blog/motion-extraction-with-mostly-css&quot;&gt;mix-blend-mode: difference и plus-lighter&lt;/a&gt;, применённых к видео, можно детектить движение&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;напоминание, как &lt;a href=&quot;https://cloudfour.com/thinks/write-alt-text-like-youre-talking-to-a-friend/&quot;&gt;писать alt к изображениям&lt;/a&gt;: представьте, что картинка — это часть окружающего текста и опишите содержимое картинки (не нужно писать, что это картинка; лучше включить знаки препинания; в декоративных изображениях &lt;code&gt;alt&lt;/code&gt; не стоит писать; &lt;code&gt;alt&lt;/code&gt; можно не писать, если рядом уже есть текст содержимого картинки, например, имя пользователя)&lt;/li&gt;
&lt;li&gt;использование атрибута &lt;a href=&quot;https://adamsilver.io/blog/dont-use-the-maxlength-attribute-to-stop-users-from-exceeding-the-limit/&quot;&gt;maxlength у инпутов — антипаттерн&lt;/a&gt;: текст обрезается, иногда сложно угадать точное количество символов, которые обрезать безопасно; вместо этого лучше показать ошибку о превышении длины&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;если взять страницу с 1mb HTML, CSS и JS, а потом открыть её по 3G, то только на соединение и парсинг потратится 0.5s (&lt;a href=&quot;https://vercel.com/blog/latency-numbers-every-web-developer-should-know&quot;&gt;также приводятся другие метрики&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 10.05.2024</title><link>https://juwain.github.io/web-platform/blog/2024-05-10/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-10/</guid><description>Новости веб-платформы</description><pubDate>Fri, 10 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v22.1.0&quot;&gt;выпущена Node v22.1.0&lt;/a&gt;: появилась поддержка &lt;code&gt;NODE_COMPILE_CACHE&lt;/code&gt; для включения режима кеширования V8 (если граф модулей не меняется, то повторная пересборка становится быстрее за счёт кэша)&lt;/li&gt;
&lt;li&gt;только недавно в Next.js решили не патчить &lt;code&gt;fetch&lt;/code&gt;, как в &lt;a href=&quot;https://twitter.com/acdlite/status/1785691330988986587&quot;&gt;React решили патчить Date&lt;/a&gt;: «мы по-тихому, никому мешать не будем, со стандартами будет совместимо, вы же полифиллы используете, вот и дату норм пропатчить»; вроде так, но есть нюанс: в случае полифиллов добавляются костыли для воссоздания недостающих стандартных возможностей платформы, а фича-патчи добавляют проприетарные костыли, что уже не то же самое&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dai-shi/react-tracked&quot;&gt;react-tracked&lt;/a&gt; — представьте, что у вас есть &lt;code&gt;useState/useReducer&lt;/code&gt;, которые триггерят ререндеры не всегда, когда стейт перезадался, а когда он именно изменился, стал другим (под капотом Proxy, работает для вложенных уровней стейта тоже)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://atlassian.design/components/pragmatic-drag-and-drop/about&quot;&gt;pragmatic-drag-and-drop&lt;/a&gt; — многообещающая либа для драг-н-дропа (для травмированных React DnD)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kettanaito.com/blog/why-patching-globals-is-harmful&quot;&gt;почему таки плохо патчить globals&lt;/a&gt;: автоматом создаёт техдолг, нестандартные фичи работают непредсказуемо в разных средах, скрывают магию внутри, лочат на вендора и в целом тормозят прогресс в долгую&lt;/li&gt;
&lt;li&gt;Bun может ускорить не только локальную разработку, но и сборку и деплой на CI, так как, &lt;a href=&quot;https://render.com/blog/hello-bun-deploy-2x-faster-on-github-render&quot;&gt;например&lt;/a&gt;, заменяет yarn и Vitest&lt;/li&gt;
&lt;li&gt;(не совсем JS, но это не так важно) как разложить &lt;a href=&quot;https://testing.googleblog.com/2024/04/isbooleantoolongandcomplex.html&quot;&gt;одно нечитаемое условное выражение&lt;/a&gt; на несколько мелких или же вынести в отдельную функцию&lt;/li&gt;
&lt;li&gt;чтоб не оборачивать &lt;code&gt;new URL(urlstring)&lt;/code&gt; в &lt;code&gt;try catch&lt;/code&gt; для &lt;a href=&quot;https://kilianvalkhof.com/2024/javascript/the-problem-with-new-url-and-how-url-parse-fixes-that/&quot;&gt;обработки невалидных урлов&lt;/a&gt;, можно использовать &lt;code&gt;URL.canParse(urlstring)&lt;/code&gt;, а также скоро можно будет &lt;code&gt;URL.parse&lt;/code&gt; (начиная с Chrome 126 и Firefox 126)&lt;/li&gt;
&lt;li&gt;React хорош для организации UI-компонентов, но когда речь заходит про дата-фетчинг, то всё что предлагает React из коробки — это выйти в окно; и в этом случае &lt;a href=&quot;https://ui.dev/why-react-query&quot;&gt;на помощь приходит React Query&lt;/a&gt;, который позаботится о кэшировании, оффлайне, восстановлении скролла и тд, чтобы вы спокойно могли с чистой совестью выключить компьютер в конце рабочего дня&lt;/li&gt;
&lt;li&gt;лучший способ гарантировано отправить неблокирующий запрос при закрытии страницы — &lt;a href=&quot;https://webdeveloper.beehiiv.com/p/securely-send-request-closing-tabs&quot;&gt;на событии visibilitychange выполнить navigator.sendBeacon()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;возможно для управления версиями Node стоит попробовать &lt;a href=&quot;https://pavel-romanov.com/5-node-version-managers-compared-which-is-right-for-you&quot;&gt;альтернативы nvm&lt;/a&gt;: самой перспективной выглядит Volta, которая не требует доп файлов (конфиг в package.json), кроссплатформенна, автопереключает версию при смене проекта, а заодно может переключать версию yarn&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;как-то незаметно в повседневной разработке мы перестали думать про минификацию стилей, тк &lt;a href=&quot;https://blog.sentry.io/why-dont-we-talk-about-minifying-css/&quot;&gt;эту функцию взяли на себя фреймворки&lt;/a&gt;, хотя [олдфаг mode on] раньше было почему-то важно считать сколько десятков килобайт умеет сэкономить твой минификатор [олдфаг mode off]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2024/05/05/misconceptions-about-css-specificity/&quot;&gt;мифы про специфичность&lt;/a&gt;:
&lt;ol&gt;
&lt;li&gt;специфичность — это не целое число, а набор из трёх чисел a, b, c&lt;/li&gt;
&lt;li&gt;добавление атрибута style не добавляет специфичности&lt;/li&gt;
&lt;li&gt;!important не добавляет специфичности, а уносит объявление в другой origin&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;в мире победившего &lt;code&gt;color-mix()&lt;/code&gt;-а серые палитры &lt;a href=&quot;https://css-irl.info/shades-of-grey-with-color-mix/&quot;&gt;создаются с помощью полутона&lt;/a&gt; между чёрным и белым &lt;code&gt;color-mix(in oklch, black 20%, white)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bradfrost.com/blog/post/transparent-borders/&quot;&gt;border-color: transparent — это ок&lt;/a&gt;, если, например, на hover задавать видимый цвет, чтобы при задании рамки не изменялись размеры элемента&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:has()&lt;/code&gt; — это не только «родительский» селектор, но и &lt;a href=&quot;https://www.smashingmagazine.com/2024/05/combining-css-has-html-select-conditional-styling/&quot;&gt;полноценный условный оператор для элементов интерфейса&lt;/a&gt;, например, для &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; (красим &lt;code&gt;select&lt;/code&gt; в зависимости от выбранного значения) или же для всего интерфейса (красим весь сайт в зависимости от выбранного значения (сомнительно))&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://noahliebman.net/2024/03/making-room-for-long-list-markers-with-subgrid/&quot;&gt;субгриды в помощь&lt;/a&gt; для контроля за переполнением дочерних ячеек грида на примере нумерации в упорядоченных списках&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/using-the-popover-api-for-html-tooltips/&quot;&gt;Popover API для создания тултипов&lt;/a&gt;, якорящихся на элемент-триггер (сложно, но возможно)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;разработчики React Aria поделились, как &lt;a href=&quot;https://react-spectrum.adobe.com/blog/creating-a-pointer-friendly-submenu-experience.html&quot;&gt;сделать человеческое выпадающее субменю&lt;/a&gt;, чтобы оно случайно не закрывалось во время движения курсора: строится визуальный треугольник, в рамках которого считается, что подменю не должно быть скрыто + по скорости движения предполагается, куда пользователь собрался двигать курсор&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Про Flex</title><link>https://juwain.github.io/web-platform/blog/2024-05-14/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-14/</guid><description>А это React и TypeScript моей молодости, внучок</description><pubDate>Tue, 14 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;./assets/photo_2025-01-15_18.24.49.jpeg&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;А это React и TypeScript моей молодости, внучок! 👨‍🦳&lt;/p&gt;
&lt;p&gt;Если серьёзно (и выкинуть всякую xml-требуху), то смотрите:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;типы есть;&lt;/li&gt;
&lt;li&gt;всё декларативненько;&lt;/li&gt;
&lt;li&gt;импорты «нативные»;&lt;/li&gt;
&lt;li&gt;UI-лейаут флекс-подобный резиновый был;&lt;/li&gt;
&lt;li&gt;логика отделена от UI, но собрано в одном файле;&lt;/li&gt;
&lt;li&gt;реактивность в каком-то виде, кажется, тоже была;&lt;/li&gt;
&lt;li&gt;ООП, вроде как, тоже было.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Правда загнулось вместе с флешом, но даже сейчас вызывает любопытство.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 17.05.2024</title><link>https://juwain.github.io/web-platform/blog/2024-05-17/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-17/</guid><description>Новости веб-платформы</description><pubDate>Fri, 17 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-480/&quot;&gt;вышел Astro 4.8&lt;/a&gt;: добавлена экспериментальная поддержка actions — возможность объявить методы, запускающиеся на бэкенде, и вызывать их напрямую из JS. Что сразу же мне напомнило аналогичную возможность из &lt;a href=&quot;https://ASP.NET&quot;&gt;https://ASP.NET&lt;/a&gt; образца 2008 года под названием PageMethods: это было очень удобно, а главное просто и понятно, тк серверные методы вызываются из JS напрямую, туда наглядно прокидываются нужные данные. Также добавлена экспериментальная возможность в «мидлваре» перехватывать и перенаправлять запрос на другой адрес&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/15383/webkit-features-in-safari-17-5/&quot;&gt;вышел Safari 17.5&lt;/a&gt; (третий большой апдейт в 2024): появились &lt;code&gt;text-wrap: balance&lt;/code&gt;, &lt;code&gt;color-scheme: light dark&lt;/code&gt; и &lt;code&gt;light-dark()&lt;/code&gt;, &lt;code&gt;@starting-style&lt;/code&gt;, &lt;code&gt;@import &amp;lt;url&amp;gt; supports(&amp;lt;feature&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;ситуация с неготовностью экосистемы ESLint к новой версии ESLint 9 привела к &lt;a href=&quot;https://eslint.org/blog/2024/05/eslint-compatibility-utilities/&quot;&gt;созданию особого пакета @eslint/compat&lt;/a&gt;, функцией &lt;code&gt;fixupPluginRules&lt;/code&gt; из которого можно обернуть старые плагины и обещают, что они заработают внутри 9 версии&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/learn/react-compiler&quot;&gt;вышел React Compiler&lt;/a&gt;, призванный избавить от ручного использования &lt;code&gt;useMemo&lt;/code&gt;, &lt;code&gt;useCallback&lt;/code&gt; и &lt;code&gt;memo()&lt;/code&gt;, но он как героически побеждает проблемы React, так и превносит новые проблемы с тем, что работает только в Strict-mode, несовместим с mobx, несёт чёрную магию на борту&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-125&quot;&gt;обновления Chrome 125&lt;/a&gt;: поддержан CSS Anchor Positioning, добавлены CSS-функции &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/round&quot;&gt;round()&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/mod&quot;&gt;mod()&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/rem&quot;&gt;rem()&lt;/a&gt;, а также Compute Pressure API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/blog/screen-wake-lock-supported-in-all-browsers&quot;&gt;Screen Wake Lock API&lt;/a&gt; поддерживается во всех браузерах: можно указать программно не гасить экран&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hugeicons/hugeicons-react&quot;&gt;hugeicons&lt;/a&gt; — большая коллекция компонентов иконок: кастомизируются размер, цвет, скругление и иногда вариативность&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ota-meshi/eslint-plugin-regexp&quot;&gt;eslint-plugin-regexp&lt;/a&gt; — плагин ESLint для нахождения ошибок в регекспах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/farzher/fuzzysort&quot;&gt;fuzzysort&lt;/a&gt; — быстрый и лёгкий fuzzy-поиск на JS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webstatus.dev/&quot;&gt;Web Platform Dashboard&lt;/a&gt; — таблица с данными о поддержке фич платформы в браузерах&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/drruvari/mastering-solid-principles-in-react-easy-examples-and-best-practices-142b&quot;&gt;принципы SOLID на примере Реакт-компонентов&lt;/a&gt;: даже если не называть это какими-то буквами, а руководствоваться принципами здравого смысла, то примеры здравые: не замешивать несвязаные друг с другом вещи, а связанные — наоборот держать вместе, не хардкодить, писать единообразно, просто, не усложнять логику&lt;/li&gt;
&lt;li&gt;и ещё советы по вынесению ответов API, обработки выходных или входных данных в &lt;a href=&quot;https://profy.dev/article/react-architecture-api-layer-and-data-transformations&quot;&gt;отдельный API-слой приложения&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;если вы дизайнер и напрямую не кодите, но при этом хотите вживую «править» сайты, то &lt;a href=&quot;https://frontendmasters.com/blog/5-things-designers-can-do-with-javascript/&quot;&gt;вот список, чему научиться&lt;/a&gt;: выбирать элементы, переключать классы, подписываться на эвенты, менять HTML, собирать данные с форм (бонус дизайн-режим &lt;code&gt;document.designMode = &quot;on&quot;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;если вы пишете либу, даже небольшую, неплохая идея — &lt;a href=&quot;https://deno.com/blog/document-javascript-package&quot;&gt;написать JSDoc&lt;/a&gt; для подсветки в IDE, пакетном менеджере, ридми: внутри можно писать текст, типы, теги &lt;code&gt;@param&lt;/code&gt; и &lt;code&gt;@returns&lt;/code&gt; для описания функций, примеры кода в &lt;code&gt;md&lt;/code&gt;, теги &lt;code&gt;@link&lt;/code&gt; , &lt;code&gt;@linkcode&lt;/code&gt;, &lt;code&gt;@linkplain&lt;/code&gt; для ссылок&lt;/li&gt;
&lt;li&gt;один из недооцененных хуков — &lt;a href=&quot;https://www.joshwcomeau.com/react/use-deferred-value/&quot;&gt;useDefferedValue&lt;/a&gt; — откладывает рендер компонента до более подходящего момента, чтобы, например, если компонент «тяжёлый», улучшить перфоманс или же показать лоадер&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/madsstoumann/unleashing-the-hidden-power-of-html-forms-2gkl&quot;&gt;у элементов форм есть полезные методы из коробки&lt;/a&gt;: &lt;code&gt;form.elements.namedItem&lt;/code&gt;, &lt;a href=&quot;https://form.elements.group&quot;&gt;https://form.elements.group&lt;/a&gt; для радио-групп, &lt;code&gt;app.elements.firstname.defaultValue&lt;/code&gt; для получения дефолтного значения инпута&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cssence.com/2024/superior-range-syntax/&quot;&gt;range syntax медиа-выражений&lt;/a&gt; &lt;code&gt;width &amp;gt;= 48em&lt;/code&gt;, &lt;code&gt;width &amp;lt; 48em&lt;/code&gt; лучше тем, что не вынуждает писать разные числа &lt;code&gt;min-width: 48em&lt;/code&gt;, &lt;code&gt;max-width: 47.99em&lt;/code&gt; с возможными «мёртвыми» зонами между разрешениями&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2024/05/modern-guide-making-css-shapes/&quot;&gt;гайд по созданию форм на CSS&lt;/a&gt;: сейчас всё в большинстве случае сводится к SVG или же к &lt;code&gt;clip-path: polygon()&lt;/code&gt; и &lt;code&gt;mask&lt;/code&gt; + &lt;code&gt;gradient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если взять кастомное свойство типа &lt;code&gt;&amp;lt;integer&amp;gt;&lt;/code&gt; и инкрементить его раз в миллисекунду, то у нас есть &lt;a href=&quot;https://yuanchuan.dev/time-based-css-animations&quot;&gt;централизованный счётчик для создания «анимаций»&lt;/a&gt; по типу &lt;code&gt;rotate: calc(var(--t) * .001turn);&lt;/code&gt; вся соль в том, что с наличием такого счётчика можно синхронизировать несколько анимаций без JS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/quick-trick-using-border-image-to-apply-and-overlay-gradient/&quot;&gt;фейд-градиент&lt;/a&gt; поверх картинки и под текстом &lt;code&gt;border-image: fill 0 linear-gradient(#003, #000)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/anchor-positioning-api&quot;&gt;Chrome пушит Anchor Positioning API&lt;/a&gt;: штука для позиционирования элементов относительно других элементов; вангую, через 1-2 года заработает везде, а пока есть &lt;a href=&quot;https://github.com/oddbird/css-anchor-positioning&quot;&gt;полифилл&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Частичный stage файлов в git</title><link>https://juwain.github.io/web-platform/blog/2024-05-21/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-21/</guid><description>Когда вы добавляете файл в stage — это на самом деле не целиком файл, а именно конкретное состояние этого файла, его «снепшот». То есть если в файле две текстовые правки, застейджить можно только одну из них, а вторую пока не брать.</description><pubDate>Tue, 21 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Приходилось ли вам работать с длинными JSON-ами в git-е?&lt;/p&gt;
&lt;p&gt;Мне вот приходилось, когда в проект внедрялись дизайн-токены. Схема такая: есть «источник правды» в виде хранилища значений разных элементов интерфейса (цвета, размеры шрифтов, параметры теней и тд) в виде плагина к Figma. Из этого хранилища дизайнеры применяют значения в макетах, а для разработки выгружается JSON-файл. Затем файл процессится и из него генерятся кастомные свойства аля &lt;code&gt;--ui-element-background-color-default&lt;/code&gt;, которые уже используются в стилях.&lt;/p&gt;
&lt;p&gt;Так вот, на этапе разработки эта JSON-ина была одна и большая. И часто случалось так, что от дизайнеров приходила сразу пачка разнородных изменений в один этот файл. И нужно было как-то отделить мух от котлет, и все текстовые правки одного файла разделить на несколько коммитов в разные ветки.&lt;/p&gt;
&lt;p&gt;Руками копировать правки — так себе идея. Тут пригодится возможность git-а делать добавление частичных правок файла в stage.&lt;/p&gt;
&lt;p&gt;Когда вы добавляете файл в stage — это на самом деле не целиком файл, а именно конкретное состояние этого файла, его «снепшот». То есть если в файле две текстовые правки, застейджить можно только одну из них, а вторую пока не брать.&lt;/p&gt;
&lt;p&gt;Для этого в VSCode нужно перейти в файл, выделить интересующие текстовые правки и выполнить команду &lt;code&gt;cmd(ctrl)+shift+P&lt;/code&gt; &amp;gt; &lt;code&gt;Git: Stage Selected Ranges&lt;/code&gt; и в stage уйдут только частичные правки файла, остальные правки останутся в изменённом файле.&lt;/p&gt;
&lt;p&gt;Похожим образом можно также частично откатывать изменения в файлах. Например, что бы подчистить временные логи. Для этого нужно выбрать файл, так же выделить текстовые правки и выполнить команду &lt;code&gt;cmd(ctrl)+shift+P&lt;/code&gt; &amp;gt; &lt;code&gt;Git: Revert Selected Ranges&lt;/code&gt;. Либо в окошке с диффами тыкнуть на дифф и выбрать &lt;code&gt;Revert this change&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Из консольного git-а такое частичное добавление в stage также работает. Для этого &lt;a href=&quot;https://git-scm.com/docs/git-add#Documentation/git-add.txt---patch&quot;&gt;есть команда&lt;/a&gt; &lt;code&gt;git add -p&lt;/code&gt;. Если, к примеру, была правка в двух местах файла, то появится такое сообщение &lt;code&gt;(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?&lt;/code&gt;. Выбор &lt;code&gt;y&lt;/code&gt; — правка стейджится, &lt;code&gt;n&lt;/code&gt; — не стейджится, &lt;code&gt;?&lt;/code&gt; — помощь по остальным вариантам команд.&lt;/p&gt;
&lt;p&gt;Для частичного реверта &lt;a href=&quot;https://git-scm.com/docs/git-restore#Documentation/git-restore.txt--p&quot;&gt;нужна команда&lt;/a&gt; &lt;code&gt;git restore -p&lt;/code&gt;, которая вызовет такой же интерактивный диалог только с другим вопросом: &lt;code&gt;Discard this hunk from worktree?&lt;/code&gt;.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 24.05.2024</title><link>https://juwain.github.io/web-platform/blog/2024-05-24/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-24/</guid><description>Новости веб-платформы</description><pubDate>Fri, 24 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reuters.com/technology/vercel-completes-250-mln-series-e-round-325-bln-valuation-2024-05-16/&quot;&gt;Vercel привлек 250 миллионов $&lt;/a&gt; финансирования, а это значит, что ещё больше «нетехнических» клиентов будет в один клик пользоваться облаком, генерировать компоненты на &lt;a href=&quot;https://v0.dev&quot;&gt;https://v0.dev&lt;/a&gt; и также заливать их в облако, а потом платить деньги фиксикам, чтобы это всё работало&lt;/li&gt;
&lt;li&gt;(вдогонку к прошлой новости) появилась &lt;a href=&quot;https://react.dev/learn/react-compiler&quot;&gt;экспериментальная поддержка React Compiler в Next.js&lt;/a&gt;, что гладко укладывается в концепт «дев сложный, заплати и мы сделаем проще» (а кто сделал его сложным, КТО?!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/ai/built-in&quot;&gt;в Chrome 126 собираются встроить мини-LLM&lt;/a&gt;, чтобы пользователь мог выполнять простые задачи на сайтах и в веб-приложениях с помощью ИИ напрямую из браузера (пахнет вендор-локом, но концепт прикольный, вангую ИИ-«помощники» появятся во всех браузерах, чтобы помогать пользоваться сайтами)&lt;/li&gt;
&lt;li&gt;а &lt;a href=&quot;https://developer.chrome.com/blog/new-in-devtools-125&quot;&gt;в 125 версию Chrome в девтулзы&lt;/a&gt; уже добавили ИИ-фичу в консоль (объяснение ошибки, чтоб в гуглол не ходить), также завезли отладку anchor positioning, улучшили информацию об ошибках в Sources, а в Network добавили инспект заголовков Early Hints headers, в Performance теперь показывается инфа по скорости CSS-селекторов и ещё обновился Lighthouse&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=33654&quot;&gt;Bug 33654&lt;/a&gt;, Opened 25 years ago, Closed 2 days ago: то чувство, когда сын закрыл баг отца&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jawj/littlezipper&quot;&gt;littlezipper&lt;/a&gt; — создание zip файлов в браузере и в node/deno c CompressionStream API (доступно во всех средах)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jawj/xlsxtable&quot;&gt;xlsxtable&lt;/a&gt; — создание .xlsx файлов на клиенте и сервере&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.svgviewer.dev/&quot;&gt;svgviewer&lt;/a&gt; — поисковик и просмотрщик SVG-изображений с возможностью экспорта в виде растровой картинки, data URI или react-компонента&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://2ality.com/2024/05/proposal-promise-with-resolvers.html&quot;&gt;новый статический метод&lt;/a&gt; &lt;code&gt;const { promise, resolve, reject } = Promise.withResolvers()&lt;/code&gt; позволяет управлять промисами извне конструкции &lt;code&gt;new Promise((res, rej) =&amp;gt; {})&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/sachinchaurasiya/how-typescript-type-predicates-enhance-code-safety-19o2&quot;&gt;про предикаты типов&lt;/a&gt; (&lt;code&gt;function isType(arg: any): arg is Type&lt;/code&gt;): в целом полезны, из минусов добавляют нагрузку в рантайм и дублируют логику самих типов&lt;/li&gt;
&lt;li&gt;как &lt;a href=&quot;https://dev.to/paripsky/build-your-own-react-state-management-library-in-under-40-lines-of-code-with-typescript-support-hji&quot;&gt;создать свой минималистичный стор-менеджер в React&lt;/a&gt; без использования контекста, а с useSyncExternalStore, который к тому же из коробки подцепит типы&lt;/li&gt;
&lt;li&gt;и если вы всё таки предпочтёте пользоваться контекстом, &lt;a href=&quot;https://dev.to/hyposlasher/no-more-react-context-hell-4pm3&quot;&gt;как избежать множественных вложенных друг в друга контекстов&lt;/a&gt; через &lt;code&gt;&amp;lt;Providers providers={[providersList]}&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mui.com/blog/introducing-pigment-css/&quot;&gt;официально представлена альфа-версия Pigment CSS&lt;/a&gt; — новая CSS-in-JS-либа от MUI, которая мимикрирует по синтаксис Styled Components, но при этом работает в билд-тайме (и поэтому не использует контекст, что важно для серверных компонентов)&lt;/li&gt;
&lt;li&gt;даже если вы используете React, то всё равно вы пишете JS, то есть сталкиваетесь с контекстом выполнения и замыканиями, и как следствие можете в &lt;a href=&quot;https://schiener.io/2024-03-03/react-closures&quot;&gt;замыкание мемоизированной функции затянуть какой-нибудь большой объект&lt;/a&gt;, который не будет подчищаться garbage collector-ом&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webdeveloper.beehiiv.com/p/get-perfect-deep-equal-javascript&quot;&gt;реализация идеального Deep Equal сравнения объектов в JS&lt;/a&gt;, а также вариант Shallow Equal, который используется в React&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2024/05/beyond-css-media-queries/&quot;&gt;медиа-выражения для определения размеров вьюпорта больше не нужны&lt;/a&gt;? Флексбокс, грид, контейнер-выражения (а также &lt;code&gt;:has()&lt;/code&gt;) решают задачи лучше медиа-выражений, так как специально для этого предназначены и могут стилизовать респонсив-компоненты независимо от вьюпорта, но зато учитывая окружающий контекст. А медиа-выражения теперь для определение фич и настроек девайса (тема, контраст, анимации)&lt;/li&gt;
&lt;li&gt;пока функция &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-contrast&quot;&gt;color-contrast()&lt;/a&gt; не доехала до браузеров, &lt;a href=&quot;https://lea.verou.me/blog/2024/contrast-color/&quot;&gt;задачу подбора контрастного цвета&lt;/a&gt; можно решить с помощью relative color syntax&lt;/li&gt;
&lt;li&gt;CSS-фич стало настолько много, что пора расчехлять старый-добрый w3c-маркетинг и &lt;a href=&quot;https://github.com/CSS-Next/css-next/discussions/92&quot;&gt;сделать отсечки CSS4, CSS5 и CSS6&lt;/a&gt; (а что, в ECMA-движухе же получилось)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;в &lt;a href=&quot;https://2023.stateofhtml.com/en-US/features/&quot;&gt;результатах опроса State of HTML 2023&lt;/a&gt; каждый найдёт новенькое для себя: у нескольких &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; с одинаковыми &lt;code&gt;name&lt;/code&gt; открыт может быть только один (аккордеон), &lt;code&gt;&amp;lt;script async blocking=&quot;render&quot;&amp;gt;&lt;/code&gt; блокирует рендер, &lt;code&gt;&amp;lt;input type=&quot;file&quot; accept=&quot;video/*&quot; capture&amp;gt;&lt;/code&gt; сделает запись с пользовательской камеры&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Сортировка и поиск с localeCompare</title><link>https://juwain.github.io/web-platform/blog/2024-05-29/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-29/</guid><description>Когда сортируются «неанглийские» строки, пригодится метод localeCompare у строк, который сравнивает сроки учитывая действующую локаль пользовательской системы. </description><pubDate>Wed, 29 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;С задачей обычной сортировки, если речь про английский язык или числа, норм справляется &lt;code&gt;sort()&lt;/code&gt; или &lt;code&gt;sort((a, b) =&amp;gt; a - b)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Но вот когда сортируются «неанглийские» строки, то тогда пригодится метод &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare&quot;&gt;localeCompare&lt;/a&gt; у строк: &lt;code&gt;sort((a, b) =&amp;gt; a.localeCompare(b))&lt;/code&gt;, который сравнивает сроки учитывая действующую локаль пользовательской системы. Грубо говоря, где в текущей локали один Unicode-символ находится по сравнению с другим символом – перед ним или после него?&lt;/p&gt;
&lt;p&gt;Что интересно, базовый метод появился в браузерах ещё практически с начала существования Chrome, Firefox и Safari. Но позже в него была добавлена поддержка дополнительных параметров, уточняющих как именно нужно сравнивать строки. Причём под капотом &lt;code&gt;localeCompare&lt;/code&gt; будет вызывать &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator&quot;&gt;Intl.Collator API,&lt;/a&gt; в браузерах его поддерживающих.&lt;/p&gt;
&lt;p&gt;Настройка &lt;code&gt;caseFirst&lt;/code&gt; — первыми идёт нижний регистр или верхний:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&quot;Е&quot;, &quot;а&quot;, &quot;е&quot;, &quot;А&quot;]
  .sort((a, b) =&amp;gt; a.localeCompare(b, &quot;ru&quot;))
  [
    // по умолчанию сначала нижний регистр
    // [&quot;а&quot;,&quot;А&quot;,&quot;е&quot;,&quot;Е&quot;]

    (&quot;Е&quot;, &quot;а&quot;, &quot;е&quot;, &quot;А&quot;)
  ].sort((a, b) =&amp;gt; a.localeCompare(b, &quot;ru&quot;, { caseFirst: &quot;upper&quot; }));
// теперь сначала идёт верхний регистр
// [&quot;А&quot;,&quot;а&quot;,&quot;Е&quot;,&quot;е&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Это актуально и для английских текстов тоже.&lt;/p&gt;
&lt;p&gt;Настройка &lt;code&gt;sensitivity&lt;/code&gt; — учитывать ли при сравнении регистр и вспомогательные символы вокруг буквы (a и á, е и ё):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;лёд&quot;.localeCompare(&quot;ЛЕД&quot;, &quot;ru&quot;, { sensitivity: &quot;variant&quot; }) === 0;
// л ≠ д, е ≠ ё, л ≠ Л
// false

&quot;лед&quot;.localeCompare(&quot;лёд&quot;, &quot;ru&quot;, { sensitivity: &quot;case&quot; }) === 0;
// л ≠ д, е = ё, л ≠ Л.
// true

&quot;Лёд&quot;.localeCompare(&quot;лёд&quot;, &quot;ru&quot;, { sensitivity: &quot;accent&quot; }) === 0;
// л ≠ д, е ≠ ё, л = Л
// true

&quot;лёд&quot;.localeCompare(&quot;ЛЕД&quot;, &quot;ru&quot;, { sensitivity: &quot;base&quot; }) === 0;
// л ≠ д, е = ё, л = Л
// true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;То есть если пользователь вводит в поиск &lt;code&gt;ЛЕД&lt;/code&gt;, можно однозначно определить, что это &lt;code&gt;лёд&lt;/code&gt; прямо в браузере.&lt;/p&gt;
&lt;p&gt;Настройка &lt;code&gt;numeric&lt;/code&gt; — для корректной сортировки строк с числами:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&quot;09&quot;, &quot;1&quot;, &quot;2&quot;, &quot;01&quot;, &quot;10&quot;]
  .sort((a, b) =&amp;gt; a.localeCompare(b))
  [
    // по умолчанию сортируется по символам
    // [&quot;01&quot;,&quot;09&quot;,&quot;1&quot;,&quot;10&quot;,&quot;2&quot;]

    (&quot;09&quot;, &quot;1&quot;, &quot;2&quot;, &quot;01&quot;, &quot;10&quot;)
  ].sort((a, b) =&amp;gt; a.localeCompare(b, &quot;ru&quot;, { numeric: true }));
// теперь строки учитываются как числа
// [&quot;1&quot;,&quot;01&quot;,&quot;2&quot;,&quot;09&quot;,&quot;10&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Так можно отсортировать строки с числами без явного приведения к числам.&lt;/p&gt;
&lt;p&gt;Что радует, все возможные доп настройки доступны с Chrome 87, FF 85, Safari 14.1, Node 15.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://codepen.io/juwain/pen/rNgMVed?editors=0011&quot;&gt;Демо тут&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 31.05.2024</title><link>https://juwain.github.io/web-platform/blog/2024-05-31/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-05-31/</guid><description>Новости веб-платформы</description><pubDate>Fri, 31 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;на волне новостей о React Compiler &lt;a href=&quot;https://million.dev/blog/lint-rc&quot;&gt;анонсирован выпуск Million Lint 1.0-rc&lt;/a&gt;: в отличие от компайлера, который пребилдит реакт-код, Million Lint втыкает в код точечно замеры производительности и уже на их основе выдаёт рекомендации в редакторе кода и подсвечивает проблемы с производительностью&lt;/li&gt;
&lt;li&gt;на той же волне &lt;a href=&quot;https://nextjs.org/blog/next-15-rc&quot;&gt;анонсирован Next.js 15 RC&lt;/a&gt;: поддерживает React 19 RC, React Compiler, произошёл отказ от кеширования по умолчанию в fetch, GET Route Handlers и роутере, постепенно выкатывается реактовская система частичного пререндера Partial Prerendering (PPR) и after() API для отложенного запуска второстепенных тасков после выполнения основного запроса&lt;/li&gt;
&lt;li&gt;и снова на той же самой волне &lt;a href=&quot;https://github.com/solidjs/solid-start/releases/tag/v1.0.0&quot;&gt;вышел SolidStart v1.0.0&lt;/a&gt;, метафреймворк на основе Solid, встроенного роутера, а также Vite, Nitro и другого опенсорса; конечно, не перестаю удивляться современной индустрии, которую &lt;a href=&quot;https://www.solidjs.com/blog/solid-start-the-shape-frameworks-to-come&quot;&gt;люди из опенсорса натурально тащат вперёд&lt;/a&gt; на энтузиазме и за счёт синергии составляют конкуренцию корпорациям&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://responsiveviewer.org/&quot;&gt;Responsive Viewer&lt;/a&gt; — если много верстаете или тестируете на разных разрешениях, это плагин для браузера, чтобы одновременно на одном экране открыть несколько «девайсов» с синхронизацией скролла и кликов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lowlighter/matcha&quot;&gt;matcha.css&lt;/a&gt; — CSS-либа для стилизации чистой семантической разметки + небольшой набор классов хелперов для стилизации лейаута, цветов и подсветки синтаксиса (внутри нет &lt;code&gt;!important&lt;/code&gt;-ов, то есть всё переопределяется пользовательскими стилями)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://open-props.style/&quot;&gt;open-props&lt;/a&gt; — коробка с CSS-переменными на все случаи жизни (цвета, размеры, шрифты, тени, скругления)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://visgl.github.io/react-google-maps/&quot;&gt;react-google-maps&lt;/a&gt; — реакт-компоненты и хуки для Google Maps JavaScript API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tsx.is/&quot;&gt;tsx&lt;/a&gt; — запускальщик ts-файлов в Node (одной строкой и без конфигов, бонусом есть вотчер)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/natemoo-re/clack/tree/main/packages/prompts#readme&quot;&gt;clack&lt;/a&gt; — либа для создания красивых и удобных cli-промптов&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;иногда для повышения читаемости можно &lt;a href=&quot;https://kyleshevlin.com/prefer-multiple-compositions/&quot;&gt;сделать код более «композируемым», но повторяющимся&lt;/a&gt; (на примере реакт-компонентов), лишним &lt;code&gt;if&lt;/code&gt; или &lt;code&gt;switch&lt;/code&gt; кашу не испортишь&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.stashpad.com/blog/react-developer-guide-to-solid-js&quot;&gt;Solid мимикрирует под реактовский JSX&lt;/a&gt;, но под капотом компонент в React — это функция, которая вызывается каждый раз при рендере, а в Solid — один раз и возвращает DOM-элемент; вместо &lt;code&gt;useState&lt;/code&gt; используется &lt;code&gt;createSignal&lt;/code&gt;, который тоже похож внешне и возвращает массив с функцией доступа к состоянию и сеттер, но на деле не вызовет ререндера компонента, а только изменит контент в DOM-ноде; также в Solid есть &lt;code&gt;createEffect&lt;/code&gt; (похож на &lt;code&gt;useEffect&lt;/code&gt;), в который в простейшем случае не нужно передавать зависимости, что может привести к неочевидным багам&lt;/li&gt;
&lt;li&gt;(я из 2012 понимает всю боль) реактивность — это прежде всего &lt;a href=&quot;https://habr.com/ru/companies/ruvds/articles/737114/&quot;&gt;способ избежать связанности (coupling) кода&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ещё одно напоминание, что каскадные слои можно использовать для организации типов стилей, например, отдельно объявлять &lt;code&gt;@layer reset, theme, layout&lt;/code&gt;, причём подключаться они будут в таком порядке независимо от порядка подключения в коде; также описан концепт, как через «ручки» (кастомные свойства) &lt;a href=&quot;https://www.smashingmagazine.com/2024/05/modern-css-layouts-no-framework-needed/&quot;&gt;управлять параметрами лейаута страницы&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pawelgrzybek.com/popover-element-entry-and-exit-animations-in-a-few-lines-of-css/&quot;&gt;рецепт popover + @starting-style&lt;/a&gt;, на самом деле сгодится для любых «модалок» и появляшек: &lt;code&gt;@starting-style&lt;/code&gt; привносит в этот паттерн недостающую декларативность, чтобы не приходилось вручную манипулировать классами/эвент-хэндлерами&lt;/li&gt;
&lt;li&gt;да и вообще, почему бы просто не &lt;a href=&quot;https://codepen.io/argyleink/pen/Povqdej&quot;&gt;добавить @starting-style ко всему&lt;/a&gt;
&lt;code&gt;* { transition: opacity .5s ease-in; @starting-style { opacity: 0 } }&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/state-of-html-2023-results-2/&quot;&gt;статья по мотивам недавнего опроса State of HTML 2023&lt;/a&gt;: людям нравится &lt;code&gt;datalist&lt;/code&gt; (вывод: время адопта среднего HTML-элемента — 5 лет), не нравятся формы (стилизация, инпуты, валидация, кроссбраузерность), люди помнят о существовании веб-компонентов (и немного используют), людям не хватает нативных элементов &lt;code&gt;datatable&lt;/code&gt;, &lt;code&gt;tabs&lt;/code&gt;, &lt;code&gt;switch/toggle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в 2023 людям не хватало switch, а &lt;a href=&quot;https://www.smashingmagazine.com/2024/05/switching-it-up-html-latest-control/&quot;&gt;в 2024 он уже появился&lt;/a&gt; (пока правда только в Safari 17.4, но тем не менее), &lt;code&gt;&amp;lt;input type=&quot;checkbox&quot; switch /&amp;gt;&lt;/code&gt; можно стилизовать через &lt;code&gt;::thumb&lt;/code&gt;, &lt;code&gt;::track&lt;/code&gt;, но при этом он в отличие от чекбокса не может быть в indeterminate-состоянии и может быть required (в общем, ждём 5 лет и можно использовать)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Заметки первобытного разраба</title><link>https://juwain.github.io/web-platform/blog/2024-06-05/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-06-05/</guid><description>Заметки первобытного разраба</description><pubDate>Wed, 05 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Груг не так умён, но кодит много лет и чему-то научиться&lt;/p&gt;
&lt;p&gt;Большеголовых разрабов много, и много кто думает он большеголовый разраб, сделать кислую мину, когда читать эту заметку&lt;/p&gt;
&lt;h3&gt;Сложность — плохо&lt;/h3&gt;
&lt;p&gt;Очень плохо, лучше груг сражаться с тиранозавром, он хотя бы его видит&lt;/p&gt;
&lt;p&gt;Большеголовые разрабы и менеджеры впускают демон сложности в кодовую базу, они не боятся его или даже не знают&lt;/p&gt;
&lt;p&gt;Сегодня груг работает с кодом и понимает, всё хорошо&lt;/p&gt;
&lt;p&gt;Завтра невозможно: демон сложности вошёл в код и теперь очень опасно!&lt;/p&gt;
&lt;p&gt;Груг не видит демон сложности, но чует его в коде. Демон дразнит, измени тут, сломается где-то там. Дубина не спасать от демон сложности, а бить самого груга&lt;/p&gt;
&lt;p&gt;Магическое оружие против демона сложности — слово «нет». Нет, груг не делать эту фичу. Нет, груг не строить эту абстракцию.&lt;/p&gt;
&lt;p&gt;Это хороший инженерный совет, но плохой карьерный совет. «Да», магическое слово чтобы получить больше блестящих камней или стать вождём племени разрабов&lt;/p&gt;
&lt;p&gt;Грустно, говори «да», а потом вини других гругов, когда вышел фейл, идеальный карьерный совет&lt;/p&gt;
&lt;p&gt;Но иногда всё таки блестящие камни нужны, нет мясо динозавров, жена говорить груг дети нужна крыша и еда. Тогда груг говорить «лады». Лады, груг сделать эту фичу&lt;/p&gt;
&lt;p&gt;Груг делать 80/20 решение, не со всеми свистелками, что хотеть менеджер, но делать свою работу, и демон сложности уходить&lt;/p&gt;
&lt;h3&gt;Факторинг кода&lt;/h3&gt;
&lt;p&gt;Это сложно правильно разбивать кодовую базу. Но груг понял, не разбивай кодовую базу слишком рано&lt;/p&gt;
&lt;p&gt;В начале проект как вода, очень абстрактный, мозг груга не за что зацепиться&lt;/p&gt;
&lt;p&gt;Пройдёт время, система примет форму, и появятся линии для разреза&lt;/p&gt;
&lt;p&gt;Хорошая линия для разреза иметь узкий интерфейс с системой. Мало число функций и абстракций заточают демона сложности в кристалл&lt;/p&gt;
&lt;p&gt;Большеголовый разраб не такой, часто придумывать абстракции на старте проекта. Груг тянется к дубинке и хотеть кричать: «большеголовый не поддерживать код, а уходить в другой проект, груг поддерживать код!»&lt;/p&gt;
&lt;p&gt;Рабочее демо хороший трюк, груг требовать от большеголового разраба демо завтра&lt;/p&gt;
&lt;p&gt;У большеголовый большой мозг! Нужно его ограничивать для добра, не помогать демону сложности&lt;/p&gt;
&lt;p&gt;Назови рабочее демо «прототип», менеджер будет приятно&lt;/p&gt;
&lt;h3&gt;Тесты&lt;/h3&gt;
&lt;p&gt;Груг любит и ненавидит тесты. Печально, но есть шаманы тестов. Делать из тестов идол, писать тесты до того как груг взялся за код и не понимать рабочую область&lt;/p&gt;
&lt;p&gt;Легко не писать тест, оно работает на машине груга. Очень плохо, нет гарантии что работать где-то ещё или на машине груга в будущем&lt;/p&gt;
&lt;p&gt;Груг писать интеграционные тесты, когда появляются линии разреза и система стабильна, интеграционный тест полезный долгое время&lt;/p&gt;
&lt;h3&gt;Рефакторинг&lt;/h3&gt;
&lt;p&gt;Рефакторинг хорошая идея попозже, когда код стабильный&lt;/p&gt;
&lt;p&gt;Груг заметил, большой рефакторинг большая опасность провала. Поэтому делать маленький и не отплывать далеко от берегов. Идеально система работает всё время, шаги друг за другом&lt;/p&gt;
&lt;p&gt;Много старый груг научился не ломать код бездумно, даже если он страшный&lt;/p&gt;
&lt;p&gt;Опасность тут, мир страшный и уродливый часто и поэтому такой же и код&lt;/p&gt;
&lt;p&gt;Смирение не всегда есть, груг говорит «не нравится, исправлю» и это много часов боли и система только хуже&lt;/p&gt;
&lt;p&gt;Груг говорить надо улучшать система, но надо время понять её целиком и уважать работающий неидеальный код&lt;/p&gt;
&lt;p&gt;Груг раньше писать код минимального размера, но это часто сложно читать и отлаживать&lt;/p&gt;
&lt;p&gt;Груг думать DRY хороший совет, но иногда лучше скопировать код с небольшими вариациями чем делать новый агрумент&lt;/p&gt;
&lt;p&gt;Груг считать принцип &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8&quot;&gt;SoC&lt;/a&gt; не ок. Лучше весь код штуки будет в самой штуке, не надо искать файлы где что лежит&lt;/p&gt;
&lt;h3&gt;Фронтенд&lt;/h3&gt;
&lt;p&gt;Демон сложности овладел целая индустрия!&lt;/p&gt;
&lt;p&gt;Создавать меньше сложности, не смотри на facebook или google. Реакт хорошо для карьера и некоторых приложений, но груг становиться служителем демона сложности&lt;/p&gt;
&lt;p&gt;Груг видит много моды в разработке. Груг не боится показаться тупым говоря это слишком сложно и смущает груга!&lt;/p&gt;
&lt;p&gt;Груг чувствует много синдром самозванца. Груг часто не понимает что происходит, боится сделать ошибку и разочаровать других гругов, самозванец!&lt;/p&gt;
&lt;p&gt;Само программирование такое: никто не самозванец, если все самозванец&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://grugbrain.dev&quot;&gt;https://grugbrain.dev&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 07.06.2024</title><link>https://juwain.github.io/web-platform/blog/2024-06-07/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-06-07/</guid><description>Новости веб-платформы</description><pubDate>Fri, 07 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в FF будет добавлена &lt;a href=&quot;https://hacks.mozilla.org/2024/05/experimenting-with-local-alt-text-generation-in-firefox-nightly/&quot;&gt;генерация alt-ов с помощью нейросети&lt;/a&gt; прямо на устройстве: фича хорошо ложится в тренд, что AI будет появляться в браузерах и помогать пользователям с взаимодействием с сайтами и приложениями&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/testing-library/react-testing-library/releases/tag/v16.0.0&quot;&gt;вышла react-testing-library v16.0.0&lt;/a&gt;: &lt;code&gt;@testing-library/dom&lt;/code&gt; и &lt;code&gt;@types/react-dom&lt;/code&gt; вынесены в отдельные зависимости, чтобы устранить возможные конфликты&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2024/05/eslint-configuration-migrator/&quot;&gt;история с эпичным обновлением eslint продолжается&lt;/a&gt;: анонсирован ESLint Configuration Migrator — тула для &amp;lt;s&amp;gt;автоматического перевода&amp;lt;/s&amp;gt; помощи в переводе .eslintrc.*-файлов в flat-формат eslint.config.js, чтобы не делать это руками (пока умеет немного и работает с простыми конфигами)&lt;/li&gt;
&lt;li&gt;анонсирован &lt;a href=&quot;https://groups.google.com/a/mozilla.org/g/dev-platform/c/UhQSvl_v6xk/m/HngYYWOJBwAJ?pli=1&quot;&gt;intent to ship директивы @property в FF&lt;/a&gt; (чтобы объявлять кастомное свойство с нужным типом): пригодится, например, для кроссбраузерного &lt;a href=&quot;https://frontendmasters.com/blog/how-to-make-a-css-timer/&quot;&gt;создания CSS-таймеров&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.rspack.dev/blog/announcing-0-7&quot;&gt;вышел Rspack v0.7&lt;/a&gt;: добавили lazy compilation (собирается не сразу весь проект, а только входные точки; остальное собирается на лету в момент доступа) и ускорили сборку CSS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://turbo.build/blog/turbo-2-0&quot;&gt;вышел Turborepo 2.0&lt;/a&gt;: новый консольный UI и watch mode для автозапуска скриптов, у которых нет своего режима &lt;code&gt;--watch&lt;/code&gt;, например, eslint&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/theninthsky/client-side-rendering&quot;&gt;client-side-rendering&lt;/a&gt; — у нас был Webpack, ленивая подгрузка чанков и ассетов, MutationObserver, современный React, несколько хуков, парочка сервис-воркеров и большое желание не юзать SSR. Не то, чтобы всё это было категорически необходимо в разработке, но если уж начал оптимизировать CSR, то к делу надо подходить серьёзно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/marpple/fxts&quot;&gt;fxts&lt;/a&gt; — либа для функционального программирования на JS/TS c &lt;code&gt;each&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;fx&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;pipe&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt; и другой функциональщиной на борту&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://martinfowler.com/articles/data-fetch-spa.html&quot;&gt;разбор темы дата-фетчинга в SPA&lt;/a&gt; c асинхронной реализацией, параллельными запросами, и, что показалось мне интересным, с &lt;a href=&quot;https://martinfowler.com/articles/data-fetch-spa.html#prefetching&quot;&gt;разбором паттерна prefetch&lt;/a&gt; с помощью либы &lt;a href=&quot;https://swr.vercel.app/&quot;&gt;swr&lt;/a&gt;: предзагружаем бандл следующего компонента по onMouseEnter и заодно результат запроса кешируется и больше повторно не запрашивается&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; как альтернатива moment.js и date-fns для &lt;a href=&quot;https://rafaelcamargo.com/blog/mastering-date-formatting-using-intl-date-time-format-in-javascript/&quot;&gt;форматирования даты в нужном виде&lt;/a&gt;, умеет: длинный/короткий формат в зависимости от локали, дни недели, минуты, часы, секунды, таймзоны, 12/24 часа&lt;/li&gt;
&lt;li&gt;статьи Josh Comeau всегда приятно читать, независимо от темы, вот и &lt;a href=&quot;https://www.joshwcomeau.com/javascript/promises/&quot;&gt;статья про промисы подоспела&lt;/a&gt;, вроде база, а изложена хорошо&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/perssondennis/write-solid-react-hooks-436o&quot;&gt;бестпрактисы создания хуков на примере SOLID-принципов&lt;/a&gt;: к примеру, HOC, подмешивающий данные через проп в компонент — это такой себе DI «на коленке»&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://snyk.io/blog/10-modern-node-js-runtime-features/&quot;&gt;сборник новинок Node за последнее время&lt;/a&gt;: встроенный test runner, watch mode, corepack, .env loader, &lt;code&gt;import.meta.file&lt;/code&gt; для dirname и file, timers promises&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/css-length-units/&quot;&gt;свежий гайд по единицам измерениям CSS&lt;/a&gt;, примечателен двумя моментами: 1) выглядит, что Geoff Graham вернулся к написанию статей на CSS Tricks, возможно ресурс оживёт, 2) когда объявляется кастомное свойство &lt;code&gt;@property --hue { syntax: &quot;&amp;lt;number&amp;gt;&quot; }&lt;/code&gt;, по сути это пользовательская «единица измерения»&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/the-gap/&quot;&gt;свойство gap для флексбоксов&lt;/a&gt; работает с Chrome 84, FF 63, Safari 14.1, то есть давно достойно применения, если нужен условный отступ между элементами, выключающийся при переносе на новую строку, в двунаправленных лейаутах, комбинируется с марджинами&lt;/li&gt;
&lt;li&gt;есть такой частый кейс — анимация с &lt;code&gt;0&lt;/code&gt; до &lt;code&gt;auto&lt;/code&gt;, которую из-за особенностей CSS не возможно сделать через &lt;code&gt;calc()&lt;/code&gt;, поэтому есть &lt;a href=&quot;https://github.com/w3c/csswg-drafts/blob/main/css-values-5/calc-size-explainer.md&quot;&gt;предложение ввести новую функцию calc-size()&lt;/a&gt;, которая сможет анимировать между значениями, если одно из них intrinsic (&lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;fit-content&lt;/code&gt;, &lt;code&gt;stretch&lt;/code&gt;…)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://codersblock.com/blog/anchor-links-and-how-to-make-them-awesome/&quot;&gt;как можно улучшить якорные ссылки&lt;/a&gt;: &lt;code&gt;scroll-behavior: smooth&lt;/code&gt; для плавного скролла, &lt;code&gt;scroll-margin-top&lt;/code&gt; и &lt;code&gt;scroll-padding-top&lt;/code&gt; для отступа после скролла, &lt;code&gt;:has(h1:target)&lt;/code&gt; для стилизации таргет-элемента&lt;/li&gt;
&lt;li&gt;если вы до сих пишете &lt;code&gt;rel=&quot;noopener&quot;&lt;/code&gt; для безопасности, &lt;a href=&quot;https://www.stefanjudis.com/today-i-learned/target-blank-implies-rel-noopener/&quot;&gt;это можно уже не делать&lt;/a&gt;, так как браузеры сами неявно применяют эту фичу&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;то, что размер DOM (количество DOM-элементов) напрямую влияет на перфоманс как-то интуитивно понятно, но интересна деталь, что существенно сказывается именно &lt;a href=&quot;https://frontendatscale.com/blog/how-deep-is-your-dom/&quot;&gt;глубина вложенности DOM-элементов друг в друга&lt;/a&gt; (глубина в 5000 элементов скажется уже на этапе построения дерева, даже до стилей)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Откуда взялся Octocat</title><link>https://juwain.github.io/web-platform/blog/2024-06-12/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-06-12/</guid><description>Откуда взялся Octocat</description><pubDate>Wed, 12 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Операция &lt;code&gt;git merge&lt;/code&gt; используется для слияния веток. Но слияние может происходить по-разному. Есть дефолтный алгоритм слияния, который используется, если выполнить команду &lt;code&gt;git merge&lt;/code&gt; (также мердж неявно происходит при &lt;code&gt;git pull&lt;/code&gt;). Для слияния двух веток в версиях git с v0.99.9k до v2.33.0 использовался алгоритм &lt;code&gt;recursive&lt;/code&gt; (наверняка вы видели в консоли сообщение «Merge made by the &apos;recursive&apos; strategy» — это вот оно).&lt;/p&gt;
&lt;p&gt;В более новых версиях дефолтный алгоритм &lt;code&gt;recursive&lt;/code&gt; был заменён на &lt;code&gt;ort&lt;/code&gt; (Ostensibly Recursive’s Twin — «Как будто бы близнец Recursive», видимо разработчики посчитали что называть его &lt;code&gt;recursive-v2&lt;/code&gt; как-то не оч). У него тот же интерфейс и настройки (работает для слияния двух веток), но он работает побыстрее в больших репозиториях (особенно при мерджах, где было много переименований) и учитывает граничные случаи, которые в &lt;code&gt;recursive&lt;/code&gt; решались неоптимально.&lt;/p&gt;
&lt;p&gt;Но помимо двухветочных алгоритмов есть ещё и специальная стратегия для слияния более чем двух веток. Например, когда мы сливаем несолько веток разработки в одну для тестирования:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git checkout -b testing
git merge feature/one feature/two feature/three
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В этом случае применится алгоритм слияния &lt;code&gt;octopus&lt;/code&gt;. И буквально три ветки будет слито в одну (в целом, количество веток может быть любым, но лучше не превращать слияние «осьминога» в слияние «ктулху»).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*-.   dbc6a8b (HEAD -&amp;gt; testing) Merge branches &apos;feature/one&apos;, &apos;feature/two&apos; and &apos;feature/three&apos; into testing
|\ \
| | * 0260176 (feature/three) add test-3.txt
| * | abc9e86 (feature/two) add test-2.txt
| |/
* / 77e0aa8 (feature/one) add test-1.txt
|/
* 82acd11 (master) init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Также стратегию можно передавать явно в параметре вот так: &lt;code&gt;git merge -s recursive&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Так вот, давным-давно, когда начинался GitHub, его основатели захотели создать забавную страницу ошибки и купили на стоке ту самую картинку котоосьминога, которая называлась «Octopuss» у дизайнера Simon Oxley.&lt;/p&gt;
&lt;p&gt;Позже Octopuss стал более «корпоративным» Octocat, GitHub нанял дизайнера-разработчика Cameron McEfee, чтобы сделать из одной картинки целую мерч-индустрию и, что называется, &lt;a href=&quot;https://cameronmcefee.com/work/the-octocat/&quot;&gt;завертелось.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Забавный факт: на двумерных картинках у октокота всегда видны только 5 лап (по разным версиям одна из них — хвост). И когда появилась задача сделать трёхмерную фигурку, то встал вопрос сколько всё таки у него будет ног: 4 ноги и хвост или же 8 щупалец (3 из которых не видны на картинке). В итоге решили, что у фигурки будет 4 ноги и один хвост. Впрочем, потом появились анимации, где у октокота много щупалец.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 14.06.2024</title><link>https://juwain.github.io/web-platform/blog/2024-06-14/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-06-14/</guid><description>Новости веб-платформы</description><pubDate>Fri, 14 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.webkit.org/blog/15443/news-from-wwdc24-webkit-in-safari-18-beta/&quot;&gt;анонсирован Safari 18 beta&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;добавлена поддержка View Transitions API (ждём FF), а также Style Queries &lt;code&gt;@container style()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currentcolor&lt;/code&gt; теперь заработает в relative color syntax &lt;code&gt;oklch(from currentcolor calc(L * 4) C H)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;заработала анимация для &lt;code&gt;display&lt;/code&gt;; у &lt;code&gt;backdrop-filter&lt;/code&gt; отпал вендорный префикс&lt;/li&gt;
&lt;li&gt;заработал режим &lt;code&gt;justify-content: safe center&lt;/code&gt; для флексбоксов (предотвращение обрезания при узком контейнере)&lt;/li&gt;
&lt;li&gt;поддержано свойство &lt;code&gt;content-visibility&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;доработаны инпуты (свитч-чекбокс, дата, время)&lt;/li&gt;
&lt;li&gt;появился &lt;code&gt;URL.parse()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;задепрекейчен &lt;code&gt;resize: auto&lt;/code&gt;, а также другие API, которые работали только в Safari&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/127.0/releasenotes/&quot;&gt;вышел Firefox 127&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появилась поддержка &lt;code&gt;rel=&quot;dns-prefetch&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;для &lt;code&gt;img&lt;/code&gt;, &lt;code&gt;video&lt;/code&gt;, &lt;code&gt;audio&lt;/code&gt; браузер попытается заменить ссылки http на https&lt;/li&gt;
&lt;li&gt;доработан внутренний тул скриншотов&lt;/li&gt;
&lt;li&gt;включен &lt;code&gt;navigator.clipboard.read()/write()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-126&quot;&gt;вышел Chrome 126&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;view transitions заработал для cross-document (работает так же: незаметно загружается следующая страница, делается и показывается скриншот и затем подменяется на загруженную страницу) (ребята из Astro &lt;a href=&quot;https://astro.build/blog/future-of-astro-zero-js-view-transitions/&quot;&gt;тут же выкатили обнову&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;включён CloseWatcher API, управляющий закрытием &lt;code&gt;dialog&lt;/code&gt; и &lt;code&gt;popover&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://developer.chrome.com/blog/new-in-devtools-126&quot;&gt;девтулзах&lt;/a&gt; в Network в запрос теперь можно копипастить заголовок запроса целиком, а также обновлён Lighthouse 12.0.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;в Mozilla пошли на рынок инструментов для «безкодового» создания сайтов и выпустили &lt;a href=&quot;https://soloist.ai/&quot;&gt;soloist.ai&lt;/a&gt;: готовый сайт захостится на &lt;a href=&quot;https://soloist.ai&quot;&gt;https://soloist.ai&lt;/a&gt;, под капотом будет next.js (хм, где-то это уже было 🤔)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/blog/2024/06/01/3.3.0.html&quot;&gt;вышел Prettier 3.3&lt;/a&gt;: интересен тем, что ещё лучше форматит TS, JS, React, а также Flow-код, и все улучшения для Flow написали инженеры самого Flow&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-5-rc/&quot;&gt;анонсирован TypeScript 5.5 RC&lt;/a&gt;: новые методы Set (union, intersection…); проверка синтаксиса регекспов; импорт типов в js-файлах в JSDoc; Inferred Type Predicates (решает проблему с типами &lt;code&gt;.filter(x =&amp;gt; x !== null)&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/discoveryjs/browser-extension-json-discovery&quot;&gt;JsonDiscovery&lt;/a&gt; — расширение для браузеров для интерактивного просмотра JSON (в том числе больших &amp;gt;512MB, на которых &lt;code&gt;JSON.parse&lt;/code&gt; положит браузер)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coolify.io/&quot;&gt;coolify&lt;/a&gt; — опенсорсный селф-хостед аналог netlify/versel&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://telefunc.com/&quot;&gt;telefunc&lt;/a&gt; — как-то уже писал про концепт «серверных» методов, которые напрямую «вызываются» на клиенте, вот эта либа реализует подход «функции вместо API»&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/recent/&quot;&gt;web-features-explorer&lt;/a&gt; — инструмент для проверки доступности веб-фич в браузерах (в том числе показывает разбивку по месяцам)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;тема узких горлышек в оптимизации всегда актуальна (да, я смотрю на тебя, React) и &lt;a href=&quot;https://www.iamtk.co/optimizing-inp-for-a-react-app-and-performance-learnings&quot;&gt;тут есть, где разгуляться&lt;/a&gt;: в React 18 стоит использовать concurrent-режим рендера &lt;code&gt;ReactDOM.createRoot&lt;/code&gt; вместо &lt;code&gt;ReactDOM.render&lt;/code&gt;; большие таски можно разделять «перебивками» &lt;code&gt;new Promise((resolve) =&amp;gt; setTimeout(resolve, 0))&lt;/code&gt; или &lt;code&gt;await window.scheduler.yield()&lt;/code&gt;; хуки react-router &lt;code&gt;useLocation&lt;/code&gt;, &lt;code&gt;useRouteMatch&lt;/code&gt;, &lt;code&gt;useHistory&lt;/code&gt; вызывают ререндеры, лучше пользовать &lt;code&gt;history&lt;/code&gt; и &lt;code&gt;location&lt;/code&gt; из &lt;code&gt;window&lt;/code&gt;, если дело происходит на клиенте&lt;/li&gt;
&lt;li&gt;идея использование тайп-чекинга не только для «базовой» проверки типов, но и «для чего-то большего», всегда вызывала у меня отторжение из-за «комплексности» затеи, но если вам это не страшно, можно, к примеру, писать &lt;a href=&quot;https://frontendmasters.com/blog/testing-types-in-typescript/&quot;&gt;типы-«тесты» для проверки других TS-типов&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;с Document Picture-in-Picture API можно в мини-окошке браузера рендерить произвольный контент, а не только видео, поэтому там можно показать, например, &lt;a href=&quot;https://developer.chrome.com/blog/spotify-picture-in-picture&quot;&gt;мини-плеер&lt;/a&gt; с помощью &lt;code&gt;createPortal()&lt;/code&gt; (жаль, что пока только Chrome)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/wasp/ive-been-writing-typescript-without-understanding-it-5ef4&quot;&gt;оператор satisfies&lt;/a&gt; позволяет проверить соответствие типа объекта без лишнего «расширения» этого типа&lt;/li&gt;
&lt;li&gt;чтобы &lt;a href=&quot;https://www.totaltypescript.com/how-to-use-corepack&quot;&gt;проект использовал конкретную версию пакетного менеджера&lt;/a&gt;, нужно включить &lt;code&gt;corepack enable &amp;amp;&amp;amp; corepack enable npm&lt;/code&gt; и прописать в &lt;code&gt;package.json&lt;/code&gt; конкретную версию &lt;code&gt;&quot;packageManager&quot;: &quot;yarn@3.1.1&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;решение интерфейсной проблемы &lt;a href=&quot;https://www.amitmerchant.com/nested-anchor-links-using-css/&quot;&gt;ссылки, вложенной в ссылку&lt;/a&gt;: выносим «родительскую» ссылку в отдельный слой с &lt;code&gt;position: absolute&lt;/code&gt; и растягиваем на всю ширину с &lt;code&gt;inset: 0&lt;/code&gt;, а «дочерней ссылке» задаём &lt;code&gt;position: relative&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CSS Tricks продолжает оживать с &lt;a href=&quot;https://css-tricks.com/css-container-queries/&quot;&gt;новым гайдом про Container Queries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;чтобы &lt;a href=&quot;https://andrewwalpole.com/blog/custom-top-and-bottom-css-container-masks/&quot;&gt;«прилепить» к краям контейнера картинки-маски&lt;/a&gt;, чтобы сам он тянулся по высоте, есть &lt;code&gt;mask-image&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 21.06.2024</title><link>https://juwain.github.io/web-platform/blog/2024-06-21/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-06-21/</guid><description>Новости веб-платформы</description><pubDate>Fri, 21 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в спецификацию CSS-values-5 &lt;a href=&quot;https://x.com/LeaVerou/status/1801192208025940200&quot;&gt;будет добавлен синтаксис инлайновых условий&lt;/a&gt; для кастомных свойств (&lt;a href=&quot;https://lea.verou.me/blog/2024/css-conditionals/&quot;&gt;логичное продолжение style-container-queries только для всего&lt;/a&gt;), можно будет писать так:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;background-color: if(style(--variant: success), var(--color-success-60));
border-radius: if(style(--shape: pill) ? 999em: 0.2em);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v22.3.0&quot;&gt;вышла Node 22.3.0&lt;/a&gt;: в тест-раннер добавлено снепшотное тестирование&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.codeminer42.com/how-react-19-almost-made-the-internet-slower/&quot;&gt;в React-сообществе бомбануло&lt;/a&gt;, что в 19 rc версии асинхронные сиблинги в &lt;code&gt;&amp;lt;Suspence&amp;gt;&lt;/code&gt; стали рендериться последовательно, а раньше было параллельно (что использовалось, к примеру, в tanstack-query); команде React пришлось признать, что они недооценивали, сколько людей продолжают делать SPA, а не рендерить на сервере и отложить релиз 19 версии (что забавно, &lt;a href=&quot;https://github.com/facebook/react/pull/26380&quot;&gt;pr спокойно себе был в работе с марта 2023&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://2023.stateofjs.com/&quot;&gt;опубликованы результаты опроса State of JS 2023&lt;/a&gt; (преимущественно американцы и европейцы мужчины среднего возраста поделились, что думают):
&lt;ul&gt;
&lt;li&gt;в JS из коробки не хватает статической типизации, боль вызывает ситуация с ESM/CJS-модулями, поддержка TS, работа с датами, браузерная поддержка (особенно Safari)&lt;/li&gt;
&lt;li&gt;Vite многие пользуют и почти все довольны (то же актуально для Vitest), что не скажешь о webpack — пользуют меньше и больше недовольных&lt;/li&gt;
&lt;li&gt;у Next и Vue сравнимое количество использующих и недовольных&lt;/li&gt;
&lt;li&gt;недовольных React становится больше&lt;/li&gt;
&lt;li&gt;растёт популярность pnpm в том числе как инструмента организации монореп&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jser.dev/2024-05-11-introducing-rie/&quot;&gt;React Internals Explorer&lt;/a&gt; — визуализация происходящего в дереве рендера React, в том числе проиллюстрирован пример с &lt;code&gt;&amp;lt;Suspence&amp;gt;&lt;/code&gt;: в SPA в 18 версии React они будут рендериться параллельно, а в rc 19 — последовательно&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/learn/test-runner/using-test-runner&quot;&gt;как использовать встроенный тест-раннер Node&lt;/a&gt;, в том числе свежедобавленное снепшотное тестирование: &lt;code&gt;describe&lt;/code&gt;, &lt;code&gt;mock&lt;/code&gt;, &lt;code&gt;it&lt;/code&gt; живут в &lt;code&gt;node:test&lt;/code&gt;, как и &lt;code&gt;snapshot&lt;/code&gt;; названия утилит классические, API вполне предсказуемый; &lt;code&gt;snapshot&lt;/code&gt; сам по себе не рендерит компоненты, а работает в паре с каким-либо рендерером, например, &lt;code&gt;@testing-library/react&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;вроде и маркетинговая статья, но как-то &lt;a href=&quot;https://blog.platformatic.dev/nodejs-is-here-to-stay&quot;&gt;честно составленная&lt;/a&gt;: Node — самая популярная технология, скачивания растут, баги правятся, плюшки появляются: &lt;code&gt;ems&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt;, &lt;code&gt;watch&lt;/code&gt;, &lt;code&gt;AsyncLocalStorage&lt;/code&gt;, &lt;code&gt;WebCrypto&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/blog/using-the-page-visibility-api/&quot;&gt;Page Visibility API — сто лет в обед&lt;/a&gt;, но как-то не на слуху, используется, например, чтобы на событии visibilitychange, когда страница не просматривается, отправить аналитику или понизить битрейт проигрываемого видео&lt;/li&gt;
&lt;li&gt;проблема, которую решает React Compiler с автомемоизацией состояния в компонентах, уже &lt;a href=&quot;https://www.mikejohnson.dev/posts/2024/06/mobx-react-compiler&quot;&gt;давно решена из коробки в MobX&lt;/a&gt; (видимо поэтому &lt;a href=&quot;https://github.com/facebook/react/blob/0f568418d2c9cd3d5f32eeb40d7305211bd17ccd/compiler/packages/react-compiler-healthcheck/src/config.ts#L2&quot;&gt;MobX помечен как несовместимый с RC&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/css-cap-unit/&quot;&gt;единица измерения 1cap&lt;/a&gt; — это высота заглавной буквы в шрифте, если нужно сделать что-то такой высоты (например, отступ между словами или размеры иконки), то можно пользовать (доступно во всех браузерах с декабря 2023)&lt;/li&gt;
&lt;li&gt;в браузерах в последнее время имплементировано много CSS-фишек, но &lt;a href=&quot;https://www.stefanjudis.com/blog/safari-18-what-web-features-are-usable-across-browsers/&quot;&gt;не все доступны повсеместно&lt;/a&gt;: пока нельзя использовать View transitions, Style Queries, &lt;code&gt;@starting-style&lt;/code&gt;, зато можно &lt;code&gt;URL.parse()&lt;/code&gt;, Safe flexbox alignment, &lt;code&gt;currentcolor&lt;/code&gt; в relative color syntax&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bradfrost.com/blog/post/a-rare-use-case-for-em-units/&quot;&gt;редкий юзкейс для em&lt;/a&gt; — для задания размера отступа &lt;code&gt;text-underline-offset&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/permission-element-origin-trial&quot;&gt;в Chrome предложили элемент &lt;code&gt;&amp;lt;permission&amp;gt;&lt;/code&gt;&lt;/a&gt;, который встраивается в страницу и показывает, какие есть доступы к камере и микрофону, а также позволяет включить или выключить их; интересно, 1) как с появлением веб-компонентов и React расширилось понимание элементов страницы, 2) что элемент будет не веб-компонентом, а именно стандартным браузерным элементом, чтобы гарантировано сделать его визуально доступным с ограничениями по стилизации&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;помню, когда GitHub выкатили GraphQL-песочницу, было интересно её тыкать, казалось, вот она — настоящая гибкость, но в итоге &lt;a href=&quot;https://bessey.dev/blog/2024/05/24/why-im-over-graphql/&quot;&gt;оказалось всё не так радужно&lt;/a&gt;: не легко спрятать за авторизацию частичные поля и наоборот легко с клиента отправить схему, которая выгребет мегабайты JSON-а, а также есть другие проблемы; а подходит GQL в случае, если есть контроль над всеми клиентами, их &amp;lt;= 3 и сервер и клиенты написаны на разных языках&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 28.06.2024</title><link>https://juwain.github.io/web-platform/blog/2024-06-28/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-06-28/</guid><description>Новости веб-платформы</description><pubDate>Fri, 28 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.figma.com/blog/config-2024-recap/&quot;&gt;Figma провели конференцию Config 2024,&lt;/a&gt; показали:
&lt;ul&gt;
&lt;li&gt;обновлённый UI с поддержкой светлой темы и плавающих панелек&lt;/li&gt;
&lt;li&gt;Figma Slides — режим для создания и показа презентаций (плавные переходы между слайдами, заметки докладчика, интерактивные элементы)&lt;/li&gt;
&lt;li&gt;Code Connect — режим с генерацией компонентов (отношусь скептически)&lt;/li&gt;
&lt;li&gt;более удобный dev-mode, чтоб просматривать сразу все готовые макеты&lt;/li&gt;
&lt;li&gt;допиленные автолейауты и адаптивные прототипы (подстраиваются под размер экрана)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-4110/&quot;&gt;в Astro 4.11&lt;/a&gt; поддержаны прекрасные &lt;a href=&quot;https://shiki.style/packages/transformers#shikijs-transformers&quot;&gt;Shiki transformers&lt;/a&gt; для компонента отображения &lt;code&gt;&amp;lt;Code&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sindresorhus/ky&quot;&gt;ky&lt;/a&gt; — обёртка над браузерным &lt;code&gt;fetch&lt;/code&gt;: есть алиасы для отправки всех видов запросов, retry логика, хуки (до запроса, до ошибки, до ретрая, после ответа), отправка данных формы, отменяется по &lt;code&gt;controller.abort()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pdfslick/pdfslick&quot;&gt;pdfslick&lt;/a&gt; — либа для просмотра и взаимодействия с pdf (интересно, что под капотом используется Zustand)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;у &lt;code&gt;WeakMap&lt;/code&gt; есть такая полезная особенность, что если объект более не существует, то значение, привязанное к нему, удаляется из памяти garbage collector-ом; это можно использовать, например, &lt;a href=&quot;https://dev.to/thekashey/weak-memoization-in-javascript-4po6&quot;&gt;для организации кеша,&lt;/a&gt; который автоматически подчищается, когда закешированные объекты не существуют &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap#caching&quot;&gt;(простая версия того же на mdn)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;если &lt;a href=&quot;https://www.typescriptlang.org/play/?ssl=1&amp;amp;ssc=46&amp;amp;pln=1&amp;amp;pc=1#code/C4TwDgpgBAysCGwCuBnKBeKByA9pAdllAD7YDGANjihACZGkrABOAlvgOZQBkUA3gF8oAKGFkc+JlAAeALlgJkaTFhQ4AttBzAAFhGZQmiVEQD0pqABUdrNLajwyZCGGB0xEqSHlxjy7FhAA&quot;&gt;хочется сделать тип,&lt;/a&gt; принимающий любую строку, но при этом чтобы в автокомплите выдавались «предустановленные» варианты, то в юнион в конце надо добавить &lt;code&gt;string &amp;amp; {}&lt;/code&gt;
&lt;code&gt;type Status = &apos;open&apos; | &apos;closed&apos; | string &amp;amp; {}&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;если вдруг у вас возникнет желание &lt;a href=&quot;https://www.bennadel.com/blog/4669-exploring-randomness-in-javascript.htm&quot;&gt;использовать Web Crypto API для генерации рандомных чисел&lt;/a&gt; вместо &lt;code&gt;Math.random()&lt;/code&gt;, то это будет гораздо медленее и для простых (не крипто) задач «типа немного лучше»&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;сможете сходу сказать, чем &lt;a href=&quot;https://www.smashingmagazine.com/2024/06/uniting-web-native-apps-unknown-javascript-apis/&quot;&gt;Screen Orientation API отличается от Device Orientation API?&lt;/a&gt; Screen — это горизонтальная/вертикальная раскладка, Device — это про гироскоп и ориентацию в пространстве; также есть рецепт по блокировке экрана в &lt;code&gt;Fullscreen API&lt;/code&gt;, и ещё немного про &lt;code&gt;Vibration API&lt;/code&gt; и малодоступный &lt;code&gt;Contact Picker API&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/blog/javascript-set-methods/&quot;&gt;новые методы Set (intersection, union…)&lt;/a&gt; доступны во всех браузерах, их можно адоптить, тем более, что уже поддержаны в TS 5.5&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Intersection Observer API&lt;/code&gt; норм адоптится в React, правда нужно &lt;a href=&quot;https://reactpractice.dev/articles/using-the-intersection-observer-api-with-react/&quot;&gt;намазать парочкой useRef,&lt;/a&gt; чтоб лишний раз не пересоздавать обсервер&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://dev.to/mattlewandowski93/7-use-cases-for-javascript-proxies-3b29&quot;&gt;юзкейсы Proxy:&lt;/a&gt; геттеры, подсчёт доступов, немутабельные объекты, кеширование, создание цепочки методов, валидация, вотчер изменений поля&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ещё один &lt;a href=&quot;https://noti.st/mbarker84/fD6i8r&quot;&gt;сборничек современных фишек CSS&lt;/a&gt; от Michelle Barker, из находок: inset можно задавать не только 0, но и &lt;code&gt;inset: 50% 50% 0 0&lt;/code&gt; (направление значений по часовой стрелке — верх, право, низ, лево); растяжка элементов на весь контейнер &lt;code&gt;{ display: grid; * &amp;gt; { grid area: 1 / 1; } }&lt;/code&gt;; также есть container-queries, &lt;code&gt;:has&lt;/code&gt; (куда же без него), anchor positioning&lt;/li&gt;
&lt;li&gt;если у вас Chrome-only приложение (киоск, например), то там уже завезли anchor positioning, и его можно &lt;a href=&quot;https://coryrylan.com/blog/flow-charts-with-css-anchor-positioning&quot;&gt;использовать для создания линий между элементами&lt;/a&gt; (аля стрелки в miro) — линии будут привязаны к заданному боку элемента и сохранять свою позицию при перемещении самого элемента&lt;/li&gt;
&lt;li&gt;если задать одиночный кейфрейм &lt;code&gt;50% { transform: scale(1.5) }&lt;/code&gt;, то он будет работать: на 0% будет изначальным, затем изменится до заданного, а затем снова вернётся к изначальному; тут можно &lt;a href=&quot;https://codepen.io/davideast/pen/MWxvzjm&quot;&gt;посмотреть другие одиночные кейфреймы&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/pure-css-circular-text-without-requiring-a-monospace-font/&quot;&gt;если нужно сверстать текст по кругу,&lt;/a&gt; можно использовать тригонометрические функции и transform, которые доступны во всех браузерах (похожее есть в SVG-элементе &lt;code&gt;textPath&lt;/code&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/Element/textPath&quot;&gt;расставляющем текст по path)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://verpex.com/blog/website-tips/how-to-create-cut-out-shapes-using-the-clip-path-property&quot;&gt;как на clip-path: polygon() создать форму и её инвертировать:&lt;/a&gt; прикольно, что на &lt;code&gt;polygon()&lt;/code&gt; можно создать любую геометрическую форму&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;текстовые инпуты несколько перегруженные в настройках, так что &lt;a href=&quot;https://garrettdimon.com/journal/posts/fine-tuning-text-inputs&quot;&gt;часть из них забывается:&lt;/a&gt; помимо &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;pattern&lt;/code&gt;, &lt;code&gt;inputmode&lt;/code&gt; можно ещё задать &lt;code&gt;spellcheck&lt;/code&gt; (управляет проверкой правописания), &lt;code&gt;autofocus&lt;/code&gt; (устанавливает автофокус), &lt;code&gt;autocapitalize&lt;/code&gt; (автоматическая капитализация букв, слов, предложений), &lt;code&gt;autocomplete&lt;/code&gt; (автодополнение имени, одноразовых кодов, паролей), &lt;code&gt;autocorrect&lt;/code&gt; (нестандарт в Safari исправляет правописание)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 05.07.2024</title><link>https://juwain.github.io/web-platform/blog/2024-07-05/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-07-05/</guid><description>Новости веб-платформы</description><pubDate>Fri, 05 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;математические CSS-функции &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/round&quot;&gt;round(),&lt;/a&gt; &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/mod&quot;&gt;mod()&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/rem&quot;&gt;rem()&lt;/a&gt; — теперь &lt;a href=&quot;https://web.dev/blog/css-stepped-value-functions?hl=en&quot;&gt;доступны во всех браузерах:&lt;/a&gt; это про округление и остаток от деления одной единицы на другую; интересен юзкейс округления с определённым шагом — такой своеобразный аналог «тротлинга» в CSS, когда задаются, например, только целые или кратные 5 значения, а остальные отсеиваются&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/playwright/releases/tag/v1.45.0&quot;&gt;вышел Playwright v1.45.0:&lt;/a&gt; на борту новый Clock API, который позволяет протестировать временные интервалы (устанавливаем время, пользователь закрыл ноут, перематываем время на 10 часов вперёд, возобновляем время, проверяем, что времязависимый код отработал корректно)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rolldown/rolldown/releases/tag/v0.10.5&quot;&gt;вышел Rolldown v0.10.5:&lt;/a&gt; потихоньку кродёться новый бандлер на замену Rollup в Vite, в этом релизе поддержана сборка TypeScript и разных типов файлов&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/es-tooling/eslint-plugin-depend&quot;&gt;eslint-plugin-depend&lt;/a&gt; — плагин для eslint, указывающий на либы в раздутыми зависимостями и на использование ненужных полифиллов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/LadybirdBrowser/ladybird&quot;&gt;ladybird&lt;/a&gt; — разработка нового браузера не по карману большим бизнесам, но зато &lt;a href=&quot;https://ladybird.org/announcement.html&quot;&gt;по силам энтузиастам,&lt;/a&gt; которые по приколу строят систему современного браузера (рендеринг-движок, JS-движок, WASM-имплементация, HTTP-клиент, эвент-луп и взаимодействие с ОС…)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/observatory&quot;&gt;HTTP observatory&lt;/a&gt; — сканер HTTP-заголовков, которые отдаёт сервер вашего сайта, пишет чего нет, что есть, даёт рекомендации&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://letsform.dev/&quot;&gt;letsform&lt;/a&gt; — тут рекомендация не самого сервиса, а подхода генерации форм из JSON-схемы, чтоб перенять практики при необходимости сборки своего велосипеда&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;напоминание, что для базовой конвертации строки в DOM и DOM в строку &lt;a href=&quot;https://blog.apify.com/javascript-parse-html/&quot;&gt;есть 2 браузерных API:&lt;/a&gt; &lt;code&gt;DOMParser&lt;/code&gt; и &lt;code&gt;XMLSerializer&lt;/code&gt; (для ноды есть отдельные либы типа JSDOM)&lt;/li&gt;
&lt;li&gt;замечали, что при копипасте текста иногда он вставляется вместе со стилями? &lt;a href=&quot;https://www.raymondcamden.com/2024/07/03/working-with-pasted-content-in-javascript&quot;&gt;Дело в методе вставки:&lt;/a&gt; на событии &lt;code&gt;paste&lt;/code&gt; метод &lt;code&gt;e.clipboardData.getData(&apos;text/html&apos;)&lt;/code&gt; вставит текст вместе с прилагающимися стилями&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.phpied.com/files/location-location/location-location.html&quot;&gt;534 и 1 способ перезагрузить страницу из JS:&lt;/a&gt; а на самом деле комбинации методов assign, replace и reload у location&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webdeveloper.beehiiv.com/p/cancel-promises-javascript&quot;&gt;отменяемый fetch легко реализуется&lt;/a&gt; с новым &lt;code&gt;Promise.withResolvers()&lt;/code&gt; (это правда не совсем отмена, а ранний reject), а также есть вариант с отменой с помощью &lt;code&gt;AbortController&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;тема с «неточным» округлением чисел &lt;a href=&quot;https://www.robinwieruch.de/javascript-rounding-errors/&quot;&gt;крайне важная в финансовых приложениях,&lt;/a&gt; поэтому там можно использовать или микроприбавки &lt;code&gt;Number.EPSILON&lt;/code&gt; к числам перед округлением, или спец либы типа currency.js, на которой в итоге и остановился автор, чтобы избежать проблем&lt;/li&gt;
&lt;li&gt;Deno, Bun — это конечно хорошо, но всё таки стоит их воспринимать как надстройками над Nodejs и не использовать проприетарные API, держать в уме, что должно быть можно &lt;a href=&quot;https://ckarchive.com/b/lmuehmh08vwdxid7kkm78cdoo5v00hg&quot;&gt;сфолбечиться к базовому API Nodejs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/browser-support-tests-in-javascript-for-modern-web-features/&quot;&gt;как в JS проверить наличие нужной браузерной фичи:&lt;/a&gt; CSS-фичи преимущественно с помощью &lt;code&gt;CSS.supports()&lt;/code&gt;, HTML-фичи через наличие в DOM-е определённых интерфейсов&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если принять тот факт, что в tailwind излишне выкрутили идею утилитарных классов, сделав примитивы слишком низкоуровневыми, и попытаться переосмыслить идею, то получится такое разделение: оформительские (&lt;code&gt;.card&lt;/code&gt;, &lt;code&gt;.aside&lt;/code&gt;), лейаут (&lt;code&gt;.center&lt;/code&gt;, &lt;code&gt;.cluster&lt;/code&gt;), отступы (&lt;code&gt;.gap-s&lt;/code&gt;, &lt;code&gt;.gap-m&lt;/code&gt;); классы примитивы более высокоуровневые и &lt;a href=&quot;https://www.jameskerr.blog/posts/3-types-of-css-utility-classes/&quot;&gt;из них приятно собирать композиции&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;если сделать фон из конического градиента и сдвигать его транзишном, а также применить к нему &lt;code&gt;mix-blend-mode: screen&lt;/code&gt;, то &lt;a href=&quot;https://frontendmasters.com/blog/text-reveal-with-conic-gradient/&quot;&gt;текст будет плавно проявляться «из маски»&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;короч, это не учебная тревога: в канареечный Chrome завезли &lt;code&gt;height: calc(auto)&lt;/code&gt;, чтобы &lt;a href=&quot;https://css-tricks.com/transitioning-to-auto-height/&quot;&gt;транзишном можно было плавно изменять высоту&lt;/a&gt; с &lt;code&gt;height: 0&lt;/code&gt; до актуальной без хаков&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;статья, что не стоит использовать &lt;code&gt;aria-hidden=&quot;true&quot;&lt;/code&gt; на интерактивных элементах, также напоминает, что &lt;a href=&quot;https://cerovac.com/a11y/2024/06/what-does-aria-hiddentrue-actually-do-to-interactive-elements/&quot;&gt;существует и поддерживается во всех браузерах атрибут inert,&lt;/a&gt; который «выключает» интерактивный элемент (на него нельзя нажать, дотабать или найти через средства доступности) — хороший юзкейс для ограничения пределов фокуса при показе модальных окон&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 12.07.2024</title><link>https://juwain.github.io/web-platform/blog/2024-07-12/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-07-12/</guid><description>Новости веб-платформы</description><pubDate>Fri, 12 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pnpm/pnpm/releases/tag/v9.5.0&quot;&gt;вышел pnpm v9.5.0&lt;/a&gt;: появились catalogs-алиасы, чтобы один раз в конфиге объявить набор зависимостей, например, &lt;code&gt;catalogs: react16: react: ^16.7.0 react-dom: ^16.7.0&lt;/code&gt;, а затем в &lt;code&gt;package.json&lt;/code&gt; писать алиас вместо версии напрямую &lt;code&gt;&quot;dependencies&quot;: { &quot;react&quot;: &quot;catalog:react16&quot;, &quot;react-dom&quot;: &quot;catalog:react16&quot; }&lt;/code&gt;; так можно лайтово организовать монорепу без оверхеда на одном пакетном менеджере&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/node/pull/53752&quot;&gt;SQLLite завезут в Nodejs&lt;/a&gt; для реализации &lt;code&gt;localStorage&lt;/code&gt;/&lt;code&gt;sessionStorage&lt;/code&gt;, а заодно откроют возможность его использования просто так; всё таки там, где есть борьба или хотя бы конкуренция, сразу идёт развитие (спасибо Bun и Deno)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/128&quot;&gt;вышел Firefox 128&lt;/a&gt;: появился встроенный в браузер переводчик, включен relative color syntax, поддержан &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/content#alternative_text&quot;&gt;альтернативный текст&lt;/a&gt; для свойства &lt;code&gt;content&lt;/code&gt;, заработала директива &lt;code&gt;@property&lt;/code&gt; и &lt;code&gt;registerProperty()&lt;/code&gt;, а также появился Resizeable ArrayBuffers&lt;/li&gt;
&lt;li&gt;вслед &lt;code&gt;@property&lt;/code&gt; в &lt;a href=&quot;https://front-end.social/@floscholz/112761020096320324&quot;&gt;FF вскоре появится и @starting-style&lt;/a&gt;, то есть он будет во всех браузерах&lt;/li&gt;
&lt;li&gt;после недавних больших обновлений eslint &lt;a href=&quot;https://eslint.org/blog/2024/07/whats-coming-next-for-eslint/&quot;&gt;начинается перелопачивание архитектуры&lt;/a&gt;: появятся отдельные пакеты для линтинга не-JS-файлов (json, md), агностик-ядро и пакеты переедут в новую репу, будет написан новый CLI; в общем, за этим крайне интересно наблюдать, как именно в большом проекте справляются с архитектурными проблемами, миграцией, и справятся ли в итоге&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vitest-dev/vitest/releases/tag/v2.0.0&quot;&gt;вышел vitest v2.0.0&lt;/a&gt;: браузерный режим работы, брейкинг-изменения, багфиксы&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fastify/fast-json-stringify&quot;&gt;fast-json-stringify&lt;/a&gt; — более быстрый аналог &lt;code&gt;JSON.stringify()&lt;/code&gt;, если скормить ему схему JSON, который нужно распарсить&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/SukkaW/nolyfill&quot;&gt;nolyfill&lt;/a&gt; — &lt;code&gt;npx nolyfill&lt;/code&gt; уменьшит содержимое &lt;code&gt;node_modules&lt;/code&gt; за счёт выпиливания ненужных более полифиллов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/toss/es-toolkit&quot;&gt;es-toolkit&lt;/a&gt; — новый более быстрый и компактный аналог lodash (который в свою очередь был более быстрым аналогом underscore)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TroyAlford/react-jsx-parser&quot;&gt;react-jsx-parser&lt;/a&gt; — React-компонент парсер JSX (если нужно распарсить в JSX динамически формируемую строку HTML или JSX)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;написание тестов — тонкая штука, вот и описания идеальных тестов звучат довольно расплывчато, но &lt;a href=&quot;https://web.dev/articles/ta-what-to-test&quot;&gt;как ещё описать тонкие материи&lt;/a&gt;? Тест — это скорее ассистент, а не математическая формула. Тесты должны быть простыми и сфокусированными на одной вещи. Тестов без причины не должно существовать. Тесты не должны содержать деталей реализации.&lt;/li&gt;
&lt;li&gt;сайт — это то же приложение, но которое не надо отдельно устанавливать/обновлять, а его просто когда нужно открываешь, оно подтягивает данные и работаешь с ним; &lt;a href=&quot;https://evilmartians.com/chronicles/recapping-the-first-local-first-conference-in-15-minutes&quot;&gt;если развить идею&lt;/a&gt;, то сайт может в целом иметь свою БД в браузере (IndexedDB, WASM + SQLite), хранить состояние и, когда есть возможность, синхронизировать состояние с сервером и другими клиентами; так автоматом повысится UX (не нужно на каждый чих ходить на сервер), тем более что современные клиенты позволяют&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-10/&quot;&gt;фича Isolated declarations в TS 5.5&lt;/a&gt; меняет то, как можно публиковать проекты: раньше в пакет публиковались отдельно d.ts-файлы и скомпилированные js-файлы, так как их генерация была затратной по производительности операцией; теперь же можно публиковать исходный ts-файл, а артефакты d.ts будут генериться на лету во время установки пакета за счёт более производительного движка&lt;/li&gt;
&lt;li&gt;бывают случаи, когда некорректно созданная мемоизация создаёт утечку памяти за счёт удержания замыкания с большим объектом в нём; печаль в том, что то же самое &lt;a href=&quot;https://schiener.io/2024-07-07/react-closures-compiler&quot;&gt;может сделать автомемоизатор React Compiler&lt;/a&gt;, но дебажить это станет сложнее&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tip.com/border-gradient/&quot;&gt;рецепт градиентной рамки&lt;/a&gt;: с вырезанием маской куска градиента, если нужна прозрачность, и с двойным градиентом (конический + линейный), если без прозрачности&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://emilkowal.ski/ui/the-magic-of-clip-path&quot;&gt;мощь свойства clip-path&lt;/a&gt; не только в возможности «вырезать» любую форму, но также и анимировать её (нужно в слайдерах, шторках, подложках)&lt;/li&gt;
&lt;li&gt;божественный &lt;a href=&quot;https://brucelawson.co.uk/2024/css-has-the-god-selector/&quot;&gt;селектор :has() всемогущ&lt;/a&gt; тем, что не требует структурной связи проверяемого селектора и стилизуемого элемента (проверяем одно, стилизуем другое)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;у &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; или &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; есть &lt;a href=&quot;https://frontendmasters.com/blog/script-integrity/&quot;&gt;атрибут integrity&lt;/a&gt;, в который передаётся хэш, и если содержимое файла скрипта или стилей изменится, а хэш нет, то тогда браузер выкинет ошибку и не выполнит файл (сгенерить хэш можно &lt;a href=&quot;https://www.srihash.org/&quot;&gt;тут&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 19.07.2024</title><link>https://juwain.github.io/web-platform/blog/2024-07-19/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-07-19/</guid><description>Новости веб-платформы</description><pubDate>Fri, 19 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reuters.com/markets/deals/google-backed-software-developer-gitlab-explores-sale-sources-say-2024-07-17/&quot;&gt;GitLab ищет, кому продаться&lt;/a&gt;: конкурировать с GitHub с копайлотом и нейросетям не вариант, пора выводить вложения; факт — пуллреквесты победили мерджреквесты&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/v1.45&quot;&gt;вышел Deno 1.45&lt;/a&gt;: среди прочего поддержаны &lt;a href=&quot;https://docs.npmjs.com/cli/v7/using-npm/workspaces&quot;&gt;npm workspaces&lt;/a&gt; (ну и конечно представлен свой кошерный аналог), так что работа с монорепами всячески улучшается с разных мест индустрии&lt;/li&gt;
&lt;li&gt;разработчики &lt;a href=&quot;https://blog.jquery.com/2024/07/17/second-beta-of-jquery-4-0-0/&quot;&gt;jQuery готовятся выпустить вторую бету&lt;/a&gt;, в которой переработали тесты: в нынешних реалиях нужны &lt;a href=&quot;https://github.com/jquery/jquery/pull/5429/files#diff-538a3cbad913567d5f6ff7b3f521e73b8784328305e312a58fa01d158fb0c6dc&quot;&gt;смоук-тесты&lt;/a&gt; для проверки, что проект собирается на webpack, rollup с виде cjs + esm, и чистом esm, а также импортируется в node&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/netlify-official-deployment-partner/&quot;&gt;Astro и Netlify теперь партнёры&lt;/a&gt;, будут получать ежемесячно денежку за то, что мягко приземляют проекты в облако; считаю, это хорошо, Astro — крутой проект&lt;/li&gt;
&lt;li&gt;в хромиум-браузерах &lt;a href=&quot;https://blogs.windows.com/msedgedev/2024/07/11/seamless-svg-copy-paste-on-the-web/&quot;&gt;заработал copy-paste SVG-элементов&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tinybase.org/&quot;&gt;tinybase&lt;/a&gt; — (в догонку к прошлому выпуску фронтвестника) local-first хранилище данных с возможностью синхронизации с сервером, минимального размера 5-15кб в зависимости от опций, хранит данные в виде пар ключ-значение или таблицы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nektos/act&quot;&gt;act&lt;/a&gt; — запускальщик GitHub Actions локально, чтобы не гонять CI почём зря&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bbss.dev/posts/react-learn-suspense/&quot;&gt;как на коленке собрать TanStack Query&lt;/a&gt;, а также &lt;code&gt;Suspence&lt;/code&gt; c хуком &lt;code&gt;use()&lt;/code&gt;: внутри кеши с &lt;code&gt;Map&lt;/code&gt; и &lt;code&gt;Set&lt;/code&gt;, промисы и использование их полей &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;reason&lt;/code&gt; и &lt;code&gt;value&lt;/code&gt;, а также контекст для распространения&lt;/li&gt;
&lt;li&gt;история о том, как от идеи хранения глобального состояния в React-контексте (чтобы задействовать Concurrent Mode) автор перешёл к идее отдельного стора, который по необходимости контекстом только распространяется, но не «живёт» в нём, и &lt;a href=&quot;https://blog.axlight.com/posts/how-zustand-was-born/&quot;&gt;так родился современный Zustand&lt;/a&gt;, заботливо выращенное дитя, который, верю, ждёт хорошее будущее (уже скоро Zustand 5)&lt;/li&gt;
&lt;li&gt;для &lt;a href=&quot;https://kurtextrem.de/posts/improve-inp&quot;&gt;лучшей производительности интерфейса&lt;/a&gt;, рекомендуют разбивать большие таски, загружающие тред, на более мелкие, откладывая из выполнение с помощью &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;requestAnimationFrame&lt;/code&gt;, а также нового API &lt;code&gt;scheduler.yield&lt;/code&gt;; также можно откладывать выполнение служебных задач (аналитика и тд) до срабатывания события страницы &lt;code&gt;visibilitychange&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&apos;1&apos;, &apos;5&apos;, &apos;11&apos;].map(parseInt)&lt;/code&gt; вернёт &lt;code&gt;[1, NaN, 3]&lt;/code&gt;, тк вместе &lt;code&gt;parseInt&lt;/code&gt; вместе с числом заодно получит вторым параметром индекс элемента, который будет использоваться в качестве системы счисления; вывод: так себе идея прокидывать &lt;a href=&quot;https://dev.to/safdarali/why1511mapparseint-returns-1-nan-3-in-javascript-2mhm&quot;&gt;в map напрямую «служебные» функции&lt;/a&gt;, внутри неявность, что плохо&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;из &lt;a href=&quot;https://gomakethings.com/the-many-ways-to-hide-things-in-the-dom/&quot;&gt;всех способов спрятать что-то на странице&lt;/a&gt; самый удобный — атрибут &lt;code&gt;hidden&lt;/code&gt;, если не хочется подключать CSS; &lt;code&gt;visibiliy: hidden&lt;/code&gt; и &lt;code&gt;display: none&lt;/code&gt; скрывают элементы также визуально и от скринридеров; и ещё парочка способов для сокрытия только от скринридеров и для видимости только им&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/jh3y/pen/gOeXgXv&quot;&gt;радиальный градиент внутри маски&lt;/a&gt; + карусель с картинками = эффект линзы, элегантный, чисто визуальный трюк с беспощадным кодом&lt;/li&gt;
&lt;li&gt;объявление кастомных свойств через директиву &lt;code&gt;@property&lt;/code&gt; (которая недавно, наконец, стала поддерживаться во всех браузерах) мало того, что открывает &lt;a href=&quot;https://web.dev/blog/at-property-baseline&quot;&gt;возможность анимировать переменную&lt;/a&gt;, так ещё и даёт &lt;a href=&quot;https://css-tip.com/typed-variables/&quot;&gt;лучшую поддержку типизации в браузере&lt;/a&gt; (да, в CSS тоже есть типы) + ещё есть, например, немного фриковая возможность &lt;a href=&quot;https://css-tip.com/screen-dimension/&quot;&gt;получить пиксельную ширину/высоту экрана&lt;/a&gt; &lt;code&gt;--w: tan(atan2(var(--_w),1px))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;вендорные префиксы были плохим решением для внедрения экспериментальных фич, а вот с &lt;a href=&quot;https://chenhuijing.com/blog/how-to-try-experimental-css-features/&quot;&gt;фича-флагами вышло уже хорошо&lt;/a&gt;: они доступны повсеместно во всех браузерах, чтобы попробовать экспериментальные фичи&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://utilitybend.com/blog/an-update-on-invokers-invoker-commands-in-html&quot;&gt;инициатива&lt;/a&gt; добавить в стандарт атрибуты commandfor и command, чтобы унифицировано связывать интерактивные элементы прямо в HTML: &lt;code&gt;&amp;lt;button commandfor=&quot;custom-video&quot; command=&quot;play&quot;&amp;gt;&lt;/code&gt; запустит &lt;code&gt;&amp;lt;video id=&quot;custom-video&quot;&amp;gt;&lt;/code&gt; (&lt;a href=&quot;https://open-ui.org/components/invokers.explainer/#defaults&quot;&gt;полный список предложений&lt;/a&gt; включает &lt;code&gt;dialog&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;audio/video&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;details&lt;/code&gt;…)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://conduition.io/coding/ticketmaster/&quot;&gt;кулстори&lt;/a&gt; о том, что технологические барьеры — не инновация, а бесячья тупость; о том, что offline-first — лучший подход, так как он имитирует реальность; о том, что веб — открытая среда, в которую несложно внедриться для реверс-инжиниринга (особенно когда клиент-сервер пересылают в открытую токены для генерации TOTP-строки, которая является, к примеру, билетом на концерт)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 26.07.2024</title><link>https://juwain.github.io/web-platform/blog/2024-07-26/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-07-26/</guid><description>Новости веб-платформы</description><pubDate>Fri, 26 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://workspaceupdates.googleblog.com/2024/07/import-and-export-markdown-in-google-docs.html&quot;&gt;в Google Docs завезли&lt;/a&gt; полноценную поддержку markdown (импорт/экспорт/копипейст)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-127&quot;&gt;вышел Chrome 127&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддержано свойство &lt;code&gt;font-size-adjust&lt;/code&gt; (костылим везде, &lt;a href=&quot;https://web.dev/blog/font-size-adjust&quot;&gt;теперь поддерживают все браузеры&lt;/a&gt;!)&lt;/li&gt;
&lt;li&gt;alt-текст в content&lt;/li&gt;
&lt;li&gt;Document picture-in-picture теперь общается с основным окном&lt;/li&gt;
&lt;li&gt;на контейнеры со скроллом теперь можно сфокусироваться с клавиатуры&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;в React завозят server-only плюшки: &lt;a href=&quot;https://github.com/facebook/react/pull/30105&quot;&gt;отдельный пакет renderToMarkup&lt;/a&gt; предназначен для асинхронного рендера JSX в статику, которая не будет дальше никак обновляться (например, для генерации писем и другой статики); использование state, effect будет сыпать ошибки (впрочем, всё же сделали &lt;a href=&quot;https://github.com/facebook/react/pull/30121&quot;&gt;отдельный пакет для клиент-сайда&lt;/a&gt;, пометив сразу «для поддержки легаси-сред»)&lt;/li&gt;
&lt;li&gt;вышли результаты &lt;a href=&quot;https://survey.stackoverflow.co/2024/&quot;&gt;Stackoverflow Developer Survey 2024&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;веб всё ещё на коне, хотя зарплаты, как и почти везде (за исключением Erlang) уменьшились (при этом фронтендеры — почти самые низкооплачиваемые IT-специалисты)&lt;/li&gt;
&lt;li&gt;в БД лидирует PostgreSQL&lt;/li&gt;
&lt;li&gt;jQuery популярнее Next.js&lt;/li&gt;
&lt;li&gt;Markdown File — третий по популярности инструмент для асинхронной коммуникации&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;опубликованы &lt;a href=&quot;https://2023.stateofreact.com/&quot;&gt;результаты опроса State of React 2023&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;RCS заходит туго, боли вызывает forwardRef, Redux и тот же RCS&lt;/li&gt;
&lt;li&gt;популярны Tanstack Query, Zustand, Astro, Radix, shadcn/ui, Next.js&lt;/li&gt;
&lt;li&gt;доминирует по прежнему SPA&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://swapy.tahazsh.com/&quot;&gt;swapy&lt;/a&gt; — создание в приложении виджетного лейаута с драг-н-свапом&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.designgui.io/&quot;&gt;designgui&lt;/a&gt; — расширение Chrome для просмотра и управления CSS-переменными с цветами темы (как минимум, чтобы поудобнее искать и копировать цвета)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://svg.wtf/&quot;&gt;svg.wtf&lt;/a&gt; — инструмент для изучения и экспериментирования с SVG&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/introducing-svelte-5/&quot;&gt;Svelte дозрел&lt;/a&gt; до того возраста, когда уже поднакопилось достаточно массы, чтобы нужен был двусторонний interop между двумя мажорными версиями (читать как «достаточно наворотили»), в то же время изменения к лучшему в понятности API в новой версии налицо (читать как «исправляют навороченное, но надо поддерживать старый синтаксис»); в целом, впечатления о нём странные: что-то похожее на vue c mobx, при этом с костыльками для работы с TS, типа &lt;code&gt;&amp;lt;script lang=&quot;ts&quot; generics=&quot;T extends { name: string }&quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;когда читаешь про всякие WASM SQLite, Origin Private File System (OPFS) и их использование через SharedWorker и WebWorker, обычно это всё кажется какой-то далёкой от реальности фантастикой, только если ты не работаешь в Notion и тебе надо &lt;a href=&quot;https://www.notion.so/blog/how-we-sped-up-notion-in-the-browser-with-wasm-sqlite&quot;&gt;ускорить навигацию между страницами&lt;/a&gt;, сохраняя бд в файловой системе устройства и шаря её на все открытые табы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webdeveloper.beehiiv.com/p/differences-object-object-typescript&quot;&gt;отличия «объектов» в TS&lt;/a&gt;: Object — это любые объекты типа &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;bigint&lt;/code&gt;, &lt;code&gt;symbol&lt;/code&gt; (у них есть свойства &lt;code&gt;cunstructor&lt;/code&gt;, &lt;code&gt;toString&lt;/code&gt;…), &lt;code&gt;{}&lt;/code&gt; — это пустой объект без полей, а &lt;code&gt;object&lt;/code&gt; — не непримитивные типы, то есть &lt;code&gt;{}&lt;/code&gt;, &lt;code&gt;[]&lt;/code&gt; и &lt;code&gt;() =&amp;gt; {}&lt;/code&gt; (&lt;code&gt;object&lt;/code&gt; также имеет аналог &lt;code&gt;Record&amp;lt;string, any&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://swizec.com/blog/dry-the-common-source-of-bad-abstractions/&quot;&gt;напоминание&lt;/a&gt;: DRY как самоцель может подтолкнуть к созданию ненужных абстракций, которые часто оказываются ещё и негибким, а гибкость — наверное одно из важных качеств абстракций&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reacttraining.com/blog/use-useid-instead-of-hand-making-ids&quot;&gt;хук useId&lt;/a&gt; можно использовать для генерации id DOM-элементов в рантайме&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;в гайдах от Ahmad Shadeed обычно интересны практические юзкейсы использование фич; вот и в &lt;a href=&quot;https://ishadeed.com/article/css-grid-area/&quot;&gt;этом гайде по grid-area&lt;/a&gt; приводятся жизненные примеры использования: перестановка блоков местами в лейауте на разных разрешениях, «вылезающие» из прямоугольной сетки блоки, накладывающиеся области грида, has()-комбо &lt;code&gt;.card:has(figcaption) { grid-template-areas: &apos;update layout&apos;}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tip.com/scroll-progress/&quot;&gt;схема&lt;/a&gt;, которая с появлением scroll-based-анимаций, стала ещё актуальнее: кастомное свойство — стейт, анимация — способ изменения стейта, счётчик — способ отображения стейта&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/single-directionally-allowed-overflow/&quot;&gt;напоминание&lt;/a&gt;: контейнер с &lt;code&gt;overflow: hidden&lt;/code&gt; всё равно можно проскроллить выделением текста или программно, а с overflow: clip возможность скролла будет гарантировано полностью выпилена&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 02.08.2024</title><link>https://juwain.github.io/web-platform/blog/2024-08-02/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-08-02/</guid><description>Новости веб-платформы</description><pubDate>Fri, 02 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/node/pull/53725&quot;&gt;в Node.js начали завозить «нативную поддержку» TS&lt;/a&gt;, пока на уровне вырезания аннотаций типов из кода, то есть enum-ы и другие штуки, которые просто вырезать не получится, пока что не работают (&lt;a href=&quot;https://github.com/nodejs/amaro&quot;&gt;под капотом работает либа @swc/wasm-typescript&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://babeljs.io/blog/2024/07/26/7.25.0&quot;&gt;обновился Babel до версии 7.25.0&lt;/a&gt;: как-то Babel всегда воспринимался как инструмент для использование ультрасовременных фич в браузерах; в целом, этот апдейт так же об этом, но что интересно, добавлен плагин для фикса &lt;em&gt;браузерного&lt;/em&gt; бага в Safari 16, и тут я задумался, а сколько там возможно интересного скрыто под капотом популярных инструментов типа Vite, которое незаметно что-то фиксит, и всё просто продолжает работать чуть лучше&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/15739/webkit-features-in-safari-17-6/&quot;&gt;зарелизился Safari 17.6&lt;/a&gt;: поддержали ключевое слово safe во флексбоксах justify-content: safe center, завезли багфиксы события &lt;code&gt;loadeddata&lt;/code&gt; для &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; на загрузке страницы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://privacysandbox.com/news/privacy-sandbox-update/&quot;&gt;в Google отказались от идеи блокирования 3d-party cookies&lt;/a&gt;, но зато пообещали дать браузерные настройки, где можно будет явно настроить приватность (делать это конечно же никто не будет)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mixmark-io/turndown&quot;&gt;turndown&lt;/a&gt; — преобразователь HTML в md для браузера и Node.js&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/emilkowalski/vaul&quot;&gt;vaul&lt;/a&gt; — нестилизованный компонент выдвигающейся «шторки» для React&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tajo/react-movable&quot;&gt;react-movable&lt;/a&gt; — ещё одна drag-n-drop либа для React, апишка с первого взгляда простая&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;в до-реактовые времена как-то повсеместно была распространена инфа, что &lt;code&gt;innerHTML&lt;/code&gt; медленный, и что DOM лучше менять пачкой, а не на каждый чих использовать &lt;code&gt;appendChild&lt;/code&gt;; потом как-то это всё подменилось знаниями о ререндерах в SPA, тем не менее &lt;a href=&quot;https://frontendmasters.com/blog/patterns-for-memory-efficient-dom-manipulation/&quot;&gt;DOM никуда не делся&lt;/a&gt; и все ранее работавшие приёмы, а так же новые, работают! Например, &lt;code&gt;AbortController().abort()&lt;/code&gt; может отменить пачкой навешенные event listener-ы, а &lt;code&gt;WeakMap&lt;/code&gt; и &lt;code&gt;WeakRef&lt;/code&gt; можно использовать для создания ссылок на DOM-элементы, которые при их удалении, подчищаются и из памяти&lt;/li&gt;
&lt;li&gt;в интеграционных тестах на Playwright часто &lt;a href=&quot;https://www.checklyhq.com/blog/why-page-goto-is-slowing-down-your-playwright-test/&quot;&gt;используется await page.goto()&lt;/a&gt;, которая по умолчанию открывает страницу и ждёт полной загрузки и отрисовки, что обычно избыточно для тестирования того, что, например, нажатие по кнопке вызывает появление модалки; поэтому лучше пользовать &lt;code&gt;page.goto(&quot;/&quot;, {waitUntil: &quot;commit&quot;})&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://michaeluloth.com/programming-types-unknown-why-useful/&quot;&gt;тип unknown полезен для типизации&lt;/a&gt; неизвестного user-input-а, когда он может быть, а может не быть, поэтому при попытке обращения, к примеру, к методам строки, тип ругнётся и сообщит, что этого метода может и не быть&lt;/li&gt;
&lt;li&gt;в Vercel провели прикладное исследование, как &lt;a href=&quot;https://vercel.com/blog/how-google-handles-javascript-throughout-the-indexing-process&quot;&gt;сейчас JS влияет SEO в Google&lt;/a&gt;: SPA индексируются также, как и статические сайты; JS выполняется, в том числе на «сервере» Next.js, импорты CSS тоже работают; нагруженные JS сайты индексируются также быстро, как ненагруженные, но если рендер требует большего времени и при этом страниц много, то бот будет дольше их обходить&lt;/li&gt;
&lt;li&gt;barrel-файлы (только реэкспортирующие внутренности модуля) &lt;a href=&quot;https://tkdodo.eu/blog/please-stop-using-barrel-files&quot;&gt;создают дополнительную вычислительную нагрузку&lt;/a&gt; на проект, и если таких файлов много в большом проекте, то с этим что-то нужно дополнительно делать (убирать такие файлы или преобразовывать пути импортов в обход таких файлов)&lt;/li&gt;
&lt;li&gt;затягивая в замыкание «большой» объект, следует помнить, что если к нему будет обращаться функция внутри замыкания, то это &lt;a href=&quot;https://jakearchibald.com/2024/garbage-collection-and-closures/&quot;&gt;может привести к утечке памяти&lt;/a&gt; (если создаёте замыкание, стоит проверить, что в него попадёт)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://moderncss.dev/providing-type-definitions-for-css-with-at-property/&quot;&gt;директива @property&lt;/a&gt;, недавно завезённая во все браузеры, позволяет делать типизированные наборы CSS-переменных (например, в рамках дизайн системы), и типы эти будут, если что, стрелять в рантайме в браузере (при желании наверное можно и stylelint-ом отлавливать неправильно заданные типы во время разработки); кроме того, есть интересные варианты, которые &lt;em&gt;может быть&lt;/em&gt; были позаимствованы из TS: тип &lt;code&gt;syntax: &quot;blue | cyan | dodgerblue&quot;&lt;/code&gt; для задания в переменную только этих цветов или же тип &lt;code&gt;syntax: &amp;lt;image&amp;gt;#&lt;/code&gt; для задания множественных значений через запятую (также есть тип &lt;code&gt;&apos;*&apos;&lt;/code&gt; — аналог &lt;code&gt;any&lt;/code&gt;, тип по умолчанию)&lt;/li&gt;
&lt;li&gt;если вдруг PopopevAPI (с недавнего времени доступный во всех современных браузерах) прошёл мимо вас, то вот &lt;a href=&quot;https://www.amitmerchant.com/popover-api-101/&quot;&gt;свежий гайд в тему&lt;/a&gt; (годится для создания простых модалок)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 02.09.2024</title><link>https://juwain.github.io/web-platform/blog/2024-08-09/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-08-09/</guid><description>Новости веб-платформы</description><pubDate>Fri, 09 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://dev.to/encore/encorets-9x-faster-than-expressjs-3x-faster-than-bun-zod-4boe&quot;&gt;новый бэкенд-фреймворк для TS Encore&lt;/a&gt;, который вы вряд ли будете использовать, но интересна ключевая фича, которая даёт существенный прирост в скорости работы (быстрее express в 9 раз): узкое горлышко Nodejs — однопоточный eventloop, который быстрее не сделать, поэтому создатели Encore придумали сделать ещё один эвент-луп (Rust, многопоточный), этим эвентлупом обрабатывать входящие запросы, декодировать и делать прочие дорогие операции и затем уже передавать в эвентлуп Node; заодно не нужно долго воссоздавать API для совместимости Nodejs, как это делают в Bun, так как дело всё равно в итоге происходит в Node&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v2.tauri.app/blog/tauri-2-0-0-release-candidate/&quot;&gt;выпущен Tauri 2.0 RC&lt;/a&gt;, который вы тоже вряд ли используете, но у него тоже интересный подход: вместо того, чтобы в десктопное приложение встраивать Chromium, он заменён на более лёгкий web view на Rust&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hacks.mozilla.org/2024/08/puppeteer-support-for-firefox/&quot;&gt;в Puppeteer завезли Firefox&lt;/a&gt;: большинство основных API уже поддерживается, но дольше ещё будут довозить более специфичные API&lt;/li&gt;
&lt;li&gt;6 августа исполнилось 33 года со дня выпуска &lt;a href=&quot;http://info.cern.ch/hypertext/WWW/TheProject.html&quot;&gt;первого сайта в интернете&lt;/a&gt; (это что, они 33 года подряд не забывают продлить домен?!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://formatify.pages.dev/&quot;&gt;formatify&lt;/a&gt; — аудио-видео-картиночный конвертер в любой формат&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kvin.me/css-springs&quot;&gt;css-springs&lt;/a&gt; — копипейст генератор «пружинных» CSS-изингов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lukeed/tschema&quot;&gt;tschema&lt;/a&gt; — микроутилита для создания JSON-схем и вывода TS-типов из них (идеально создавать общий контракт для бэка/фронта и затем генерить типы, всместо того, что писать их руками)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/texel-org/color&quot;&gt;color&lt;/a&gt; — либа для процессинга современных форматов цветов (oklab, xyz, p3, rec2020…)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;напоминание, &lt;a href=&quot;https://webdeveloper.beehiiv.com/p/avoid-default-exports-javascript-modules&quot;&gt;почему default-экспортами лучше не злоупотреблять&lt;/a&gt;: сложно искать в проекте, не выводится название из модуля в IDE, излишняя свобода при выборе имён разработчиками; заодно есть рецепт, как переэкспортить неименованный модуль как именованный &lt;code&gt;export { default as Row } from &apos;./Row.jsx&apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;от XSS-атаки можно защититься с помощью &lt;a href=&quot;https://www.writesoftwarewell.com/content-security-policy/&quot;&gt;CSP (Content Sucurity Policy)&lt;/a&gt; — директивы браузеру не запускать инлайновые срипты и стили, а разрешать запуск только с проверенного источника; самый простой способ её включить — метатег &lt;code&gt;&amp;lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;script-src &apos;self&apos; https://safe-external-site.com&quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://frontendmasters.com/blog/snippets-in-svelte-5/&quot;&gt;Svelte 5 представили новый концепт&lt;/a&gt; выделения небольших блоков «HTML-контента» в так называемый snippet; это что-то похожее на «шаблоны», которые можно заинжектить в компонент (&lt;code&gt;children&lt;/code&gt; в мире React такой тоже своеобразный snippet); фича выглядит, если честно, странновато, скорее как замена задепрекейченным slot-ам (хотя по мне slot-ы — норм тема, немного непривычная, но прикольная)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexkondov.com/refactoring-a-messy-react-component/&quot;&gt;рефакторинг типичного навороченного React-компонента&lt;/a&gt; в идеале начинается с написания тестов (чтоб сигнализировать, если сломалось), удаления неиспользуемого кода, разделения на более мелкие компоненты и вынос в них состояния, упрощение условных конструкций, вынос утилитарных функций, дата-фетчинга и инлайновых стилей вне компонента, улучшение отмены запросов, отправки и валидации формы&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;возможно, &lt;a href=&quot;https://scottjehl.com/posts/svgtopia/&quot;&gt;лучший способ использования стилизуемых SVG&lt;/a&gt; — это «спрайты», то есть библиотека &lt;code&gt;&amp;lt;symbol&amp;gt;&lt;/code&gt;, подключаемая с &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;; но есть и ограничение — SVG должно лежать на том же домене, где оно используется&lt;/li&gt;
&lt;li&gt;признавайтесь, вы ведь тоже не используете container queries в повседневной работе? А если вдруг всё таки решитесь использовать — &lt;a href=&quot;https://frontendmasters.com/blog/what-if-you-used-container-units-for-everything/&quot;&gt;у них есть ограничения&lt;/a&gt;: для корректного применения стилей нужен «обёрточный» элемент только для применения «контейнерных» стилей, также контейнерные единицы измерения не всегда уместно применять к тексту (надо ограничивать слишком мелкий/крупный размер шрифта)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://martinheinz.dev/blog/113&quot;&gt;cURL&lt;/a&gt; — утилита для проверки, что какой-то URL что-то отдаёт, или нет? На самом деле это целая библиотека, которая может отправлять несколько параллельных и последовательных запросов, а также POST-запросы, поддерживает передачу кастомных заголовков (например, для прокси) и логина/пароля в конфигах .curlrc и .netrc, умеет парсить URL в JSON, и ещё поддерживает не только HTTP/HTTPS-протоколы, но и, например, почтовые IMAP и SMTP, то есть с помощью cURL можно отправить письмо из консоли&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 16.08.2024</title><link>https://juwain.github.io/web-platform/blog/2024-08-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-08-16/</guid><description>Новости веб-платформы</description><pubDate>Fri, 16 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/WebKit/WebKit/pull/31616&quot;&gt;в Webkit (Safari) будет поддержано свойство scrollbar-width:&lt;/a&gt; в среде разработчиков принято считать, что монополизация индустрии веба Google с помощью Chrome приведёт к стагнации и неминуемой деградации, но есть непопулярное мнение, что централизация движухи в одной ведущей компании сразу же заставляет остальных игроков оперативнее подтягиваться за лидером; так вышло с поддержкой scrollbar-width: в FF это свойство поддерживалось сто лет в обед, но стоило его внедрить в Chrome, как зашевелились в Safari&lt;/li&gt;
&lt;li&gt;но у монополии есть и обратная сторона — к компании сразу же начинают пристальнее присматриваться регуляторы; &lt;a href=&quot;https://www.bloomberg.com/news/articles/2024-08-05/google-loses-doj-antitrust-suit-over-search&quot;&gt;вот и Google проигрывает дело,&lt;/a&gt; в котором компания обвиняется в приплачивании, чтобы сделать гуглопоиск вариантом по умолчанию; помимо штрафа речь может идти об отделении поискового бизнеса от Android и Chrome&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/129.0/releasenotes/&quot;&gt;вышел Firefox 129:&lt;/a&gt; https-протокол теперь применяется к сайтам по умолчанию, добавлена поддержка &lt;code&gt;@starting-style&lt;/code&gt; (но пока без анимации из &lt;code&gt;display: none&lt;/code&gt;) и &lt;code&gt;transition-behavior&lt;/code&gt;, добавлено превью по наведению на таб и подсветка неправильно использующихся CSS-свойств в дев-тулзах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openai.com/index/introducing-structured-outputs-in-the-api/&quot;&gt;OpenAI выкатили Structured Outputs API:&lt;/a&gt; в предыдущих сериях в компании научили LLM выдавать данные в виде JSON, но проблема в том, что не было гарантии, что в 100% случаев будет соблюдена схема данных и формат; с новым API можно приложить JSON schema и данные будут валидироваться по ней, как если бы это делалось, например, с помощью Zod&lt;/li&gt;
&lt;li&gt;в Sentry придумали и запустили новый вид лицензии открытого кода — &lt;a href=&quot;https://fair.io/&quot;&gt;Fair Source Software,&lt;/a&gt; идея такая: вы опенсорсов продаёте? нет только показываю&lt;/li&gt;
&lt;li&gt;появилось предложение &lt;a href=&quot;https://github.com/arthurfiorette/proposal-safe-assignment-operator&quot;&gt;ECMAScript Safe Assignment Operator Proposal&lt;/a&gt; для более краткого написания возможного фейла промиса или throw ошибки: &lt;code&gt;const [error, response] ?= await fetch(&quot;https://url&quot;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/css-chronicles-xlii/&quot;&gt;CSS Tricks подтвердили, что они ожили!&lt;/a&gt; Не просто так начали появляться статьи в последнее время, на ресурсе будут теперь публиковаться Geoff Graham, Juan Diego Rodriguez (ранее часто писал для SmashingMag-а) и Ryan Trimble; так глядишь и Крис вернётся&lt;/li&gt;
&lt;li&gt;история с нативной поддержкой TS в Node &lt;a href=&quot;https://github.com/nodejs/node/pull/54283&quot;&gt;получила продолжение:&lt;/a&gt; теперь поддерживаются TS-only штуки (Enum and namespace)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.raymondcamden.com/2024/08/13/a-quick-look-at-ai-in-chrome&quot;&gt;в Chrome начали завозить ai:&lt;/a&gt; в dev-версии браузера появился объект &lt;code&gt;window.ai&lt;/code&gt; с методами &lt;code&gt;canCreateTextSession&lt;/code&gt;, &lt;code&gt;createTextSession&lt;/code&gt;, &lt;code&gt;textModelInfo&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pdomdev/pdom&quot;&gt;pdom&lt;/a&gt; — ещё один заход в «параллелизацию потоков» DOM, трюк такой: создаём cross origin фрейм для «параллельного» компонента, рендерим туда нужный компонент, встраиваем в хост-приложение и общаемся с компонентом через postMessage&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://floating-ui.com/&quot;&gt;floating-ui&lt;/a&gt; — Popper умер, да здравствует Floating UI! Либа-наследник Popper для показа всплывающихся тултипов с плюшками в виде анимаций, якорения, обработки скролла&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/react-figma/react-figma&quot;&gt;react-figma&lt;/a&gt; — рендерер React-компонентов в Figma (не наоборот!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://scottjehl.com/posts/html-web-components-shadow-dom/&quot;&gt;в веб-компонентах в &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt;&lt;/a&gt; можно прокидывать внутрь shadow DOM обычный DOM-элемент, а с помощью псевдоэлемента &lt;code&gt;::slotted(SELECTOR)&lt;/code&gt; можно изнутри shadow DOM стилизовать обычный DOM-элемент (при этом стили снаружи веб-компонента будут приоритетнее внутренних): с печалью считаю, что в рабочем коде это всё будет выглядеть как минимум экзотикой, а как максимум оверинжинирингом&lt;/li&gt;
&lt;li&gt;если вы используете zustand, но вам не хватает событийной модели, можно &lt;a href=&quot;https://tkdodo.eu/blog/introducing-x-state-store&quot;&gt;присмотреться к xstate/store,&lt;/a&gt; у которого похожий API, но ещё есть вдобавок и триггер событий типа &lt;code&gt;store.send({ type: &apos;actionName&apos;, someEventParam: 123 })&lt;/code&gt;; бонусом идёт конверт сторов в полноценную state machine (конечный автомат) xstate&lt;/li&gt;
&lt;li&gt;а что если БД будет поставляться прямо в браузер в сжатом виде, с UI и со встроенным ai-помощником? &lt;a href=&quot;https://supabase.com/blog/postgres-new&quot;&gt;Получите&lt;/a&gt; &lt;a href=&quot;https://postgres.new&quot;&gt;https://postgres.new&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;раньше, чтобы сделать текущий цвет более прозрачным, тёмным или светлым, использовались цветовые функции CSS-препроцессоров; ожидаемо, эту функциональность воссоздали со стороны платформы, только не в виде функций, а с помощью нового цветового формата — &lt;a href=&quot;https://frontendmasters.com/blog/relative-color-syntax-basic-use-cases/&quot;&gt;relative color syntax&lt;/a&gt; (с недавних пор доступного во всех браузерах)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 23.08.2024</title><link>https://juwain.github.io/web-platform/blog/2024-08-23/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-08-23/</guid><description>Новости веб-платформы</description><pubDate>Fri, 23 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/node-js-takes-steps-towards-removing-corepack&quot;&gt;в Node.js решили не включать corepack по умолчанию&lt;/a&gt;, а также выделить его в отдельный проект и выпилить его из базовой поставки Node; с одной стороны вроде как шаг назад, с другой — corepack даёт возможность установки пакетных менеджеров не из npm, что создаёт риски безопасности, и на мой взгляд явно воспринимается как инородный инструмент внутри Node, так что отдельным проектом ему быть не повредит&lt;/li&gt;
&lt;li&gt;в альтернативный RSC-фреймворк &lt;a href=&quot;https://waku.gg/blog/server-actions-are-here&quot;&gt;Waku завезли Server Actions&lt;/a&gt;, и это безусловно хорошо в качестве альтернативы и конкуренции&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://astro.build/blog/astro-4140/&quot;&gt;Astro 4.14&lt;/a&gt; появилась API для загрузки контентной структуры файлов извне проекта, есть теперь не обязательно держать движок контентного сайта и сам контент в одном проекте&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://nodejs.org/en/blog/release/v22.7.0&quot;&gt;Node v22.7.0&lt;/a&gt; (current) появилась экспериментальная поддержка TS-синтаксиса (Enum и namespace)&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://nodejs.org/en/blog/release/v20.17.0&quot;&gt;Node v20.17.0&lt;/a&gt; (lts) бэкпортирован require ESM-модулей, CommonJs-подход окончательно уходит&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://cheerio.js.org/blog/cheerio-1.0&quot;&gt;Cheerio 1.0&lt;/a&gt; (7 лет разрабатывали до 1.0!) — либа для парсинга и манипуляций с HTML и XML, позволяет, к примеру, методом &lt;code&gt;fromURL&lt;/code&gt; спарсить HTML с урла, может быть полезно для скрейпинга&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/damianricobelli/stepperize&quot;&gt;stepperize&lt;/a&gt; — React-либа для создания пошаговых интерфейсов (например, визардов), типизированная, мало весит, без дефолтных стилей&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dahlia/logtape&quot;&gt;logtape&lt;/a&gt; — логгер для JS/TS с подсветкой типа лога, встроенными фильтрами и выводами в разные места назначения (консоль, поток, файл…)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vercel/little-date&quot;&gt;little-date&lt;/a&gt; — форматтер диапазонов дат на основе date-fns&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://defensivecss.dev/tips&quot;&gt;defensivecss&lt;/a&gt; — сборник «пуленепробиваемых» техник в вёрстке от Ahmad Shadeed&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;в двух словах для чего нужны &lt;a href=&quot;https://noahflk.com/blog/typesafe-rest-api&quot;&gt;TanstackQuery&lt;/a&gt; — чтобы обернуть асинхронный запрос в синхронный хук и обработать кеширование, и &lt;a href=&quot;https://noahflk.com/blog/typesafe-rest-api&quot;&gt;Zod&lt;/a&gt; — для объявления типа данных один раз в схеме и инфера типов из схемы, а также для валидации приходящих данных (тк TS не гарантирует типобезопасности входящих данных, &lt;code&gt;Promise&amp;lt;FetchedData&amp;gt;&lt;/code&gt; усыпляет бдительность)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;если нужно &lt;a href=&quot;https://spacejelly.dev/posts/generate-a-pdf-from-html-in-javascript&quot;&gt;сгенерить pdf из сайта&lt;/a&gt;, то для этого есть пара специализированных либ, либо Puppetier, в котором как и обычном браузере, можно программно сохранить страницу как pdf&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;в последнее время развелось так много state-менеджеров, что их уже начинают использовать для продвижения других либ: вот, к примеру, &lt;a href=&quot;https://www.legendapp.com/open-source/state/v3/&quot;&gt;Legend State — реактивный state-менеджер&lt;/a&gt;, стейт заворачивается в &lt;code&gt;observable&lt;/code&gt;, а компонент в &lt;code&gt;observer&lt;/code&gt;, у стейта есть методы &lt;code&gt;get&lt;/code&gt; и &lt;code&gt;set&lt;/code&gt;, а если понравилось, то можно купить оптимизированные для этого стейт-менеджера компоненты, хуки и хелперы за 200$ (на торрентах отсутствует)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2024/08/history-future-regular-expressions-javascript/&quot;&gt;в истории развития регекспов&lt;/a&gt; есть интересные моменты, например, появление lookbehind-выражения &lt;code&gt;?&amp;lt;=..&lt;/code&gt;. в es2018, &lt;code&gt;matchAll&lt;/code&gt; в es2020 и flag &lt;code&gt;v&lt;/code&gt; в es2024, но тем не менее регекспы нечитаемые (навечно) и поэтому есть пространство для появления либ, «очеловечивающих» регекспы, например, regex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.covicale.com/blog/using-javascript-generators-to-visualize-algorithms&quot;&gt;основной юзкейс генераторов в JS&lt;/a&gt; — пошаговое исполнение &lt;em&gt;чего-либо&lt;/em&gt;, например, пошаговое исполнение цикла алгоритма с целью демонстрации его процесса&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если вы всё ещё используете sass, то в Vite и Webpack можно переключить компилятор с sass на sass-embedded &lt;a href=&quot;https://www.oddbird.net/2024/08/14/sass-compiler/&quot;&gt;для ускорения работы&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2024/07/11/feature-detect-css-starting-style-support/&quot;&gt;проверка поддержки @starting-style в CSS&lt;/a&gt;: создаётся числовое кастомное свойство и внутри &lt;code&gt;@starting-style&lt;/code&gt; задаётся значение 1, дальше используется в качестве «реле» в транзишнах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/the-css-contain-property/&quot;&gt;свойство contain позволяет изолировать элемент&lt;/a&gt;, то есть элемент как бы рендерится внутри страницы, но не влияет на общий рендер&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если вдруг вам нужно отрендерить огромные таблицы, используя colspan и rowspan, то вероятно можно уткнуться в &lt;a href=&quot;https://mas.to/@j9t/112926368766374917&quot;&gt;максимальное значение&lt;/a&gt; для colspan — это 1000, а для rowspan — 65534; если так подумать, то наиболее распространены высокие и неширокие таблицы, что вероятно пошло от бумажного формата ленты и перекочевало в браузеры, это отражено в магических значениях&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;а что если подсветку синтаксиса кода в браузере &lt;a href=&quot;https://blog.glyphdrawing.club/font-with-built-in-syntax-highlighting/&quot;&gt;можно сделать без JS и даже CSS&lt;/a&gt;? Просто встроить цветные глифы в сам моноширинный шрифт! Правда размер шрифта должен подрасти (из-за дублей одинаковых символов во всех цветах), но зато для работы достаточно загрузить и подключить один шрифт&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 30.08.2024</title><link>https://juwain.github.io/web-platform/blog/2024-08-30/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-08-30/</guid><description>Новости веб-платформы</description><pubDate>Fri, 30 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;выпущен &lt;a href=&quot;https://deno.com/blog/v1.46&quot;&gt;Deno 1.46:&lt;/a&gt; удивительный пример живучего проекта (6 лет!), который чтобы выжить всё больше адаптируется к Node и её экосистеме (playwright, pglite, mysql2…), но при этом переосмысляет отдельные вещи типа file watcher, лок-файла, менеджа зависимостей, делая их проще и удобнее, и в добавок ещё и привносит свою &lt;a href=&quot;https://github.com/denoland/std&quot;&gt;библиотеку&lt;/a&gt; «часто используемых велосипедов», чтобы не тянуть это отдельными зависимостями&lt;/li&gt;
&lt;li&gt;если ваш проект с webpack не новый и Vite завезти туда сходу не получится, то возможно это повод попробовать бандлер &lt;a href=&quot;https://github.com/web-infra-dev/rspack&quot;&gt;Rspack,&lt;/a&gt; тем более, что &lt;a href=&quot;https://rspack.dev/blog/announcing-1-0&quot;&gt;вышла его версия 1.0&lt;/a&gt; (с версии 0.1 прошло 18 месяцев), то есть он теперь хорошо совместим с webpack v5 API, но при этом в 10 раз шустрее, а в добавок имеет отдельные тулы, например, билд-тула &lt;a href=&quot;https://github.com/web-infra-dev/rsbuild&quot;&gt;Rsbuild&lt;/a&gt; — аналог CRA или Vue CLI для создания «просто работающего» приложения без доп настроек и танцев с бубном или &lt;a href=&quot;https://github.com/web-infra-dev/rspress&quot;&gt;Rspress&lt;/a&gt; — генератор статических сайтов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/scroll-snap-events&quot;&gt;в Chrome 129 появятся события&lt;/a&gt; &lt;code&gt;scrollSnapChange&lt;/code&gt; и &lt;code&gt;scrollSnapChanging&lt;/code&gt;, чтобы добавлять обработчики snap-скролл-событий (нативное «прилипание» блоков при скролле/свайпе): будет легче делать карусели и обходиться без &lt;code&gt;Intersection Observer&lt;/code&gt; или вычислений&lt;/li&gt;
&lt;li&gt;анонсирован &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-6-rc/&quot;&gt;TypeScript 5.6 RC:&lt;/a&gt; появится опция &lt;code&gt;--noCheck&lt;/code&gt;, которая позволяет не запускать тайпчекинг, а совместно с опцией &lt;code&gt;--isolatedDeclarations&lt;/code&gt; &lt;code&gt;--noCheck&lt;/code&gt; позволяет быстро генерить &lt;code&gt;.d.ts&lt;/code&gt;-файлы без тайпчекинга&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.freepublicapis.com/&quot;&gt;freepublicapis&lt;/a&gt; — курируемый список свободно доступных публичных API с тестовыми данными (есть фильтрация по скорости и надёжности работы)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepo8.github.io/dearconsole/&quot;&gt;dearconsole&lt;/a&gt; — набор копипейст-скриптов для браузерной консоли, есть интересные находки, например, &lt;code&gt;document.fonts&lt;/code&gt; выдаст набор шрифтов сайта&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://evercoder.github.io/clipboard-inspector/&quot;&gt;clipboard-inspector&lt;/a&gt; — анализ содержимого буфера обмена: туда копируется не только сам текст, но и окружающие HTML и CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://noahflk.com/blog/typesafe-rest-api&quot;&gt;грядущий,&lt;/a&gt; но уже доступный через полифилл стандарт &lt;a href=&quot;https://docs.timetime.in/blog/js-dates-finally-fixed/&quot;&gt;Temporal.ZonedDateTime,&lt;/a&gt; расширяет дату в формате ISO явным указанием таймзоны и региональности календаря, что снимает боль при работе с датами в разных часовых поясах, а заодно приносит приятные плюшки типа &lt;code&gt;hoursInDay&lt;/code&gt; — размера суток с учётом «летнего» времени или сравнения двух дат в разных часовых поясах, чтобы понять какая более ранняя&lt;/li&gt;
&lt;li&gt;в React Router есть &lt;a href=&quot;https://iamsahaj.xyz/blog/typesafe-routing-with-react-router/&quot;&gt;встроенная функция generatePath&lt;/a&gt; для того, чтобы типобезопасно сгенерировать строку роута по схеме из данных, то есть перед непосредственно навигацией нужно выполнить построение роута &lt;code&gt;navigate(generatePath(Routes.USER_DETAILS, { userId: &quot;1&quot; }))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;здесь просто &lt;a href=&quot;https://www.totaltypescript.com/how-to-create-an-npm-package&quot;&gt;пошаговая инструкция,&lt;/a&gt; как не сдаться в процессе публикации нового npm-пакета, интересные части: &lt;code&gt;@arethetypeswrong/cli&lt;/code&gt; — либа для проверки корректности экспортов перед публикацией пакета; &lt;code&gt;tsup&lt;/code&gt; — либа для компиляции TS-кода сразу в оба формата CJS и ESM; опция &lt;code&gt;&quot;noEmit&quot;: true&lt;/code&gt; для TS, чтобы использовать &lt;code&gt;tsc&lt;/code&gt; только для тайпчекинга кода; либа &lt;code&gt;@changesets/cli&lt;/code&gt; для публикации пакета, в том числе для локальной публикации с целью проверки&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;наверняка вам когда-нибудь приходила в голову мысль, что с помощью &lt;code&gt;box-shadow&lt;/code&gt;можно «сгенерировать» попиксельно целую картинку (теней при это потребуется много: один «пиксель» — одна тень); так вот эту идею можно развить дальше и &lt;a href=&quot;https://dgerrells.com/blog/can-you-convert-a-video-to-pure-css&quot;&gt;сделать из теней «видео»:&lt;/a&gt; генерируем для каждого кадра «видео» кейфрейм анимации и затем проигрываем анимацию, например, по скроллу!&lt;/li&gt;
&lt;li&gt;среди всего навороченного CSS 70lvl (который мало где работает) &lt;a href=&quot;https://frontendmasters.com/blog/custom-range-slider-using-anchor-positioning-scroll-driven-animations/&quot;&gt;из этого демо&lt;/a&gt; можно выцепить годные идеи, которые можно использовать уже сейчас, например, &lt;code&gt;transition: --e .1s ease-out&lt;/code&gt; для кастомного свойства, объявленного с &lt;code&gt;@property&lt;/code&gt;, или же использование кастомного свойства внутри CSS-счётчика &lt;code&gt;counter-reset: num var(--val)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tip.com/quantity-queries/&quot;&gt;примеры селекторов c :has(),&lt;/a&gt; выбирающие контейнер в зависимости от количества потомков, например, &lt;code&gt;.container:has(&amp;gt; :last-child:nth-child(even))&lt;/code&gt; выберет контейнер с чётным количеством элементов&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 06.09.2024</title><link>https://juwain.github.io/web-platform/blog/2024-09-06/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-09-06/</guid><description>Новости веб-платформы</description><pubDate>Fri, 06 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в &lt;a href=&quot;https://webkit.org/blog/15798/release-notes-for-safari-technology-preview-202/&quot;&gt;Safari Technology Preview 202&lt;/a&gt; поддержано CSS-свойство &lt;code&gt;scrollbar-width&lt;/code&gt;, добавлена возможность анимации для нечасто встречающихся свойств, доработан API PointerEvent, а также появилась поддержка garbage collection в WASM, пофикшено применение &lt;code&gt;clip-path&lt;/code&gt; к SVG-элементам&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/128&quot;&gt;вышел Chrome 128&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;добавлена поддержка &lt;code&gt;Promise.try&lt;/code&gt; (тест функции возвращает ли она промис без её вызова), жаль пока Chromium-only, но полифиллится&lt;/li&gt;
&lt;li&gt;CSS-свойство &lt;code&gt;zoom&lt;/code&gt; теперь стандартизированное и кроссбраузерное (кстати, и в FF 126 тоже)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/130&quot;&gt;вышел Firefox 130&lt;/a&gt;: поддержана технология WebDriver BiDi (Puppeteer теперь работает с Firefox «нативно»), а также множественные &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; с одинаковыми &lt;code&gt;name&lt;/code&gt; (HTML-аккордеоны), больше ничего интересного&lt;/li&gt;
&lt;li&gt;в будущих версиях Chrome будет раскатана &lt;a href=&quot;https://www.debugbear.com/blog/fix-web-performance-devtools&quot;&gt;новая экспериментальная версия панели Performance в дев-тулзах&lt;/a&gt;: в ней по умолчанию будет показываться информация о Web Vitals (сейчас инфа доступна через отдельный браузерный плагин), а также станет можно записывать процесс с заданием тротлинга прямо из панели&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://github.com/facebook/react/pull/30800&quot;&gt;React-команде начали разбираться с ситуацией&lt;/a&gt; блокировки отрисовки фоллбека при использовании &lt;code&gt;&amp;lt;Suspence&amp;gt;&lt;/code&gt;: теперь сначала будет показываться фоллбек, а потом уже запускаться рендер&lt;/li&gt;
&lt;li&gt;формат изображений &lt;a href=&quot;https://developers.google.com/search/blog/2024/08/happy-avifriday&quot;&gt;AVIF теперь индексируется в Google Search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.vuejs.org/posts/vue-3-5&quot;&gt;анонсирован Vue 3.5&lt;/a&gt;: давно не заглядывал внутрь, заглянул, а там внутри React 🙂: &lt;code&gt;useId()&lt;/code&gt; для генерации уникальных наборов символов, &lt;code&gt;useTemplateRef&lt;/code&gt; для создания динамических рефов, &lt;code&gt;onWatcherCleanup&lt;/code&gt; для очистки «эффекта» (аналог возвращаемого колбека в &lt;code&gt;useEffect&lt;/code&gt;), но есть и того, что в React нет — более тесная интеграция с веб-компонентами&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/bramus/style-observer&quot;&gt;style-observer&lt;/a&gt; — аналог API MutationObserver, но позволяющий отследить изменение значения определённого CSS-свойства, например, переменной: под капотом для всех отслеживаемых свойств создаётся подписка на событие &lt;code&gt;transitionstart&lt;/code&gt; и если значение свойства меняется, то триггерится и микро-транзишн, по которому срабатывает колбек (только для браузеров поддерживающих &lt;code&gt;transition-behavior: allow-discrete&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reasonable.work/colors/#getting-started&quot;&gt;reasonable colors&lt;/a&gt; — простая, доступная, контрастная палитра в CSS/SCSS&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;e2e-тестирование хорошо тем, что тестирует реальный интерфейс, который увидит и пользователь, но тесты выполняются медленно, представляют собой чёрный ящик без доступа внутрь и не покрывают всех состояний и сценариев; &lt;a href=&quot;https://storybook.js.org/blog/component-testing/&quot;&gt;в Storybook предлагают альтернативный подход&lt;/a&gt; — компонентное тестирование: вместо того, чтобы прогонять целый большой сценарий, берутся стори-компоненты, мокаются данные и проверяется соответствие всех состояний компонента «образцовым» в сторибуке (выглядит прикольно, но лочит на API @storybook)&lt;/li&gt;
&lt;li&gt;обычно при старте нового проекта файл tsconfig.json копируется из предыдущего, а если вам хочется наконец настроить его осознанно, пригодится &lt;a href=&quot;https://www.totaltypescript.com/tsconfig-cheat-sheet&quot;&gt;шпаргалка по tsconfig.json&lt;/a&gt; от Matt Pocock: варианты опций с транспиляцией и без, билда для библиотеки (в том числе в монорепе), если проект живёт в DOM или нет&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;начиная с Chrome 123, Firefox 125, Safari 17.4 свойство &lt;code&gt;align-content&lt;/code&gt; &lt;a href=&quot;https://build-your-own.org/blog/20240813_css_vertical_center/&quot;&gt;работает для обычных flow-элементов&lt;/a&gt; с &lt;code&gt;display: block&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;с помощью неказистого на первый взгляд свойства &lt;code&gt;background-clip&lt;/code&gt; можно, например, сделать так, чтобы &lt;a href=&quot;https://frontendmasters.com/blog/backgrounds-for-the-box-model-and-why-it-can-be-useful/&quot;&gt;одно фоновое изображение «выглядывало» из-под другого&lt;/a&gt;, а если это «нижнее» изображение — это анимированный конический градиент (с динамическим параметром угла), то выйдет спецэффект «сверкающей» кнопки&lt;/li&gt;
&lt;li&gt;не анимируйте свойство &lt;code&gt;mask-position&lt;/code&gt;, &lt;a href=&quot;https://component-odyssey.com/articles/13-improving-performance-by-changing-two-lines-of-css&quot;&gt;вызывает репейнты&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;синтаксис &lt;code&gt;:nth-child(2 of .foo)&lt;/code&gt;, выбирающий N-й элемент с определённым классом, &lt;a href=&quot;https://caniuse.com/css-nth-child-of&quot;&gt;уже с 2023 поддерживается во всех браузерах&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/display-contents/&quot;&gt;разбор &lt;code&gt;display: contents&lt;/code&gt; и его юзкейсы&lt;/a&gt;: «стилевое устранение» нежелательной обёртки в сгененированной разметке &lt;code&gt;.content p:has(img) {display: contents}&lt;/code&gt; или «реструктуризация» разметки при адаптивной перестройке&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eieio.games/essays/the-secret-in-one-million-checkboxes/&quot;&gt;однажды один разработчик сделал сайт One Million Checkboxes&lt;/a&gt;, где любой желающий мог нажимать на чекбоксы, результат сохранялся в БД и был виден другим людям; так вот люди начали рисовать на этом холсте 1000Х1000 «пикселей-чекбоксов» картинки и даже «видео», а также кодировать из комбинаций выделенных (1) и пустых (0) чекбоксов побитово символы ASCII и составлять из этих символов URL на свой фанатский дискорд-сервер, куда и пришёл познакомиться создатель сайта&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 13.09.2024</title><link>https://juwain.github.io/web-platform/blog/2024-09-13/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-09-13/</guid><description>Новости веб-платформы</description><pubDate>Fri, 13 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2024/09/eslint-v8-eol-version-support/&quot;&gt;ESLint v8.x перестанет поддерживаться&lt;/a&gt; мейнтейнерами 5.10.2024, вот и сказке конец, пора или болезненно переезжать, или выбирать альтернативу (кстати, &lt;a href=&quot;https://biomejs.dev/blog/biome-v1-9/&quot;&gt;Biome исполнился уже 1 годик&lt;/a&gt; и ещё он стал поддерживать &lt;code&gt;.editorconfig&lt;/code&gt;) или оставаться на коммерческой поддержке legacy-версии специального партнёра HeroDevs; ещё из интересненького про ESLint — &lt;a href=&quot;https://eslint.org/blog/2024/09/eslint-v9.10.0-released/&quot;&gt;в версии v9.10.0 в пакет включены также типы&lt;/a&gt; &lt;code&gt;@types/eslint&lt;/code&gt;, которые раньше шли отдельно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/editor/vscode-web&quot;&gt;веб-версия VSCode for the Web&lt;/a&gt; уже настолько хорошо работает, что даже &lt;a href=&quot;https://codesandbox.io/blog/a-new-and-improved-editor-powered-by-vs-code-web&quot;&gt;в CodeSandbox окончательно задепрекейтили свой собственный редактор&lt;/a&gt; в пользу встроенного VSCode ftW (а помните, у Edge тоже когда-то был собственный рендеринг движок?)&lt;/li&gt;
&lt;li&gt;к Font Awesome, недавно «поглотившей» библиотеку компонентов Shoelace, &lt;a href=&quot;https://www.11ty.dev/blog/eleventy-font-awesome/&quot;&gt;теперь присоедняется и 11ty&lt;/a&gt; (движок статических сайтов); норм они на иконках-то зарабатывают&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode/issues/226260&quot;&gt;VSCode переходят на ESM с AMD&lt;/a&gt; (помните такое)?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vercel/satori&quot;&gt;satori&lt;/a&gt; — инструмент от vercel для конвертирования HTML-CSS в SVG (может быть для генерации OG-картинок для embed-ов)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fpapado/svg-use&quot;&gt;svg-use&lt;/a&gt; — если в JS-приложении инлайнить SVG в DOM как есть, то распухает как сам DOM, так и итоговый JS-бандл; заместо этого авторы либы предлагают использовать тег &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt;, который ссылается на внешний ресурс с конкретным символом без инлайнинга с возможностью задать доп стили, например, для покраски&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/desko27/react-call&quot;&gt;react-call&lt;/a&gt; — API для создания асинхронных оконных диалогов (конфирмов) потипу &lt;code&gt;window.confirm&lt;/code&gt;, но прикручиваемое к любому React-компоненту&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;извечная история фронтендеров, которые куда-то постоянно откуда-то мигрируют, в &lt;a href=&quot;https://blog.logto.io/parcel-to-vite&quot;&gt;этом случае&lt;/a&gt; интересно изучить итоговый &lt;code&gt;vite.config.js&lt;/code&gt; (подсмотрел плагин &lt;code&gt;viteCompression&lt;/code&gt;, к примеру)&lt;/li&gt;
&lt;li&gt;Zod как-то обычно воспринимается как валидатор приходящих с бэка данных, но может использоваться для «типизации» по схеме пользовательского ввода в форму, в &lt;a href=&quot;https://reacttraining.com/blog/react-and-form-data&quot;&gt;том числе через API FormData&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.totaltypescript.com/type-safe-children-in-react-and-typescript&quot;&gt;children в React никак не сделать «типобезопасными»&lt;/a&gt;, выход — использовать пропы вместо children, там где нужна типобезопасность&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://philipwalton.com/articles/the-state-of-es5-on-the-web/&quot;&gt;многие сайты и приложения в вебе до сих пор транспилируются в ES5&lt;/a&gt;, хотя чаще всего по недосмотру, так как одновременно в бандле оказываются и нетранспилированные ES6+ куски: рекомендуется не фиксировать версии в browserlist, сторонние либы нужно тоже прогонять через процесс билда&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alexharri.com/blog/clipboard&quot;&gt;что происходит когда вы нажимаете copy в Figma&lt;/a&gt;: в буфере обмена контент оказывается в виде HTML, в data-атрибут &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; внутри записывается base64-строка, в которую закодирован мини-файл в формате &lt;code&gt;.fig&lt;/code&gt;; также есть много другой инфы про копирование в браузере, например, что в событии &lt;code&gt;copy&lt;/code&gt; есть поле &lt;code&gt;e.isTrusted&lt;/code&gt;, которое в true выставляется только для событий вызванных действиями пользователя, а не синтетически стриггерённых через &lt;code&gt;dispatchEvent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;для встроенной в браузер валидации инпутов &lt;a href=&quot;https://css-tricks.com/two-ways-to-create-custom-translated-messaging-for-html-forms/&quot;&gt;можно задать кастомное сообщение&lt;/a&gt; через &lt;code&gt;input.setCustomValidity(&apos;MESSAGE&apos;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если нужно растянуть грид на определённую высоту, но при этом нет возможности задавать высоту видимым элементам грида, то &lt;a href=&quot;https://www.smashingmagazine.com/2024/09/sticky-headers-full-height-elements-tricky-combination/&quot;&gt;в грид можно добавить пустой элемент,&lt;/a&gt; на который могут накладывать другие элементы, а он будет выступать только «распоркой» (повеяло табличной вёрсткой под старые IE)&lt;/li&gt;
&lt;li&gt;помимо зрелищности, свойственной туториалам Josh Comeau, &lt;a href=&quot;https://www.joshwcomeau.com/css/has/&quot;&gt;этот рассказ&lt;/a&gt; о &lt;code&gt;:has()&lt;/code&gt; несёт главное предназначение этого селектора: он позволяет декларативно объединять элементы не только в родительско-дочернем направлении, но и в обратном дочерне-родительском, да и вообще в любом (что раньше достигалось только императивным скриптом); самый типичный кейс — убрать у &lt;code&gt;html&lt;/code&gt; скроллбар в момент показа модалки:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;html:has([data-disable-document-scroll=&quot;true&quot;]) {
  overflow: hidden;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div data-disable-document-scroll=&quot;{isOpen}&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.developerway.com/posts/replacing-react-with-css&quot;&gt;ещё немного юзкейсов &lt;code&gt;:has()&lt;/code&gt;&lt;/a&gt;: стилизация рядов в таблице или элементов формы в зависимости от содержимого, изменение стилей фокуса по наличию внутри элемента определённого контента&lt;/li&gt;
&lt;li&gt;помимо примера «сверкающей кнопки», которая уже была в прошлом выпуске, в этом демо &lt;a href=&quot;https://ryanmulligan.dev/blog/css-property-new-style/&quot;&gt;к кнопке применяется одновременно две одинаковых анимации&lt;/a&gt;, одна из которых работает по умолчанию (крутит угол градиента), а вторая (в два раза замедленная) поставлена на паузу, и по ховеру включается и оверрайдит первую анимацию, а при убирании ховера продолжается в ускоренном режиме&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 27.09.2024</title><link>https://juwain.github.io/web-platform/blog/2024-09-27/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-09-27/</guid><description>Новости веб-платформы</description><pubDate>Fri, 27 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;опубликован первый черновик &lt;a href=&quot;https://www.w3.org/TR/css-values-5/&quot;&gt;CSS Values and Units Module Level 5 Working Draft&lt;/a&gt;, пожалуй, &lt;a href=&quot;https://alvaromontoro.com/blog/68062/new-values-and-functions-in-CSS&quot;&gt;самое долгожданное нововведение&lt;/a&gt; — это возможность использовать функцию &lt;code&gt;attr()&lt;/code&gt; не только в свойстве &lt;code&gt;content&lt;/code&gt;, а с любым другим свойством: &lt;code&gt;&amp;lt;span data-length=&quot;4&quot;/&amp;gt; span { width: attr(length em, 0px)}&lt;/code&gt;, чтобы не инлайнить в &lt;code&gt;style&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;вышла версия &lt;a href=&quot;https://www.trevorlasn.com/blog/whats-new-in-express-5&quot;&gt;Express.js 5.0&lt;/a&gt;: удалена часть методов; изменён паттерн-матчинг роутов: было &lt;code&gt;/user*&lt;/code&gt;, стало &lt;code&gt;/user(.*)&lt;/code&gt;; при ошибке в асинхронных функциях теперь не нужно вручную вызывать &lt;code&gt;next(err)&lt;/code&gt;; минимальная версия Node.js теперь 18&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/verdaccio/verdaccio/releases/tag/v6.0.0&quot;&gt;вышла версия verdaccio v6.0&lt;/a&gt; (приватный npm-реестр): дропнута поддержка Node 14, 16&lt;/li&gt;
&lt;li&gt;выпущен &lt;a href=&quot;https://deno.com/blog/v2.0-release-candidate&quot;&gt;Deno 2.0 Release Candidate&lt;/a&gt;: лучше поддержаны cjs-модули; ещё более тесно сынтегрировались с npm; добавили тестирование примеров в коментах JSDoc (тайпчек и выполнение); поддержали новый TS 5.6&lt;/li&gt;
&lt;li&gt;а вот в Node.js наоборот двигаются в сторону прекращения поддержки cjs-модулей, флаг &lt;code&gt;--experimental-require-module&lt;/code&gt; &lt;a href=&quot;https://github.com/nodejs/node/pull/55085&quot;&gt;перестаёт быть экспериментальным&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/soldair/node-qrcode&quot;&gt;qrcode&lt;/a&gt; — либа для генерации QR-кода в браузере (отрисовывается в &lt;code&gt;canvas&lt;/code&gt;) или Node.js в рантайме&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/schedule-x/schedule-x&quot;&gt;schedule-x&lt;/a&gt; — полноэкранный календарь аля Google Calendar с интеграциями в React, Vue, Angular&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/projectstorm/react-diagrams&quot;&gt;react-diagrams&lt;/a&gt; — генерация диаграмм, много гибкости и настроек&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/code42cate/how-to-dockerize-vite-44d3&quot;&gt;манимальный докер-конфиг&lt;/a&gt; для «контейнирования» Vite-приложения (используется &lt;code&gt;busybox&lt;/code&gt; для минимального рантайма)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.robinwieruch.de/react-fetching-data/&quot;&gt;что по дата-фетчингу в React в 2024&lt;/a&gt;: фетч в серверном компонента, проброс промиса в клиентский компонент и резолв данных с помощью &lt;code&gt;use&lt;/code&gt; — в теории красиво, но пока всё ещё экспериментальная фича; &lt;code&gt;React Query&lt;/code&gt; для SPA и клиентских компонентов; &lt;code&gt;trpc&lt;/code&gt; для создания типобезопасной API-прослойки, но требует Node.js и TS на бэкенде&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://macwright.com/2024/09/19/the-extra-rules-of-hooks&quot;&gt;в React в зависимости &lt;code&gt;useEffect&lt;/code&gt;&lt;/a&gt; можно не включать сеттер &lt;code&gt;useState&lt;/code&gt;, диспатчер &lt;code&gt;useReducer&lt;/code&gt; и &lt;code&gt;useActionState&lt;/code&gt;, ссылку &lt;code&gt;useRef&lt;/code&gt; и &lt;code&gt;useEffectEvent&lt;/code&gt;, так как они и так стабильны, то есть ссылаются каждый рендер на один и тот же объект; если говорить про сторонние хуки типа &lt;code&gt;useAtom&lt;/code&gt; из Jotai или &lt;code&gt;useMutation&lt;/code&gt; из tanstack-query, то про их «стабильность» достоверно неизвестно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.debugbear.com/blog/defer-offscreen-images&quot;&gt;рецепт собирания велосипеда по отложенной загрузке изображений&lt;/a&gt;: выносим изображение в CSS-фон, по умолчанию убираем все фоны спец классом &lt;code&gt;deffered&lt;/code&gt;, при попадании изображения во вьюпорт (хэндлим через &lt;code&gt;IntersectionObserver&lt;/code&gt;) убираем класс &lt;code&gt;deffered&lt;/code&gt; и задаётся актуальный фон&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kettanaito.com/blog/dont-sleep-on-abort-controller&quot;&gt;&lt;code&gt;AbortController&lt;/code&gt; API&lt;/a&gt; позволяет прерывать fetch-запросы (также по таймауту), убирать все event-listener-ы разом, а также несколько контроллеров можно сгруппировать через &lt;code&gt;AbortSignal.any&lt;/code&gt; (как &lt;code&gt;Promise.race()&lt;/code&gt;); такой вполне себе дизайн-паттерн: передаём контроллер извне внутрь модуля и прерываем внутренние запросы или отменяем события&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://abhisaha.com/blog/no-authentication-like-button&quot;&gt;интересная идея&lt;/a&gt;, как можно использовать &lt;code&gt;Web Audio API&lt;/code&gt; для создания фингерпринта текущего устройства: с помощью &lt;code&gt;OfflineAudioContext&lt;/code&gt; создаётся осциллятор, который «рендерит» уникальную для текущего устройства звуковую волну, затем она преобразуется в строку и из строки генерится хэш&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/denisputnov/8e53d557a513ffb0ecb45e6713a18e5e&quot;&gt;пример реализации шины событий на React/TS&lt;/a&gt;: иногда по тем или иным причинам, например, чтобы избежать проп-дриллинга или чтобы связать (не увеличивая coupling) совсем разнесённые части одной системы, выгодно создать собственный канал межмодульного общения посредством событий — эта реализация шины в React выглядит хорошо и минималистично&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ivicabatinic.from.hr/posts/multipart-namespace-components-addressing-rsc-and-dot-notation-issues&quot;&gt;подход к организации React-компонентов&lt;/a&gt;, чтобы заключать дочерние подкомпоненты в родительский «неймспейс» типа &lt;code&gt;&amp;lt;Card.Header&amp;gt;&lt;/code&gt; может создавать проблемы с сериализацией (актуально для серверных компонентов) и с тришейкингом, но если приготовить его правильно, то тогда проблем не будет:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// card.tsx
export function CardRoot() {}

// namespaces.ts
export { CardRoot as Root } from &quot;./card&quot;;

// index.tsx
export * as Card from &quot;./namespace&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nolanlawson.com/2024/09/18/improving-rendering-performance-with-css-content-visibility/&quot;&gt;свойство content-visibility&lt;/a&gt; — наколеночное средство виртуализации большого количества DOM-элементов (&amp;gt;40k), которое может ограничить размеры области для рендера, внутри которой происходит обычная отрисовка, а на всё вне этой области браузер не тратит драгоценные ресурсы (заодно выяснилось, что &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; не такой уж и бесплатный, а велосипед с &lt;code&gt;IntersectionObserver&lt;/code&gt; работает лучше)&lt;/li&gt;
&lt;li&gt;появилось предложение добавлять &lt;code&gt;:root { interpolate-size: allow-keywords; }&lt;/code&gt; в базовые стили проекта, чтобы &lt;a href=&quot;https://front-end.social/@bramus/113192802274531981&quot;&gt;была возможность анимировать от числа до ключевого слова&lt;/a&gt; (например, &lt;code&gt;auto&lt;/code&gt;) — жаль пока работает только в последнем Chrome&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;вообще-то это &lt;a href=&quot;https://alvaromontoro.com/blog/68063/bad-css-dad-jokes-ii&quot;&gt;пост с несмешными IT-шутками&lt;/a&gt;, но напомнил мне о существовании &lt;code&gt;&amp;lt;input type=&quot;hidden&quot;&amp;gt;&lt;/code&gt;, который раньше как-то часто использовался при клиент-серверном взаимодействии, а в последнее время стал как-то позабыт&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 20.09.2024</title><link>https://juwain.github.io/web-platform/blog/2024-09-20/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-09-20/</guid><description>Новости веб-платформы</description><pubDate>Fri, 20 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в Font Awesome, к которому недавно присоединился Zach Leatherman с 11ty, &lt;a href=&quot;https://lea.verou.me/blog/2024/awesome/&quot;&gt;начинает работать Lea Verou в качестве Product Lead&lt;/a&gt;, видимо будут продвигать Pro-иконки через движок статических сайтов, а также общую поддержку веб-стандартов и платформы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/15865/webkit-features-in-safari-18-0/&quot;&gt;выпущен Safari 18.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;в браузер добавлен блокировщик попапов (привет, дизайнеры, любящие модалки 👋)&lt;/li&gt;
&lt;li&gt;в связке с новой macOS появилась интеграция с iPhone, чтобы проще дебажить iOS на десктопе&lt;/li&gt;
&lt;li&gt;поддержаны View Transitions и Style Queries &lt;code&gt;@container style(--background: black)&lt;/code&gt;, а также анимация свойства &lt;code&gt;display&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;окончательно поддержан &lt;code&gt;backdrop-filter&lt;/code&gt; и свитч-режим чекбокса &lt;code&gt;&amp;lt;input type=checkbox switch&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в JS появился метод &lt;code&gt;URL.parse()&lt;/code&gt;, возвращающий &lt;code&gt;null&lt;/code&gt; вместо исключения в случае ошибки&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/129&quot;&gt;зарелижен Chrome 129&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддержано CSS-свойсво &lt;code&gt;interpolate-size&lt;/code&gt; и функция &lt;code&gt;calc-size()&lt;/code&gt;, позволяющие &lt;a href=&quot;https://developer.chrome.com/docs/css-ui/animate-to-height-auto/&quot;&gt;анимировать значение до &lt;code&gt;auto&lt;/code&gt;&lt;/a&gt; (выглядят костыльненько)&lt;/li&gt;
&lt;li&gt;добавлена поддержка &lt;code&gt;Intl.DurationFormat&lt;/code&gt; для форматирования длительности в нужной локали&lt;/li&gt;
&lt;li&gt;появились обещанные ранее Snap Events для колбеков snap-скроллов и &lt;code&gt;scheduler.yield()&lt;/code&gt; для разгрузки потока от длинных непрерывных тасок&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-5-beta/&quot;&gt;вышла Astro 5.0 Beta&lt;/a&gt;, в которой стабилизирована фича Content Layer с запросом контента из внешнего ресурса (топчик!), Server Islands для отложенного рендеринга с сервера (сложна), а также фича &lt;code&gt;astro:env&lt;/code&gt; для типобезопасной работы с env-ами на клиенте и сервере (удобство)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.date-fns.org/v40-with-time-zone-support/&quot;&gt;вышла date-fns 4.0&lt;/a&gt;: появилась широкая поддержка для работы с таймзонами, также автор морально готовится к грядущей эре господства Temporal API&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openjsf.org/blog/fastifys-growth-and-success&quot;&gt;выпущена Fastify v5&lt;/a&gt;: поддерживает Node20+ (из-за лучшей поддержки &lt;code&gt;node:test&lt;/code&gt;), загрузки, спонсоры и контрибьюторы растут&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/DavidWells/safe-await&quot;&gt;safe-await&lt;/a&gt; — либа, добавляющая возможность «распаковки» промисов &lt;code&gt;const [error, data] = await safeAwait(promiseOne())&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/system-fonts/modern-font-stacks&quot;&gt;modern-font-stacks&lt;/a&gt; — наборы похожих системных шрифтов на разных системах, если не нужен pixel-perfect (также есть отдельный набор шрифтов эмодзи)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bloomberg.github.io/ts-blank-space/&quot;&gt;ts-blank-space&lt;/a&gt; — «а что так можно было?» из мира компиляторов TS-&amp;gt;JS: все указания типов заменяются символами пробела, сохраняя при этом структуру оригинального кода (поэтому не нужны сорсмапы)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;чтобы побороть развесистые условия или вложенные тернарники (особенно может быть актуально в JSX), можно &lt;a href=&quot;https://dev.to/tauantcamargo/how-ts-pattern-can-improve-your-code-readability-37dd&quot;&gt;использовать pattern-matching-подход&lt;/a&gt; (возможно будущее развитие подхода &lt;a href=&quot;https://github.com/tc39/proposal-pattern-matching&quot;&gt;в стандарте&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;когда речь заходит про типобезопасность, не очень понятно сходу, где остановиться: на &lt;a href=&quot;https://tanstack.com/blog/tanstack-router-typescript-performance&quot;&gt;TS можно нагрузить задачу проверять корректность роутов&lt;/a&gt;, или, например, забахать типизацию стилей, чтобы нельзя было задать неправильный стиль. Всё это как будто бы хорошо, то есть ради всего хорошего и против всего плохого, но при этом порождает сложности с перфомансом и создаёт переусложнённые абстракции (хотели как лучше, а получилось как всегда: героически созданные сложности героически побеждаются)&lt;/li&gt;
&lt;li&gt;в React Router есть специальное &lt;a href=&quot;https://reacttraining.com/blog/spa-lazy-loading-pitfalls&quot;&gt;API для параллелизации запросов&lt;/a&gt; самого компонента и нужных данных для него &lt;code&gt;&amp;lt;Route path=&quot;/users/:userId&quot; loader={loader} lazy={() =&amp;gt; import(&apos;../components/UserProfile&apos;)} /&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если ли что-то сильнее &lt;code&gt;!important&lt;/code&gt;? Да, это &lt;a href=&quot;https://noahliebman.net/2024/08/beating-important-user-agent-styles/&quot;&gt;вечный транзишн, который всегда показывает окончательные стили&lt;/a&gt;: &lt;code&gt;input { transition: background-color calc(infinity * 1s) step-end; background-color: transparent; }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;разработчики Chrome на правах «законодателя мод» выкатили &lt;a href=&quot;https://developer.chrome.com/blog/rfc-customizable-select&quot;&gt;экспериментальную стилизацию &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;&lt;/a&gt; с помощью &lt;code&gt;::picker(select) {}, option::before, option:hover, option:checked {}&lt;/code&gt; (глядишь через пару лет наконец заборят финального босса CSS)&lt;/li&gt;
&lt;li&gt;если применить &lt;code&gt;gap&lt;/code&gt; к контейнеру с &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; внутри, то в&lt;a href=&quot;https://blog.jim-nielsen.com/2024/sanding-ui/&quot;&gt; промежутке возможно появление «мёртвой зоны»&lt;/a&gt;, в которой клик по лейлбу не выберет инпут&lt;/li&gt;
&lt;li&gt;интересное наблюдение, что &lt;a href=&quot;https://codersblock.com/blog/making-orbit-animations-with-css-custom-properties/&quot;&gt;анимация кастомных свойств выполняется на CPU&lt;/a&gt; даже если в итоге меняется значение &lt;code&gt;transform&lt;/code&gt;, которое по идее должно вытаскиваться браузером в композитный слой и просчитываться GPU (лечится немного &lt;code&gt;will-change&lt;/code&gt;, но не везде)&lt;/li&gt;
&lt;li&gt;простой &lt;a href=&quot;https://frontendmasters.com/blog/selecting-previous-siblings/&quot;&gt;селектор предыдущего элемента&lt;/a&gt; &lt;code&gt;:has(+ &amp;amp;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://daverupert.com/2024/09/good-forms/&quot;&gt;чеклист по созданию идеальных форм&lt;/a&gt;: естественно, это тег &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;; инпуты с верными &lt;code&gt;inputmode&lt;/code&gt; и &lt;code&gt;autocomplete&lt;/code&gt;, которые часто забываются; стилизованы базово через &lt;code&gt;accent-color&lt;/code&gt;; а также есть проверка &lt;code&gt;navigator.onLine&lt;/code&gt; перед попыткой отправки&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 04.10.2024</title><link>https://juwain.github.io/web-platform/blog/2024-10-04/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-10-04/</guid><description>Новости веб-платформы</description><pubDate>Fri, 04 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;обновилась &lt;a href=&quot;https://react-spectrum.adobe.com/releases/2024-09-30.html&quot;&gt;библиотека компонентов React Spectrum&lt;/a&gt;: компоненты для работы с цветом (пикер, колесо, инпут…) вышли из беты, а компоненты Tree и TreeView выведены в бету&lt;/li&gt;
&lt;li&gt;Evan You сотоварищи &lt;a href=&quot;https://voidzero.dev/posts/announcing-voidzero-inc&quot;&gt;основали компанию void(0) и подняли денег&lt;/a&gt;, чтобы дальше пилить Rolldown и Oxc, а на их основе сделать коммерческий тулчейн для энтерпрайзов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy/releases/tag/v3.0.0&quot;&gt;вышла версия Eleventy v3.0.0&lt;/a&gt;: теперь на ESM, поддерживает pnpm, yarn, Deno, разнообразные улучшения API (например, поддержка темплейтных языков вынесена из кора во внешние плагины)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2024/10/eslint-json-markdown-support/&quot;&gt;ESLint теперь поддерживает&lt;/a&gt; линтинг JSON- и Markdown-файлов (ждём официального переименования в E(xtremely)S(uper)Lint)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pnpm/pnpm/releases/tag/v9.12.0&quot;&gt;вышла pnpm 9.12&lt;/a&gt;: команда &lt;code&gt;pnpm outdated&lt;/code&gt; сортирует пакеты по алфавиту, добавлена возможность убрать пакет из зависимостей в &lt;code&gt;overrides&lt;/code&gt; указанием &lt;code&gt;&quot;-&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v2.tauri.app/blog/tauri-20/&quot;&gt;выпущена версия Tauri 2.0&lt;/a&gt; (фреймворк для создания кроссплатформенных нативных приложений из фронтенд-кода): появилась поддержка мобилок iOS и Android (также поддержан Hot-Module Replacement (HMR) для мобилок), добавлена онбординг-установка для шелла и популярных менеджеров пакетов, обогащена система плагинов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react/blob/main/packages/react-devtools/CHANGELOG.md&quot;&gt;вышли React DevTools 6.0.0&lt;/a&gt;: поддержаны ServerComponents&lt;/li&gt;
&lt;li&gt;в яндексовском ui-kit GravityUI &lt;a href=&quot;https://github.com/gravity-ui/markdown-editor/&quot;&gt;вышел wysiwyg-редактор&lt;/a&gt;, поддерживающий markdown (заодно выяснили, что кит остался тому Яндексу, который остался в РФ)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/DoneDeal0/superdiff&quot;&gt;superdiff&lt;/a&gt; — либа для отображения diff-а между двумя массивами или объектами&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zod.fyi/&quot;&gt;zod.fyi&lt;/a&gt; — «визуализатор» JSON ошибки ZodError&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mockoon/mockoon&quot;&gt;mockoon&lt;/a&gt; — инструмент для разворачивания локального мок-сервера API&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://janhesters.com/blog/unleash-javascripts-potential-with-functional-programming&quot;&gt;гайд по парадигме функционального программирования&lt;/a&gt; применительно к JS: раскрываются темы чистых функций, идемпотентности, замыканий, иммутабельности, а также как с этим жить в контексте JS; в контексте React, кстати, видел такой фокус: чтобы не вкладывать контексты друг в друга матрёшкой, они создаются друг за другом, а потом «функциональным методом» &lt;code&gt;compose&lt;/code&gt; вкладываются друг в друга&lt;/li&gt;
&lt;li&gt;обычно про воркеры вспоминаешь, когда начинаются проблемы с производительностью, но об их существовании &lt;a href=&quot;https://medium.com/deno-the-complete-reference/5-use-cases-of-worker-threads-in-javascript-5ce94ce1365d&quot;&gt;хорошо бы вспоминать почаще&lt;/a&gt;: в случае тяжёлых вычислений, процессинга картинок или видео, аналитики данных, фоновых задач, реалтайм-соединений&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если элемент с &lt;code&gt;position: absolute&lt;/code&gt; не имеет предков, то он позиционируется относительно &lt;a href=&quot;https://css-tip.com/initial-containing-block/&quot;&gt;initial containing block&lt;/a&gt; — прямоугольника по размерам совпадающего с вьюпортом, но при этом сдвигающего при скролле&lt;/li&gt;
&lt;li&gt;в дев-тулзах Chrome во вкладке Performance сейчас есть &lt;a href=&quot;https://www.trysmudford.com/blog/i-spent-a-day-making-the-website-go-2ms-faster/&quot;&gt;возможность записать влияние CSS-селекторов на быстродействие&lt;/a&gt;, но нужно учитывать, что включённый анализ сам по себе увеличивает время отрисовки&lt;/li&gt;
&lt;li&gt;при &lt;a href=&quot;https://web.dev/blog/at-property-performance&quot;&gt;объявлении кастомного свойства&lt;/a&gt; через &lt;code&gt;@property&lt;/code&gt; немного быстрее будет задавать параметр &lt;code&gt;inherits: false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/t_afif/pen/XWPvgZo&quot;&gt;короткий сниппет&lt;/a&gt; для создания цветового колеса со всем цветовым спектром &lt;code&gt;background: conic-gradient(in hsl longer hue,red 0 0);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;признаюсь, есть у меня некий фетиш на применение платформенных штучек, которые решают проблемы каким-либо простым способом с неожиданной стороны; вот всё жду, когда подвернётся шанс «легально» использовать &lt;a href=&quot;https://flaviocopes.com/an-html-element-id-is-a-global-variable/&quot;&gt;этот трюк&lt;/a&gt;: HTML-элементы с прописанными &lt;code&gt;id&lt;/code&gt; доступны по этому &lt;code&gt;id&lt;/code&gt; напрямую в &lt;code&gt;window&lt;/code&gt;: &lt;code&gt;&amp;lt;form id=&quot;x&quot;&amp;gt;&amp;lt;input name=&quot;em&quot;&amp;gt;&amp;lt;/form&amp;gt;  x.em.onclick = …&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;чем &lt;a href=&quot;https://frontendmasters.com/blog/whats-the-difference-between-htmls-dialog-element-and-popovers/&quot;&gt;хороши&lt;/a&gt; &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; и &lt;code&gt;popover&lt;/code&gt; помимо прочего (центровка, оверлей…), так это тем, что они гарантированно будут «выше» всех остальных элементов, так как рендерятся в специальный браузерный контейнер &lt;code&gt;#top layer&lt;/code&gt; (больше никакая z-index-выскочка случайно не «всплывёт» над модалкой)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;как бы платформа не развивалась, всё равно будут места, которые отстают в развитии больше других; такие вещи бесят и вынуждают, порой, добавлять костыли, и хуже всего, когда проблема кроется в браузере, и что ещё хуже — в мобильном: да, вы правильно поняли, я про iOS Safari, где &lt;a href=&quot;https://webventures.rejh.nl/blog/2024/history-of-safari-show-stoppers/&quot;&gt;встречаются баги&lt;/a&gt;, которые фиксились только спустя годы после их «релиза» или не фиксились совсем (например, наверняка вы сталкивались с проблемой скролла &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; с &lt;code&gt;overflow: hidden&lt;/code&gt;); но ладно скролл, в целом уже все как-то привыкли к «неудобной» мобильной версии, но когда ломается IndexedDB — это уже печальнее&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://erikbern.com/2024/09/27/its-hard-to-write-code-for-humans&quot;&gt;советы по написанию ПО&lt;/a&gt;: не бояться делать API достаточно многословным для удобочитаемости; специально не подсвечивать дефолты и внутреннюю магию (кому нужно, сами найдут); использовать в API устоявшиеся в умах ментальные модели; для изучения API вашего ПО дать возможность потыкать и посовмещать готовые примеры, вместо подхода к изучению «построим всё с нуля»&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 11.10.2024</title><link>https://juwain.github.io/web-platform/blog/2024-10-11/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-10-11/</guid><description>Новости веб-платформы</description><pubDate>Fri, 11 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/131&quot;&gt;вышел Firefox 131&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;из интересного поддержана фича &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/URI/Fragment/Text_fragments&quot;&gt;Text fragments&lt;/a&gt; — возможность ссылаться не только на якорную ссылку на странице (&lt;code&gt;#anchor&lt;/code&gt;), но и на произвольный текстовый фрагмент, например, &lt;code&gt;https://example.com/page[#:~:text=human]&lt;/code&gt; проскроллит страницу к первому встретившемуся слову «human», которое заодно можно стилизовать с помощью псевдокласса &lt;code&gt;::target-text&lt;/code&gt; (к слову фича поддерживается теперь во всех браузерах)&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://fxdx.dev/firefox-devtools-newsletter-131/&quot;&gt;девтулзах&lt;/a&gt; улучшены поповеры кастомных свойств, теперь они показывают computed-значение и параметры свойства, если оно было объявлено через &lt;code&gt;@property&lt;/code&gt;, а также более удобным стало редактирование HTML и CSS в инспекторе&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://19.react.dev/reference/rsc/server-functions&quot;&gt;Server Actions в 19 React стали называться Server Functions&lt;/a&gt;, а точнее стали подмножеством «серверных функций», которые не обязательно являются «экшном»&lt;/li&gt;
&lt;li&gt;есть такое сообщество e18e, которые взяли на себя роль «санитаров платформы», ходят к мейнтейнерам популярных пакетов, предлагают улучшения перфоманса, помогают выпилить ненужные зависимости; &lt;a href=&quot;https://e18e.dev/blog/september-contributions-showcase.html&quot;&gt;вот в сентябре&lt;/a&gt; удалось помочь выпилить смешную (да не очень) зависимость &lt;code&gt;is-number&lt;/code&gt; из &lt;a href=&quot;https://github.com/paulmillr/chokidar&quot;&gt;chokidar&lt;/a&gt;, также хорошо так подчистили &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt; и &lt;a href=&quot;https://github.com/jimp-dev/jimp&quot;&gt;jimp&lt;/a&gt;; важная движуха — уважуха!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/v2.0&quot;&gt;выпущен Deno 2.0&lt;/a&gt;: уже рассказывал о фичах раньше про RC, в этом релизе обратил внимание на команду &lt;code&gt;deno compile&lt;/code&gt; , которая собирает приложение в запускаемый файл (даже с иконкой в Windows); я раньше не понимал, а потом как понял, что на самом деле Deno конкурирует больше с Bun, чем с Node, на поприще все-инструменты-в-одном&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-v1.1.30&quot;&gt;в Bun завезли&lt;/a&gt; экспериментальную поддержку сборки CSS на базе &lt;a href=&quot;https://github.com/parcel-bundler/lightningcss&quot;&gt;LightningCSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://onestack.dev/&quot;&gt;one&lt;/a&gt; — React-фреймворк, собирающий приложение в веб и нейтив: под капотом Vite, также обещают локальную БД Zero (попробовать можно командой &lt;code&gt;npx one&lt;/code&gt; — интересно, а козырные названия пакетов, как и домены нынче покупают-продают?)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/scalar/scalar&quot;&gt;scalar&lt;/a&gt; — REST-API-клиент в формате OpenAPI (для одного пользователя бесплатно)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;«если хочешь сделать хорошо — сделай сам», — подумал один разработчик и написал &lt;a href=&quot;https://jakelazaroff.com/words/a-local-first-case-study/&quot;&gt;local-first веб-приложение&lt;/a&gt;, в котором можно описывать путешествие текстом и сразу смотреть маршрут на карте: из интересного на клиенте используется CRDT-либа  &lt;a href=&quot;https://yjs.dev/&quot;&gt;Yjs&lt;/a&gt;, которая позволяет хранить данные локально на устройстве, и  &lt;a href=&quot;https://y-sweet.cloud/&quot;&gt;Y-Sweet&lt;/a&gt; — клиент и сервер для синхронизации состояния на S3 по вебсокет-соединению, чтобы пользоваться приложением одновременно с нескольких устройств в реалтайме (ещё один мой фетиш detected)&lt;/li&gt;
&lt;li&gt;держать секреты типы паролей в env-файлах довольно удобно, но при этом, чем больше секретов попадает env-файл, тем &lt;a href=&quot;https://www.nodejs-security.com/blog/do-not-use-secrets-in-environment-variables-and-here-is-how-to-do-it-better&quot;&gt;менее надёжной становится эта система&lt;/a&gt;: env-утекают на фронте/SSR, через логи или просто во время видео-стрима; отдельный прикол — env-переменные, с которыми запущен node-процесс видны в списке процессов в Unix-like-системах&lt;/li&gt;
&lt;li&gt;вообще-то это &lt;a href=&quot;https://developer.chrome.com/blog/devtools-catch-prediction&quot;&gt;статья про то, как работает фича девтулзов Chrome&lt;/a&gt; «pause on uncaught exceptions» (этот факт надо «предсказывать», так как в момент выбрасывания исключения неясно, будет ли оно поймано дальше в коде); но меня заинтересовало другое: на сайте используется куча веб-компонентов (без драм и обсуждений), например, &lt;code&gt;&amp;lt;devsite-code&amp;gt;&lt;/code&gt; для отображения блоков кода, причём используются они корректно, в виде «виджетов»: кастомные элементы — это обёртки, докидывающие стилизацию и часть функциональности, а благодаря прогрессивному улучшению, в браузерах, не поддерживающих кастомные элементы, контент всё равно покажется, но немного коряво и с меньшей функциональностью, красота!&lt;/li&gt;
&lt;li&gt;нативный нестинг в CSS правилах появился без флага в Chrome 112, но с немного другим синтаксисом (нужно было в некоторых случаях проставлять дополнительный &lt;code&gt;&amp;amp;&lt;/code&gt;) и это &lt;a href=&quot;https://web.dev/blog/css-nesting-cssnesteddeclarations&quot;&gt;окончательно починили в грядущем Chrome 130&lt;/a&gt;, а чтобы не сесть в лужу со старыми версиями теперь нужно в нестинге обычные правила писать перед медиа-выражениями (что и логично)&lt;/li&gt;
&lt;li&gt;как на коленке &lt;a href=&quot;https://www.smashingmagazine.com/2024/10/build-static-rss-reader-fight-fomo/&quot;&gt;собрать RSS-агрегатор&lt;/a&gt; с помощью Astro и &lt;code&gt;rss-parser&lt;/code&gt; (сам тоже стал собирать RSS, но в тг-бота)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dmitripavlutin.com/maps-vs-plain-objects-javascript/&quot;&gt;Map в JS пригодится&lt;/a&gt;, если нужно, чтобы ключами было что-то, кроме строк или символов, например, другие объекты или числа&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://aaadaaam.com/notes/chasing-color/&quot;&gt;хороший пример&lt;/a&gt;, как построить цветовую тему с нативной поддержкой темной/светлой схемы: очень выразительно и гибко получается комбинировать oklch-формат и функцию &lt;code&gt;light-dark()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;color: light-dark(
  oklch(from var(--secondary) var(--600)),
  oklch(from var(--secondary) var(--200))
);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;директива &lt;code&gt;@supports&lt;/code&gt; не может проверять доступность других директив, но есть обходной путь — проверять наличие «родственного» обычного свойства, например: &lt;code&gt;@container&lt;/code&gt; проверяется &lt;code&gt;@supports (container-type: size)&lt;/code&gt;; в &lt;a href=&quot;https://css-tricks.com/recipes-for-detecting-support-for-css-at-rules/&quot;&gt;статье&lt;/a&gt; есть рецепты для проверки многих директив, кроме &lt;code&gt;@layer&lt;/code&gt;, &lt;code&gt;@property&lt;/code&gt;, &lt;code&gt;@starting-style&lt;/code&gt; (от себя добавлю сам &lt;code&gt;@supports&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;значение свойства &lt;code&gt;grid-template-rows: repeat(calc(var(--int)), 0px)&lt;/code&gt; &lt;a href=&quot;https://frontendmasters.com/blog/css-fan-out-with-grid-and-property/&quot;&gt;можно сделать динамическим&lt;/a&gt;, если анимировать кастомное свойство &lt;code&gt;--int&lt;/code&gt;, объявленное через &lt;code&gt;@property&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;кажется мы стали забывать свои корни (а они уже разрослись), вот &lt;a href=&quot;https://plainvanillaweb.com/pages/applications.html&quot;&gt;напоминание&lt;/a&gt;: роутер можно собрать на веб-компонентах (подход, популяризированный в React Router, когда вьюхи оборачиваются в «теги» роутов идеально ложатся на кастомные элементы); для централизованного хранения состояния можно использовать события &lt;code&gt;CustomEvent&lt;/code&gt;, доступные сто лет в обед; компоненты нативно реагируют на смену атрибутов («пропсы») и по умолчанию можно сделать фолбек-состояния компонентов&lt;/li&gt;
&lt;li&gt;привязка названий двухбуквенных доменов к названиям стран, а точнее использование их не по назначению, имеет сайд-эффект: если страна перестаёт существовать, то что делать с более неактуальным доменом? Вот &lt;a href=&quot;https://every.to/p/the-disappearance-of-an-internet-domain&quot;&gt;эта ситуация коснулась домена .io&lt;/a&gt; (Indian Ocean), «страна-владелец» которого перестаёт существовать&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 18.10.2024</title><link>https://juwain.github.io/web-platform/blog/2024-10-18/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-10-18/</guid><description>Новости веб-платформы</description><pubDate>Fri, 18 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/130&quot;&gt;вышел Chrome 130&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;окончательно пофикшен CSS Nesting&lt;/li&gt;
&lt;li&gt;в Picture-in-Picture добавлена настройка &lt;code&gt;preferInitialWindowPlacement&lt;/code&gt; для сброса предыдущей привязки pip-окна&lt;/li&gt;
&lt;li&gt;поддержано свойство &lt;code&gt;box-decoration-break: clone&lt;/code&gt; для создания красивых переносов текстовых блоков&lt;/li&gt;
&lt;li&gt;плавный скролл &lt;code&gt;scrollIntoView()&lt;/code&gt; с опцией &lt;code&gt;behavior: &quot;smooth&quot;&lt;/code&gt; больше не отменяется в случае случайного «конкурентного» скролла&lt;/li&gt;
&lt;li&gt;выкачен клавиатурный скролл по фокусу (например, на &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;в девтулзах в инспекторе появилась пометка контейнеров со скроллом (проще найти на чём появился внезапный скроллбар)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1ylROTu3N6MyHzNzWJXQAc7Bo1O0FHO3lNKfQMfPOA4o/edit#slide=id.g30432c5cd9c_0_856&quot;&gt;в TC39 созревает новый план&lt;/a&gt;, как сделать JS более устойчивым для конечных пользователей и при этом более удобным для разработчиков: разделить JS на условный core JS0 (это то, что уже есть сейчас) + JSSugar (это надстройка, которая компилируется в JS0), и при этом обе части стандартизировать; да, вы как и я, наверное сразу же вспомнили CoffeeScript, и, да, сейчас предлагается по сути та же схема, то есть распространить стандартизацию на вот эту самую «мутант»-версию языка, из которой особо удачные и обкатанные фичи смогут переводиться в «стабильную» версию: а там, вангую, мы получим и «ванильную» типизацию, и всё остальное, что сейчас добавляется надстройками&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pmndrs/zustand/releases/tag/v5.0.0&quot;&gt;Zustand обновился до v5&lt;/a&gt;: новых фич нет, дропнута поддержка ES5, React &amp;lt;18, TS &amp;lt;4.5, небольшие поведенческие breaking-изменения&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v23.0.0&quot;&gt;вышла Node 23.0.0&lt;/a&gt;: по умолчанию теперь работает &lt;code&gt;require()&lt;/code&gt; ES-модулей, дропнута поддержка 32-bit Windows,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gsap.com/blog/webflow-GSAP/&quot;&gt;Webflow купили GSAP&lt;/a&gt;: ждём выхода фаундеров через полгода 🙂&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://brisa.build/building-your-application/components-details/web-components&quot;&gt;brisa&lt;/a&gt; — появилась попытка поженить веб-компоненты и JSX, а также серверный рендеринг и actions, и украшено это всё реактивными сигналами; что сказать, это больше всё похоже на шутку юмора, чем на что-то жизнеспособное, плюс ещё JSX совсем плохо сочетается с кастомными элементами, получается нечитаемая костыльная каша; сравните, например, с &lt;a href=&quot;https://symbiotejs.org/2x/docs/Get_started/&quot;&gt;symbiote&lt;/a&gt;, насколько легковесно и свежо смотрится (уже ранее рассказывал про этот проект, он жив-здоров и развивается)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jeasx.dev&quot;&gt;jeasx&lt;/a&gt; — а вот ещё один заход в JSX + серверный рендеринг (под капотом &lt;code&gt;fastify&lt;/code&gt; и &lt;code&gt;esbuild&lt;/code&gt;), который уже похож на React здорового человека: можно использовать &lt;code&gt;await&lt;/code&gt; просто так, &lt;code&gt;class&lt;/code&gt; вместо &lt;code&gt;className&lt;/code&gt;, «контекст» лежит в &lt;code&gt;this&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hello-pangea/dnd&quot;&gt;hello-pangea/dnd&lt;/a&gt; — ещё одна попытка в dnd-сортировки для React (дед-mode-on: зачем в зависимостях redux?!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/secretlint/secretlint&quot;&gt;secretlint&lt;/a&gt; — линтер возможной секретов (вешается на прекоммит или запускается в Docker)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;обратная сторона удобства экосистемы npm — из неё так удобно и быстро можно &lt;a href=&quot;https://socket.dev/blog/nightmares-on-npm-how-two-malicious-packages-facilitate-data-theft-and-destruction&quot;&gt;поставить в проект зловредное ПО&lt;/a&gt;: иногда злоумышленники для своих пакетов «захватывают» имена, похожие на общеизвестные названия, либо могут замаскировать пакет под «легальный», но внутри будет &lt;code&gt;rm -rf ~/*&lt;/code&gt;, который запустится по таймеру через час после установки&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.robinwieruch.de/react-folder-structure/&quot;&gt;эволюция структурирования кода в React-проекте&lt;/a&gt; от папки &lt;code&gt;components&lt;/code&gt; к лайтовому варианту &lt;code&gt;FSD&lt;/code&gt; (но не раскрыта тема, где лежат сторы — их желательно держать в фичах или же выносить в &lt;code&gt;entities&lt;/code&gt;, чтобы мочь импортировать в несколько фич сразу)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshuawootonn.com/react-drag-to-select&quot;&gt;реализация drag-to-select&lt;/a&gt;, из которой я узнал о существовании метода &lt;code&gt;e.currentTarget.setPointerCapture(e.pointerId)&lt;/code&gt;, который не полностью выключает pointer-events, а ловит только те события, которые исходят от текущего элемента&lt;/li&gt;
&lt;li&gt;если нужен перфоманс, то проще делегировать его самому браузеру, чем опираться на JS-надстройки типа React, которые по умолчанию будут медленнее; к такому же выводу &lt;a href=&quot;https://thenewstack.io/how-microsoft-edge-is-replacing-react-with-web-components/&quot;&gt;пришли разработчики Edge&lt;/a&gt;, которые до этого затащили в браузер React, а потом решили от него отказаться&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/handling-paste-events-in-javascript/&quot;&gt;в объекте события &lt;code&gt;paste&lt;/code&gt;&lt;/a&gt; есть поле &lt;code&gt;clipboardData&lt;/code&gt;, откуда можно вызвать метод &lt;code&gt;getData(&apos;text/plain&apos;)&lt;/code&gt;, что получить скопированный текст или HTML, а также есть &lt;code&gt;clipboardData.files&lt;/code&gt;, где лежат скопированные файлы&lt;/li&gt;
&lt;li&gt;вряд ли вам это пригодится, но &lt;code&gt;setTimeout&lt;/code&gt; &lt;a href=&quot;https://evanhahn.com/set-big-timeout/&quot;&gt;может выполняться максимально ~25 дней&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://macarthur.me/posts/sibling-parameters/&quot;&gt;в значениях по умолчанию у аргументов функции&lt;/a&gt; можно использовать соседние аргументы или операции с ними &lt;code&gt;function myFunc(arg1, arg2 = arg1)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.taniarascia.com/horizontal-scroll-fixed-headers-table/&quot;&gt;скроллящаяся таблица со стики хедером и боковым столбцом&lt;/a&gt; делается с помощью &lt;code&gt;position: sticky&lt;/code&gt;, а чтобы ограничить область скролла контейнеру задаётся &lt;code&gt;overflow-x: auto&lt;/code&gt; и высота вьюпорта; а заодно из решения почерпнул, что один элемент с &lt;code&gt;position: sticky&lt;/code&gt; можно включить внутрь другого sticky-элемента&lt;/li&gt;
&lt;li&gt;чтобы протестировать стили для печати не обязательно каждый раз запускать печать в браузере, &lt;a href=&quot;https://glebbahmutov.com/blog/test-print-styles/&quot;&gt;в девтулзах есть эмуляция&lt;/a&gt; &lt;code&gt;print media type&lt;/code&gt;, которая также работает и в &lt;code&gt;cypress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://abhisaha.com/blog/interactive-post-oklch-color-space/&quot;&gt;небольшой и симпатичный гайд про цветовой формат OKlch&lt;/a&gt;: автор всё хорошо рассказывает и показывает на примере с градиентом, а также говорит, что хорошо знать, но не обязательно применять это цветовое пространство; от себя я же добавлю, что фронтендерам удобнее всего затаскивать эту тему в проекты (поддержка позволяет — с 2023 работает во всех браузерах)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/css-tricks-that-use-only-one-gradient/&quot;&gt;конический градиент&lt;/a&gt; можно использовать для создания не только круглых форм, но и прямоугольных, например, &lt;code&gt;repeating-conic-gradient(#000 0 25%, #fff 0 50%)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;на чём &lt;a href=&quot;https://github.com/web-platform-tests/interop/labels/focus-area-proposal&quot;&gt;сфокусировать усилия по сближению кроссбраузерности вендоров в 2025&lt;/a&gt;, витрина с пропоузалами: core web vitals, депрефиксация оставшихся CSS-свойств, &lt;code&gt;::before&lt;/code&gt; / &lt;code&gt;::after&lt;/code&gt; на replaced-элементах, Container Queries, SVG и фильтры, CSS Anchor Positioning, Navigation API&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>dev fiction</title><link>https://juwain.github.io/web-platform/blog/2024-10-22/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-10-22/</guid><description>dev fiction</description><pubDate>Tue, 22 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Придумал новый жанр. Вот есть science-fiction, а в мире разработки пусть будет dev-fiction. А что, индустрии веб-разработки явно не хватает своих философов, футуристов и фантастов. Если бы были, то может быть и не появилось в своё время никакого «фронтенда». Начну это исправлять.&lt;/p&gt;
&lt;p&gt;2027 год. После релиза 20 версии React и выхода нескольких мажорных версий Next.js команду разработки React вместе с проектом окончательно поглощает Vercel. Meta открещивается от React и веба и уходит целиком в индустрию ИИ. Бизнес-модель Vercel медленно загоняет развитие платформы в тупик: всё больше продуктовых компаний отказываются от хостинга переусложнённых приложений в Vercel и выбирают миграцию на альтернативные опенсорсные хостинги. Vercel теряет прибыль и перестаёт вкладываться в развитие React.&lt;/p&gt;
&lt;p&gt;2028 год. TC39 в окончательно уходит от «ежегодного» версионирования языка ES. Теперь baseline-версия языка зафиксирована в версии ESBase и больше практически не изменяется. Все нововведения в язык привносятся в sugar-версию языка — ESNext. -ESNext-версия кода комплируется в базовую ESBase. Для этого TC39 в коллаборации с разработчиками Babel, которые остались не у дел, выпускает выпускает альфа-, а затем бета-версию ESNext-компилятора для преобразования ESNext в ESBase.
В языке ESNext появляется типизация. «Нативные» типы ESNext оказываются намного лучше по перфомансу, чем TypeScript, и поэтому TS проигрывает конкуренцию и медленно деградирует. Происходит раскол в команде разработки VSCode и одна часть разработчиков присоединяется к проекту Zed, чтобы разрабатывать новый быстрый редактор для ESNext. VSCode, после ухода части команды, нанесён непоправимый урон, поэтому VSCode по факту останавливается в развитии.&lt;/p&gt;
&lt;p&gt;2030 год. Команда React несколько лет пребывает в упадке. Компании всё чаще ищут альтернативное решение, которое будет позволять создавать более быстрые SPA с простым SSR, но его нет на рынке. Многочисленные попытки уйти от React и создать альтернативное JSX+SSR-решение спотыкаются о то, что в них не работают существующие на рынке дизайн-системы и UI-киты, «залоченные» на React API. При этом Angular и Vue так и не обретают большой популярности и остаются нишевыми проектами. Проблема всё больше назревает и требует какого-то разрешения.&lt;/p&gt;
&lt;p&gt;Внутри Google решают сделать ставку на создание нового быстрого фронтенд-фреймворка на основе веб-компонентов. Для этого создаётся команда во главе с Addy Osmani, которая сначала в короткие сроки в коллаборации с Open UI, Brad Frost, а также с группой разработчиков Devon Govett, создаёт новый универсальный не привязанный к конкретному фреймворку набор компонентов на основе React Aria. Он получает название GlobalComponents.&lt;/p&gt;
&lt;p&gt;2032 год. Команда берётся за создание самого фреймворка, FinalFramework, который тесно сынтегрирован с новым набором компонентов GlobalComponents.
Киллер-преимущество нового фреймворка в том, что он не требует дополнительной сборки, кроме компиляции ESNext в ESBase (если писать код сразу на ESBase, то его можно в принципе не билдить, а запускать как есть в браузере, подключив один JS-файл фреймворка в рантайме).&lt;/p&gt;
&lt;p&gt;Кроме того, в браузере Chrome в дев-тулзах (инспекторе, профайлере и дебаггере) также появляется нативная интеграция с GlobalComponents и FinalFramework, которая позволяет удобно отлаживать приложения и быстро учиться работе с FinalFramework.&lt;/p&gt;
&lt;p&gt;Помимо средств работы непосредственно с DOM (JSX отсутствует, его заменяет надстройка над темплейт-литералами), фреймворк содержит встроенную систему атомарных реактивных сторов, основанную на событийной модели. Также из коробки предоставляется инкапсуляция стилей и JS-скоупы, что больше не требует от команд заботиться о бандлировании и болезненно внедрять «микрофронтенды» посредством тяжеловесного тулинга. Парадигма меняется: один веб-компонент — это и есть «микрофронт» со своим JS-файлом. Данными с окружающим миром он обменивается посредством событий, глобального контекста и нативных браузерных API.
Из-за того, что фреймворк построен на веб-компонентах, которые могут отдаваться с сервера как есть простыми строками , SSR включается одним ключом в настройке компонента.&lt;/p&gt;
&lt;p&gt;«Примитивный» подход к веб-разработке становится модным, дев-блогеры призывают к «get back to the roots!». Webpack уже давно в стагнации, Evan You вместе с компанией void(0) несколько лет как переключился на коммерческую поддержку легаси-проектов в крупных корпорациях.&lt;/p&gt;
&lt;p&gt;2035 год. Из-за своего быстродействия и лёгкости ментальной модели разработки, а также удачного маркетинга, FinalFramework бурно захватывает рынок. Благодаря нативной интеграции с основными браузерами, пошедшими на поводу у удачной стратегии Google, FinalFramework начинает использоваться не только в веб-SPA, но также в создании мини-аппов внутри других крупных приложений и в качестве решения для десктоп-приложений на основе Electron. Веб вновь захватывает мир.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 25.10.2024</title><link>https://juwain.github.io/web-platform/blog/2024-10-25/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-10-25/</guid><description>Новости веб-платформы</description><pubDate>Fri, 25 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://svelte.dev/blog/svelte-5-is-alive&quot;&gt;вышел Svelte 5&lt;/a&gt;, главные изменения: реактивные элементы теперь описываются явно (раньше было более магически); убран синтаксис &lt;code&gt;slot&lt;/code&gt;, &lt;code&gt;let:&lt;/code&gt; и &lt;code&gt;&amp;lt;svelte:fragment&amp;gt;&lt;/code&gt; в пользу &lt;code&gt;{#snippet …}&lt;/code&gt;; нативно поддержан TS; появился новый CLI; SvelteKit будет доработан под Svelte 5, но работает уже сейчас&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/blog/next-15&quot;&gt;вышел Next.js 15&lt;/a&gt;: API &lt;code&gt;headers&lt;/code&gt;, &lt;code&gt;cookies&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt; и &lt;code&gt;searchParams&lt;/code&gt; стали асинхронными; кеширование &lt;code&gt;GET&lt;/code&gt; Route Handlers и Client Router Cache выключено по умолчанию; поддержан React 19 и ESLint 9; добавлен новый компонент &lt;code&gt;&amp;lt;Form&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/blog/2024/10/21/react-compiler-beta-release&quot;&gt;выпущена React Compiler Beta&lt;/a&gt;: чтобы компайлер работал корректнее, код должен соответствовать требованиям специального плагина &lt;code&gt;eslint-plugin-react-compiler&lt;/code&gt; (также сохранена обратная совместимость с React 17 и 18)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netlify.com/blog/netlify-joins-opennext/&quot;&gt;Netlify вслед за Cloudflare присоединяется к проекту OpenNext&lt;/a&gt;, но они и так раньше полноценно хостили Next.js проекты, так что это всё маркетинг&lt;/li&gt;
&lt;li&gt;в shadcn зарелизили «семейство» &lt;a href=&quot;https://ui.shadcn.com/docs/components/sidebar&quot;&gt;компонентов сайдбара&lt;/a&gt;, много всяких их вариаций, есть «ручки» CSS-переменных для стилизации, но одним большим НО всё ещё остаётся Tailwind в ядре этого кита; православный React Spectrum пока что на эту тему имеет только &lt;a href=&quot;https://react-spectrum.adobe.com/react-spectrum/TreeView.html&quot;&gt;beta-версию компонента Tree View&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.jetbrains.com/blog/2024/10/24/webstorm-and-rider-are-now-free-for-non-commercial-use/&quot;&gt;IDE WebStorm стал Free for non-commercial use&lt;/a&gt;, делаю вывод: редактор Fleet не полетел, в JetBrains решили потратить прибыль от лицензий WebStorm на маркетинг, в момент когда есть повсеместно некая усталость от VSCode (кстати, а где моя доля?!)&lt;/li&gt;
&lt;li&gt;появились результаты опроса &lt;a href=&quot;https://2024.stateofcss.com&quot;&gt;State of CSS 2024&lt;/a&gt;, интересные факты:
&lt;ul&gt;
&lt;li&gt;25% опрошенных создают свои дизайны сразу в CSS&lt;/li&gt;
&lt;li&gt;большинство CSS-фич уже вышло, но при этом всё ещё есть болит кроссбраузерность&lt;/li&gt;
&lt;li&gt;самые любимые фичи &lt;code&gt;:has()&lt;/code&gt; и subgrid&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://huggingface.co/blog/transformersjs-v3&quot;&gt;обновилась версия Transformers.js v3&lt;/a&gt;, JS-реализации популярных ИИ-моделей (около 120 штук): появилась поддержка WebGPU; совместим с Node, Bun, Deno; теперь хостится в официальном хранилище Hugging Face&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hexp3.com&quot;&gt;hexp3&lt;/a&gt; — быстрый конвертер цвета hex в похожий цвет в пространстве P3&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/atlassian/pragmatic-drag-and-drop&quot;&gt;pragmatic-drag-and-drop&lt;/a&gt; — dnd-либы приходят и уходят, вот и новый подход Atlassian после &lt;a href=&quot;https://github.com/atlassian/react-beautiful-dnd/issues/2672&quot;&gt;депрекейта react-beautiful-dnd&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nolanlawson.com/2024/10/20/why-im-skeptical-of-rewriting-javascript-tools-in-faster-languages/&quot;&gt;обратная сторона&lt;/a&gt; того, что веб-тулинг написан на ненативном языке (например, Rust вместо JS), его становится сложно продебажить, а также если тулинг работает в браузерном рантайме, то уходят бесплатные браузерные плюшки — JIT и кэширование байт-кода (это когда во второй раз скрипт берётся в прекомпилированном виде из кэша, а в n-ннадцатый раз ещё и дополнительно оптимизируется); кстати, ещё есть рецепт, как включить &lt;a href=&quot;https://github.com/nodejs/node/pull/52535&quot;&gt;compile cache&lt;/a&gt; в Node: &lt;code&gt;export NODE_COMPILE_CACHE=~/.cache/nodejs-compile-cache&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;мнения по поводу предложения в TC39 разделить версии языка на JS0/JSSugar разделились: &lt;a href=&quot;https://bleepbloop.studio/posts/new-tc39-proposal-does-javascript-require-a-compiler-soon&quot;&gt;сторонник&lt;/a&gt; изменений будет рад появлению &lt;code&gt;pipes&lt;/code&gt; в JSSugar, а вот &lt;a href=&quot;https://caolan.uk/notes/2024-10-14_js0_jssugar.cm&quot;&gt;противник&lt;/a&gt; хочет продолжать писать на «низком уровне» и дальше (хотя вроде как ему этого и не запрещают)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/convert-cjs-to-esm&quot;&gt;статья про перевод cjs в esm&lt;/a&gt;: в целом, ничего нового, но ребята из Deno напоминают, что в Node уже давно есть &lt;code&gt;import.meta.dirname&lt;/code&gt; и &lt;code&gt;import.meta.filename&lt;/code&gt;, а также что в VSCode есть рефакторинг-тула для перевода cjs-модулей в esm (также можно выполнить &lt;code&gt;deno lint --fix&lt;/code&gt;, но его ещё установить надо)&lt;/li&gt;
&lt;li&gt;недавний выход в Node.js возможности require-ить esm-модули &lt;a href=&quot;https://evertpot.com/using-top-level-await-is-bc-break/&quot;&gt;создало проблему&lt;/a&gt;: это работает только если в импортируемых esm-модулях (а также их внутренних зависимостях) не используется top-level &lt;code&gt;await&lt;/code&gt;; таким образом имели два конфликтующих типа модулей CommonJS и ESM, а появился ещё и третий — ESM без top-level &lt;code&gt;await&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если нужно сделать &lt;a href=&quot;https://www.letsbuildui.dev/articles/fun-with-custom-cursors/&quot;&gt;кастомный курсор&lt;/a&gt; с анимацией по наведению на элемент интерфейса и доп инфой рядом с курсором, то свойством &lt;code&gt;cursor&lt;/code&gt; не обойтись: нужно создать невидимый элемент, которому на &lt;code&gt;mousemove&lt;/code&gt; будут прокидываться координаты и он будет становиться видимым в момент &lt;code&gt;:root:has(button:hover) {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jsdev.space/memory-management-js/&quot;&gt;WeakRef в JS&lt;/a&gt; даёт возможность создать ссылку на другой объект, которая уберётся из памяти Garbage Collector-ом, а с FinalizationRegistry можно создать колбек на сам момент очистки памяти&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;для того, чтобы стать КМС по теням, градиентам, а также их комбинациям с масками + &lt;code&gt;clip-path&lt;/code&gt; можно рисовать &lt;a href=&quot;https://codepen.io/alvaromontoro/pen/ZEgezbN&quot;&gt;пластилиновых человечков на CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;функция &lt;code&gt;min()&lt;/code&gt; понятна сходу (в отличие от container queries) и её можно &lt;a href=&quot;https://www.smashingmagazine.com/2024/10/css-min-all-the-things/&quot;&gt;применять как «односторонний стопор»&lt;/a&gt; при задании динамических значений для &lt;code&gt;width&lt;/code&gt;, &lt;code&gt;margin&lt;/code&gt;, `font-size&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wicg.github.io/scroll-to-text-fragment/&quot;&gt;Text fragments&lt;/a&gt; — возможность ссылаться на определённый текст на странице &lt;a href=&quot;https://alfy.blog/2024/10/19/linking-directly-to-web-page-content.html&quot;&gt;хороша ещё и тем&lt;/a&gt;, что в Chromium-браузерах есть фича «Copy link to highlight» в контекстом меню на выделенном тексте, которая сгенерит эту ссылку&lt;/li&gt;
&lt;li&gt;чтобы фон вложенного элемента не вылезал за скругленные углы родителя, &lt;a href=&quot;https://css-tricks.com/preventing-child-background-overflow-with-inherited-border-radii/&quot;&gt;можно принудительно унаследовать&lt;/a&gt; &lt;code&gt;border-radius: inherit&lt;/code&gt; вместо добавления &lt;code&gt;overflow: hidden&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://daverupert.com/2024/10/super-web-components-sunshine/&quot;&gt;в чём веб-компоненты плохи&lt;/a&gt; (там есть и хорошая часть, но плохая всегда интереснее): Shadow DOM катастрофически переусложнён; SSR сложно и делается только из-под фреймворков; роутер на веб-компонентах лучше не делать; есть проблемы с доступностью; и главная проблема — нет широкой поддержки в популярных фреймворках&lt;/li&gt;
&lt;li&gt;по аналогии с conventional commits есть &lt;a href=&quot;https://www.stefanjudis.com/blog/processes-and-rules-make-code-review-less-intimidating/&quot;&gt;conventional comments&lt;/a&gt;, для того, чтобы сделать комментарии в процессе ревью кода более осмысленными и сразу было видно, какие комментарии пишутся только чтобы поумничать и их можно не учитывать и отправлять прямиком в глубокий бэклог&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fhur.me/posts/2024/thats-not-an-abstraction&quot;&gt;хорошая абстракция&lt;/a&gt; в коде абсорбирует сложность, влезать внутрь приходится редко; плохая абстракция маскирует сложность дополнительными слоями смыслов и в неё надо часто залезать&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 01.11.2024</title><link>https://juwain.github.io/web-platform/blog/2024-11-01/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-11-01/</guid><description>Новости веб-платформы</description><pubDate>Fri, 01 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v23.1.0&quot;&gt;обновилась Node до v23.1.0&lt;/a&gt;: стабилизировано встроенное в &apos;node:test&apos; MockTimers API, позволяющее замокать системное время &lt;code&gt;mock.timers.enable({ apis: [&apos;Date&apos;], now: new Date(&apos;1970-01-01&apos;) });&lt;/code&gt;, а также теперь стабильны JSON modules и import attributes — это когда к импорту JSON-файла приписывается уточнение &lt;code&gt;with { type: &apos;json&apos; }&lt;/code&gt; для повышения безопасности, чтобы среда проверила, что внутри действительно JSON (также с &lt;a href=&quot;https://nodejs.org/en/blog/release/v22.11.0&quot;&gt;выходом Node 22.11.0&lt;/a&gt; все дальнейшие 22.x-релизы будут считаться LTS)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/195gc4ut4gJ6kbgxlLfCKws0pY505c7uNWbmIoap2CkQ/edit#slide=id.p&quot;&gt;состоялся первый митинг рабочей группы JSR&lt;/a&gt; (аналог npm от создателей Deno), из слайдов можно узнать, что: JSR не всегда может опубликовать существующий проект на &lt;code&gt;.js + .d.ts&lt;/code&gt;; хостинг проекта стоит ~$400 в месяц; хотят сделать тул для генерации JSR-конфига из &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://open-web-advocacy.org/blog/apple-implements-six-of-owas-dma-compliance-requests/&quot;&gt;Apple пошла на уступки&lt;/a&gt; контролирующим органам в EU и добавила в новой бете iOS послабления (только для EU) в истории с монопольностью Safari: браузерные вендоры теперь могут включать бинарник с собственным движком в браузер, но он всё равно будет использоваться на пару с webkit, правда тестировать это дело за пределами EU всё равно нельзя; выбор браузера по умолчанию появится в более заметном месте и в явном виде; Safari можно будет удалить из системы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/132.0/releasenotes/&quot;&gt;вышел Firefox 132&lt;/a&gt;: улучшена поддержка аппаратного ускорения для SVG-фильтров; HTTP-фавиконки будут блокироваться, если их невозможно получить через https; поддержан атрибут &lt;code&gt;fetchpriority&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/1111mp/nvm-desktop&quot;&gt;nvm-desktop&lt;/a&gt; — собранный на Tauri кроссcистемный десктопный клиент Node Version Manager&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/frinyvonnick/node-html-to-image&quot;&gt;node-html-to-image&lt;/a&gt; — Node-надстройка над puppeteer, чтобы отрендерить страницу и снять скриншот (опционально поддерживается Handlerbars для разметки)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://duckduckgo.com/aichat&quot;&gt;DuckDuckGo AI Chat&lt;/a&gt; — через сервис можно бесплатно и без VPN пользоваться чатом с моделями GPT, Claude, Llama, Mixtral&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/knowler/html-/&quot;&gt;html-&lt;/a&gt; — попытка воссоздать стандартные HTML-элементы с помощью веб-компонентов (которая обречена на провал, но смотреть интересно); вот, например, &lt;a href=&quot;https://github.com/knowler/html-/blob/main/button-element.js&quot;&gt;кнопка&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://samthor.au/2024/node-run-typescript/&quot;&gt;нативная поддержка TS в Node&lt;/a&gt; уже сама по себе хороша, но также позволяет импортировать TS-файлы просто так &lt;code&gt;const module = await import(&apos;./module.ts&apos;);&lt;/code&gt;; включить можно экспериментальным флагом при запуске Node, в том числе в сразу внутри &lt;code&gt;.bashrc&lt;/code&gt;: &lt;code&gt;export NODE_OPTIONS=&quot;--experimental-transform-types --disable-warning=ExperimentalWarning&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ручной вызов метода &lt;code&gt;submit()&lt;/code&gt; у формы совершит отправку не учитывая валидации и не запуская события &lt;code&gt;submit&lt;/code&gt;; а чтобы перед отправкой формы триггерить событие и проводить валидации, &lt;a href=&quot;https://www.stefanjudis.com/today-i-learned/requestsubmit-offers-a-way-to-validate-a-form-before-submitting-it/&quot;&gt;есть давно доступный в браузерах метод &lt;code&gt;requestSubmit()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cloudflare.com/fragment-piercing/&quot;&gt;пример реализации микрофронтендов&lt;/a&gt; с помощью Cloudflare Workers: приводится пример реализации с гейтвеем, через который проходят все запросы, и который отдаёт нужный микрофронт, а также с кастомными элементами для обозначения, куда инжектить микрофронт и с общей шиной событий (честно говоря, это уже почти похоже на набор iframe-ов, в которых грузятся независимые страницы)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/come-to-the-light-dark-side/&quot;&gt;«нативное» управление светлой-тёмной темой&lt;/a&gt; через &lt;code&gt;&amp;lt;meta name=&quot;color-scheme&quot; content=&quot;light dark&quot;&amp;gt;&lt;/code&gt; прикольно тем, что можно буквально найти meta-элемент через &lt;code&gt;document.querySelector&lt;/code&gt; и менять его значение&lt;/li&gt;
&lt;li&gt;«нативная» валидация форм (атрибут метод &lt;code&gt;setCustomValidity&lt;/code&gt; у инпутов) позволяет на коленке сделать проверку введённого значения в инпуты и отобразить это в виде системного уведомления (&lt;a href=&quot;https://expressionstatement.com/html-form-validation-is-heavily-underused&quot;&gt;пример для React&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jsdev.space/file-blob-js/&quot;&gt;&lt;code&gt;File&lt;/code&gt; — это расширение &lt;code&gt;Blob&lt;/code&gt;&lt;/a&gt;, с добавленными методами &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;lastModified&lt;/code&gt;, &lt;code&gt;webkitRelativePath&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;селектор &lt;code&gt;.container:has(.element:last-child:nth-child(-n + 3))&lt;/code&gt; применится, если в контейнере содержится 3 или меньше количество элементов, удобно, к примеру, &lt;a href=&quot;https://piccalil.li/blog/making-content-aware-components-using-css-has-grid-and-quantity-queries/&quot;&gt;для перестроения грида&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/unleash-the-power-of-scroll-driven-animations/&quot;&gt;гайд&lt;/a&gt; по Scroll-Driven Animations (пока доступны только в Хромиум-браузерах): киллер-фича — разгружается основной поток браузерного движка и поэтому анимации получаются гарантировано более плавными (&lt;a href=&quot;https://frontendmasters.com/blog/scroll-driven-sections/&quot;&gt;бонусом пример&lt;/a&gt; связки анимации кастомного свойства посредством скролл-анимации)&lt;/li&gt;
&lt;li&gt;с частым появлением новых фич в CSS можно регулярно их обновлять в CSS Reset; в &lt;a href=&quot;https://jakelazaroff.com/words/my-modern-css-reset/&quot;&gt;предлагаемом варианте&lt;/a&gt; используются &lt;code&gt;@layer&lt;/code&gt;, чтобы подключать стили не обязательно в самом начале , и нативная вложенность селекторов &lt;code&gt;:not([class]) { h1&amp;amp; {…}}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://evilmartians.com/chronicles/woah-opacity-a-full-guide-to-this-badass-hero-of-efficient-ui-design&quot;&gt;использование полупрозрачного цвета вместо сплошного&lt;/a&gt; — хороший лайфхак, чтобы не плодить цвета для разных состояний кнопок или рамок, годится для приложений с несколькими цветовыми темами&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/top-cwv&quot;&gt;сборник рекомендаций по улучшению Core Web Vitals&lt;/a&gt;, из интересного: в Chrome есть вкладка Coverage, чтобы увидеть загруженный, но неиспользующийся код; картинки лучше всего подключать в &lt;code&gt;&amp;lt;img src|srcset&amp;gt;&lt;/code&gt;, так они начинают грузиться раньше, а не ждут загрузки стилей/скриптов; не стоит пользовать событие &lt;code&gt;unload&lt;/code&gt; и заголовок &lt;code&gt;Cache-Control: no-store&lt;/code&gt;, так как они мешают браузеру доставать страницу из кеша при переходе «назад»&lt;/li&gt;
&lt;li&gt;обычно поиском по истории коммитов пользуешься, чтобы посмотреть, кто что изменил в конкретном файле или строке файла; а вот &lt;code&gt;git log&lt;/code&gt; с ключом &lt;code&gt;-S&lt;/code&gt; — &lt;a href=&quot;https://alexharri.com/blog/searching-and-navigating-git-commits&quot;&gt;«поисковик» по диффам коммитов определённой строки&lt;/a&gt;, не привязываясь к конкретному файлу&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://t.me/web_platform/142&quot;&gt;недавно писал dev-fiction&lt;/a&gt;, где предполагал появление web-components-фреймворка от Google и «глобального UI-kit-а», помните? Как вы возможно догадались, «прототипы» не были взяты мной из воздуха. Фреймворк самом деле существует — это &lt;a href=&quot;https://lit.dev&quot;&gt;Lit&lt;/a&gt; (остаётся довезти туда &lt;a href=&quot;https://lit.dev/blog/2024-10-08-signals/&quot;&gt;нативные сигналы&lt;/a&gt;, упростить SSR, добавить тесную интеграцию с дев-тулзами и включить маркетинговую машину), а прототип «глобального» UI-kit-а — это &lt;a href=&quot;https://shoelace.style&quot;&gt;Shoelace&lt;/a&gt; (недавно переродившийся в Web Awesome), основанный на Lit (остаётся перестать быть местечковым проектом одного человека). Так вот, я к чему веду: посмотрите на &lt;a href=&quot;https://github.com/web-platform-dx/baseline-status/blob/main/baseline-status.js&quot;&gt;код веб-компонента&lt;/a&gt; статусной плашки, у меня этот код вызывает приятные ощущения, а у вас?&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 08.11.2024</title><link>https://juwain.github.io/web-platform/blog/2024-11-08/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-11-08/</guid><description>Новости веб-платформы</description><pubDate>Fri, 08 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Nicholas C. Zakas &lt;a href=&quot;https://github.com/eslint/rfcs/blob/main/designs/2022-languages/README.md&quot;&gt;прорабатывает поддержку &lt;/a&gt;в ESLint плагинов для других (неES) языков, например, началась работа над &lt;a href=&quot;https://github.com/eslint/css/&quot;&gt;плагином для линтинга CSS&lt;/a&gt;, а что Stylelint по сути делает схожие манипуляции, почему бы не делать это в самом ESLint?&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://getflocked.dev/blog/posts/we-are-forking-flutter-this-is-why/&quot;&gt;часть OSS-разработчиков Flutter создали форк Flock&lt;/a&gt;, из-за недовольства, что баги в оригинальной команде долго фиксятся, планируют активно работать с сообществом, но при этом не отходить от оригинального Flutter (пока что)&lt;/li&gt;
&lt;li&gt;в Mozilla Foundation (НКО) &lt;a href=&quot;https://techcrunch.com/2024/11/05/mozilla-foundation-lays-off-30-staff-drops-advocacy-division/&quot;&gt;сократили 30% персонала&lt;/a&gt; (отделы advocacy и global)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jsonvisualizer-v2.web.app/visualize&quot;&gt;jsonvisualizer&lt;/a&gt; — визуализация JSON в виде диаграммы, например, чтобы окинуть взглядом сразу весь ваш развесистый &lt;code&gt;package.json&lt;/code&gt; или JSON-ину с большой вложенностью&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.codingfont.com/&quot;&gt;codingfont&lt;/a&gt; — шрифтовый батл, чтобы остался тольк один: удобный, моноширинный, твой (у меня победил Source Code Pro)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/prerender/prerender&quot;&gt;prerender&lt;/a&gt; — Node-сервер, который в безголовом Chrome отрендерит SPA и отдаст готовый HTML (например, для поисковиков)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если отбросить хэллоуинскую тематику, то в одном месте &lt;a href=&quot;https://nerdy.dev/headless-boneless-and-skinless-ui&quot;&gt;сравниваются подходы к организации UI-китов&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;headless (безголовый) — кит предоставляет компоненты и минимальные стили, разработчик сам организует CSS для них (Radix Primitives)&lt;/li&gt;
&lt;li&gt;boneless (безкостный) — кит предоставляет атомарные классы, из которых разработчик уже составляет компоненты (Bootstrap, Tailwind)&lt;/li&gt;
&lt;li&gt;skinless (безкожный) — как кит предоставляет компоненты, но совсем без стилей (React Aria)&lt;/li&gt;
&lt;li&gt;lifeless (безжизненный) — набор «голых» хуков и абстрактной функциональности, в которые нужно самостоятельно передать «физическое воплощение», чтобы система «ожила» (TanStack, React Aria Hooks)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;идея: &lt;a href=&quot;https://dev.to/noah-00/no-more-trycatch-a-better-way-to-handle-errors-in-typescript-5hbd&quot;&gt;не использовать try/catch напрямую&lt;/a&gt;, а оборачивать код в функцию, возвращающую промис, а уже внутри этой функции прописать catch у промиса&lt;/li&gt;
&lt;li&gt;пока в Vercel проводят конференции и выпускают новые версии с поддержкой «серверного» React, в мире работает один (на самом деле нет) Tanner Linsley, &lt;a href=&quot;https://bobaekang.com/blog/two-ways-to-the-two-reacts/&quot;&gt;пытающийся вернуть React на клиент&lt;/a&gt;, сделав сервер ещё одним способом работы с асинхронными данными, но при этом оставив прежнюю клиентскую природу React в TanStack Start, очень интересно, что же получится&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.trevorlasn.com/blog/javascript-nullish-coalescing-assignment-operator&quot;&gt;оператор &lt;code&gt;??=&lt;/code&gt;&lt;/a&gt; позволяет избавиться от бойлерплейтного кода, когда нужно проверить значение на null/undefined и присвоить дефолтное значение: вместо &lt;code&gt;user.name = user.name ?? &apos;Anonymous&apos;&lt;/code&gt; пишем &lt;code&gt;user.name ??= &apos;Anonymous&apos;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;свойство &lt;code&gt;text-wrap: balance&lt;/code&gt; ожидаемо из названия подравнивает длинные многострочные заголовки и короткие тексты, но уже неожиданно может быть использовано для &lt;a href=&quot;https://shkspr.mobi/blog/2024/10/you-can-use-text-wrap-balance-on-icons/&quot;&gt;подравнивания любых inline-элементов, переносящихся на несколько строк&lt;/a&gt;, например, &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt; с &lt;code&gt;display: inline-block&lt;/code&gt; и иконками внутри&lt;/li&gt;
&lt;li&gt;в &lt;code&gt;@layer&lt;/code&gt; можно включать не только reset-стили, но и в целом &lt;a href=&quot;https://mayank.co/blog/css-reset-layer/&quot;&gt;любые глобальные стили на весь проект&lt;/a&gt;, если хочется избежать проблем со нарастающей специфичностью и порядком подключения стилей (&lt;code&gt;@layer&lt;/code&gt; — это как будто &lt;code&gt;!unimportant&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;этот год был богат на урожай CSS-фич, которые ещё несколько лет будут входить в обиход, а пока остаётся просматривать списки фич и запоминать, чтобы при случае удачно применить; в &lt;a href=&quot;https://argyle-at-devfest-2024.netlify.app/16-user-valid/&quot;&gt;этом списке&lt;/a&gt;, например, среди прочего есть упоминание о псевдоклассах &lt;code&gt;:user-valid&lt;/code&gt; и &lt;code&gt;:user-invalid&lt;/code&gt;, которыми с связке с &lt;code&gt;:has()&lt;/code&gt; можно связать стилизацию &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; с последующим пользовательским неверным заполнением &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;: &lt;code&gt;input { label:has(+ &amp;amp;:user-invalid) { text-decoration: underline wavy red }}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;значение &lt;code&gt;width: stretch&lt;/code&gt;, оно же &lt;code&gt;-moz-available&lt;/code&gt; и &lt;code&gt;-webkit-fill-available&lt;/code&gt; несмотря на до сих пор требуемые префиксы, доступная во всех браузерах альтернатива высчитыванию &lt;code&gt;width: calc(100% - 48px)&lt;/code&gt;, если &lt;a href=&quot;https://fullystacked.net/stretch/&quot;&gt;нужно «компенсировать» отступы&lt;/a&gt; у &lt;code&gt;100%&lt;/code&gt; ширины&lt;/li&gt;
&lt;li&gt;есть такие моменты во фронтендерских буднях, на которые можно забить, а можно &lt;a href=&quot;https://medienbaecker.com/articles/focus-outlines&quot;&gt;мимикрокодилом улучшить интерфейс по-мелочи&lt;/a&gt;: много времени не займёт, конечному пользователю будет приятнее; вот, например, &lt;code&gt;outline&lt;/code&gt; — его обычно выключают, чтобы убрать «проблему», но ведь можно его оставить, но при этом сделать симпатичным: показывать по &lt;code&gt;:focus-visible&lt;/code&gt;, выставить цвет &lt;code&gt;currentcolor&lt;/code&gt;, сделать элемент «блочным», немного скруглить углы, задать &lt;code&gt;outline-offset&lt;/code&gt; и возможно немного его анимировать&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://evilmartians.com/chronicles/html-best-practices-for-login-and-signup-forms&quot;&gt;ещё одна статья&lt;/a&gt; к подтверждению предыдущей мысли: расставить HTML-атрибуты или обернуть чекбоксы в лейблы, а кнопки в формы несложно, но пользовательский опыт улучшится и на мобильных, и на десктопных платформах&lt;/li&gt;
&lt;li&gt;недавно ставший с выходом FF повсеместно доступный атрибут &lt;code&gt;fetchpriority&lt;/code&gt; &lt;a href=&quot;https://web.dev/articles/fetch-priority&quot;&gt;помогает браузеру понять&lt;/a&gt;, какие ресурсы грузить первым приоритетом (LCP-картинку), а какие можно отложить (второстепенные скрипты и стили); интересный приём — прелоадим стили с низким приоритетом без блокирования рендера &lt;code&gt;&amp;lt;link rel=&quot;preload&quot; as=&quot;style&quot; href=&quot;theme.css&quot; fetchpriority=&quot;low&quot; onload=&quot;this.rel=&apos;stylesheet&apos;&quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ответ на вопрос собеседования «&lt;a href=&quot;https://abhisaha.com/blog/exploring-browser-rendering-process&quot;&gt;что происходит, когда вы набираете адрес сайта в браузере&lt;/a&gt;»: DNS Lookup → TCP/TLS Handshake → HTTP Request/Response Cycle → Tokenization → DOM Tree Creation → CSSOM Tree Creation → Render Tree Creation → Layout → Painting&lt;/li&gt;
&lt;li&gt;вы наверняка сталкивались уже с проектом &lt;a href=&quot;https://webstatus.dev&quot;&gt;webstatus.dev&lt;/a&gt;, где показывается в скольких процентах браузеров поддерживаются те или иные фичи; так вот к этим данным есть API &lt;a href=&quot;https://api.webstatus.dev&quot;&gt;api.webstatus.dev&lt;/a&gt; (описание &lt;a href=&quot;https://github.com/GoogleChrome/webstatus.dev/blob/main/openapi/backend/openapi.yaml&quot;&gt;схемы openapi&lt;/a&gt;) на поиграться&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 15.11.2024</title><link>https://juwain.github.io/web-platform/blog/2024-11-15/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-11-15/</guid><description>Новости веб-платформы</description><pubDate>Fri, 15 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;свойства для «подрезки» текста от верхнего и нижнего отступа точно по высоте строки &lt;code&gt;text-box-trim&lt;/code&gt; и &lt;code&gt;text-box-edge&lt;/code&gt;, доступные сейчас в &lt;a href=&quot;https://developer.apple.com/documentation/safari-release-notes/safari-18_2-release-notes&quot;&gt;бете Safari 18.2&lt;/a&gt; вероятно скоро &lt;a href=&quot;https://issues.chromium.org/issues/40254880&quot;&gt;доедут и до Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/css-values-5/#if-notation&quot;&gt;обновился черновик CSS Values and Units Module Level 5&lt;/a&gt;, внесли синтаксис &lt;code&gt;if()&lt;/code&gt;, чтобы можно было писать в CSS инлайновые условия в духе: &lt;code&gt;display: if(style(--feature-flag: true): block; else: none)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;вышел новый npm-совместимый менеджер пакетов от создателя npm и других достойных мужей — &lt;a href=&quot;https://www.vlt.sh/client&quot;&gt;vlt&lt;/a&gt;, позволяющий, к примеру, отображать зависимости проекта в виде диаграммы или вообще в gui; также вниманию предлагается npm-совместимый реестр &lt;a href=&quot;https://www.vlt.sh/serverless-registry&quot;&gt;vsr&lt;/a&gt;, который можно самостоятельно развернуть у себя бесплатно&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://motion.dev/blog/framer-motion-is-now-independent-introducing-motion&quot;&gt;либа Framer Motion стала независимой&lt;/a&gt; и переименована её автором Matt Perry в просто в Motion&lt;/li&gt;
&lt;li&gt;если вдруг вы искали способы, как уменьшить количество зависимостей вашего проекта, можете &lt;a href=&quot;https://storybook.js.org/blog/storybook-8-4/&quot;&gt;подглядеть в Storybook 8.4&lt;/a&gt;: с помощью активистов проекта &lt;a href=&quot;https://e18e.dev/&quot;&gt;e18e&lt;/a&gt; ребята снизили размер проекта на 50+%, а размер лок-файла на 75+% (удалены fs-extra, handlebars, file-system-cache; заменены &lt;code&gt;lodash&lt;/code&gt; ⇒ &lt;code&gt;es-toolkit&lt;/code&gt;, &lt;code&gt;express&lt;/code&gt; ⇒ &lt;code&gt;polka&lt;/code&gt;, &lt;code&gt;chalk&lt;/code&gt; ⇒ &lt;code&gt;picocolors&lt;/code&gt;, &lt;code&gt;qs&lt;/code&gt; ⇒ &lt;code&gt;picoquery&lt;/code&gt;; использован production-mode &lt;code&gt;react&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CSS-Next/logo.css&quot;&gt;у CSS появился «официальный» логотип&lt;/a&gt;, а заодно продумывается &lt;a href=&quot;https://github.com/CSS-Next/css-next/discussions/92&quot;&gt;категоризация&lt;/a&gt; на уровни CSS4 и CSS5&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://nodejs.org/en/blog/release/v18.20.5&quot;&gt;Node v18.20.5 LTS&lt;/a&gt; import attributes и JSON module помечены как stable и в догонку &lt;a href=&quot;https://www.trevorlasn.com/blog/import-attributes-in-javascript&quot;&gt;статья с объяснениями зачем эта фича нужна&lt;/a&gt; — чтобы гарантировать, что если в JSON файле придёт исполняемый JS-код, то он не будет выполнен&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/posva/pinia-colada&quot;&gt;pinia-colada&lt;/a&gt; — data-fetching слой для совместной работы со стейт-менеджером Pinia (Vue.js), похоже на Tanstack query, но напрямую подключается к Pinia&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/usmanyunusov/nano-staged&quot;&gt;nano-staged&lt;/a&gt; — легковесная альтернатива lint-staged для запуска команд при добавлении в стейдж, коммите файлов в git&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/lexical&quot;&gt;lexical&lt;/a&gt; — оказывается у facebook есть свой опенсорсный текcтовый WYSIWYG-редактор&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;метод &lt;code&gt;dangerouslySetInnerHTML&lt;/code&gt; своим названием как бы напоминает, что если источник HTML вне контроля, то стоит обязательно предварительно &lt;a href=&quot;https://macarthur.me/posts/safer-dangerouslysetinnerhtml/&quot;&gt;санитайзить контент&lt;/a&gt;, ведь внутри может оказать вредоносный скрипт (и не только в теге &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, но и просто в &lt;code&gt;src&lt;/code&gt; или обработчике &lt;code&gt;onclick&lt;/code&gt;, &lt;code&gt;onerror&lt;/code&gt;…); помимо спецлиб для санитайзинга типа &lt;a href=&quot;https://www.npmjs.com/package/sanitize-html&quot;&gt;sanitize-html&lt;/a&gt;, можно воспользоваться браузерной технологией &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&quot;&gt;CSP&lt;/a&gt;, которая ограничивает возможность запуска инлайновых скриптов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.robinwieruch.de/react-form-data/&quot;&gt;рецепт для работы с формами в React&lt;/a&gt;: на &lt;code&gt;action&lt;/code&gt; (сервер) или &lt;code&gt;submit&lt;/code&gt; (клиент) вешается колбек, возвращающий &lt;code&gt;FormData&lt;/code&gt;, которая парсится &lt;code&gt;zod&lt;/code&gt; или &lt;code&gt;zod-form-data&lt;/code&gt;, и при успехе возвращаются деструктурированые значения&lt;/li&gt;
&lt;li&gt;свойства &lt;code&gt;screenX&lt;/code&gt; и &lt;code&gt;screenY&lt;/code&gt; &lt;a href=&quot;https://www.joshtumath.uk/posts/2024-11-08-how-a-bbc-navigation-bar-component-broke-depending-on-which-external-monitor-it-was-on/&quot;&gt;при использовании внешних мониторов&lt;/a&gt; могут рассчитываться по-разному в разных браузерах, иногда принимая отрицательные значения&lt;/li&gt;
&lt;li&gt;напоминание, когда выйдете в понедельник на работу: &lt;a href=&quot;https://tduyng.com/blog/tsconfig-options-you-should-use/&quot;&gt;проверить tsconfig.json&lt;/a&gt; в вашем проекте на наличие в них ключей &lt;code&gt;incremental&lt;/code&gt; и &lt;code&gt;noErrorTruncation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;иногда в одном интерфейсе &lt;a href=&quot;https://elanmed.dev/blog/conditional-props-using-type-discrimination&quot;&gt;не уместить несколько смежных полей&lt;/a&gt;, например, два разных вида id, в таком случае можно разделить интерфейс на два, в каждом пометить ненужный id опциональным и задать значение never, а затем снова объединить их в один тип через &lt;code&gt;|&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;среди новинок CSS много тех, которые пока что работают только в Chrome, но также много и &lt;a href=&quot;https://thomasorus.com/new-css-that-can-actually-be-used-in-2024.html&quot;&gt;кроссбраузерных фич&lt;/a&gt;, которые не на слуху, но их можно смело использовать: &lt;code&gt;inset&lt;/code&gt; и логические значения свойств &lt;code&gt;block-size&lt;/code&gt;, &lt;code&gt;inline-start&lt;/code&gt;, &lt;code&gt;inset-block&lt;/code&gt; и другие, группирующие селекторы &lt;code&gt;:is&lt;/code&gt;, &lt;code&gt;:where&lt;/code&gt;, функции сравнения &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;clamp&lt;/code&gt;, единица измерения динамической высоты вьюпорта dvh, media queries range syntax &lt;code&gt;(width &amp;lt;= 1140px)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshwcomeau.com/css/container-queries-introduction/&quot;&gt;при работе с container queries&lt;/a&gt; для &lt;code&gt;container-type&lt;/code&gt; можно задать &lt;code&gt;inline-size&lt;/code&gt; и &lt;code&gt;size&lt;/code&gt;; значение &lt;code&gt;inline-size&lt;/code&gt; указывает браузеру, что инлайновый размер (то есть ширина, width) контейнера больше не связан с его содержимым, то есть в директиве &lt;code&gt;@container&lt;/code&gt; можно указывать &lt;code&gt;min-width&lt;/code&gt;/&lt;code&gt;max-width&lt;/code&gt; не боясь «зацикленности»; значение &lt;code&gt;container-type: size&lt;/code&gt; наоборот разрывает связь высоты контейнера с его содержимым, то есть можно безопасно «квейрить» свойства «высоты» &lt;code&gt;@container (min-height/max-height)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;overflow: clip&lt;/code&gt; отличается от &lt;code&gt;overflow: hidden&lt;/code&gt; тем, что &lt;a href=&quot;https://ishadeed.com/article/overflow-clip/&quot;&gt;не создаёт скроллов и может обрезать только по одной стороне&lt;/a&gt; вместо сразу двух; кроме того, есть свойство &lt;code&gt;overflow-clip-margin&lt;/code&gt;, которое может задать дополнительное пространство внутри обрезаемой области (жаль, что не поддерживается в Safari)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 22.11.2024</title><link>https://juwain.github.io/web-platform/blog/2024-11-22/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-11-22/</guid><description>Новости веб-платформы</description><pubDate>Fri, 22 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышли &lt;a href=&quot;https://2024.stateofhtml.com/en-US&quot;&gt;результаты опроса State of HTML&lt;/a&gt;, в целом, мало нового:
&lt;ul&gt;
&lt;li&gt;новые API типа Popover и &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; появляются (это хорошо), но есть баги, например, на &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?id=267688&quot;&gt;iOS не работает сокрытие при клике на backdrop&lt;/a&gt; (это плохо)&lt;/li&gt;
&lt;li&gt;некоторые новые API типа Anchor positioning и View transitions API только начинают расползаться по платформе и ещё не везде поддерживаются, соответственно проще их не использовать, чем поддерживать две версии&lt;/li&gt;
&lt;li&gt;традиционная боль, которая мало утихает с годами, — стилизация и кастомизация элементов форм&lt;/li&gt;
&lt;li&gt;в топе нехватающих элементов — data table, tabs, switch/toggle, skeleton-ui, context-menu, carousel, inifinite scroll — топ фич, для реализации в либах веб-компонентов&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/new-in-chrome-131&quot;&gt;вышел Chrome 131&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;псевдоэлементы &lt;code&gt;::selection&lt;/code&gt; и &lt;code&gt;::highlight&lt;/code&gt; теперь более логично наследуют значения CSS-свойств родителей&lt;/li&gt;
&lt;li&gt;к &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;summary&amp;gt;&lt;/code&gt; теперь можно применять &lt;code&gt;display: flex&lt;/code&gt; и &lt;code&gt;grid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;починили &lt;code&gt;@property&lt;/code&gt; и теперь поддерживается тип &lt;code&gt;&amp;lt;string&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в элементе &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; теперь валидно включать другие теги помимо &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;optgroup&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currentcolor&lt;/code&gt; поддержан для relative color syntax&lt;/li&gt;
&lt;li&gt;Summarization и Translator API для суммаризации и перевода с помощью AI, встроенного в браузер&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://developer.chrome.com/blog/new-in-devtools-131&quot;&gt;дев-тулзы&lt;/a&gt; также завезли AI, появилась даж отдельная вкладка в настройках, теперь и браузер будет советовать, как писать код лучше&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;департамент юстиции США может &lt;a href=&quot;https://www.forbes.com/sites/antoniopequenoiv/2024/11/18/justice-department-will-request-judge-order-google-to-sell-chrome-in-antitrust-case-report-says/&quot;&gt;надавить на Google и заставить продать Chrome&lt;/a&gt; предположительно родительской компании Alphabet, чтобы более явно отслеживать по взаимодействию двух компаний, как через Chrome Google манипулирует рекламным рынком, и уменьшить возможности собора данных для AI через Chrome&lt;/li&gt;
&lt;li&gt;есть в языке и стандартной платформе такие узкоспециализированные фичи, которые нужны достаточно редко, поэтому забываются и вовремя не вспоминаются, когда бы пригодились; например, &lt;a href=&quot;https://www.stefanjudis.com/today-i-learned/hide-object-properties-with-javascript-symbols/&quot;&gt;&lt;code&gt;Symbol&lt;/code&gt; может пригодиться&lt;/a&gt;, чтобы спрятать поле или метку в объекте без боязни, что оно где-то вылезет, так символьные поля объекта недоступны в &lt;code&gt;Object.keys()&lt;/code&gt; и &lt;code&gt;JSON.stringify()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aidenybai/react-scan&quot;&gt;react-scan&lt;/a&gt; — либа для проверки перфоманса в React-приложениях, подключается с помощью одного скрипта (наконец-то достаточно просто, чтобы (любопытство пересилило лень) попробовать на вашей приложухе) и показывает ререндеры: хороший способ отследить наличие ненужных рендеров, а также обнаружить зависимость между несвязанными друг с другом компонентов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/jscodeshift&quot;&gt;jscodeshift&lt;/a&gt; — если вам нужно зараз изменить много JS/TS-файлов, то не обязательно это делать руками и писать велосипед: есть придуманный тулкит для запуска codemod-ов (программ, которые сделают нужные изменения в файлах) и получения отчёта о выполненной работе&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;раньше уже писал про команду &lt;code&gt;deno complile&lt;/code&gt;, а тут как раз вышел &lt;a href=&quot;https://deno.com/blog/deno-compile-executable-programs&quot;&gt;обзор с интересной мыслью&lt;/a&gt;: помимо очевидного юзкейса собрать в бинарник свою JS/TS-программу и запускать её на десктопе (как будто бы дело не первой необходимости), ещё можно собирать ваше приложение с вереницей npm-пакетов в зависимостях в один файл и уже его транспортировать на CI вместо того, чтобы на самом CI разворачивать приложение и там скачивать и устанавливать все зависимости — как минимум это сэкономит время работы и мощности CI&lt;/li&gt;
&lt;li&gt;в догонку к вопросу экономии ресурсов CI: в вашем &lt;code&gt;package.json&lt;/code&gt; файле &lt;code&gt;devDependencies&lt;/code&gt; отличаются от &lt;code&gt;dependencies&lt;/code&gt; тем, что &lt;a href=&quot;https://angelika.me/2024/11/11/dependencies-vs-dev-dependencies-javascript-apps/&quot;&gt;не будут установлены на CI&lt;/a&gt;, ведь они нужны только локально при разработке; запускать production-вариант сборки можно ключом &lt;code&gt;npm install --production&lt;/code&gt;, переменной &lt;code&gt;NODE_ENV=production&lt;/code&gt;, а также ключом &lt;code&gt;--omit=dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если вы когда-нибудь &lt;a href=&quot;https://abdisalan.com/posts/tragedy-running-old-node-project&quot;&gt;пытались завести проект&lt;/a&gt; &lt;em&gt;несколько&lt;/em&gt;летней давности, то наверняка испытывали фрустрацию, когда что-то почему-то не работает и нужно методом тыка и гуглежа и выяснять, что именно, и потому знаете, что самое верное средство — попереключать версии node и python, чтобы найти заветную рабочую комбинацию!&lt;/li&gt;
&lt;li&gt;один из методов защиты от таких фрустраций и потерянного времени — &lt;a href=&quot;https://jvns.ca/blog/2024/11/18/how-to-import-a-javascript-library/&quot;&gt;не использовать билд-систему совсем&lt;/a&gt;: то есть можно установить либу из npm во временную папку, руками оттуда скопировать сбилженные JS-файлы и подключить их руками на сайте: с обычным js-файлом проблем нет совсем, с ESM-файлом нужно озаботиться import map-ами, если внутри модуль включает зависимости, а вот с CJS-файлами придётся использовать &lt;a href=&quot;https://esm.sh/#docs&quot;&gt;esm.sh&lt;/a&gt; для преобразования их в в ESM&lt;/li&gt;
&lt;li&gt;если вы паблишили npm-пакеты, то наверняка знаете про команды &lt;code&gt;npm version major/minor/patch&lt;/code&gt;, и для пререлизов (альфа/бета ) &lt;a href=&quot;https://cloudfour.com/thinks/how-to-prerelease-an-npm-package/&quot;&gt;тоже есть подобные команды&lt;/a&gt;: &lt;code&gt;npm version premajor --preid=alpha&lt;/code&gt; сменит &lt;code&gt;23.1.6&lt;/code&gt; на &lt;code&gt;24.0.0-alpha.0&lt;/code&gt;, а &lt;code&gt;npm version prerelease&lt;/code&gt; бампнет версию с &lt;code&gt;24.0.0-alpha.0&lt;/code&gt; до &lt;code&gt;24.0.0-alpha.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;мы используем те или иные инструменты, потому что они делают свою работу, и привыкаем терпеть их несовершенство, так как или им нет альтернатив, или альтернативы чересчур нишевые и маргинальные; но если &lt;a href=&quot;https://korban.net/posts/elm/2024-11-16-typescript-react-impressions/&quot;&gt;посмотреть со стороны&lt;/a&gt;, то картина сразу становится очевидной — React и TS достаточно вербозны и не лишены недостатков&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;в пошаговой анимации &lt;code&gt;steps(5)&lt;/code&gt; указывается количество шагов, на сколько разделить анимацию, но &lt;a href=&quot;https://css-tip.com/steps/&quot;&gt;также есть дополнительная настройка&lt;/a&gt;, указывающая как именно выставляются эти шаги:  0%, 20%, 40%, 60% и 80%, или же 20%, 40%, 60%, 80% и 100%, или же 0%, 25%, 50%, 75% и 100%; настройка &lt;code&gt;steps(3, jump-none)&lt;/code&gt; разделит шаги на равные интервалы, что более логичное, но не дефолтное значение&lt;/li&gt;
&lt;li&gt;если есть задача выполнять повторяющуюся анимацию с задержкой до начала и после окончания, то можно обойтись без «фейковых пустот» в кейфреймах, а использовать функцию &lt;code&gt;linear()&lt;/code&gt; &lt;a href=&quot;https://codepen.io/nocksock/pen/rNEPMjJ?editors=1100&quot;&gt;для динамического расчёта задержки&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>day 0</title><link>https://juwain.github.io/web-platform/blog/2024-11-26/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-11-26/</guid><description>История из серии</description><pubDate>Tue, 26 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Фил устало открыл крышку своего ноутбука. Рабочий день только начинался, но на часах уже был полдень. Может быть сказывалась глубокая осень, или же давно не случавшийся с ним отпуск, но Фил чувствовал себя выжатым досуха. Он работал разработчиком в большой, поросшей бюрократическими мхами компании. Проект, над которым сейчас велась работа, шёл сложно. Вроде и хорошо, что наконец взялись за переписывание фронтенда большого легаси-проекта, но от него было ощущение засасывающего ненасытного болота, которое пока что не удавалось даже целиком охватить умом, зато ум болото осваивало успешно.&lt;/p&gt;
&lt;p&gt;Чтобы как-то взбодриться, Фил принёс с кухни за рабочий стол в комнату полулитровый стакан кофе, недавно принесённый курьером вместе с бургером, который Фил заточил на завтрак. Потягивая кофе, он надел наушники и врубил музыку со стриминга. Какой-то незнакомый рок-н-рольный голос бодро пел под акустику: «Может быть это алкоголизм? Может быть недостаток любви и добра? В этом мире так мало тепла…»&lt;/p&gt;
&lt;p&gt;Фил зачекинился в командном мессенджере и погрузился в дебри зависимостей старого проекта. Пока что попытки разобрать гигантский монолитный модуль не приводили к успеху. Изменение какой-нибудь штуки в одном месте вызывало ошибки в других несвязанных местах. Сложности также добавляло то, что в последнее время участились взломы пакетов в экосистеме npm, пребывающей в упадке. Многие некогда крупные и успешные пакеты, сейчас в 2030 году, были в лучшем случае заброшены мейнтенерами, а в худшем — распространяли рекламу или скам. С тех пор, как широко распространились AI-модели, генерирующие код, в реестр npm хлынули пакеты сомнительного качества. Поэтому ставить что-то из реестра можно было только на свой страх и риск, сканируя бандл AI-ботом-аудитором. Фил как раз недавно поставил себе такой — новый быстрый бот Phosphor. В большинстве случаев откровенное вредоносное ПО бот отлавливал, но мелочи часто приходилось править и дорабатывать самому, форкая проект.&lt;/p&gt;
&lt;p&gt;Фила бесило, что часть незаменимых пакетов собиралась только под какой-то древней версией Node.js, и ещё они при этом не дружили друг с другом. Тут ещё как назло две домашние кошки Фила устроили между собой разборки и опрокинули стакан с недопитым кофе на стол, едва не залив на ноут.&lt;/p&gt;
&lt;p&gt;Фил выругался и пошёл на кухню за салфетками, чтобы устранить последствия потопа. Вернувшись и вытерев лужи со стола, Фил глянул на экран в открытую консоль браузера и заметил, что там по одной выплёвываются рандомные английские буквы раз в какой-то интервал. «Это что ещё за хрень», — проворчал Фил. «Странно, ведь в новых пакетах бот не нашёл ничего криминального», — подумал он и начал искать в исходниках, что могло выкидывать странные логи в консоль. Как будто отдельные буквы выводились в консоль из разных мест по независимым друг от друга таймерам, потому что какого-то единого лога Фил найти не смог.&lt;/p&gt;
&lt;p&gt;Промучившись с поиском источника странных логов и ничего не найдя, Фил в раздражении плюнул и решил проветриться. Уже стемнело, он брёл вдоль дороги в холодном свете светодиодных фонарей и думал. Всё это нашествие AI-кодописателей, кодоревьюеров и кодотестировщиков вгоняло в уныние. Программы и тулинг вокруг них стали более непредсказуемыми и ненадёжными, ведь в случае большинства AI-продуктов даже их создатели толком не знали, от чего и как именно AI выдаёт тот или иной результат.&lt;/p&gt;
&lt;p&gt;И тут в голове у Фила щёлкнуло: «А что если эти странные логи в проекте появились не от новых пакетов, которые он установил, а от нового бота-аудитора, который эти пакеты проверял? Что если бот заинжектил что-то в код пакетов? Эта блестящая чёрная коробка вполне могла, чёрт знает что внутри неё творится!»&lt;/p&gt;
&lt;p&gt;Фил поспешил вернуться домой. Включив ноут и открыв браузерную консоль он с удивлением понял, что рандомные буквы сложились в понятную последовательность:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;d e s i n e s p e r a r e q u i h i c i n t r a s n e t l i f y a p p&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/blog/2024-12-30&quot;&gt;Следующая часть&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 29.11.2024</title><link>https://juwain.github.io/web-platform/blog/2024-11-29/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-11-29/</guid><description>Новости веб-платформы</description><pubDate>Fri, 29 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://blog.angular.dev/meet-angular-v19-7b29dfd05b84&quot;&gt;Angular 19&lt;/a&gt;: в современном фронтенде, если фреймворк не поддерживает SSR и гидрацию, а также сигналы, конкуренцию среди модной-молодёжной аудитории уже не выдержать; и Angular в этом плане снова с строю:
&lt;ul&gt;
&lt;li&gt;для каждого роута можно задать отдельно режим рендера Server/Client|Prepender&lt;/li&gt;
&lt;li&gt;для отрендеренного, но незагидрированного HTML будет записываться события пользователя (клики), чтобы когда доедут скрипты, «проиграть» их заново и запустить&lt;/li&gt;
&lt;li&gt;с помощью signal и нового примитива linkedSignal можно сделать что-то типа «связанного сигнала» для реализации реактивной связи между несколькими сигналами напрямую, без использования отдельного «эффекта»&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://www.mozilla.org/en-US/firefox/133.0/releasenotes/&quot;&gt;Firefox 133&lt;/a&gt;: поддержана опция &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#keepalive&quot;&gt;&lt;code&gt;keepalive&lt;/code&gt;&lt;/a&gt; у fetch, так что теперь во всех браузерах можно пользоваться fetch c keepalive вместо &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon&quot;&gt;&lt;code&gt;Navigator.sendBeacon()&lt;/code&gt;&lt;/a&gt;, если важно, чтобы определённый запрос завершился, а не прерывался, в случае unload-а страницы; Canvas2D с GPU-ускорением теперь включен по умолчанию в Windows&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/&quot;&gt;TypeScript 5.7&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;улучшена проверка для никогда не инициализируемых переменных&lt;/li&gt;
&lt;li&gt;поддержан таргет до &lt;code&gt;es2024&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поиск tsconfig.json по родителям теперь не будет останавливаться на первом найденном&lt;/li&gt;
&lt;li&gt;поддержано API Node.js 22 &lt;a href=&quot;https://github.com/nodejs/node/pull/54501&quot;&gt;module.enableCompileCache()&lt;/a&gt; для более быстрого выполнения повторных операций&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://tailwindcss.com/blog/tailwindcss-v4-beta&quot;&gt;Tailwind CSS v4.0 Beta&lt;/a&gt;: интересна траектория развития в сторону CSS-first конфигурации (т.е. использование кастомных переменных, слоёв и директив) вместо конфигурации в JS; изначальный спорный подход с вынесением всего в classname уже стреляет по ногам, требуя от разработчиков soul-crushing backward compatibility work — это рано или поздно или приведёт TW в тупик, или заставит переродиться в тулкит с «естественным» набор миксинов, пресетов и ручек для управлениях внутрянкой&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/v2.1&quot;&gt;вышедший Deno 2.1&lt;/a&gt; стал первым LTS-релизом и среди прочего включает новую команду &lt;code&gt;deno outdated&lt;/code&gt; для проверки устаревших версий пакетов, эмбеддинг «статических» файлов в бинарник при запуске &lt;code&gt;deno compile&lt;/code&gt;, а также возможность указать зависимые команды при запуске других команд&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/deno-v-oracle&quot;&gt;на что только не пойдут&lt;/a&gt; в Deno для популяризации своего продукта: вот, например, создали петицию к Oracle, чтоб уже освободили, наконец, JavaScript от торговой марки — норм «судебный» маркетинг&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://vite.dev/blog/announcing-vite6.html&quot;&gt;мажор Vite 6.0&lt;/a&gt;: для небольших проектов ломающие изменения не выглядят болезненными, скорее добавились новые фичи и апдейтнуты зависимости&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/node/pull/55217&quot;&gt;в Node 22 завезли&lt;/a&gt; поведение &lt;code&gt;--experimental-require-module&lt;/code&gt; без флага&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pkg-graph.info&quot;&gt;pkg-graph&lt;/a&gt; — ещё один проект для визуального исследования зависимостей npm-пакета, строит граф на лету в браузере&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spoiled.vercel.app&quot;&gt;spoiled&lt;/a&gt; — компонент спойлера для React, под капотом Paint API (для Safari предусмотрен фолбек)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/stanko/dual-range-input&quot;&gt;dual-range-input&lt;/a&gt; — двойной range-инпут, собранный из двух обычных range-инпутов&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;базовые типы TS для React в доках разбросаны повсюду, а тут &lt;a href=&quot;https://www.jacobparis.com/content/react-ts&quot;&gt;собраны в одно месте&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;чтобы выцепить тип возвращаемого значения функции — &lt;code&gt;&amp;lt;ReturnType&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;Awaited&amp;lt;ReturnType&amp;gt;&amp;gt;&lt;/code&gt; — для асинхронной функции&lt;/li&gt;
&lt;li&gt;тип ReactNode лучше ReactElement тем, что шире&lt;/li&gt;
&lt;li&gt;&lt;code&gt;props: React.ComponentProps&amp;lt;&quot;button&quot;&amp;gt;&lt;/code&gt; для типизации базовых пропсов HTML-элемента или компонента&lt;/li&gt;
&lt;li&gt;использование &lt;code&gt;as const&lt;/code&gt; для типизации tuples, чтобы TS не считал их массивами&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/RedditEng/comments/1dhztk8/building_reddits_frontend_with_vite/&quot;&gt;история, как в Reddit в разросшуюся монорепу внедряли Vite&lt;/a&gt;, пара интересных фактов: чтобы подружиться с Lit пришлось добавлять &lt;code&gt;?inline&lt;/code&gt; ко всем путям стилей, чтоб не вставлять их в страницу, а инлайнить строками в бандл; чтобы заюзать на полную ESM пришлось во всех модулях добавить &lt;code&gt;export maps&lt;/code&gt;, которыми раньше пренебрегали&lt;/li&gt;
&lt;li&gt;favicon — единственно гарантировано видная часть сайта во вкладке браузера, поэтому &lt;a href=&quot;https://www.raymondcamden.com/2024/11/25/using-your-favicon-for-monitoring-long-processes&quot;&gt;её можно использовать&lt;/a&gt; для индикации неактивности пользователя или нотификации о каком-то событии в свёрнутой вкладке&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;когда-то в Safari затащили эффектное свойство &lt;code&gt;background-clip: text&lt;/code&gt; для создания «текстурного» текста путём «вырезания» фона, и оно долго работало только с префиксом &lt;code&gt;-webkit&lt;/code&gt;, и вот &lt;a href=&quot;https://webkit.org/blog/16214/background-clip-border-area/&quot;&gt;теперь только в Safari появился ещё один вариант&lt;/a&gt; — &lt;code&gt;background-clip: border-area&lt;/code&gt; — только теперь, чтобы текстура фоновой картинки осталась на месте рамки, а не букв&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oklch&lt;/code&gt; удобен тем, что позволяет &lt;a href=&quot;https://frontendmasters.com/blog/tweaking-one-set-of-colors-for-light-dark-modes/&quot;&gt;легко подстроить один из параметров цвета&lt;/a&gt;, например, &lt;code&gt;lightness&lt;/code&gt;, чтобы сделать один и тот же цвет на тёмном фоне более ярким, а на светлом — более тусклым &lt;code&gt;oklch(calc(0.75 - var(--colorAdjuster)) 0.2 328)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tabindex&lt;/code&gt; с отрицательным значением сделает элемент &lt;a href=&quot;https://yatil.net/blog/focusable-ui-elements&quot;&gt;программно фокусируемым&lt;/a&gt; по &lt;code&gt;.focus()&lt;/code&gt;, но при этом он не будет включён в очередь фокусов по интерактивным элементам: ссылкам с &lt;code&gt;href&lt;/code&gt;, &lt;code&gt;button&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;textarea&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;с помощью &lt;code&gt;&amp;lt;link rel=&quot;preload&quot; as=&quot;image&quot;&amp;gt;&lt;/code&gt; с атрибутами &lt;code&gt;imagesrcset&lt;/code&gt;, &lt;code&gt;imagesizes&lt;/code&gt; и &lt;code&gt;type&lt;/code&gt; можно &lt;a href=&quot;https://www.trevorlasn.com/blog/preloading-responsive-images&quot;&gt;прелоадить картинки только в браузере&lt;/a&gt;, поддерживающий формат, заданный в type, например, &lt;code&gt;type=&quot;image/avif&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 06.12.2024</title><link>https://juwain.github.io/web-platform/blog/2024-12-06/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-12-06/</guid><description>Новости веб-платформы</description><pubDate>Fri, 06 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вышел релиз библиотеки компонентов React Aria/Spectrum:
&lt;ul&gt;
&lt;li&gt;добавлены компоненты &lt;a href=&quot;https://react-spectrum.adobe.com/react-spectrum/Disclosure.html&quot;&gt;Disclosure&lt;/a&gt; and &lt;a href=&quot;https://react-spectrum.adobe.com/react-spectrum/Accordion.html&quot;&gt;Accordion&lt;/a&gt;; что примечательно, под капотом не используется summary/details, видимо ещё не до конца распространилось стабилизировавшееся API&lt;/li&gt;
&lt;li&gt;также в React Aria появился компонент &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/ToggleButtonGroup.html&quot;&gt;ToggleButtonGroup&lt;/a&gt;, управляемый с клавиатуры&lt;/li&gt;
&lt;li&gt;также либа теперь полностью &lt;a href=&quot;https://www.typescriptlang.org/tsconfig/#strict&quot;&gt;Typescript Strict&lt;/a&gt;-совместима&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-5/&quot;&gt;выпущен Astro 5.0&lt;/a&gt;: всё то же, что было в бете (Content Layer — запрос контента из внешнего ресурса, Server Islands — отложенный рендеринг с сервера, &lt;code&gt;astro:env&lt;/code&gt; — типобезопасный env-ы) + экспериментальные фичи для отображения респонсив-картинок, кропа, а также импорта SVG-компонентов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/blog/2024/12/05/react-19&quot;&gt;вышла стабильная версия React 19&lt;/a&gt;: помимо новых API теперь одинаковые подключенные стили не будут дублироваться и будут подключаться в указанном порядке, также можно указывать &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; без дополнительных либ и ещё полностью поддерживаются кастомные элементы (веб-компоненты)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/blog/2024/11/26/3.4.0.html&quot;&gt;вышла версия Prettier 3.4&lt;/a&gt;: просто напоминание обновить в вашем проекте, так как было пофикшено много багов (кажется в таком проекте их невозможно пофиксить все)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;представьте, что вы разработчик нового React-фреймворка и хотите, чтобы приложение, написанное на вашем фреймворке, могло одной кнопкой деплоиться на Vercel, Netlify и ещё многие другие хостинги… Создание адаптеров ко всем сервисам и поддержка этого добра сразу начинает навевать тоску. Но выход есть! Можно использовать oss-наработку &lt;a href=&quot;https://github.com/nksaraf/vinxi&quot;&gt;vinxi&lt;/a&gt;, чтобы одной строчкой в Vite-конфиге подключить поддержку определённого провайдера, как и сделал &lt;a href=&quot;https://tanstack.com/blog/why-tanstack-start-is-ditching-adapters&quot;&gt;Tanner Linsley в своём фреймворке TanStack Start&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/onlook-dev/onlook&quot;&gt;onlook&lt;/a&gt; — oss визуальный редактор React-приложения: люди всё не оставляют попыток избавиться от разделения макет/код, собственно, чтобы был только код и «макет» накидывался сразу в коде&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/andreaswilli/react-verification-input&quot;&gt;react-verification-input&lt;/a&gt; — маск-инпут для ввода пин-кодов, React&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dontfuckwithscroll.com&quot;&gt;dontfuckwithscroll&lt;/a&gt; — не воруйте скролл, наглядное пособие&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если вы знаете куда с одной страницы пользователь пойдёт дальше, можно &lt;a href=&quot;https://csswizardry.com/2024/12/a-layered-approach-to-speculation-rules/&quot;&gt;предзагрузить или даже пререндерить этот урл&lt;/a&gt;; для этого с помощью Speculation Rules API в скрипте &lt;code&gt;&amp;lt;script type=&quot;speculationrules&quot;&amp;gt;&lt;/code&gt; нужно указать секцию &lt;code&gt;prerender&lt;/code&gt; и &lt;code&gt;prefetch&lt;/code&gt; с возможной настройкой условий запуска (если адрес включает строку, селектор соответствует выражению и тп); пока работает только в Chromium&lt;/li&gt;
&lt;li&gt;при создании модалки нужно по-хорошему &lt;a href=&quot;https://www.developerway.com/posts/hard-react-questions-and-modal-dialog&quot;&gt;предусмотреть много вещей&lt;/a&gt;: интерфейс, триггерный элемент для показа модалки, передачу кастомного контента и класснеймов, обработчики событий, рендер в Portal-е, управление фокусом внутри модалки; в общем, проще всего взять готовую безголовую либу, например,  &lt;a href=&quot;https://www.radix-ui.com/themes/docs/components/dialog&quot;&gt;Radix&lt;/a&gt; или &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/&quot;&gt;React Aria&lt;/a&gt; и прикрутить свою логику и стили&lt;/li&gt;
&lt;li&gt;если стоит задача заняться перфомансом, то можно начать с &lt;code&gt;PerformanceObserver&lt;/code&gt;, с помощью которого можно программно получить не только разовое значение метрик (FID, CLS, LCP), но и &lt;a href=&quot;https://www.trevorlasn.com/blog/performance-web-api-in-javascript&quot;&gt;обсёрвить&lt;/a&gt;, то есть повторно снимать метрики во время пользования приложением&lt;/li&gt;
&lt;li&gt;а что если не рендерить SPA-целиком в &lt;code&gt;&amp;lt;div id=&quot;root&quot;&amp;gt;&lt;/code&gt;, а подгружать React только &lt;a href=&quot;https://swizec.com/blog/the-anatomy-of-a-react-island/&quot;&gt;в определённый интерактивный островок&lt;/a&gt; вашего сайта? да не, бред какой-то… или нет?&lt;/li&gt;
&lt;li&gt;с View Transitions API можно методом &lt;code&gt;startViewTransition&lt;/code&gt; запустить нативную плавную смену двух DOM-нод; но что если как раз императивно запускать не хочется, а хочется, чтобы DOM-нода добавилась и &lt;a href=&quot;https://www.bram.us/2024/11/25/experiment-automatically-triggered-view-transitions-with-mutationobserver/&quot;&gt;транзишн автоматом выполнился&lt;/a&gt;? Берём &lt;code&gt;MutationObserver&lt;/code&gt; и вуаля: нода появилась, обсёрвер триггернулся, колбек запустился, а в нём уже и &lt;code&gt;startViewTransition&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если нужно создать у элемента &lt;a href=&quot;https://www.tyleo.com/html-glass.html&quot;&gt;эффект замёрзшего стекла&lt;/a&gt;, рецепт: взять &lt;code&gt;backdrop-filter: blur(10px)&lt;/code&gt; и насыпать кучу теней для создания глубины; для создания &lt;a href=&quot;https://www.joshwcomeau.com/css/backdrop-filter/&quot;&gt;«стеклянной прозрачности» у блока определённой формы&lt;/a&gt; можно добавить ещё и &lt;code&gt;mask-image&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.trevorlasn.com/blog/css-lh-and-rlh-units&quot;&gt;единицы измерения &lt;code&gt;lh&lt;/code&gt;&lt;/a&gt; — величина вычисленного значения &lt;code&gt;line-height&lt;/code&gt;, её удобно использовать для задания динамических отступов между тестовыми блоками (&lt;code&gt;rlh&lt;/code&gt; — аналог для рутового элемента)&lt;/li&gt;
&lt;li&gt;впервые встретился такой UI-элемент, &lt;a href=&quot;https://frontendmasters.com/blog/multi-state-buttons/&quot;&gt;кнопка в трёх состояниях&lt;/a&gt; (да, нет, не знаю): её можно реализовать на чекбоксах, &lt;code&gt;:has(:checked)&lt;/code&gt; и &lt;code&gt;pointer-events&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;в HTML у ссылок &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; есть атрибут &lt;code&gt;ping&lt;/code&gt; — &lt;a href=&quot;https://jsdev.space/html-ping-attribute/&quot;&gt;легальный способ отслеживать нажатие по ссылке&lt;/a&gt;, отсылая запрос по указанному в значении адресу, которое к тому же сложнее заблочить&lt;/li&gt;
&lt;li&gt;напоминание в следующий раз, когда будете &lt;a href=&quot;https://www.smashingmagazine.com/2024/12/creating-effective-multistep-form-better-user-experience/&quot;&gt;собирать форм-визард&lt;/a&gt;, использовать &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt; для каждого «шага» с набором полей (правда, если не столкнётесь с проблемой стилизации, хехе)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshwcomeau.com/css/browser-support/&quot;&gt;при принятии решения&lt;/a&gt; использовать ли платформенную фичу или нет, обычно руководствуются браузерной поддержкой глобальной CanIUse, но суть в том, что аудитория именно вашего сервиса может существенно от глобальной; в таком случае логично использовать аналитику своей аудитории, и данные, например, Google Analytics или Simple Analytics &lt;a href=&quot;https://caniuse.com/ciu/import&quot;&gt;можно скормить самому CanIUse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 13.12.2024</title><link>https://juwain.github.io/web-platform/blog/2024-12-13/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-12-13/</guid><description>Новости веб-платформы</description><pubDate>Fri, 13 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/16301/webkit-features-in-safari-18-2/&quot;&gt;вышла новая версия Safari 18.2&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддержано свойство &lt;code&gt;text-box&lt;/code&gt; (&lt;code&gt;text-box-trim&lt;/code&gt; + &lt;code&gt;text-box-edge&lt;/code&gt;) для «подрезки» вертикальных отступов у тестовых строк&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@view-transition&lt;/code&gt; заработал не только в пределах одного документа, но и между разных страниц&lt;/li&gt;
&lt;li&gt;из беты вышел &lt;code&gt;background-clip: border-area&lt;/code&gt; для маскирования рамки низлежащим слоем; в &lt;code&gt;calc&lt;/code&gt; теперь работает деление на единицы измерения &lt;code&gt;calc(100vw / 1px)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержаны &lt;code&gt;scrollbar-width&lt;/code&gt; и &lt;code&gt;scrollbar-gutter&lt;/code&gt; для стилизации скроллбаров&lt;/li&gt;
&lt;li&gt;добавлена функция Scroll to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/URI/Fragment/Text_fragments&quot;&gt;Text Fragments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;поддержан &lt;code&gt;&amp;lt;input type=week&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;у &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent&quot;&gt;&lt;code&gt;PointerEvent&lt;/code&gt;&lt;/a&gt; появились методы &lt;code&gt;getPredictedEvents()&lt;/code&gt; и &lt;code&gt;getCoalescedEvents()&lt;/code&gt; для предсказания будущих позиций курсора и получения нескольких сгруппированных &lt;code&gt;PointerEvent&lt;/code&gt; в &lt;code&gt;pointermove&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержан &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try&quot;&gt;&lt;code&gt;Promise.try&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.mozilla.org/en/mozilla/mozilla-brand-next-era-of-tech/&quot;&gt;в Mozilla представили новый брендинг&lt;/a&gt; с консольным динозавром-флажком, а также &lt;a href=&quot;https://blog.mozilla.org/en/mozilla/new-executives/&quot;&gt;наняли три новых топа&lt;/a&gt;: в Firefox выходят вице-президент FF и вице-президент по продукту FF, а также в компании появился вице-президент по инфраструктуре; в общем, кажется готовятся, что у Google (с возможной продажей Chrome) дела могут пойти плохо и тогда лишатся финансирования, придётся поднимать флаг и самостоятельно расправлять паруса&lt;/li&gt;
&lt;li&gt;CSSWG подытоживают год и выкатывают 4 новых FPWD: &lt;a href=&quot;https://drafts.csswg.org/css-display-4/&quot;&gt;Display 4&lt;/a&gt;, &lt;a href=&quot;https://drafts.csswg.org/css-overflow-5/&quot;&gt;Overflow 5&lt;/a&gt;, &lt;a href=&quot;https://drafts.csswg.org/css-multicol-2/&quot;&gt;Multicol 2&lt;/a&gt; и &lt;a href=&quot;https://drafts.csswg.org/css-color-hdr/&quot;&gt;Color HDR 1&lt;/a&gt;, из интересных нововведений:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://drafts.csswg.org/css-display-4/#propdef-reading-flow&quot;&gt;reading-flow&lt;/a&gt; для управления порядком чтения контента скринридером в flex- и grid-контейнере&lt;/li&gt;
&lt;li&gt;интерполяция и анимация свойства &lt;code&gt;display&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;псевдоэлемент &lt;code&gt;::column&lt;/code&gt; в многоколоночном контейнере&lt;/li&gt;
&lt;li&gt;свойство &lt;code&gt;scroll-marker-group&lt;/code&gt; и группа псевдоэлементов &lt;a href=&quot;https://drafts.csswg.org/css-overflow-5/#scroll-navigation&quot;&gt;&lt;code&gt;::scroll-marker-*&lt;/code&gt;&lt;/a&gt; для стилизации скролл-контейнера&lt;/li&gt;
&lt;li&gt;управление яркостью HDR-контента&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://radar.cloudflare.com/year-in-review/2024&quot;&gt;вышел отчёт Cloudflare Radar 2024&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;HTTP/2 вдвое опережает HTTP/3&lt;/li&gt;
&lt;li&gt;React, Next.js — самые популярные фреймворки&lt;/li&gt;
&lt;li&gt;PHP вдвое популярнее Node.js&lt;/li&gt;
&lt;li&gt;для создания API Go используется чаще Node.js&lt;/li&gt;
&lt;li&gt;Yandex — второй по популярности поисковик — подсдал к концу года&lt;/li&gt;
&lt;li&gt;сради браузеров Chrome держится на 65%, потом идёт Safari, Edge, а у Forefox 4% пользователей&lt;/li&gt;
&lt;li&gt;IPv4 всё ещё доминирует над IPv6&lt;/li&gt;
&lt;li&gt;в развитых странах преобладает десктопный трафик, в Африке, Индии, Южной Америке — мобильный&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://skia-canvas.org/&quot;&gt;skia-canvas&lt;/a&gt; — «безбраузерная» реализация API canvas для node или десктопа на GPU&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/remarkablemark/html-react-parser&quot;&gt;html-react-parser&lt;/a&gt; — парсер HTML в React-компонент&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;общение компонентов посредством создания и запуска событий помогает избежать проп-дриллинга или связывает (не увеличивая coupling) совсем разнесённые части одной системы; есть &lt;a href=&quot;https://dev.to/nicolalc/event-driven-architecture-for-clean-react-component-communication-fph&quot;&gt;простой вариант хука useEvent&lt;/a&gt;, который создаёт эвент и отдаёт диспатчер или &lt;a href=&quot;https://gist.github.com/denisputnov/8e53d557a513ffb0ecb45e6713a18e5e&quot;&gt;более сложный в виде шины событий&lt;/a&gt;, о котором писал ранее&lt;/li&gt;
&lt;li&gt;порой бывает нужно сделать небольшой проект, куда тянуть React не обязательно, и в таком случае не обязательно тянуть и &lt;a href=&quot;https://playfulprogramming.com/posts/modern-js-bundleless&quot;&gt;бандлер вместе с процессом билда&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;для локального сервера и HMR сгодится &lt;code&gt;browser-sync&lt;/code&gt;, сторонние пакеты можно загрузить с  &lt;a href=&quot;https://unpkg.com/&quot;&gt;unpkg.com&lt;/a&gt; или из npm и прописать алиасы в &lt;code&gt;&amp;lt;script type=&quot;importmap&quot;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;правда не все пакеты, к сожалению, можно просто брать и использовать в сбилженном виде, некоторые, например, &lt;code&gt;lodash-es&lt;/code&gt;, придётся сбилдить самостоятельно с помощью &lt;code&gt;esbuild&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;TS заменяется на JS с JSDoc, а с помощью &lt;code&gt;tsc&lt;/code&gt; код проверяется на соответствие типов&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;в &lt;code&gt;ref&lt;/code&gt; элемента &lt;a href=&quot;https://tkdodo.eu/blog/ref-callbacks-react-19-and-the-compiler&quot;&gt;в React можно передать функцию&lt;/a&gt;, в параметре которой будет DOM-нода и в React 19 &lt;code&gt;ref&lt;/code&gt;-функция теперь может возвращать cleanup-функцию, как в &lt;code&gt;useEffect&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;вслед за React 19 &lt;a href=&quot;https://nextjs.org/blog/next-15-1&quot;&gt;вышел Next 15.1&lt;/a&gt; со свежим React на борту (для Pages Router по-прежнему доступен React 18), улучшен дебаг ошибок, обещают, что найти место ошибки теперь стало проще&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;в бете Tailwind 4 был представлен &lt;a href=&quot;https://nmn.sh/blog/2024-11-30-thoughts-on-tailwind-4#descendant-variants&quot;&gt;механизм стилизации дочерних элементов из заданного варианта родителю&lt;/a&gt; &lt;code&gt;&amp;lt;div class=&quot;**:data-avatar:rounded-full&quot;&amp;gt;&lt;/code&gt; (все дочерние элементы с атрибутом &lt;code&gt;data-avatar&lt;/code&gt; будут скруглёнными), что дизраптит саму идею атомарных классов, помещая в classname «мета-CSS» и открывая возможность использовать фреймворк ещё более противоестественно, приближая его конец&lt;/li&gt;
&lt;li&gt;с тех пор, как иконочные шрифты стали считаться анти-паттерном, &lt;a href=&quot;https://fullystacked.net/icon-fonts/&quot;&gt;технологии пошли вперёд&lt;/a&gt;: появились вариативные и цветные COLR шрифты, хорошо сжимающий формат &lt;code&gt;woff2&lt;/code&gt; и &lt;code&gt;font-display&lt;/code&gt; стали повсеместно поддерживаемыми, &lt;code&gt;content&lt;/code&gt; стал поддерживать alt-текст для скринридеров, да и проекты вроде Font Awesome по-прежнему популярны; но тем не менее шрифт может не загрузиться или может быть проигнорирован системными настройками браузера, поэтому SVG — всё ещё предпочтительный вариант для иконок в вебе&lt;/li&gt;
&lt;li&gt;&lt;code&gt;color: lch(from var(--bg) calc((49.44 - l) * infinity) 0 0)&lt;/code&gt; &lt;a href=&quot;https://til.jakelazaroff.com/css/swap-between-black-and-white-text-based-on-background-color/&quot;&gt;автоматически меняет цвет текста&lt;/a&gt; с чёрного на белый в зависимости от цвета фона&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2024/12/10/spot-non-composited-animations-in-chrome-devtools/&quot;&gt;в девтулзах Chrome 131&lt;/a&gt; теперь помечаются те анимации, для которых не задействовался процесс «композиции», например, в случае анимации свойства &lt;code&gt;height&lt;/code&gt; или кастомного свойства&lt;/li&gt;
&lt;li&gt;база, которая мне близка: если знаешь особенности платформы, базового языка (JS, CSS, HTML) и браузеров, то тогда становится легче кастомизировать вещи в рамках фреймворков, находить баги и фиксить их, решать проблемы и задачи легче и элегантнее, &lt;a href=&quot;https://helloanselm.com/writings/knowing-css-is-mastery-to-frontend-development&quot;&gt;всем платформенным респект&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 20.12.2024</title><link>https://juwain.github.io/web-platform/blog/2024-12-20/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-12-20/</guid><description>Новости веб-платформы</description><pubDate>Fri, 20 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v23.4.0&quot;&gt;вышла Node.js v23.4.0&lt;/a&gt;: из-под флага вынесен модуль &lt;code&gt;node:sqlite&lt;/code&gt;, то есть теперь по дефолту доступно создание SQLite-бд, &lt;a href=&quot;https://nodejs.org/api/sqlite.html&quot;&gt;выполнение SQL-запросов&lt;/a&gt; напрямую в Node&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/hemanth/updates-from-the-105th-tc39-meeting-3gkh&quot;&gt;прошёл 105-й митинг TC39&lt;/a&gt;: &lt;a href=&quot;https://github.com/tc39/proposal-intl-duration-format&quot;&gt;Intl.DurationFormat&lt;/a&gt; продвинулся на Stage 4, &lt;a href=&quot;https://github.com/es-shims/Error.isError&quot;&gt;Error.isError&lt;/a&gt; на Stage 3, а также на Stage 1 появился &lt;a href=&quot;https://github.com/tc39/proposal-import-sync&quot;&gt;Import Sync&lt;/a&gt; — нативный способ синхронных импортов в JS &lt;code&gt;import.sync(&apos;react&apos;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://2024.stateofjs.com/&quot;&gt;появились результаты опроса State of JS 2024&lt;/a&gt;, 14к разработчиков преимущественно мужчины из США и EC среднего возраста и 5-10 лет работы в индустрии поделились статой:
&lt;ul&gt;
&lt;li&gt;уже довольно популярны &lt;code&gt;Object.groupBy()&lt;/code&gt;, &lt;code&gt;Promise.allSettled()&lt;/code&gt;, &lt;code&gt;array.toSorted()&lt;/code&gt;, &lt;code&gt;string.replaceAll/matchAll()&lt;/code&gt;, но в мешает браузерная поддержка, а также болит отсутствие статической типизации из коробки&lt;/li&gt;
&lt;li&gt;webpack, Parcel, а также отдельно esbuild и Rollup продолжили уступать позиции Vite&lt;/li&gt;
&lt;li&gt;React/Next.js в целом в топе, но с годами популярность падает и люди страдают от их разнообразных проблем и сложности, Vue.js примерно на том же месте по популярности, что и в 2021&lt;/li&gt;
&lt;li&gt;pnpm заметно популярнее npm/yarn workspaces&lt;/li&gt;
&lt;li&gt;Astro многим нравится, популярность Lit чуть подросла&lt;/li&gt;
&lt;li&gt;Vitest стремительно набирает популярность, но Jest всё ещё также в топе, хоть и вызывает страдания (Deno и Node с их встроенными возможностями тестирования пока на дне)&lt;/li&gt;
&lt;li&gt;в топе используемых либ Lodash, date-fns, Zod, Moment, Day.js&lt;/li&gt;
&lt;li&gt;Express всё ещё намного популярнее Nest и Fastify&lt;/li&gt;
&lt;li&gt;большинство опрошенных используют TS на фронте, больше половины — на бэке&lt;/li&gt;
&lt;li&gt;больные точки: архитектура, стейт-менеджмент, управление состоянием, билд-тулы&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://426.ecma-international.org/1.0/index.html&quot;&gt;Ecma выпустили спецификацию Source map format&lt;/a&gt;: цели — поддержать двунаправленный маппинг сорсов и деобфускация стэк-трейсов на сервере&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/press-releases/1996/css1-rec/&quot;&gt;17 декабря исполнилось 28 лет CSS&lt;/a&gt;: забавно, что со временем всё больше людей начинают работать с технологиями, которые старше их самих, и от этого воспринимают их «древними»&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/simonw/prompts-js&quot;&gt;prompts-js&lt;/a&gt; — асинхронные версии вызова диалогов &lt;code&gt;alert&lt;/code&gt;, &lt;code&gt;confirm&lt;/code&gt; и &lt;code&gt;prompt&lt;/code&gt; на промисах и нативном элементе &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; (просто JS-файл, красота, если бы ещё добавить JSDoc с описанием типов, то вообще было бы идеально)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://turso.tech/blog/introducing-limbo-a-complete-rewrite-of-sqlite-in-rust&quot;&gt;некоторое время назад&lt;/a&gt; SQLite решили полностью переписать на Rust (оригинальный модуль &lt;a href=&quot;https://github.com/tursodatabase/libsql&quot;&gt;libsql&lt;/a&gt; написан на C, что делает его уязвимым со стороны памяти по своей природе) и так появился проект &lt;a href=&quot;https://github.com/tursodatabase/limbo&quot;&gt;limbo&lt;/a&gt;, который в случае успешного завершения заменит libsql; интересно, как будет выглядеть в этом случае поддержка со стороны Node&lt;/li&gt;
&lt;li&gt;забавное замечание: чтобы выполнить полный test suite Node.js может занять несколько дней, поэтому это делает не на каждый чих, и поэтому &lt;a href=&quot;https://nodesource.com/blog/State-of-Nodejs-Performance-2024&quot;&gt;сравнивая 20 и 22 версии ноды&lt;/a&gt;, некоторые API показали улучшение по перфомансу, а некоторые наоборот просадку&lt;/li&gt;
&lt;li&gt;общепринято, что в JSON нельзя добавлять комментарии, но это правило можно нарушить, если вы уверены, что JSON-парсер, который будет читать ваш файл, &lt;a href=&quot;https://douglascrockfordisnotyourdad.technomancy.us&quot;&gt;не сломается в процессе&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;если вы задались &lt;a href=&quot;https://jakelazaroff.com/words/isomorphic-web-components/&quot;&gt;задачей рендерить веб-компоненты на сервере&lt;/a&gt;, то нужно решить проблему отсутствия DOM-а и глобальных объектов (window, document…): для этого можно использовать фреймворк (&lt;a href=&quot;https://lit.dev/&quot;&gt;Lit&lt;/a&gt;, &lt;a href=&quot;https://www.11ty.dev/docs/languages/webc/&quot;&gt;WebC&lt;/a&gt;, &lt;a href=&quot;https://enhance.dev/&quot;&gt;Enhance&lt;/a&gt;) или же взять либу &lt;a href=&quot;https://www.npmjs.com/package/happy-dom&quot;&gt;Happy DOM&lt;/a&gt; — «безголовую» эмуляцию DOM, взять оттуда необходимые объекты и сгенерить HTML и JS&lt;/li&gt;
&lt;li&gt;в React 19 появилась &lt;a href=&quot;https://frontendmasters.com/blog/react-19-and-web-component-examples/&quot;&gt;более полная поддержка веб-компонентов&lt;/a&gt;: теперь можно в «пропах» веб-компонента прокидывать объекты или функцию-колбек (даже с кастомным событием)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.frontendundefined.com/posts/monthly/react-state-management-reflections/&quot;&gt;в управлении состоянием в React-приложениях&lt;/a&gt; стоит выносить работу с ним из рендер-функций, в идеале не используя &lt;code&gt;useState&lt;/code&gt;/&lt;code&gt;useEffect&lt;/code&gt; там, где можно их использовать (то есть почти везде)&lt;/li&gt;
&lt;li&gt;в случае прокидывания сеттера в дочерний компонент вместо использования «общей» функции-колбека начинает «течь» абстракция, &lt;a href=&quot;https://matanbobi.dev/posts/stop-passing-setter-functions-to-components&quot;&gt;этого лучше всего по умолчанию избегать&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/case-studies/netflix-cq&quot;&gt;ключевой момент из внедрения Container Queries в Netflix&lt;/a&gt; — меньше использования CSS- и JS-кода для управлением лейаутом → меньше багов, но при этом если использовать полифилл, то могут быть проблемы с перфом, надо проверять&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 27.12.2024</title><link>https://juwain.github.io/web-platform/blog/2024-12-27/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-12-27/</guid><description>Новости веб-платформы</description><pubDate>Fri, 27 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://base-ui.com/react/overview/quick-start&quot;&gt;у React Aria/Spectrum появился конкурент Base UI&lt;/a&gt; в виде движка, извлечённого из недр Material UI, без определённой системы стилей (движок предоставляет класснеймы и CSS-переменные), с поддержкой data- и aria-атрибутов: пока представлена альфа-версия, &lt;a href=&quot;https://github.com/orgs/mui/projects/1&quot;&gt;в планах&lt;/a&gt; запилить ещё компоненты, Tailwind-плагин, багфиксы и документация&lt;/li&gt;
&lt;li&gt;опубликован отчёт по опросу &lt;a href=&quot;https://www.jetbrains.com/lp/devecosystem-2024/&quot;&gt;JetBrains State of Developer Ecosystem Report 2024&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;JS всё ещё в топе языков, TS медленно растёт, HTML/CSS так же медленно падает, что в целом показывает инертность платформы несмотря на хайповость некоторых инфоповодов&lt;/li&gt;
&lt;li&gt;Go и Rust — языки, которые респонденты собираются заадоптить&lt;/li&gt;
&lt;li&gt;TS, Rust и Python — самые многообещающие языки (вот будет революция, если в JS таки случится разделение на базовую/надстроечную часть)&lt;/li&gt;
&lt;li&gt;на JS/TS больше всего реализуют UI&lt;/li&gt;
&lt;li&gt;AI используют для более быстрого поиска информации, кодинга и выполнения рутинных задач, а также для изучения новых технологий&lt;/li&gt;
&lt;li&gt;зарплата в US и Индии различается в 8 раз&lt;/li&gt;
&lt;li&gt;топовых зарплат больше у Scala-специалистов, меньше всего — у PHP-, HTML/CSS- и JS-разработчиков&lt;/li&gt;
&lt;li&gt;самые сложные части работы разработчика — коммуникации и понимание требований&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-lock-text-lockfile&quot;&gt;в новой версии Bun&lt;/a&gt; сделали лок-файлы &lt;code&gt;bun.lock&lt;/code&gt; в JSONC-человекочитаемом-формате (так удобнее мерджить в git → DX — существенное конкурентное преимущество)&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://github.com/colinhacks/zod/releases/tag/v3.24.0&quot;&gt;версии Zod v3.24.0&lt;/a&gt; впервые имплементирована спека  &lt;a href=&quot;https://github.com/standard-schema/standard-schema&quot;&gt;Standard Schema&lt;/a&gt; — попытка объединить усилия авторов валидационных либ для создания общего интерфейса, который позволит проще интегрировать разные части экосистемы между собой&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://whatunit.com&quot;&gt;whatunit&lt;/a&gt; — единиц измерения в CSS становится всё больше и все их в памяти уже не удержать, поэтому появилась такая диаграмма решения, какую единицу выбрать в той или иной ситуации (текст/отступы/позиционирование, респонсив/фикс, флекс/грид); из тех, что я уже забыл — текстовые &lt;code&gt;ch&lt;/code&gt; для ширины символа , &lt;code&gt;ex&lt;/code&gt; для высоты строчной буквы , &lt;code&gt;cap&lt;/code&gt; для высоты заглавной буквы&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://habr.com/ru/companies/otus/articles/865512/&quot;&gt;WeakMap и WeakSet&lt;/a&gt; — это «самоочищающиеся» аналоги Map и Set, которые помогают бороться с утечками памяти в задачах, где необходимо хранить набор ссылок на DOM-ноды или же создать кэш вида «ключ-значение»&lt;/li&gt;
&lt;li&gt;оказывается, в DOM есть &lt;a href=&quot;https://12daysofweb.dev/2024/broadcastchannel-api/&quot;&gt;встроенная «шина сообщений»&lt;/a&gt; &lt;code&gt;BroadcastChannel&lt;/code&gt;, которая предназначена для обмена сообщениями посредством &lt;code&gt;postMessage&lt;/code&gt; и подписки на событие &lt;code&gt;&quot;message&quot;&lt;/code&gt; в рамках одного ориджина, годится для обмена сообщениями между вкладок браузера, окнами, айфреймами, например, чтобы прокинуть по всем вкладкам сессию залогиненного пользователя или заполненную форму&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;семейство «подрезающих текст» свойств &lt;code&gt;text-box&lt;/code&gt; (&lt;code&gt;text-box-trim&lt;/code&gt;, &lt;code&gt;text-box-edge&lt;/code&gt;) должно облегчить взаимодействие с дизайнерами в тонких материях, &lt;a href=&quot;https://piccalil.li/blog/why-im-excited-about-text-box-trim-as-a-designer/&quot;&gt;там где отступы реально нужны для решения задач дизайна&lt;/a&gt;, а из-за дополнительного отступа тестовых боксов в браузере эти отступы или убираются костылями (привет тем, кто выравнивал текст в кнопке по центру), или на них забивают&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/the-little-triangle-in-the-tooltip/&quot;&gt;тот самый «указывающий» треугольник у тултипа&lt;/a&gt; можно реализовать с помощью одностороннего бордера, выглядывающей из под тултипа половины перевёрнутого квадрата, вырезания &lt;code&gt;clip-path&lt;/code&gt;-ом нужной фигуры из прямоугольника или же &lt;code&gt;border-image&lt;/code&gt; + &lt;code&gt;conic-gradient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/vEBmZNw&quot;&gt;текст с цветом анимированного градиента&lt;/a&gt; достигается с помощью модерновой комбинации свойств &lt;code&gt;@property&lt;/code&gt; + &lt;code&gt;linear-gradient()&lt;/code&gt; + &lt;code&gt;background-clip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;напоминание: &lt;a href=&quot;https://calendar.perfplanet.com/2024/the-curious-performance-case-of-css-import/&quot;&gt;«нативный» импорт стилей из других стилей&lt;/a&gt; &lt;code&gt;@import url(&quot;https://somesite.net/xxxxxxx.css&quot;)&lt;/code&gt; всё ещё плохо работает в браузерах, а точнее блокирует рендер до полного скачивания и парсинга CSS-файлов, по возможности избегайте этого подхода&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;если взять бесконечную ленту, на которой можно печатать, печатающий элемент, индикатор состояния машины и программу, а также 5 команд: печать символа, сдвиг печатающего элемента вправо и влево, переход на определённое состояние машины и её остановка, то можно вычислить в принципе любое вычисление, с которым сталкивается современный компьютер (computer собсна «вычислитель»); пожалуй, без&lt;a href=&quot;https://samwho.dev/turing-machines/&quot;&gt; этой идеи Алана Тьюринга&lt;/a&gt; мир бы сейчас был совсем другой&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>transition</title><link>https://juwain.github.io/web-platform/blog/2024-12-30/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2024-12-30/</guid><description>История из серии</description><pubDate>Mon, 30 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;/blog/2024-11-26&quot;&gt;Предыдущая часть&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;«Всё понятно», — пробурчал себе под нос Фил, глядя на буквы, которые сложились в ссылку на домене netlify. «Очередной скам», — подумал он и решил удалить с машины бот-аудитор, но что-то его остановило. Название поддомена в ссылке было какое-то странное. Сначала Фил принял его за хэш, но тут явно вырисовывались какие-то слова на незнакомом языке.&lt;/p&gt;
&lt;p&gt;Любопытство взяло верх, и Фил решил перейти по ссылке &lt;a href=&quot;https://desinesperarequihicintras.netlify.app&quot;&gt;desinesperarequihicintras.netlify.app&lt;/a&gt;. Если что браузер работает в stealth-режиме под VPN, так что украсть куки или отследить трафик с его машины не удастся.&lt;/p&gt;
&lt;p&gt;«Наверное реклама очередного майнд-трекера… Таргетологи хреновы!», — подумал Фил. Подобные штуки его уже давно не интересовали, и своей электроэнцефалограммой ни с какой корпорацией он делиться не собирался.&lt;/p&gt;
&lt;p&gt;Перейдя на сайт, Фил удивлённо увидел текст на пустой странице:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;А и Б сидели на трубе,
А упала, Б пропала,
Кто остался на трубе?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;«Ээээ…», — промычал Фил. В этот самый момент часы на руке у него завибрировали и на них показалось пуш-уведомление, призывающее через две минуты подключиться к синку. «Чёрт!», — выругался Фил. Он совсем забыл о сегодняшнем позднем синке с рабочей группой. Фил полез в ящик стола, пошарил рукой и достал корпоративный VR-сет.&lt;/p&gt;
&lt;p&gt;Надевая VR-сет, Фил старался освежить в памяти, чем сегодня был занят. Он понял, что многого про сегодняшний день рассказать на синке не сможет. Целый день он провозился с рефакторингом, но пока мог похвастаться только частично загруженным в голову контекстом проекта и парочкой переписанных небольших модулей системы.&lt;/p&gt;
&lt;p&gt;К слову, сейчас уже такая прямая работа с кодом встречалась в ежедневной рутине Фила нечасто. Обычно для разработки новых фич приходили сырые описания от менеджеров. Задачей Фила было внятно оформить новое описание в базе знаний о системе, снабдить инфой о краевых случаях и исключениях, добавить контракты и тестовые кейсы. После этого обновление базы знаний уходило корпоративной AI-системе Levia-3, которая сама генерила новый код фичи по обновлённым описаниям, контрактам и тест-кейсам.&lt;/p&gt;
&lt;p&gt;Да, название профессии «оператор ЭВМ» из прошлого века в таком подходе играло новыми красками. Оператор корпоративной AI-шайтан-машины. Которая знает ответ всегда. Ну или почти всегда.&lt;/p&gt;
&lt;p&gt;В случае, когда Levia-3 всё таки не справлялась, но делала вид, что справляется, её нужно было дообучить для решения конкретно этого типа задачи или кейса. Вот тут уже приходилось включать в работу «кожаного» разработчика и писать, составлять и размечать датасеты, создавать новые тесткейсы.&lt;/p&gt;
&lt;p&gt;Всяческие рефакторинги и доработки легаси-части системы, ранее не описанные в базе знаний, тоже нужно было выполнять вручную. Собственно говоря, именно этой задачей Фил сейчас и занимался — нужно было загнать ранее не описанную часть фронтенд-системы в ведение Levia-3 и решить все сопутствующие проблемы.&lt;/p&gt;
&lt;p&gt;Не то чтобы супер-увлекательное дело, но за дообучение Levia-3 полагались дополнительные токены, а токены лишними не бывают.&lt;/p&gt;
&lt;p&gt;Синк прошёл без неожиданностей, и после его окончания Фил устало снял VR-сет, положил на стол, замер и недвигающимися глазами посмотрел куда-то сквозь монитор. Он так сидел некоторое время, а затем взгляд его сфокусировался на открытой в браузере странице с детским стишком.&lt;/p&gt;
&lt;p&gt;«Так, таааак…», — задумчиво протянул Фил и открыл инспектор кода браузера. Помимо текста в HTML-коде он увидел скрытое поле &lt;code&gt;&amp;lt;input type=&quot;hidden&quot; value=&quot;bGltYm8=&quot; /&amp;gt;&lt;/code&gt;. «Скрытое и зашифрованное поле, хммммм…», — пробормотал Фил и как-то машинально стал думать над разгадкой. «А и Б, А и Б…». Что-то это напоминало…&lt;/p&gt;
&lt;p&gt;И тут Фила озарило — &lt;code&gt;atob&lt;/code&gt;! Шифровку можно разгадать прямо в консоли. Фил написал в консоли вызов функции &lt;code&gt;atob&lt;/code&gt;, передал туда значение из скрытого инпута и запустил код. Консоль выдала разгадку — &lt;code&gt;limbo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;«Эээмммм», — в задумчивости протянул Фил, размышляя, что с этим делать дальше. «Может быть это роут?», — подумал он, вписал в адресную строку &lt;a href=&quot;https://desinesperarequihicintras.netlify.app/limbo&quot;&gt;desinesperarequihicintras.netlify.app/limbo&lt;/a&gt; и нажал Enter.&lt;/p&gt;
</content:encoded></item><item><title>Пульс веб-платформы 03.01.2025</title><link>https://juwain.github.io/web-platform/blog/2025-01-03/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-01-03/</guid><description>Новости веб-платформы</description><pubDate>Fri, 03 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;вышла версия новая &lt;a href=&quot;https://astro.build/blog/astro-510/&quot;&gt;версия Astro 5.1&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;завезли экспериментальную поддержку хранения на севере данных сессии пользователя (на клиенте не хранятся никакие данные, кроме session id в куки), есть интеграции хранилища сессий с Redis и другими БД&lt;/li&gt;
&lt;li&gt;появилось кеширование не только локальных картинок, но и удалённых&lt;/li&gt;
&lt;li&gt;добавили хэлпер &lt;code&gt;getActionPath&lt;/code&gt; для того, чтобы узнать урл определённого серверного action-а на клиенте.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Резюме: Astro всё ещё вызывает симпатию DX-ом, тщательным выбором новых API, появляющихся в проекте, вниманием к деталям; проект уверенно занимает нишу React-фреймворка для «стандартных» приложений типа CMS и контентных сайтов&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;почти не пишу про видео, но эта новость из мира видео достойна упоминания: MPJ, известный в узких кругах как автор канала Fun Fun Function, после четырёхлетнего перерыва &lt;a href=&quot;https://www.youtube.com/watch?v=dfVdFC4EGj8&quot;&gt;вернулся с курсом по D3.js&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ghostty-org/ghostty&quot;&gt;ghostty&lt;/a&gt; — быстрый и заточенный под «нативность» терминал для macOS и Linux&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;напоминание, что &lt;a href=&quot;https://blog.axlight.com/posts/thoughts-on-what-rsc-means-for-spas/&quot;&gt;React Server Components могут работать и без рантаймового сервера&lt;/a&gt;, в этом случае &lt;a href=&quot;https://react.dev/reference/rsc/server-components#server-components-without-a-server&quot;&gt;«сервер» в билд-тайме рендерит компоненты&lt;/a&gt; и сериализует их в текст, а уже этот текст может быть доставлен в SPA в виде статического файла с обычного файлового хостинга: в таком случае разгружается общий клиентский JS-бандл, так как часть JS-кода выносится в «пререндеренном» текстовом виде в отдельные файлы, которые SPA уже может запросить «лениво» по необходимости, то есть теперь SPA уже не всегда означает чистый client-side-render&lt;/li&gt;
&lt;li&gt;если вы занялись &lt;s&gt;неблагодарным&lt;/s&gt; &lt;a href=&quot;https://byteofdev.com/posts/javascript-benchmarking-mess/&quot;&gt;делом бенчмаркинга кода&lt;/a&gt;, то на пути вас ждут как минимум пара движков: V8 (Chrome, Node, Deno) и JavaScriptCore (Safari, Bun), и в каждом есть свои трюки, оптимизирующие выполнение кода (JIT-кэширование, рандомный Garbage Collector, Tail Call Optimization), которые при бенчмаркинге надо наоборот обойти; но для обычных смертных из полезного можно вынести, что &lt;code&gt;performance.now()&lt;/code&gt; более точен, чем &lt;code&gt;console.time()/console.timeEnd()&lt;/code&gt;, но при этом нужно помнить, что точность выполнения кода &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/High_precision_timing#reduced_precision&quot;&gt;специально может немного задерживаться&lt;/a&gt; для защиты от фингерпринтинга&lt;/li&gt;
&lt;li&gt;писать на TS, в целом, приятно (не всегда), но вот преобразовывать TS в JS вручную бывает заморочно почти всегда (&lt;code&gt;tsc&lt;/code&gt; медленный, нужны режимы билда/вотча…), но хорошо, что уже много тулов поддерживает TS из коробки, в том числе &lt;a href=&quot;https://github.com/nodejs/node/pull/56350&quot;&gt;в скором времени и Node 23&lt;/a&gt;, так что все в дальнейшем будут ориентироваться на подход Node — просто вырезать типы (а пока будущее не докатилось до чётной версии Node, есть &lt;a href=&quot;https://tsx.is/&quot;&gt;tsx&lt;/a&gt; — беззаморочный запускальщик ts-файлов в Node)&lt;/li&gt;
&lt;li&gt;методы &lt;code&gt;forEach&lt;/code&gt; и &lt;code&gt;map&lt;/code&gt; массивов — всегда синхронные, то есть если вы обрабатываете ими большие объёмы данных, то эта обработка создаёт длинные таски, которые блокируют выполнение других задач в потоке, что в свою очередь может привести к зависаниям вкладки, лагающим анимациям; &lt;a href=&quot;https://calendar.perfplanet.com/2024/breaking-up-with-long-tasks-or-how-i-learned-to-group-loops-and-wield-the-yield/&quot;&gt;решается проблема переходом на цикл &lt;code&gt;for .. of&lt;/code&gt; и батчингом&lt;/a&gt;: в процессе цикла нужно проверить, пора ли делать «паузу» и если да, то запускать &lt;code&gt;await new Promise(requestAnimationFrame)&lt;/code&gt; для запуска отложенных перерисовок и &lt;code&gt;scheduler.yield()&lt;/code&gt; для выполнения параллельных задач&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jantimon/text-box-trim-examples#usecases&quot;&gt;юзкейсы&lt;/a&gt; нового «подрезающего» свойства &lt;code&gt;text-box&lt;/code&gt;(&lt;code&gt;text-box-trim/text-box-edge&lt;/code&gt;), о котором упоминал недавно: кнопки, отступы в лейаутах, выравнивание иконки/картинки + текста, дизайнерские выкрутасы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://codepen.io/argyleink/pen/ByBdYyJ&quot;&gt;при вырезании текста из фона&lt;/a&gt; с помощью &lt;code&gt;background-clip: text&lt;/code&gt; фоновой «картинкой» может быть, например, полосатый &lt;code&gt;repeating-linear-gradient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://calendar.perfplanet.com/2024/fabulous-font-face-fallbacks/&quot;&gt;фоллбек-шрифт можно не просто перечислить&lt;/a&gt; в &lt;code&gt;font-family&lt;/code&gt;, но объявить в &lt;code&gt;@font-face&lt;/code&gt;, а внутри подключить гарантированный локальный шрифт через &lt;code&gt;local(&quot;Arial&quot;)&lt;/code&gt;, и затем потвикать его настройки с помощью &lt;code&gt;size-adjust&lt;/code&gt;, &lt;code&gt;ascent-override&lt;/code&gt;… для большего визуального соответствия основному шрифту&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ryanmulligan.dev/blog/some-things-about-keyframes/&quot;&gt;несколько полезных фактов о кейфреймах&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;одинаковые значения свойств можно не дублировать в нескольких правилах, а объединять в одно правило через запятую &lt;code&gt;0%, 50% {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;порядок следования правил в кейфрейме может быть произвольным &lt;code&gt;{ from {} to {} from, 50% {}}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;правила с одинаковыми процентами каскадируются, то есть последнее перекрывает предыдущие&lt;/li&gt;
&lt;li&gt;внутри отдельного правила в кейфрейме можно подправить &lt;code&gt;animation-timing-function&lt;/code&gt;, задав шагу функцию &lt;code&gt;linear()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;во вкладке Sources &amp;gt; Overrides можно &lt;a href=&quot;https://calendar.perfplanet.com/2024/using-devtools-to-validate-web-performance-improvements/&quot;&gt;подредактировать контент в файлах сайта&lt;/a&gt;, например, в HTML-файле отредактировать подключение картинок, чтобы протестировать фикс перфоманса без модификации исходного кода&lt;/li&gt;
&lt;li&gt;как в своё время ES впитал новшества CoffeeScript, так и &lt;a href=&quot;https://plainvanillaweb.com/blog/articles/2025-01-01-new-years-resolve/&quot;&gt;веб-платформа со временем впитывает&lt;/a&gt; то, что предоставлялось билд-тулами и фреймворками: резолв пути к файлу есть в нативном &lt;code&gt;import.meta.resolve()&lt;/code&gt; и &lt;code&gt;import.meta.url&lt;/code&gt;, динамические импорты позволяют «лениво» запрашивать модули, минификация файлов реализуется на сервере с gzip или brotli, конкатенация файлов становится не нужна благодаря HTTP2/3; поэтому базовые кейсы из задач фреймворков/бандлеров вымываются, и на их стороне остаются DX и сложные/узкоспециализированные вещи&lt;/li&gt;
&lt;li&gt;мастерство разработчика — &lt;a href=&quot;https://gomakethings.com/just-grab-a-library/&quot;&gt;балансировать в промежутке&lt;/a&gt; между «написать свой велосипед» и «использовать готовую либу» и, прикинув трейд-оффы, выбрать правильный инструмент для конкретного случая&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Kent Beck, Tidy First. A Personal Exercise in Empirical Software Design, 2023 </title><link>https://juwain.github.io/web-platform/blog/2025-01-08/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-01-08/</guid><description>Книжный клуб веб-платформы</description><pubDate>Wed, 08 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Чистка и рефатокторинг кода — это гиковская забота о себе. Можно её не делать, но с ней чувствуешь себя лучше.&lt;/p&gt;
&lt;p&gt;Самая большая часть «стоимости» при работе с кодом в его чтении и понимании, а не в написании. Когда вы пишите код, вы не только пишете инструкцию компьютеру, но скорее объясняете свои намерения компьютеру для других людей. Просто написать код для компьютера, который будет работать, не особо интересная конечная цель. В хаотично написанный код довольно быстро станет трудно вносить изменения из-за многочисленных связей (часто неявных) между его элементами и сущностями.&lt;/p&gt;
&lt;p&gt;Если думать о себе как о писателе, код которого будут изучать читатели, то можно и приводить в код в порядок с этой же мыслью: делать код из запутанного более понятным, единообразным, раскладывать по коду «подсказки» для его понимания, упорядочивать последовательность «повествования» кода. Всегда можно прикинуть, как будет код читаться, ведь каждый из нас читатель.&lt;/p&gt;
&lt;h3&gt;Какие вещи можно учитывать при рефакторинге&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;подчистку лучше делать маленькими шагами, настолько маленькими, чтобы их было делать не страшно; небольшая подчистка — самая лучшая&lt;/li&gt;
&lt;li&gt;много мелких рефакторингов и подчисток дополняют друг друга и со временем становятся большой переработкой модуля или системы, за которую будут благодарны ваши коллеги&lt;/li&gt;
&lt;li&gt;разделение кода на мелкие части важно сделать так, чтобы это помогало пониманию; то есть если связать воедино кучу мелких несвязных сущностей, то это усложнит их понимание; а если объединить однородные сущности, то их можно без проблем вынести в отдельную упрощающую понимание абстракцию&lt;/li&gt;
&lt;li&gt;если собирать связанные друг с другом по смыслу и коду вещи (функции, модули, файлы) в одном месте, то нужно будет меньше держать в голове для понимания и работы с этим кодом&lt;/li&gt;
&lt;li&gt;«подчищающие» изменения стоит отделять от меняющего поведение в разные коммиты&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Про код&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вместо того чтобы вкладывать условия друг в друга, условия проверяются в начале функции и выполнение функции прекращается, если условия не выполняются&lt;/li&gt;
&lt;li&gt;кусок кода, выполняющий одно понятное назначение и не сильно связанный с остальным кодом, можно вынести во внешний хелпер&lt;/li&gt;
&lt;li&gt;куски кода, выполняющие разные вещи, можно отделить друг от друга пустой строкой&lt;/li&gt;
&lt;li&gt;если в глубине кода встречается использование env-ов, лучше заменить их на явные параметры&lt;/li&gt;
&lt;li&gt;разросшиеся выражения лучше поделить на отдельные промежуточные части&lt;/li&gt;
&lt;li&gt;код про получение параметров лучше сконцентрировать в начале модуля, остальной код — после&lt;/li&gt;
&lt;li&gt;если объявление и инициализация переменной сильно разнесены по коду, это усложняет понимание&lt;/li&gt;
&lt;li&gt;если у модели есть интерфейс, который вам не нравится, можно сделать для него «фасад» — свой интерфейс, который вам нравится, а уже внутри вызывать старый интерфейс&lt;/li&gt;
&lt;li&gt;не выполняющийся код можно смело удалять&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Про комментарии&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;комментарий, который описывает дословно то, что происходит в коде, можно смело удалять&lt;/li&gt;
&lt;li&gt;если вы читаете файл и уловили момент, когда начали понимать, что к чему в этом файле, это ключевой момент! Можно это место/понимание зафиксировать в комменте (иногда полезно оставлять такие комменты в «шапке» файла)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 10.01.2025</title><link>https://juwain.github.io/web-platform/blog/2025-01-10/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-01-10/</guid><description>Новости веб-платформы</description><pubDate>Fri, 10 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://risingstars.js.org/2024/en&quot;&gt;вышел отчёт 2024 JavaScript Rising Stars&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;самый «быстрозвездеющий» проект года — shadcn/ui — не нуждается в представлении, второй — Excalidraw — инструмент для создания рисунков и диаграмм, тоже на слуху, третий — AFFiNE — опенсорсный Notion&lt;/li&gt;
&lt;li&gt;htmx — больше всех набрал из фронтенд-фреймворков, даже перегнав React&lt;/li&gt;
&lt;li&gt;из бэкенд/фулстек-фреймворков в топе по популярности Next.js, Hono и Astro&lt;/li&gt;
&lt;li&gt;в тулингах чемпионы Biome, Bun, Vite — чувствуется, что обычному разработчику нужно, чтобы просто работало&lt;/li&gt;
&lt;li&gt;среди state manager-ов победил Zustand, Jotai и XState (Valtio тоже в топе, Redux замыкает лист)&lt;/li&gt;
&lt;li&gt;в CSS-либах топ заняли Tailwind, DaisyUI (либа под TW) и Bootstrap&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hexagoncircle/pixel-canvas&quot;&gt;pixel-canvas&lt;/a&gt; — веб-компонент, применяющий блестящий фон на &lt;code&gt;canvas&lt;/code&gt; к элементу&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/trimmiddle&quot;&gt;trimmiddle&lt;/a&gt; — либа, вырезающая текст из середины строки (недостающий метод строки вдовесок к &lt;code&gt;trimStart()&lt;/code&gt; и &lt;code&gt;trimEnd()&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Temporal API, ещё нигде в стабильных релизах браузеров не реализованный, хорошо интегрируется с другим полезным Internationalization API, который есть везде уже сейчас и &lt;a href=&quot;https://fullystacked.net/formatting-dates-and-times/&quot;&gt;может&lt;/a&gt;, например, перевести часы в секунды без доп вычислений с помощью &lt;code&gt;Intl.DurationFormat&lt;/code&gt; или отобразить время относительно другого времени с &lt;code&gt;Intl.RelativeTimeFormat&lt;/code&gt; (кроме того: у даты есть метод &lt;code&gt;toLocaleString()&lt;/code&gt;, выдающий дату в строки в текущей локали, а локаль модно получить в &lt;code&gt;navigator.language&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.comfydeploy.com/blog/you-dont-need-nextjs&quot;&gt;история команды&lt;/a&gt;, осознавшей, что борется с Next.js больше времени, чем кодит продукт, и перешедшей на обычный React: потеряли фулстек-подход, кеширование и пререндер, серверные компоненты и actions, приобрели быстрый билд и деплой и счастье команды&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://2ality.com/2025/01/nodejs-strip-type.html&quot;&gt;детали того, как работает TS в Node.js&lt;/a&gt;: типы отбрасываются, работают для файлов с разрешениями .ts, .mts, .cts (.tsx не поддерживается), пока что по умолчанию не поддерживаются фичи, требующие транспиляции (enum, decorators, namespaces), сорсмапы не создаются, так как расположение кода остаётся тем же&lt;/li&gt;
&lt;li&gt;Daishi Kato, автор стейт-менеджеров Zustand, Jotai, Valtio, &lt;a href=&quot;https://blog.axlight.com/posts/thoughts-on-state-management-libraries-in-the-react-compiler-era/&quot;&gt;поделился мыслями о будущем либ&lt;/a&gt; в эру React Compiler/React Server Components: возможно в будущем оптимизации RC сделают встроенные инструменты управления стейтом useState/useContext более эффективными в плане оптимизации необходимости перерендеров, а кеширование в RSC — сделают ненужными комплексные стейты, но тем не менее юзкейсы всех трёх подходов либ продолжают быть актуальными и скорее всего так и будет дальше&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ishadeed.com/article/balancing-text-css/&quot;&gt;необычный юзкейс&lt;/a&gt; свойства &lt;code&gt;text-wrap: balance&lt;/code&gt;: решает проблему переноса на следующую строку иконки за текстом&lt;/li&gt;
&lt;li&gt;селектор &lt;code&gt;&amp;amp;:hover &amp;gt; *:not(:hover)&lt;/code&gt; применит &lt;a href=&quot;https://nerdy.dev/hover-not-hover-sorry-not-sorry&quot;&gt;стили по наведению ко всем элементам внутри контейнера, кроме текущего&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;интересный концепт &lt;a href=&quot;https://css-tip.com/animation-without-keyframes/&quot;&gt;безкейфреймовой «анимации»&lt;/a&gt;: объявляется кастомное свойство типа integer (значение — конечное в «анимации»), в &lt;code&gt;@starting-style&lt;/code&gt; прописывается начальное значение в «анимации», создаётся довольно длинный &lt;code&gt;transition&lt;/code&gt; для этого кастомного свойства, в процессе которого выполняется «анимация»&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;атрибут &lt;code&gt;translate=&quot;no&quot;&lt;/code&gt; &lt;a href=&quot;https://www.stefanjudis.com/today-i-learned/non-translatable-html-elements/&quot;&gt;выключит нежелательный перевод&lt;/a&gt; HTML-элемента в браузере&lt;/li&gt;
&lt;li&gt;подборка, чтобы &lt;a href=&quot;https://frontendmasters.com/blog/bone-up-html-2025/&quot;&gt;обновить представление&lt;/a&gt;, на что способен современный HTML: для себя нашёл атрибут &lt;a href=&quot;https://developer.chrome.com/docs/css-ui/hidden-until-found&quot;&gt;&lt;code&gt;hidden=until-found&lt;/code&gt;&lt;/a&gt;, скрывающий элемент до тех пор, пока текст внутри его не нашли поиском по странице, и вспомнил атрибут &lt;code&gt;inert&lt;/code&gt;, делающий элемент недоступным для взаимодействия (мощнее, чем &lt;code&gt;pointer-events: none&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 17.01.2025</title><link>https://juwain.github.io/web-platform/blog/2025-01-17/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-01-17/</guid><description>Новости веб-платформы</description><pubDate>Fri, 17 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/132&quot;&gt;вышел Chrome 132&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;улучшены события и исправлены баги для элементов popover и dialog&lt;/li&gt;
&lt;li&gt;продолжают допиливать CSS Anchor Positioning&lt;/li&gt;
&lt;li&gt;заголовки &lt;code&gt;Strict-Transport-Security (STS)&lt;/code&gt; теперь игнорятся для &lt;code&gt;localhost&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;довыкатили Keyboard focusable scroll containers, которые раньше забаговали&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/capabilities/web-apis/file-system-access&quot;&gt;File System Access API&lt;/a&gt; стало доступно на Android-девайсах и WebView&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/134.0/releasenotes/&quot;&gt;вышел Firefox 134.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддержан &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try&quot;&gt;&lt;code&gt;Promise.try()&lt;/code&gt;&lt;/a&gt;, теперь он кроссбраузерный&lt;/li&gt;
&lt;li&gt;экспериментально добавлена поддержка &lt;code&gt;Intl.DurationFormat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поправлен баг с применением &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/align-self&quot;&gt;&lt;code&gt;align-self&lt;/code&gt;&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self&quot;&gt;&lt;code&gt;justify-self&lt;/code&gt;&lt;/a&gt; к абсолютно позиционированным элементам&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v22.13.0&quot;&gt;в Node.js v22.13.0&lt;/a&gt; стабилизирована фича &lt;a href=&quot;https://nodejs.org/api/permissions.html#permissions&quot;&gt;Permission Model&lt;/a&gt;: это «ремень безопасности» для вашего кода, а не защита от чужого вредоносного кода; запуск файла с флагом &lt;code&gt;node --permission index.js&lt;/code&gt; по умолчанию обрежет все права (чтение и запись в fs, порождение процессов…), а указание явных флагов типа &lt;code&gt;--allow-fs-read&lt;/code&gt; и &lt;code&gt;--allow-fs-write&lt;/code&gt; уже включит только нужное&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-v1.1.43#html-bundler&quot;&gt;в Bun v1.1.43&lt;/a&gt; появился экспериментальный HTML Bundler: команда &lt;code&gt;bun build --experimental-html --experimental-css ./index.html --outdir=dist&lt;/code&gt; склеит все js-, css-файлы и ассеты в один файл и подключит их в итоговом html-файле&lt;/li&gt;
&lt;li&gt;WinterCG, группа разрабочиков Deno, &lt;a href=&quot;https://deno.com/blog/wintertc&quot;&gt;слилась с Ecma International&lt;/a&gt;, сформировала новый &lt;a href=&quot;https://wintercg.org&quot;&gt;комитет TC55&lt;/a&gt; и выпустила первый черновик их стандарта &lt;a href=&quot;https://min-common-api.proposal.wintercg.org&quot;&gt;Minimum Common Web Platform API&lt;/a&gt;, где собраны список базовых API для конситентности между разными JS-райнтаймами&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react/pull/31975&quot;&gt;в React-е (и Next-е) появится&lt;/a&gt; первое API про анимацию — компонент &lt;code&gt;&amp;lt;ViewTransition&amp;gt;&lt;/code&gt; на основе View Transitions API (&lt;a href=&quot;https://caniuse.com/view-transitions&quot;&gt;не поддерживается только в FF&lt;/a&gt;), обещают удобство в работе с Suspence, под капотом React будет в определённый момент назначать элементу &lt;code&gt;view-transition-name&lt;/code&gt; и вызывать &lt;code&gt;startViewTransition&lt;/code&gt; во время мутации DOM-а:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ViewTransition&amp;gt;
  &amp;lt;Suspense fallback={&amp;lt;Skeleton /&amp;gt;}&amp;gt;
    &amp;lt;Content /&amp;gt;
  &amp;lt;/Suspense&amp;gt;
&amp;lt;/ViewTransition&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/threepointone/emojico&quot;&gt;emojico&lt;/a&gt; — cli-тула для генерации набора favicon-ок из эмодзи: под капотом буднично открывается puppeteer и снимается скриншот со страницы с иконкой&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@smoores/epub&quot;&gt;@smoores/epub&lt;/a&gt; — оказывается формат электронных книг epub — &lt;a href=&quot;https://www.w3.org/TR/epub-33/&quot;&gt;открытый стандарт W3C&lt;/a&gt;, и это либа для работы с epub-файлами&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/theKashey/react-focus-lock&quot;&gt;react-focus-lock&lt;/a&gt; — «ловушка» фокуса при показе модалок&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;спред объекта/массива в объекте не скопирует его, а создаст ссылку на него &lt;code&gt;const state = { ...defaultState, prop: value }&lt;/code&gt; — это механизм Shallow Copy; если же нужно &lt;a href=&quot;https://philna.sh/blog/2024/12/30/shallow-clones-versus-structured-clones/&quot;&gt;именно склонировать объект&lt;/a&gt;, то в современном JS для этого есть специальный метод &lt;code&gt;structuredClone&lt;/code&gt; (поддерживается везде с 2022):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const state = structuredClone(defaultState);
state.prop = value;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;доля ESM-only и dual (ESM + CJS) npm-пакетов &lt;a href=&quot;https://github.com/wooorm/npm-esm-vs-cjs&quot;&gt;медленно, но верно растёт&lt;/a&gt;: в ноябре 2024 у CJS 63%, у dual + ESM 25%&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tigerabrodi.blog/how-reacts-render-effects-and-refs-work-under-the-hood&quot;&gt;напоминание для реактоводов&lt;/a&gt;: рефы обрабатываются до &lt;code&gt;useLayoutEffect&lt;/code&gt; и &lt;code&gt;useEffect&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;псевдокласс &lt;code&gt;:empty&lt;/code&gt; помогает &lt;a href=&quot;https://gomakethings.com/the-empty-pseudo-class-in-css/&quot;&gt;скрыть элементы с пустым контентом&lt;/a&gt; (правда пока что в браузеры не доехало &lt;a href=&quot;https://drafts.csswg.org/selectors-4/#the-empty-pseudo&quot;&gt;обновление спеки по этому поводу&lt;/a&gt;, то есть блок с пробелами скрыт не будет):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;.list &amp;gt; div:empty {
  display: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;бонус использования нативного &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; — &lt;a href=&quot;https://cassidoo.co/post/css-for-dialogs/&quot;&gt;его части легко стилизовать&lt;/a&gt;: подложка &lt;code&gt;dialog::backdrop {}&lt;/code&gt;, убирание скролла &lt;code&gt;body:has(dialog[open]) { overflow: hidden }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в современных браузерах &lt;a href=&quot;https://addyosmani.com/blog/double-keyed-caching/&quot;&gt;изменился подход к кешированию ресурсов&lt;/a&gt;: если раньше файл мог быть единожды закеширован по урлу и потом для другого сайта браться из общего кеша &lt;code&gt;&quot;https://cdn.example.com/jquery-3.6.0.min.js&quot;: resourceData&lt;/code&gt;, то теперь для защиты от отслеживания для каждого сайта кеш файла будет храниться отдельно &lt;code&gt;{ topLevelSite: &quot;site-a.com&quot;, resource: &quot;https://cdn.example.com/jquery-3.6.0.min.js&quot; }: resourceData&lt;/code&gt;; как следствие — больше нет выгоды от CDN, дешевле селф-хостить на своём домене типа &lt;code&gt;static.company.com/js/react.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://martijnhols.nl/blog/accessibility-essentials-every-front-end-developer-should-know&quot;&gt;для базовой доступности&lt;/a&gt; достаточно использовать теги по назначению (кнопки, формы, лейблы + инпуты), не убирать стили фокуса, при открытой модалке ловить фокус и «выключать» контент под ней атрибутом &lt;code&gt;inert&lt;/code&gt;, расширять область клика на интерактивных элементах&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>HAR-файл для выгрузки сетевой активности</title><link>https://juwain.github.io/web-platform/blog/2025-01-22/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-01-22/</guid><description>Из средств разработчика DevTools в браузерах можно выгружать сетевую активность</description><pubDate>Wed, 22 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Все вы знакомы со вкладкой Network в браузерах, где отображаются ушедшие запросы, пришедшие ответы с заголовками, куками и так далее. Так вот всё это богатство можно из браузера выгрузить в виде файла в формате HAR, во вкладке есть для этого кнопки со стрелками Import/Export HAR file: Export — сохраняет текущую историю сетевых запросов в файл, Import — открывает уже имеющийся файл в дев-тулзах.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/har-1.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Сам файл — это JSON с определённо именованными полями. И формат этот даже в каком-то виде стандартизирован, хоть и не окончательно: нашёлся &lt;a href=&quot;https://w3c.github.io/web-performance/specs/HAR/Overview.html&quot;&gt;черновик «HTTP Archive (HAR) format»&lt;/a&gt;, в котором примерно описан формат, но при этом написано «не пользуйтесь этим черновиком»; а также удалось найти &lt;a href=&quot;https://www.w3.org/community/bigdata-tools/files/2017/10/HAR_VocabularySpecification_Draft003.pdf&quot;&gt;пре-спеку HAR Vocabulary Specification Draft 0.03&lt;/a&gt;, в котором тоже описан формат файла.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./assets/har-2.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Помимо браузеров &lt;a href=&quot;https://en.wikipedia.org/wiki/HAR_%28file_format%29&quot;&gt;HAR-файлы понимают другие веб-сервисы&lt;/a&gt;: просмотрщики, тестовые и автоматизационные тулы.&lt;/p&gt;
&lt;p&gt;Юзкейсы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;поделиться между разработчиками, QA или пользователями «записью состояния» приложения, как воспроизвести определённую ситуацию, когда подёргали в нужном порядке бэк-ручки, передали куки&lt;/li&gt;
&lt;li&gt;предоставить сценарий для проведения нагрузочного тестирования, чтобы выполнить определённый набор запросов в нужном порядке и с нужными параметрами без UI&lt;/li&gt;
&lt;li&gt;открыть файл с логами сетевого взаимодействия в текстовом редакторе для удобного редактирования&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 31.01.2025</title><link>https://juwain.github.io/web-platform/blog/2025-01-31/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-01-31/</guid><description>Новости веб-платформы</description><pubDate>Fri, 31 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-v1.2&quot;&gt;вышел Bun 1.2&lt;/a&gt;, наносящий конкурентный удар Deno (а также замахнувшийся на поляну Vite):
&lt;ul&gt;
&lt;li&gt;всё больше совместимость с Node.js (90-100%)&lt;/li&gt;
&lt;li&gt;встроенная поддержка облачного хранилища S3, а также БД помимо SQLite ещё и Postgres и вскоре MySQL&lt;/li&gt;
&lt;li&gt;текстовый лок-файл взамен бинарного при установке npm-пакетов  &lt;code&gt;bun install&lt;/code&gt;, также JSONC (JSON с комментами) для package.json&lt;/li&gt;
&lt;li&gt;поддержан &lt;code&gt;.npmrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;есть мониторинг версий пакетов &lt;code&gt;bun outdated&lt;/code&gt; и публикация &lt;code&gt;bun publish&lt;/code&gt;, а также патчинг пакетов &lt;code&gt;bun patch&lt;/code&gt; (чтоб захаркодить что-то локально в пакете)&lt;/li&gt;
&lt;li&gt;улучшен &lt;code&gt;bun test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавлен бандлинг HTML-файлов с собранными скриптами, стилями и ассетами&lt;/li&gt;
&lt;li&gt;появилась возможность запуска кода C++&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;а пока Bun ещё не забрался в область форматирования и линтинга &lt;a href=&quot;https://biomejs.dev/blog/roadmap-2025/&quot;&gt;Biome опубликовали свои планы на 2025&lt;/a&gt;: добавить поддержку HTML, поддержка одних языков внутри других (например, CSS в JS), а также Markdown, взаимодействие с TS и JSDoc&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2025/01/eslint-2024-year-review/&quot;&gt;и отчёт о работе ESLint в 2024&lt;/a&gt;: всего проект заработал 189k$ (74% из которых дали крупные компании)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.mozilla.org/en/mozilla/ai/ai-tech/running-inference-in-web-extensions/&quot;&gt;в FF тоже появится AI&lt;/a&gt;, но обещают не воровать пользовательские данные, а запускать локально &lt;a href=&quot;https://huggingface.co/docs/transformers.js/index&quot;&gt;Transformers.js&lt;/a&gt; с базовыми ML-умелками (распознавание объектов, суммаризация…)&lt;/li&gt;
&lt;li&gt;Yeoman (помните такой?) &lt;a href=&quot;https://yeoman.io/blog/maintenance-reboot&quot;&gt;воскресили&lt;/a&gt;, чтобы поддерживать стабильность в системах, всё ещё использующих его, и пока не выпускать новые фичи&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-beta/&quot;&gt;в TypeScript 5.8 Beta&lt;/a&gt; появился флаг &lt;code&gt;--erasableSyntaxOnly&lt;/code&gt;, который будет помечать ошибочными «расширяющие» конструкции языка, которые нельзя просто вырезать, а нужно компилировать (goodbye, Enum?)&lt;/li&gt;
&lt;li&gt;CreateReactApp официально &lt;a href=&quot;https://github.com/facebook/create-react-app/pull/17003&quot;&gt;помечен deprecated&lt;/a&gt;, если вы его ещё используете, вот знак, чтобы этого больше не делать&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jsonquerylang/jsonquery&quot;&gt;jsonquery&lt;/a&gt; — DSL для выборки нужных данных (для больших JSON-ов)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://standardschema.dev/&quot;&gt;Standard Schema&lt;/a&gt; — спека, объединяющая усилия авторов валидационных либ (&lt;a href=&quot;https://zod.dev/&quot;&gt;Zod&lt;/a&gt;, &lt;a href=&quot;https://valibot.dev/&quot;&gt;Valibot&lt;/a&gt;) и тул/фреймворков (&lt;a href=&quot;https://trpc.io/&quot;&gt;tRPC&lt;/a&gt;, &lt;a href=&quot;https://tanstack.com/form&quot;&gt;TanStack Form&lt;/a&gt;) в создании общего интерфейса для интеграции разных частей экосистемы между собой&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/httptoolkit/react-reverse-portal&quot;&gt;react-reverse-portal&lt;/a&gt; — либа, позволяющая перенести отрендеренную React-ноду из одного места в другое без перерендера (сгодится для отображения в разных местах тяжёлых компонентов)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nodejs/is-my-node-vulnerable&quot;&gt;is-my-node-vulnerable&lt;/a&gt; — &lt;code&gt;npx is-my-node-vulnerable&lt;/code&gt; проверит версию Node на наличие уязвимостей (рекомендуется для включения в CI)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://typescript-eslint.io/blog/avoiding-anys/&quot;&gt;способы искоренения&lt;/a&gt; &lt;code&gt;any&lt;/code&gt; в коде: если флага &lt;code&gt;noImplicitAny&lt;/code&gt; вам недостаточно (&lt;code&gt;JSON.stringify&lt;/code&gt; и &lt;code&gt;Function&lt;/code&gt; всё равно будут производить &lt;code&gt;any&lt;/code&gt;), то будут полезны правила для линтинга: &lt;a href=&quot;https://typescript-eslint.io/rules/no-explicit-any&quot;&gt;&lt;code&gt;@typescript-eslint/no-explicit-any&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://typescript-eslint.io/rules/no-unsafe-function-type&quot;&gt;&lt;code&gt;@typescript-eslint/no-unsafe-function-type&lt;/code&gt;&lt;/a&gt;, а также либа &lt;a href=&quot;https://www.totaltypescript.com/ts-reset&quot;&gt;&lt;code&gt;ts-reset&lt;/code&gt;&lt;/a&gt;, которая заменяет &lt;code&gt;any&lt;/code&gt; во встроенных типах на &lt;code&gt;unknown&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fetch&lt;/code&gt; с поддержкой HTTP/2 пока &lt;a href=&quot;https://blog.disintegrator.dev/posts/http2-support-in-js-runtimes/&quot;&gt;не работает по умолчанию в Node и Bun&lt;/a&gt;, но работает в Deno&lt;/li&gt;
&lt;li&gt;оказывается в &lt;code&gt;try {} catch {}&lt;/code&gt; можно не указывать скобки и аргумент у &lt;code&gt;catch&lt;/code&gt;, и всё &lt;a href=&quot;https://www.stefanjudis.com/today-i-learned/error-catch-bindings-are-finally-optional/&quot;&gt;будет работать в современных браузерах&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://2ality.com/2025/01/template-literal-types.html&quot;&gt;Template literal types&lt;/a&gt; — мощнейшая штука, затрагивал пару примеров в прошлом выпуске, но тут прям много юзкейсов и примеров типа такого:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;type ToString&amp;lt;T extends string | number | bigint | boolean | null | undefined&amp;gt; =
  `${T}`;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://una.im/advanced-attr/&quot;&gt;юзкейсы&lt;/a&gt; для грядущего в ближайшем Chrome обновлении &lt;code&gt;attr()&lt;/code&gt;: по сути это долгожданная связка HTML и CSS без использования JS, храним данные в разметке, используем в стилях:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;li color=&quot;{props.colorVal}&quot; color-name=&quot;{props.colorName}&quot;&amp;gt;
  &amp;lt;div class=&quot;item&quot; place-col=&quot;2&quot;&amp;gt;column 2&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;background-color: attr(color type(&amp;lt;color&amp;gt;));
grid-column: attr(place-col type(&amp;lt;number&amp;gt;));
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;накопление ошибок и противоречий в легаси неизбежно, &lt;a href=&quot;https://wiki.csswg.org/ideas/mistakes&quot;&gt;не избежал этой участи и CSS&lt;/a&gt;: в списке приводятся плохие решения, с которыми мы живём, например, &lt;code&gt;box-sizing&lt;/code&gt; по умолчанию не &lt;code&gt;border-box&lt;/code&gt;, &lt;code&gt;border-radius&lt;/code&gt; следовало быть &lt;code&gt;corner-radius&lt;/code&gt;, составные селекторы должны разделяться по запятым, а не ломаться полностью при незнакомом синтаксисе&lt;/li&gt;
&lt;li&gt;если вам не нравится хранить цвет и полупрозрачный цвет в двух разных переменных, &lt;a href=&quot;https://osvaldas.info/opacify-hex-color-in-css/&quot;&gt;то на помощь приходит функция&lt;/a&gt; &lt;code&gt;color-mix(in srgb, var(--green), transparent 50%)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.stefanjudis.com/blog/load-the-default-os-font-with-css/&quot;&gt;дефолтный системный шрифт&lt;/a&gt; &lt;code&gt;font-family: system-ui, sans-serif&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@counter-style&lt;/code&gt; — &lt;a href=&quot;https://css-tricks.com/some-things-you-might-not-know-about-custom-counter-styles/&quot;&gt;тема кастомного буллета в списках раскрыта полностью&lt;/a&gt;: префиксы, суффиксы и иконки&lt;/li&gt;
&lt;li&gt;семейство свойств &lt;code&gt;offset-*&lt;/code&gt; позволяет &lt;a href=&quot;https://css-tricks.com/positioning-text-around-elements-with-css-offset/&quot;&gt;располагать элементы относительно какой-либо формы&lt;/a&gt;, в том числе произвольной, а если добавить &lt;code&gt;transition&lt;/code&gt;, то и двигать относительно неё&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;просто страница, на которой &lt;a href=&quot;https://iamwillwang.com/dollar/every-html-element/&quot;&gt;используются всё HTML-теги&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;нативный &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; внезапно &lt;a href=&quot;https://fullystacked.net/portal/&quot;&gt;решает проблему&lt;/a&gt;, по которой появились portal-ы во фреймворках&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;при задаче оптимизации сайта/приложения немаловажную роль &lt;a href=&quot;https://www.developerway.com/posts/initial-load-performance&quot;&gt;играют заголовки Cache-Control Headers&lt;/a&gt;, которые у некоторых CDN-провайдеров имеют значения &lt;code&gt;max-age=0&lt;/code&gt; и &lt;code&gt;must-revalidate&lt;/code&gt; по умолчанию для CSS и JS-файлов&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 24.01.2025</title><link>https://juwain.github.io/web-platform/blog/2025-01-24/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-01-24/</guid><description>Новости веб-платформы</description><pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/blog/tailwindcss-v4&quot;&gt;вышла версия Tailwind 4.0&lt;/a&gt;: как уже писал раньше, TW впитывает фичи платформы (что хорошо), но по-прежнему запихивает всё в &lt;code&gt;className&lt;/code&gt;, при этом есть и вариант с добавлением «миксинов» с помощью директив &lt;code&gt;@apply&lt;/code&gt;, &lt;code&gt;@variant&lt;/code&gt; (что в целом ни хорошо, ни плохо, а уже было в SASS)&lt;/li&gt;
&lt;li&gt;поисковая страница Google теперь &lt;a href=&quot;https://techcrunch.com/2025/01/17/google-begins-requiring-javascript-for-google-search/&quot;&gt;может требовать у пользователя включить JS&lt;/a&gt;, что само по себе ок мув, как и то, что сейчас SPA-страницы индексируются тоже уже ок на равне со статическими&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rolldown/rolldown/releases/tag/v1.0.0-beta.1&quot;&gt;вышла первая бета Rolldown&lt;/a&gt; — замены Rollup + esbuild для Vite: переписанный на Rust новый бандлер Rolldown помимо обратно-совместимого API будет иметь в будущем ещё и фичи, которые Rollup не поддерживает: аналог webpack-овского &lt;a href=&quot;https://webpack.js.org/plugins/split-chunks-plugin/#optimizationsplitchunks&quot;&gt;&lt;code&gt;optimization.splitChunks&lt;/code&gt;&lt;/a&gt;, HMR, а так же Module Federation&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vitest.dev/blog/vitest-3&quot;&gt;выпущен Vitest 3.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;доработан вывод репортов в консоль (стало выглядеть приятнее)&lt;/li&gt;
&lt;li&gt;при наличии нескольких проектов, теперь удобно конфигурировать это в поле &lt;code&gt;workspace&lt;/code&gt; в &lt;code&gt;vitest.config&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавлена поддержка конфигурации нескольких браузеров, чтобы использовать один сервер для прогона тестов сразу в нескольких браузерах&lt;/li&gt;
&lt;li&gt;запуск теста по номеру строки в файле, где он написан&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/advanced-attr&quot;&gt;в Chrome 133+ появится поддержка&lt;/a&gt; обновлённой функции &lt;code&gt;attr()&lt;/code&gt;, которая раньше работала только внутри свойства &lt;code&gt;content&lt;/code&gt;, а теперь сможет работать с любым свойством:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div data-foo=&quot;blue&quot;&amp;gt;test&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;div {
  color: attr(data-foo type(&amp;lt;color&amp;gt;), red);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://react-spectrum.adobe.com/releases/2025-01-15.html&quot;&gt;вышло январское обновление React Spectrum/Aria&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;в компоненте дейт-пикера и календаря добавлен проп &lt;code&gt;firstDayOfWeek&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавлены CSS-транзишны для оверлеев &lt;code&gt;Modal&lt;/code&gt;, &lt;code&gt;Popover&lt;/code&gt;, &lt;code&gt;Tooltip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;выпущена альфа-версия компонента &lt;code&gt;Autocomplete&lt;/code&gt; и &lt;a href=&quot;https://www.npmjs.com/package/@react-aria/test-utils&quot;&gt;@react-aria/test-utils&lt;/a&gt; — либы с тест-утилитами для компонентов&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ohshitgit.com/&quot;&gt;ohshitgit&lt;/a&gt; — набор кейсов, когда у вас случилось что-то нехорошее в git, и как это вернуть взад&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/ruilisi/fortune-sheet&quot;&gt;fortune-sheet&lt;/a&gt; — либа &lt;code&gt;React&lt;/code&gt; / &lt;code&gt;Vue&lt;/code&gt; + &lt;code&gt;immer&lt;/code&gt; на TS для создания Excel-like-таблиц&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/arktypeio/arktype&quot;&gt;arktype&lt;/a&gt; — рантайм валидатор, инферит TS-типы, быстрый&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tigerabrodi.blog/become-expert-in-react-query&quot;&gt;React Query&lt;/a&gt; — это не data-fetching-либа, а менеджер состояния, которое живёт на сервере; именно поэтому, если источник правды вашего приложения сохраняется на бэке, то React Query заменяет собой необходимость использования отдельного стейт-менеджера на клиенте&lt;/li&gt;
&lt;li&gt;все либы для работы с хоткеями &lt;a href=&quot;https://blog.duvallj.pw/posts/2025-01-10-all-javascript-keyboard-shortcut-libraries-are-broken.html&quot;&gt;опираются на задепрекейченные поля&lt;/a&gt;, поэтому использовать их нужно осторожно; если ли работать с хоткеями без либ, то нужно использовать поле &lt;code&gt;key&lt;/code&gt;, латинские буквы (A-Z) и арабские цифры (0-9), нормализовывать символ с помощью &lt;code&gt;.toLowerCase()&lt;/code&gt; и &lt;code&gt;.toUpperCase()&lt;/code&gt;, использовать &lt;code&gt;Shift&lt;/code&gt; для модификации и не использовать для неё &lt;code&gt;Alt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://macarthur.me/posts/template-literal-types/&quot;&gt;фишки динамических строковых литералов в TS&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// ключи
interface User {
  customerKey: `cus_${string}`;
}

// версия
type Version = `v${number}.${number}.${number}`;

// расширение
type ImageExtension = `png` | `jp${`e` | ``}g` | `webp`;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.photoroom.com/inside-photoroom/picking-a-state-management-library-why-we-went-with-mobx-&quot;&gt;опыт миграции стейта&lt;/a&gt; с &lt;code&gt;useContext&lt;/code&gt; на MobX: всё ништяк, но пришлось писать свою обёртку для использования &lt;code&gt;useQuery&lt;/code&gt; из &lt;a href=&quot;https://tanstack.com/query/latest&quot;&gt;TanStack Query&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://2ality.com/2025/01/tsconfig-json.html&quot;&gt;разложенный по косточкам tsconfig&lt;/a&gt; с вариациями: база, npm-пакет, Node.js, web, запуск ts напрямую (без js), только тайпчекинг&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nerdy.dev/6-css-snippets-every-front-end-developer-should-know-in-2025&quot;&gt;ежегодная подборка свежих CSS-фич&lt;/a&gt;, которые можно уже использовать: всё, что касается &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; и &lt;code&gt;popover&lt;/code&gt;, конечно, только для внутренних проектов сгодится, а вот применение &lt;code&gt;@property&lt;/code&gt; и &lt;code&gt;linear()&lt;/code&gt; для анимаций, которые не страшно, если отвалятся, уже прям маст-хэв&lt;/li&gt;
&lt;li&gt;напоминание, что ссылки не только на &lt;code&gt;#якорь&lt;/code&gt;, но и &lt;a href=&quot;https://codepen.io/chriscoyier/pen/GgKMrMP&quot;&gt;на определённый текстовый фрагмент на странице&lt;/a&gt; (а заодно и стилизация выделенного текста по &lt;code&gt;::target-text&lt;/code&gt;) уже работают по всех современных браузерах, для некритичных вещей точно можно тащить в прод&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cispa.de/en/research/publications/84162-cascading-spy-sheets-exploiting-the-complexity-of-modern-css-for-email-and-browser-fingerprinting&quot;&gt;современные CSS-фичи&lt;/a&gt; типа &lt;code&gt;@container()&lt;/code&gt;, &lt;code&gt;@container style()&lt;/code&gt;, &lt;code&gt;@supports&lt;/code&gt; дают возможность старгетироваться на конкретное устройство и это приводит к возможности злонамеренного отслеживания типа устройства, ОС, почтового клиента: решение — предзагружать все «условные» ассеты (картинки, шрифты) заранее, а не только те, которые «подходят» устройству&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;вместо использования &lt;code&gt;role=button&lt;/code&gt;, &lt;code&gt;role=link&lt;/code&gt; и остальных проще &lt;a href=&quot;https://html5accessibility.com/stuff/2025/01/11/html-developers-please-consider-in-the-year-of-2021/&quot;&gt;использовать соответствующий HTML-элемент&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;множественные редиректы на открытии страницы могут &lt;a href=&quot;https://www.debugbear.com/blog/avoid-multiple-page-redirects&quot;&gt;влиять в негативную строну&lt;/a&gt; на метрики перфоманса LCP и FCP&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 14.02.2025</title><link>https://juwain.github.io/web-platform/blog/2025-02-14/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-02-14/</guid><description>Новости веб-платформы</description><pubDate>Fri, 14 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/133&quot;&gt;вышел Chrome 133&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;допилили &lt;code&gt;popover&lt;/code&gt; в HTML и JS&lt;/li&gt;
&lt;li&gt;поддержали обновление функции &lt;code&gt;attr()&lt;/code&gt;, которая раньше работала только внутри свойства &lt;code&gt;content&lt;/code&gt;, а теперь сможет работать с любым свойством&lt;/li&gt;
&lt;li&gt;добавили псевдокласс &lt;code&gt;:open&lt;/code&gt; для открытых &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;заработали &lt;code&gt;@container&lt;/code&gt;-запросы, управляющие скроллом &lt;code&gt;@container scroll-state((stuck: top) and (stuck: left))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержали семейство «подрезающих» свойств &lt;code&gt;text-box&lt;/code&gt;, &lt;code&gt;text-box-trim&lt;/code&gt;, &lt;code&gt;text-box-edge&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в &lt;code&gt;Animation API&lt;/code&gt; появилось свойство &lt;code&gt;overallProgress&lt;/code&gt;, показывающее прогресс анимации&lt;/li&gt;
&lt;li&gt;у нод появился метод &lt;code&gt;Node.prototype.moveBefore&lt;/code&gt;, позволяющий перемещать DOM-ноду в другое место без потери состояния (&lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; не перезагружается, активный элемент остаётся в фокусе, анимации/транзишны продолжают проигрываться) (&lt;a href=&quot;https://github.com/facebook/react/pull/32036&quot;&gt;в React тоже собираются оперативно поддержать&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;добавлена возможность включать несколько import maps в один документ, браузер смерджит их сам&lt;/li&gt;
&lt;li&gt;появился интерфейс &lt;code&gt;FileSystemObserver&lt;/code&gt;, который может оповещать сайт об изменениях в файловой системе, к которой был выдан доступ&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;у JSR (альтернативный npm-реестр от создателей Deno) &lt;a href=&quot;https://deno.com/blog/jsr-open-governance-board&quot;&gt;появился совет директоров&lt;/a&gt; в крайне интересном составе (Evan You, Isaac Schlueter, James Snell, Luca Casonato, Ryan Dahl), поэтому возможно в обозримом будущем вы таки начнёте пользоваться JSR&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/blog/2025/02/09/3.5.0&quot;&gt;вышла новая версия Prettiter 3.5&lt;/a&gt;: добавлена пара новых опций и поддержан ts-формат конфига (с началом экспериментальной поддержки TS в Node.js видимо многие будут переводить конфиги на .ts)&lt;/li&gt;
&lt;li&gt;вышли &lt;a href=&quot;https://2024.stateofreact.com/en-US&quot;&gt;результаты опроса State of React&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;многим доставляет боль использование &lt;code&gt;forwardRef&lt;/code&gt; (видимо потому что в основном используют 18 версию React для SPA), указание зависимостей в &lt;code&gt;useEffect&lt;/code&gt;, а также сложность Next.js и Server Components&lt;/li&gt;
&lt;li&gt;самые популярные либы: Zustand, семейство TanStack, Astro, shadcn/ui, Radix, React Aria, Jotai; самые непопулярные: CRA, Redux, Gatsby, Reaact Bootstrap; для анимаций пользуются Motion, React-Spring, GSAP; для работы с формами React Hook Form, Formik; для тестов Jest и Testing Library; для валидации Zod, Yup; для аутентификации Auth0, Auth.js, Passport&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/XaveScor/smartbundle&quot;&gt;smartbundle&lt;/a&gt; — тула для сборки приложений без дополнительных конфигов: команда &lt;code&gt;smartbundle&lt;/code&gt; сгенерит CJS- и ESM-сборки, автоматически трансформирует JSX, не забудет о сорсмапах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jonschlinkert/get-value&quot;&gt;get-value&lt;/a&gt; — аналог lodash-евского &lt;code&gt;_.get&lt;/code&gt;, чтобы достать значение объекта по строке &lt;code&gt;a.b.c.d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lea.verou.me/blog/2025/style-observer/&quot;&gt;Style Observer&lt;/a&gt; — обзёрвер изменения значений CSS-свойств и кастомных свойств на основе &lt;a href=&quot;https://caniuse.com/mdn-css_properties_transition-behavior&quot;&gt;&lt;code&gt;transition-behavior: allow-discrete&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://enes.in/sorted-colors/&quot;&gt;sorted-colors&lt;/a&gt; — проект для тех, кто испытывает необъяснимую симпатию к именованным цветам в CSS, позволяет увидеть их все по оттенку&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;про разбиение лонг-тасков в JS уже писал ранее, но тут &lt;a href=&quot;https://macarthur.me/posts/long-tasks/&quot;&gt;автор собрал в одной статье почти все рецепты&lt;/a&gt;: &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;async/await&lt;/code&gt; + &lt;code&gt;Promise&lt;/code&gt;, &lt;code&gt;scheduler.postTask()&lt;/code&gt;, &lt;code&gt;scheduler.yield()&lt;/code&gt;, &lt;code&gt;requestAnimationFrame()&lt;/code&gt; и даже экзотический &lt;code&gt;MessageChannel()&lt;/code&gt; — если послать туда сообщение, то оно сразу же выполнится (разве что не упомянуто о &lt;code&gt;queueMicrotask&lt;/code&gt; и &lt;code&gt;requestIdleCallback&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://liveblocks.io/blog/which-rich-text-editor-framework-should-you-choose-in-2025#comparison-table&quot;&gt;сравнительная таблица текстовых редакторов&lt;/a&gt;, если вам нужно сделать этот выбор в 2025: фреймворкоориентированность, многопользовательский режим + комментарии (сразу предостережение — &lt;a href=&quot;https://smoores.dev/post/why_i_rebuilt_prosemirror_view/&quot;&gt;ProseMirror с React не дружит&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;и в догонку &lt;a href=&quot;https://github.com/Elanis/web-to-desktop-framework-comparison&quot;&gt;сравнительная таблица web-to-desktop-фреймворков&lt;/a&gt; (Electron, Tauri…): язык, движок, зависимости, фичи, интеграция во фреймворки, поддержка ОС, размер приложений, расход памяти, время билда и старта&lt;/li&gt;
&lt;li&gt;если вам приходится &lt;a href=&quot;https://www.stefanjudis.com/today-i-learned/the-difference-ts-ignore-and-ts-expect-error/&quot;&gt;сознательно заглушать ошибки в TS&lt;/a&gt;, то лучше использовать &lt;code&gt;@ts-expect-error&lt;/code&gt;, чем &lt;code&gt;@ts-ignore&lt;/code&gt;, так вы явно заметите заглушенное место, когда ошибка перестанет происходить и сможете убрать заглушку&lt;/li&gt;
&lt;li&gt;никогда не поздно вдруг понять, что &lt;code&gt;npm ci&lt;/code&gt; это «&lt;a href=&quot;https://dev.to/impranavkale/avoiding-production-disasters-with-npm-ci-the-key-to-stable-deployments-47ib&quot;&gt;clean install&lt;/a&gt;», а не «continuous integration»&lt;/li&gt;
&lt;li&gt;оператор &lt;code&gt;satisfies&lt;/code&gt; в TS &lt;a href=&quot;https://2ality.com/2025/02/satisfies-operator.html&quot;&gt;может быть полезен&lt;/a&gt; для:
&lt;ul&gt;
&lt;li&gt;уточнения, что объект с неполным набором полей — это ок &lt;code&gt;satisfies Partial&amp;lt;Record&amp;lt;key, val&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;типизации при преобразовании в JSON-строку &lt;code&gt;JSON.stringify({ /*···*/ } satisfies SomeType)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;типизации default-экспорта &lt;code&gt;export default ((str) =&amp;gt; str.toUpperCase()) satisfies StringCallback;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;доехавший везде &lt;code&gt;@property&lt;/code&gt; даёт возможность создать &lt;a href=&quot;https://www.jomaendle.com/blog/focus-zoom-at-property&quot;&gt;эффект «динамического фокуса»&lt;/a&gt; (всё в блюре, круглая область в «фокусе») с помощью &lt;code&gt;mask-image: radial-gradient(... var(--focal-size) ...)&lt;/code&gt;, к кастомному свойству внутри функции применяется транзишн&lt;/li&gt;
&lt;li&gt;на мониторах с крупными пикселями ультра-тонкие шрифты будут выглядеть нечётко, лучше &lt;a href=&quot;https://muffinman.io/blog/font-weight-based-on-dpi/&quot;&gt;включать такую насыщенность шрифтов под медиа-фичей&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
  h1 {
    font-weight: 100;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:focus-visible&lt;/code&gt; &lt;a href=&quot;https://fullystacked.net/programmatic-focus-styles/&quot;&gt;стилизует только фокусировку с клавиатуры&lt;/a&gt;, но есть ещё и дополнительная опция у метода &lt;code&gt;.focus({focusVisible: false})&lt;/code&gt; (Safari TP и FF)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloudfour.com/thinks/a-content-list-with-bulk-actions-using-ancient-html-and-modern-css/&quot;&gt;ещё один юзкейс&lt;/a&gt; для селектора &lt;code&gt;:has&lt;/code&gt;: показывать/скрывать дополнительный блок, когда выбран/не выбран чекбокс в списке: &lt;code&gt;:has(:checked) {}, :not(:has(:checked)) {}, :not(:has(:focus-visible)) {}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;значения в атрибуте &lt;code&gt;step&lt;/code&gt; у &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; &lt;a href=&quot;https://piccalil.li/blog/using-the-step-and-pattern-attributes-to-make-number-inputs-more-useful/&quot;&gt;могут быть не только целочисленными&lt;/a&gt;, а в &lt;code&gt;pattern&lt;/code&gt;-е можно проверить корректность этих значений&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;если вы хотите неиронично использовать GIF-ку в 2025, то &lt;a href=&quot;https://fullystacked.net/how-to-gif-2025/&quot;&gt;лучше заместо использовать видео-формат AV1&lt;/a&gt; (поддерживается во всех браузерах, кроме Safari, там нужен фолбек в mp4)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 21.02.2025</title><link>https://juwain.github.io/web-platform/blog/2025-02-21/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-02-21/</guid><description>Новости веб-платформы</description><pubDate>Fri, 21 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v20.18.3&quot;&gt;в стабильную Node.js 20&lt;/a&gt; бэкпортирована фича &lt;code&gt;require(esm)&lt;/code&gt; (импорт EMS-модулей через синтаксис CJS-&lt;code&gt;require&lt;/code&gt;), а это значит, что в апреле 2025, когда закончится поддержка Node.js 18, CJS из сборок можно будет выпиливать&lt;/li&gt;
&lt;li&gt;в апреле 2024 &lt;a href=&quot;https://web.dev/blog/popover-baseline&quot;&gt;Popover API выкатился во всех браузерах&lt;/a&gt;, но по январь 2025 был крит-баг в iOS Safari (до выхода Safari 18.3), который не давал полноценно использовать фичу (так что если вы с новой фичей выкатили баг в прод и сразу его поправили, считайте, что ничего не было)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-530/&quot;&gt;обновился Astro 5.3&lt;/a&gt;: ускорили, допиливают Session Storage API и интеграцию с Netlify&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/githubnext/monaspace/releases/tag/v1.200&quot;&gt;обновился моноширинный шрифт Monaspace от Github&lt;/a&gt;, теперь в него включены иконки &lt;a href=&quot;https://www.nerdfonts.com/&quot;&gt;Nerd Fonts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/blog/interop-2025&quot;&gt;выработали фокус инициативы Interop на 2025 год&lt;/a&gt;, предположительно в этом году у нас появятся во всех браузерах: Anchor positioning, View transitions ,&lt;code&gt;@scope&lt;/code&gt;, &lt;code&gt;scrollend&lt;/code&gt; event, Core Web Vitals, а также исправятся баги с &lt;code&gt;backdrop-filter&lt;/code&gt;, &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;, &lt;code&gt;text-decoration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ESLint больше не EcmaScriptLint, а ExtremelySuperLint (шутка), а именно &lt;a href=&quot;https://eslint.org/blog/2025/02/eslint-css-support/&quot;&gt;стал официально поддерживать линтинг CSS&lt;/a&gt;: встроенные в &lt;code&gt;@eslint/css&lt;/code&gt; правила проверяют пустые блоки, дублирующиеся импорты, невалидные @-правила, а также способствуют использованию правил &lt;a href=&quot;https://web.dev/baseline&quot;&gt;baseline&lt;/a&gt; и @-layer (не шутка)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/blog/2025/02/14/sunsetting-create-react-app&quot;&gt;CreateReactApp окончательно и бесповоротно задепрекейчен&lt;/a&gt;, так как нет мейнтейнера и плюшек внутри и вообще таки зачем вам голый React, давайте уже скорее устанавливайте метафреймворк&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/TanStack/create-tsrouter-app&quot;&gt;create-tsrouter-app&lt;/a&gt; — банда TanStack поджидала момент, когда анонсируют депрекейт CRA, подсуетились и подготовили свою замену с поддержкой JS/TS, TW/CSS и конечно же TanStack Router&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/DavidHDev/react-bits&quot;&gt;react-bits&lt;/a&gt; — React-компоненты с анимациями и красивыми свистелками (меня впечатлили &lt;a href=&quot;https://www.reactbits.dev/animations/splash-cursor&quot;&gt;splash-cursor&lt;/a&gt; и &lt;a href=&quot;https://www.reactbits.dev/backgrounds/orb&quot;&gt;orb&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dai-shi/use-context-selector&quot;&gt;use-context-selector&lt;/a&gt; — селектор из React-контекста в стиле Zustand &lt;code&gt;useContextSelector(context, (v) =&amp;gt; v[0].count)&lt;/code&gt; (от создателя, внезапно, Zustand)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Intl.DurationFormat&lt;/code&gt;, который вскоре доедет в оставшийся FF, даёт возможность в разном виде в зависимости от локали &lt;a href=&quot;https://www.raymondcamden.com/2025/02/13/using-intldurationformat-for-localized-durations&quot;&gt;форматировать период даты-времени&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const durationFormatter = new Intl.DurationFormat(navigator.language, {
  style: &quot;long&quot;,
});

durationFormatter.format(duration);

// 360 minutes, 360m, 0:360:00, 360 Min...
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;если для вас в TS дженерики с тернарниками внутри выглядят устрашающе, не пугайтесь, &lt;a href=&quot;https://www.stefanjudis.com/today-i-learned/iterate-typescript-union-type/&quot;&gt;они добрые&lt;/a&gt;: если тип с дженериком — это «функция с параметрами», то тернарник внутри — это просто единственный возможный в TS способ описать «условие», в зависимости от которого «функция» будет возвращать то или иное значение:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;type Something&amp;lt;T&amp;gt; = T extends number ? never : T;
// «функция» возвращает ничего, если в T передано число, иначе - переданное значение

type Remove&amp;lt;T, R&amp;gt; = T extends R ? never : T;
// «функция» возвращает ничего, если T содержится в R, иначе - переданное значение

type AllColors = &quot;Black&quot; | &quot;White&quot; | &quot;Orange&quot;;
type RealColors = Remove&amp;lt;AllColors, &quot;Black&quot; | &quot;White&quot;&amp;gt;;
// type RealColors = &quot;Orange&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;если нужно реализовать &lt;a href=&quot;https://dev.to/zakariachahboun/say-goodbye-to-websockets-why-sse-might-be-your-new-best-friend-4d7n&quot;&gt;одностороннюю отправку сообщения с сервера на клиент&lt;/a&gt; (а не двустороннее соединение), то можно использовать SSE вместо WebSockets: общение идёт по HTTP, нативно работает во всех браузерах через &lt;code&gt;new EventSource()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cloudfour.com/thinks/faux-containers-in-css-grids/&quot;&gt;чтобы создать выезжающие за пределы блока элементы&lt;/a&gt;, но при этом чтобы они были в потоке и занимали место, можно воспользоваться гридом с пустыми «рядами», размером &lt;code&gt;auto&lt;/code&gt;, чтобы они растянулись на нужное «выпирающее» пространство &lt;code&gt;grid-template-rows: auto [container-start] repeat(4, auto) [container-end] auto;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://polypane.app/blog/decoding-css-selectors-has-not-vs-not-has/&quot;&gt;селекторы &lt;code&gt;:has&lt;/code&gt; и &lt;code&gt;:not&lt;/code&gt; не так просты&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.card:has(:not(img))&lt;/code&gt; выберет &lt;code&gt;.card&lt;/code&gt;, в котором внутри есть любой элемент, кроме &lt;code&gt;img&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.card:not(:has(img))&lt;/code&gt; выберет &lt;code&gt;.card&lt;/code&gt;, в котором вообще нет &lt;code&gt;img&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;псевдокласс &lt;code&gt;::selection&lt;/code&gt; меняет фоновый цвет выделенного текста, но прикол в том, что &lt;a href=&quot;https://frontendmasters.com/blog/rainbow-selection-in-css/&quot;&gt;цвет не обязательно делать один для всей страницы&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;::selection {
  background-color: var(--brandColor);
}

:nth-child(2n) {
  --brandColor: red;
}

:nth-child(2n + 1) {
  --brandColor: blue;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;свойство &lt;code&gt;zoom&lt;/code&gt; делает похожую на &lt;code&gt;scale&lt;/code&gt; операцию, но при этом &lt;a href=&quot;https://css-tip.com/zoom/&quot;&gt;«отскейленный» блок не влияет на лейаут&lt;/a&gt; (изменяется по сути композитный слой с «картинкой» блока), а «отзумленный» — влияет, то есть вызывает перестроение лейаута&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oreilly.com/radar/the-end-of-programming-as-we-know-it/&quot;&gt;ещё один тейк&lt;/a&gt; к сторону того, что AI меняет нашу работу, но не отбирает её: каким бы хорошим и быстрым AI не был для создания прототипов, чтобы пройти путь от протототипа до продакшена нужно учесть краевые случаи, соединить с другими частями системы и, в конце концов, взять ответственность за итоговое решение, а для этого нужны мы с вами (от себя добавлю, что в последнее время отключил ассистента в IDE, со временем задалбывают неостанавливающиеся «советы», порой не хватает интроверсного соло-кодинга)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 07.02.2025</title><link>https://juwain.github.io/web-platform/blog/2025-02-07/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-02-07/</guid><description>Новости веб-платформы</description><pubDate>Fri, 07 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://vercel.com/blog/vercel-acquires-tremor&quot;&gt;Vercel поглощает компанию Tremor&lt;/a&gt; (опенсорсная UI-либа на React, TW, Radix), чтобы использовать дашборды/чарты у себя в админке и в генераторе интерфейсов v0&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-520/&quot;&gt;вышел Astro 5.2&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддержан TW 4 через плагин &lt;code&gt;@tailwindcss/vite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавлен редирект с trailing-slash урлов: &lt;code&gt;/about/&lt;/code&gt;, &lt;code&gt;/about&lt;/code&gt; или даже &lt;code&gt;/about///&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;а также редиректы на &lt;code&gt;http&lt;/code&gt; или &lt;code&gt;https&lt;/code&gt;, прописываемые сразу в конфиге&lt;/li&gt;
&lt;li&gt;поддержан формат TOML для мета-информации в контентных файлах&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;выпущен &lt;a href=&quot;https://github.com/npm/cli/blob/latest/CHANGELOG.md#1110-2025-01-29&quot;&gt;npm 11.1.0&lt;/a&gt;: добавлена команда &lt;code&gt;undeprecate&lt;/code&gt; (заодно узнал, что существует команда &lt;code&gt;deprecate&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://guybedford.com/es-module-shims-2.0&quot;&gt;вышел набор полифиллов ES Module Shims 2.0&lt;/a&gt;: помимо поддержки &lt;code&gt;import maps&lt;/code&gt; в старых браузерах эти полифиллы открывают возможность запускать type-erasable-код на TS прямиком в браузере, без компиляции&lt;/li&gt;
&lt;li&gt;обновился &lt;a href=&quot;https://turbo.build/blog/turbo-2-4&quot;&gt;Turborepo 2.4&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появились эксперименты: команда &lt;code&gt;boundaries&lt;/code&gt; (проверяет реп на следование бестпрактисам для лучшего кеширования сборки) и кеширование в watch-режиме&lt;/li&gt;
&lt;li&gt;тула теперь даёт рекомендации по найденным кольцевым зависимостям в проекте&lt;/li&gt;
&lt;li&gt;поддерживает новый тип конфига ESLint&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/135.0/releasenotes/&quot;&gt;выпущен Firefox 135.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;прекратилась поддержка нестандартного &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-user-input&quot;&gt;&lt;code&gt;-moz-user-input&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;появилась поддержка &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/rawJSON&quot;&gt;&lt;code&gt;JSON.rawJSON()&lt;/code&gt;&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/isRawJSON&quot;&gt;&lt;code&gt;JSON.isRawJSON()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;выкатили за флагом поддержку Temporal API (продвинутая работа с датами) и Prioritized Task Scheduling API (&lt;code&gt;scheduler.yield()&lt;/code&gt; для «создания пауз» в работе эвент-лупа)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gravity-ui/uikit/releases/tag/v7.0.0&quot;&gt;обновился яндексовский ui-kit GravityUI до версии v7.0.0&lt;/a&gt;: смигрировали с popper.js на floating-ui, теперь билдится в ES2022&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/huozhi/bunchee&quot;&gt;bunchee&lt;/a&gt; — безконфиговый бандлер для JS/TS-пакетов (все нужные данные для конфига берутся из &lt;code&gt;package.json&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/puffinsoft/jscanify&quot;&gt;jscanify&lt;/a&gt; — либа для сканирования бумажных документов из картинки или из потока камеры&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shapecatcher.com/index.html&quot;&gt;shapecatcher&lt;/a&gt; — если нужно найти unicode-символ (в том числе эмодзи), то можно его коряво нарисовать руками и поиск выдаст похожие&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/antfu/node-modules-inspector&quot;&gt;node-modules-inspector&lt;/a&gt; — интерактивный интерфейс для изучения &lt;code&gt;node_modules&lt;/code&gt; в проекте&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://marvinh.dev/blog/modern-way-to-write-javascript-servers/&quot;&gt;простейший подход к сервингу&lt;/a&gt;, который возможно вскоре будет работать и в Node (но уже сейчас поддерживается в Deno):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// server
const myApp = async (req: Request) =&amp;gt; {
  return new Response(&quot;Hello world!&quot;);
};

const response = await myApp(new Request(&quot;http://localhost/&quot;));
const text = await response.text();
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fullystacked.net/cookiestore-api/&quot;&gt;Cookie Store API&lt;/a&gt; — асинхронное API на смену &lt;code&gt;document.cookie&lt;/code&gt; (только Хромиум, но есть в «ночных» версия Safari и FF):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;await cookieStore.set()/get()/getAll()/delete()

// а также эвент на изменение
cookieStore.addEventListener(&quot;change&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;хук &lt;code&gt;useOptimistic&lt;/code&gt; из React 19 подходит &lt;a href=&quot;https://spin.atomicobject.com/useoptimistic-asynchronous-updates/&quot;&gt;для обработки кейсов «промежуточных» состояний интерфейса&lt;/a&gt; при асинхронном выполнением действий: ушёл запрос, ждём ответ, пока что оптимистично показали результат&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cekrem.github.io/posts/open-closed-principle-in-react/&quot;&gt;принцип Open-Closed (sOlid) на примере React-компонентов и хуков&lt;/a&gt;: добавляем новую модификацию компонента/функции, не трогаем базовый, а дополняем в новом компоненте/функции&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@starting-style&lt;/code&gt; можно применять в том числе для анимации показа/сокрытия &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; и подложки &lt;code&gt;::backdrop&lt;/code&gt;: &lt;a href=&quot;https://www.smashingmagazine.com/2025/01/transitioning-top-layer-entries-display-property-css/&quot;&gt;чтобы они плавно показывались и скрывались&lt;/a&gt; без дополнительных телодвижений в коде (типа сменить туда-сюда &lt;code&gt;opacity&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bram.us/2025/01/29/view-transitions-page-interactivity/&quot;&gt;при выполнении View Transition-ов&lt;/a&gt; страница перестаёт быть интерактивной — это из-за псевдоэлемента &lt;code&gt;::view-transition&lt;/code&gt;, который показывается оверлеем над всем вьюпортом; поправить это можно, выключив &lt;code&gt;pointer-events&lt;/code&gt; для него:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;::view-transition {
  pointer-events: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/revisiting-css-multi-column-layout/&quot;&gt;многоклоночный лейаут&lt;/a&gt; уже в CSS сто лет в обед, но всё время был какой-то багованый; сейчас же ситуация получше, вполне годится для адаптивных лейаутов длинных текстов, когда текст «перетекает» из одной колонки в другу (кейс специфичный, но конкретно для него не годятся флексбоксы/гриды)&lt;/li&gt;
&lt;li&gt;для &lt;a href=&quot;https://html-css-tip-of-the-week.netlify.app/tip/max-width-fit-content/&quot;&gt;кейса&lt;/a&gt;, когда происходит нежелательный перенос текста (например, в кнопке), уместнее использовать &lt;code&gt;min-width: fit-content&lt;/code&gt;, который подтянет ширину под контент и справится с задачей переноса более аккуратно, чем &lt;code&gt;text-wrap: nowrap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cloudfour.com/thinks/justified-text-better-than-expected/&quot;&gt;для послогового переноса слов&lt;/a&gt; используется &lt;code&gt;hyphens: auto&lt;/code&gt;, но в дополнение есть ещё свойство &lt;code&gt;hyphenate-limit-chars&lt;/code&gt;, ограничивающее количество символов, которые будут перенесены (только Хромиум)&lt;/li&gt;
&lt;li&gt;стилизация HTML-элемента &lt;code&gt;&amp;lt;meter&amp;gt;&lt;/code&gt; под &lt;a href=&quot;https://www.mikeaparicio.com/posts/2025-01-23-styling-a-meter-element-with-css-and-svg/&quot;&gt;«звёздный» рейтинг&lt;/a&gt;: ставим на фон SVG с прозрачной «маской», заполняем цветом&lt;/li&gt;
&lt;li&gt;с &lt;code&gt;clip-path: polygon()&lt;/code&gt; и &lt;code&gt;transition&lt;/code&gt; можно сделать &lt;a href=&quot;https://frontendmasters.com/blog/creating-an-angled-slider/&quot;&gt;«скошенный» слайдер&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;если вы собираете стили с помощью Vite или обходитесь вообще без билд-тулы, то дополнительно &lt;a href=&quot;https://css-tricks.com/compiling-css-with-vite-and-lightning-css/&quot;&gt;можно использовать LightningCSS&lt;/a&gt; в качестве минификатора + «пост»-процессора стилей (новенькие CSS-фичи в коде будут фолбечиться до стабильных)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://evanhahn.com/my-failed-attempt-to-shrink-all-npm-packages-by-5-percent/&quot;&gt;история&lt;/a&gt; про то, как разработчик выяснил, что Zopfli лучше сжимает в формат &lt;code&gt;gzip&lt;/code&gt;, но при этом медленнее, чем сам &lt;code&gt;gzip&lt;/code&gt;, и попробовал «продать» эту тему в &lt;code&gt;npm&lt;/code&gt;, чтобы сжать все npm-пакеты; его предложение не приняли, но зато теперь вы знаете, что если нужно максимальное сжатие в ущерб скорости, то есть Zopfli&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 28.02.2025</title><link>https://juwain.github.io/web-platform/blog/2025-02-28/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-02-28/</guid><description>Новости веб-платформы</description><pubDate>Fri, 28 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;лучше поздно, чем никогда: опубликован &lt;a href=&quot;https://www.w3.org/TR/2025/NOTE-css-2024-20250225/&quot;&gt;CSS Snapshot 2024&lt;/a&gt;, внутри появился новый раздел &lt;a href=&quot;https://www.w3.org/TR/2025/NOTE-css-2024-20250225/#reliable-cr&quot;&gt;Reliable Candidate Recommendations&lt;/a&gt;, куда собраны устоявшиеся спеки со стабильной реализацией в браузерах, но ещё немного косячной, сейчас туда включили: Media Queries Level 4, CSS Scroll Snap Module Level 1, CSS Scrollbars Styling Module Level 1, CSS Grid Layout Module Level 1 и 2&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/v2.2&quot;&gt;обновился Deno до 2.2&lt;/a&gt;: главное, что стал поддерживаться &lt;code&gt;node:sqlite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/vuejs/pinia/releases/tag/v3.0.0&quot;&gt;в Pinia 3.0&lt;/a&gt; убрана поддержка Vue 2&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-v1.2.3&quot;&gt;вышел Bun v1.2.3&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;вернули то, с чего начинался Bun — дев-сервер, &lt;code&gt;bun ./index.html&lt;/code&gt; поднимет локальный сервер для статики&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Bun.serve()&lt;/code&gt; на сервере теперь умеет в роуты, то есть можно описать полноценный API с ощущением «на коленке»&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://techcrunch.com/2025/02/24/perplexity-teases-a-web-browser-called-comet/&quot;&gt;в AI-поисковике Perplexity объявили&lt;/a&gt;, что разрабатывают свой браузер Comet (под капотом видимо всё равно будет chromium 😏), видимо прям разогналась волна «а давайте перепридумаем велосипед с агентами и нейросетями»; считаю, что, чем пихать AI-фичи в уже привычные браузеры, всё лучше выделить это всё в отдельную нишу любителей AI-приблуд&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/aidenybai/react-scan/releases/tag/v0.2.0&quot;&gt;обновился React Scan до v0.2.0&lt;/a&gt;: интересный мув из разового использования инструмента для нахождения перфоманс-проблем в сторону постоянного использования и накопления «уведомлений» о собранных проблемах&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nextjs.org/blog/next-15-2&quot;&gt;в Next.js 15.2&lt;/a&gt; появилась экспериментальная поддержка &lt;code&gt;View Transitions API&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-8-rc/&quot;&gt;анонсирован TS 5.8 RC&lt;/a&gt;: поддерживает &lt;code&gt;require(esm)&lt;/code&gt; (а также флажок обратной совместимости &lt;code&gt;--module node18&lt;/code&gt;) и флаг &lt;code&gt;--erasableSyntaxOnly&lt;/code&gt; для искоренения enums, namespaces, параметрических свойств класса и import-алиасов (мсье &lt;a href=&quot;https://www.totaltypescript.com/erasable-syntax-only&quot;&gt;Matt Pocock настроен считать эти фичи TS&lt;/a&gt;, требующие компиляции, ошибками в проектировании, и рад нововведениям)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/L-Blondy/up-fetch&quot;&gt;up-fetch&lt;/a&gt; — обёртка над &lt;code&gt;fetch&lt;/code&gt;, что интересно с поддержкой недавно вышедшей &lt;a href=&quot;https://github.com/standard-schema/standard-schema&quot;&gt;Standard Schema Specification&lt;/a&gt;: в параметрах запроса передаётся валидационная схема в стандартизированном виде, например, с Zod&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nolanlawson/fuite&quot;&gt;fuite&lt;/a&gt; — тула, запускающая Puppeteer и долго ходящая по ссылкам вашей SPA в поисках &lt;s&gt;потерянного времени&lt;/s&gt; утечек памяти&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;юзкейс, когда нужно в DOM переставить первый элемент в контейнере в конец (в слайдере, например, при показе последнего слайда), &lt;a href=&quot;https://joshtronic.com/2025/02/16/how-to-move-the-first-element-to-the-end-in-javascript/&quot;&gt;решается строчкой&lt;/a&gt; &lt;code&gt;container.appendChild(container.firstElementChild)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.royalbhati.com/posts/why-js-is-fast&quot;&gt;JS часто бывает быстр за счёт JIT-компиляции&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;JS-код парсится в AST (Abstract Syntax Tree) →&lt;/li&gt;
&lt;li&gt;AST преобразуется в байт-код (промежуточная версия кода, выполняемая V8) и оптимизируется →&lt;/li&gt;
&lt;li&gt;если определённая функция/цикл становятся «горячими», то есть выполняются 10000 раз, то байт-код преобразуется в неоптимизированный машинный код (он быстрее, чем код для интерпретатора) →&lt;/li&gt;
&lt;li&gt;а если код продолжает оставаться «горячим», то он преобразуется оптимизирующим JIT-компилятором в высокооптимизированный машинный код, работающий максимально быстро →&lt;/li&gt;
&lt;li&gt;если код перестаёт быть «горячим», то он деоптимизируется обратно в байт-код&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bennett.ink/its-probably-time-to-stop-recommending-redux&quot;&gt;пара мыслей про стейт во фронте&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появление API cache в React Query показало, что часто собственный «стейт» фронтового приложения — это не стейт вовсе, а иммутабельные данные с сервера (из API), и наличие API cache часто убирает необходимость использовать менеджер состояния на фронте&lt;/li&gt;
&lt;li&gt;пропы — изначально, идея для «естественного» разделения зон ответственности модулей, но из-за того, что их начали использовать неправильно (проп-дриллинг), появились, наоборот, связывающие концепты типа глобального Redux-стора, которые во многих случаях не нужны&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;индивидуальные свойства трансформации &lt;code&gt;translate&lt;/code&gt;, &lt;code&gt;rotate&lt;/code&gt; и &lt;code&gt;scale&lt;/code&gt; не переопределяют значение свойства &lt;code&gt;transform&lt;/code&gt;, &lt;a href=&quot;https://polypane.app/blog/the-css-transform-property-and-individual-transforms-are-additive/&quot;&gt;а дополняют его&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/how-to-use-attr-in-css-for-columns-colors-and-font-size/&quot;&gt;грядущий в Chrome типизированный &lt;code&gt;attr()&lt;/code&gt;&lt;/a&gt; несёт парочку приятных (но сейчас уже не кажущихся революционными) моментов:
&lt;ul&gt;
&lt;li&gt;(при необходимости пробросить что-то в стили) отсутствие необходимости объявлять стили в &lt;code&gt;style&lt;/code&gt;, возможность оставлять значения в «чистых» data-атрибутах &lt;code&gt;&amp;lt;span data-color=&quot;oklch(84.08% 0.3256 143.87 / 86.52%)&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;возможность прокидывать произвольную строку из атрибутов в CSS, например, из &lt;code&gt;id&lt;/code&gt; напрямую, то есть без необходимости дублировать значение в &lt;code&gt;style&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;если вы всё ещё считаете, что &lt;code&gt;#ff0000&lt;/code&gt; или &lt;code&gt;rgb(255, 0, 0)&lt;/code&gt; — это самый красный цвет, какой только может быть, &lt;a href=&quot;https://karuna.dev/colormaxxing/&quot;&gt;то вы ошибаетесь&lt;/a&gt;; значение &lt;code&gt;color(display-p3 1 0 0)&lt;/code&gt; существенно «краснее», а точнее ярче (но при условии, что ваш девайс поддерживает цветовое пространство &lt;a href=&quot;https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/&quot;&gt;Display-P3&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;как сделать &lt;a href=&quot;https://css-tip.com/equal-width-button/&quot;&gt;строку или столбец с элементами одинаковой ширины, равной самому широкому из них&lt;/a&gt; (например, кнопки одинаковой ширины, равняющиеся по самой широкой кнопке):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;.container {
  display: inline grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;префетч ресурсов типа &lt;code&gt;&amp;lt;link rel=&quot;prefetch&quot; as=&quot;style&quot; href=&quot;page-2.css&quot; /&amp;gt;&lt;/code&gt; может, внезапно, &lt;a href=&quot;https://www.debugbear.com/blog/prefetch-slower-website&quot;&gt;откладывать загрузку основных ресурсов&lt;/a&gt;, так что лучше эту префетч-оптимизацию докидывать для некритичных ресурсов и уже из JS, после загрузки `window&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kanenarraway.com/posts/ai-killed-the-tech-interview-now-what/&quot;&gt;AI-тулы доламывают процесс найма&lt;/a&gt;: «хакнуть» интервью становится всё проще, но пройти собес — это только пол-дела, внутри работы при этом придётся нелегко, так как там случаются инциденты, проектирование архитектуры и коммуникация (универы при этом не помогают)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 07.03.2025</title><link>https://juwain.github.io/web-platform/blog/2025-03-07/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-03-07/</guid><description>Новости веб-платформы</description><pubDate>Fri, 07 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-5-8/&quot;&gt;вышел TS 5.8&lt;/a&gt;, с момента RC изменений нет: &lt;code&gt;require(esm)&lt;/code&gt; ( + флаг обратной совместимости &lt;code&gt;--module node18&lt;/code&gt;) и флаг &lt;code&gt;--erasableSyntaxOnly&lt;/code&gt; на борту&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://webkit.org/blog/16512/release-notes-for-safari-technology-preview-214/&quot;&gt;Safari Technology Preview 214&lt;/a&gt;: внутри долгожданная поддержка &lt;code&gt;data:&lt;/code&gt; URL в favicon, то есть теперь можно будет во всех браузерах использовать SVG- и эмодзи-фавиконки:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;link
  rel=&quot;icon&quot;
  type=&quot;image/svg+xml&quot;
  href=&quot;data:image/svg+xml,[YOUR ENCODED SVG HERE]&quot;
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;вовсю идёт работа по &lt;a href=&quot;https://github.com/vitejs/rolldown-vite&quot;&gt;внедрению rolldown в Vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;вышла стабильная версия &lt;a href=&quot;https://tanstack.com/blog/announcing-tanstack-form-v1&quot;&gt;TanStack Form v1&lt;/a&gt; для основных фреймворков:
&lt;ul&gt;
&lt;li&gt;TS валидирует связку модели данных и значения в компоненте, причём не нужно передавать дженерики, а всё инферится з коробки&lt;/li&gt;
&lt;li&gt;встроеная поддержка валидационных либ (Zod, ArkType…)&lt;/li&gt;
&lt;li&gt;есть возможность задать асинхронную функцию для валидации&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;выпустили черновик спеки &lt;a href=&quot;https://drafts.csswg.org/css-forms/&quot;&gt;CSS Form Control Styling Level 1&lt;/a&gt; про стилизацию элементов форм: &lt;code&gt;appearance: base&lt;/code&gt; для базовой стилизации элементов, псевдоэлементы &lt;code&gt;::picker&lt;/code&gt;, &lt;code&gt;::thumb&lt;/code&gt;, &lt;code&gt;::track&lt;/code&gt;, &lt;code&gt;::fill&lt;/code&gt; и другие для стилизации UI-элементов&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://react-spectrum.adobe.com/releases/2025-03-05.html&quot;&gt;мартовский апдейт React Aria/Spectrum&lt;/a&gt; с компонентами &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/Toast.html&quot;&gt;Toast&lt;/a&gt;, &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/Tree.html&quot;&gt;Tree&lt;/a&gt; и &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/Virtualizer.html&quot;&gt;Virtualizer&lt;/a&gt;, также допилен хук &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/usePress.html&quot;&gt;usePress&lt;/a&gt; и компонент &lt;a href=&quot;https://react-spectrum.adobe.com/react-aria/Autocomplete.html&quot;&gt;Autocomplete&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://developer.chrome.com/release-notes/134&quot;&gt;Chrome 134&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;добавили возможность добавлять внутрь &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; дополнительные элементы помимо &lt;code&gt;&amp;lt;option&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;optgroup&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;hr&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;допилили вариации закрытия &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;дополнили обратносовместимо &lt;code&gt;console.timeStamp()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://groups.google.com/a/chromium.org/g/blink-dev/c/stxSgTgMHog?pli=1&quot;&gt;Chrome 135&lt;/a&gt; будет внедрён &lt;a href=&quot;https://github.com/WICG/observable&quot;&gt;пропоузал Observable API&lt;/a&gt; (позиции WebKit и Mozilla по поводу этого API пока неясны):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;container
  .when(&quot;click&quot;)
  .filter((e) =&amp;gt; e.target.closest(&quot;a&quot;))
  .subscribe({
    next: (e) =&amp;gt; {
      // …
    },
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jantimon/chrome-react-scan-inspector&quot;&gt;React Scan Inspector&lt;/a&gt; — &lt;a href=&quot;https://github.com/aidenybai/react-scan&quot;&gt;инструмент&lt;/a&gt; для анализа перерисовок React теперь в виде Chrome-плагина&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://openapi-ts.dev/openapi-fetch/&quot;&gt;openapi-fetch&lt;/a&gt; — типизированный fetch-клиент, согласующийся с OpenAPI схемой&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://voxels.layoutit.com/&quot;&gt;CSS Voxel Editor&lt;/a&gt; — трёхмерный «пиксельный» редактор на базе CSS-трансформов и гридов (&lt;a href=&quot;https://tympanus.net/codrops/2025/03/03/css-meets-voxel-art-building-a-rendering-engine-with-stacked-grids/&quot;&gt;тут&lt;/a&gt; про движок)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://suricrasia.online/puzzlebox/&quot;&gt;CSS Puzzle Box&lt;/a&gt; — головоломка, написанная на HTML/SVG/CSS (&lt;a href=&quot;https://suricrasia.online/blog/inline-css-puzzle-box/&quot;&gt;тут&lt;/a&gt; про процесс создания), наполненная трюкохаками, например, «самоскрывающимся» &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;parseInt(&apos;1️⃣&apos;) === 1 // true&lt;/code&gt;, потому что внутри &lt;code&gt;parseInt&lt;/code&gt; &lt;a href=&quot;https://www.aleksandrhovhannisyan.com/blog/parseint-keycap-emoji/&quot;&gt;находит в unicode-символе&lt;/a&gt; сначала &lt;code&gt;1&lt;/code&gt;, а последующий нечисловой «вариационный» символ отбрасывается&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;input type=&quot;range&quot;&amp;gt;&lt;/code&gt; &lt;a href=&quot;https://css-tricks.com/a-css-only-star-rating-component-and-more-part-1/&quot;&gt;превращается в «звёздный рейтинг»&lt;/a&gt;, чем удобно: использует нативное управления с клавиатуры, а также инпут имеет нативные атрибуты &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, &lt;code&gt;step&lt;/code&gt;, значения которых пробрасываются в CSS через новоиспечённый &lt;code&gt;attr&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;только привыкли к функциям-дженерикам в TS, а как &lt;a href=&quot;https://css-tricks.com/functions-in-css/&quot;&gt;вам функции в CSS&lt;/a&gt; (пока что почти что фэнтези-синтаксис)?&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@function --dashed-border(--color: red) {
  result: 2px dashed var(--color);
}

.argument {
  border: --dashed-border(blue);
}

.default {
  border: --dashed-border();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;вырезаем &lt;a href=&quot;https://css-tip.com/inner-border/&quot;&gt;прямоугольную прозрачную рамку&lt;/a&gt; внутри картинки с помощью &lt;code&gt;mask&lt;/code&gt; и конического градиента&lt;/li&gt;
&lt;li&gt;кастомное свойство может быть &lt;a href=&quot;https://css-tricks.com/the-css-custom-property-toggle-trick/&quot;&gt;«выключено» по умолчанию&lt;/a&gt;, правда это хак и синтаксис выглядит сломанным:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;button {
  --has-border: ; /* off by default */
  border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));
}

.bordered {
  --has-border: initial; /* turn on */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nerdy.dev/css-kaleidoscopes&quot;&gt;эффект калейдоскопа&lt;/a&gt; с помощью анимации кастомного свойства (&lt;code&gt;@property&lt;/code&gt;) внутри градиента&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.gitbutler.com/how-git-core-devs-configure-git/&quot;&gt;полезные настройки git-а&lt;/a&gt; в ваш &lt;code&gt;.gitconfig&lt;/code&gt;, например, &lt;code&gt;push.autoSetupRemote true&lt;/code&gt; для автозадания апстрима или &lt;code&gt;pull.rebase true&lt;/code&gt; для авторебейза при пулле&lt;/li&gt;
&lt;li&gt;скажи что-нибудь на дедовском: — кхе-кхе, ноутбук, дискета, ajax (&lt;a href=&quot;https://web.archive.org/web/20080302121152/http://adaptivepath.com/ideas/essays/archives/000385.php&quot;&gt;20 назад, кстати, был обозначен, тогда были ещё актуальны XML and XSLT&lt;/a&gt;)!&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 21.03.2025</title><link>https://juwain.github.io/web-platform/blog/2025-03-21/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-03-21/</guid><description>Новости веб-платформы</description><pubDate>Fri, 21 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-v1.2.5&quot;&gt;в Bun v1.2.5&lt;/a&gt; стала достпна поддержка Svelte и CSS modules в бандлере и дев-сервере&lt;/li&gt;
&lt;li&gt;как и в случае Node.js vs Bun/Deno, &lt;a href=&quot;https://oxc.rs/blog/2025-03-15-oxlint-beta.html&quot;&gt;в мире линтеров образуется похожая ситуация&lt;/a&gt;: к противостоянию ESLint vs Biome присоединяется вышедший в бету Oxlint, который написан на Rust, поэтому оч быстрый, &amp;gt;500 правил работает из коробки, есть автофиксы + планируют запилить поддержку кастомных ESLint-плагинов&lt;/li&gt;
&lt;li&gt;у Vercel есть Next.js, а &lt;a href=&quot;https://www.netlify.com/blog/tanstack-start-netlify-official-deployment-partner/&quot;&gt;у Netlify теперь есть TanStack Start&lt;/a&gt; и это хорошо и для TanStack, так как будет деньги, и для нас, так как будет альтернатива пропушиваемой парадигме RSC, то есть появляется неиллюзорная возможность появления полноценного React-фреймворка «здорового человека»:
&lt;ul&gt;
&lt;li&gt;в TanStack типобезопасные роуты благодаря дому, что роуты основаны не на файлах, а на функциях, которые создают роуты&lt;/li&gt;
&lt;li&gt;серверные функции тоже более явные и гибкие, в отличие от директивы &quot;use server&quot;&lt;/li&gt;
&lt;li&gt;нативная интеграция с TanStack Query&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;в &lt;a href=&quot;https://webkit.org/blog/16523/release-notes-for-safari-technology-preview-215/&quot;&gt;Safari Technology Preview 215&lt;/a&gt; появились Scroll Driven Animations (итого в Chrome уже есть, в FF есть за флагом), CSS Anchor Positioning (в FF нет) и на десерт &lt;code&gt;text-wrap-style: pretty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://opencollective.com/styled-components/updates/thank-you&quot;&gt;проект styled-components переведён в режим поддержки&lt;/a&gt;, так как Context API не поддерживается в серверных компонентах, экосистема в целом ушла в сторону другого подхода к написанию стилей (атомизация стилей, jit-сборка), мейнтейнер сам перестал использовать styled-components в больших приложениях. Это, в целом, ничего страшного, если нравится такой подход к написанию стилей (мне нравится, так позволяют часть UI логики пробрасывать внутрь стилевых компонентов) есть build-time решения со styled-like API (linaria, panda css)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://parceljs.org/blog/v2-14-0/&quot;&gt;Parcel v2.14.0&lt;/a&gt; стал поддерживать рендер React Server Components в CSR, SSR или в build-time просто в HTML, заодно стали глубоко поддерживать MDX, и кроме того, появился инструмент миграции проекта с CRA &lt;code&gt;npx cra-to-parcel&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/eslint-community/eslint-plugin-eslint-plugin&quot;&gt;eslint-plugin-eslint-plugin&lt;/a&gt; — ESLint-плагин для линтинга ESLint-плагинов, если желаете разработать свой, то может подсобить&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/nonzzz/vite-bundle-analyzer&quot;&gt;vite-bundle-analyzer&lt;/a&gt; — визуальная и CLI-утилита для инспекции содержимого вашего Vite-бандла&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;прикол: в JS символы &lt;code&gt;&amp;lt;!--&lt;/code&gt; и &lt;code&gt;--&amp;gt;&lt;/code&gt; из-за проблем с легаси-совместимостью — &lt;a href=&quot;https://www.hillelwayne.com/post/javascript-puzzle/&quot;&gt;это валидные символы&lt;/a&gt; для создания комментария&lt;/li&gt;
&lt;li&gt;Document Picture-in-Picture API может быть использовано не только для показа видео-контента в отдельном окошке, в &lt;a href=&quot;https://developer.chrome.com/blog/document-pip-use-case&quot;&gt;PiP можно рендерить своё кастомное содержимое&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const pipWindow = await documentPictureInPicture.requestWindow({
  width: window.innerWidth,
  height: window.innerHeight,
});

pipWindow.document.documentElement.innerHTML = htmlCode;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kylegill.com/essays/next-vs-tanstack/&quot;&gt;ещё один наброс на Next.js vs Vite + TanStack&lt;/a&gt; от человека, который устал скрестись о комплексность API и хочет, чтобы оно просто работало и на клиенте, и на сервере&lt;/li&gt;
&lt;li&gt;если вы не поддались искушению мигрировать на Biome или Oxlint, а хотите сквозь тернии мигрировать таки ваш проект на 9 версию ESLint, то тут &lt;a href=&quot;https://www.neoxs.me/blog/migration-to-eslint-v9&quot;&gt;предлагают чеклист миграции&lt;/a&gt;; я пытался в миграцию полгода назад, но не осилил, так как не были готовы основные сторонние плагины, может быть пора попробовать снова&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://piccalil.li/blog/real-world-uses-of-typescripts-utility-types/&quot;&gt;практические юзкейсы утилитарных типов в TS&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype&quot;&gt;&lt;code&gt;Partial&lt;/code&gt;&lt;/a&gt; в случае, если не хочется при добавлении новых полей в тип, ходить по всем местам и править это; правда встроенный Partial распространяется только на один уровень вложенности, но «&lt;a href=&quot;https://millsp.github.io/ts-toolbelt/modules/object_partial.html&quot;&gt;deep partial&lt;/a&gt;» из стороннего &lt;a href=&quot;https://github.com/millsp/ts-toolbelt&quot;&gt;ts-toolbet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys&quot;&gt;&lt;code&gt;Omit&lt;/code&gt;&lt;/a&gt; для типизации объекта, ещё не сохранённого в БД, то есть у него есть все поля, кроме id&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype&quot;&gt;&lt;code&gt;ReturnType&lt;/code&gt;&lt;/a&gt; для вытаскивания типа, который возвращает функция&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype&quot;&gt;&lt;code&gt;Readonly&lt;/code&gt;&lt;/a&gt; для типизации копии объекта, которую нельзя модифицировать&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;псевдокласс &lt;code&gt;:in-range&lt;/code&gt; позволяет подвязаться на то, что значение в инпуте &lt;a href=&quot;https://html-css-tip-of-the-week.netlify.app/tip/in-range/&quot;&gt;находится в пределах&lt;/a&gt; значений, заданных в &lt;code&gt;min&lt;/code&gt; и &lt;code&gt;max&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если &lt;a href=&quot;https://til.simonwillison.net/css/dialog-full-height&quot;&gt;попробовать растянуть элемент&lt;/a&gt; &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; на всю высоту вьюпорта, то можно упереться в дефолтное браузерное значение &lt;code&gt;max-height: calc(100% - 2em - 6px)&lt;/code&gt;, которое надо вручную перезадать на желаемое&lt;/li&gt;
&lt;li&gt;почему так сложилось — хз, тут так заведено, но &lt;a href=&quot;https://css-tricks.com/styling-counters-in-css/&quot;&gt;есть несколько способов управлять буллетами в списках&lt;/a&gt;: псевдоэлемент &lt;code&gt;::marker&lt;/code&gt;, свойство &lt;code&gt;list-style-type&lt;/code&gt;, счётчик  &lt;code&gt;counter()&lt;/code&gt; и его стилизация через &lt;code&gt;@counter-style&lt;/code&gt;, изображение в &lt;code&gt;list-style-image&lt;/code&gt; или же старый-добрый `::before&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tip.com/assemble-image/&quot;&gt;эффект «расколотого» на части изображения&lt;/a&gt; через &lt;code&gt;mask&lt;/code&gt; и &lt;code&gt;conic-gradient&lt;/code&gt; не испортишь добавлением &lt;code&gt;transition&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если хотите попробовать &lt;a href=&quot;https://www.amitmerchant.com/bare-minimum-view-transitions/&quot;&gt;встроенные межстраничные &lt;code&gt;View Transitions&lt;/code&gt;&lt;/a&gt; достаточно добавить &lt;code&gt;&amp;lt;meta name=&quot;view-transition&quot; content=&quot;same-origin&quot; /&amp;gt;&lt;/code&gt; и &lt;code&gt;@view-transition { navigation: auto }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;чем больше уровней абстракций люди строят в технологиях (энергия → чип → сервер → веб-платформа → препроцессоры → библиотеки → фреймворки…), тем больше софта требуется, чтобы это всё обслуживать; &lt;a href=&quot;https://seldo.com/posts/ai-effect-on-programming-jobs&quot;&gt;поэтому AI не лишит нас работы&lt;/a&gt; (ведь даже сейчас есть работа для программистов Ассемблера), а просто кратно увеличит количество разработчиков, которые будут делать ещё больше софта ещё более разнообразными способами (возможно менее оплачиваемыми), и этим разработчикам так или иначе всё равно придётся осваивать основы просто другим путём&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wattenberger.com/thoughts/our-interfaces-have-lost-their-senses&quot;&gt;а вот это просто красиво смотреть&lt;/a&gt;: интерфейсы — как человеческая сущность: тёплые, вязаные, твои&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 14.03.2025</title><link>https://juwain.github.io/web-platform/blog/2025-03-14/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-03-14/</guid><description>Новости веб-платформы</description><pubDate>Fri, 14 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/136.0/releasenotes/&quot;&gt;вышел Firefox 136&lt;/a&gt;, поддержали:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/DurationFormat&quot;&gt;Intl.DurationFormat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;псевдокласс &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/:open&quot;&gt;:open&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/CookieStore&quot;&gt;CookieStore API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;а также значение &lt;code&gt;plaintext-only&lt;/code&gt; для атрибута &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable&quot;&gt;contenteditable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2025/03/flat-config-extends-define-config-global-ignores/&quot;&gt;в новый формат конфига ESLint добавили&lt;/a&gt; функцию &lt;code&gt;defineConfig&lt;/code&gt; и вернули &lt;code&gt;extends&lt;/code&gt;, это и правда удобно, чтобы замиксовать несколько предсобранных конфигов для проекта:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;export default defineConfig({
  files: [&quot;**/*.js&quot;],
  extends: [&quot;js/recommended&quot;, reactPlugin.configs.flat.recommended],
});
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://2ality.com/2025/03/typescript-in-go.html&quot;&gt;компилятор TS будет портирован на Go к 7 версии&lt;/a&gt; (к ноябрю 2025 ожидается бета-версия) и ускорен в 10 раз:
&lt;ul&gt;
&lt;li&gt;компилятор именно портируется, а не переписывается с нуля (Go хорошо подходит под формат уже имеющегося кода)&lt;/li&gt;
&lt;li&gt;выигрыш по перфомансу за счёт многопоточности и отсутствия необходимости компиляции нативного кода (в JS упёрлись в потолок)&lt;/li&gt;
&lt;li&gt;Go-версия может запускаться в браузере через WebAssembly&lt;/li&gt;
&lt;li&gt;ожидается, что JS- и нативный движок будут существовать долгое время параллельно&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://almanac.httparchive.org/en/2024/javascript&quot;&gt;вышла последняя глава Web Almanac про JS&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;в среднем вес JS на сайтах дорос до 500-600kb (часть кода не используется), &amp;gt;20 запросов за JS на странице&lt;/li&gt;
&lt;li&gt;из бандлеров чаще всего используется webpack, с заметным отставанием Parcel&lt;/li&gt;
&lt;li&gt;в найденных сорсмапах: TS используется в 6% сайтов, Babel — в 12% из топа 10к мобильных сайтов&lt;/li&gt;
&lt;li&gt;jQuery используется в 74% сайтов, Swiper — в 15%, React — в 10%, веб-компоненты в 7.8%&lt;/li&gt;
&lt;li&gt;67% сайтов включает бесполезно транспилированный JS-код&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;выпуск CSS &lt;code&gt;@function&lt;/code&gt; &lt;a href=&quot;https://developer.chrome.com/blog/delaying-shipping-of-css-functions&quot;&gt;откладывается с Chrome 136 на 139 версию&lt;/a&gt;, так как пока ещё устаканивается спека&lt;/li&gt;
&lt;li&gt;в редакторе Zed &lt;a href=&quot;https://zed.dev/blog/git&quot;&gt;появилась поддержка GUI для работы с git&lt;/a&gt; (в общем, у Zed и компании есть ещё примерно полгода-год, пока TS в VSCode станет работать супербыстро, и все перестанут с него убегать)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://endoflife.date&quot;&gt;endoflife.date&lt;/a&gt; — тут можно посмотреть даты поддержки многих версий либ, программ и фреймворков&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://node-modules.dev&quot;&gt;node-modules.dev&lt;/a&gt; — &lt;code&gt;npx node-modules-inspector&lt;/code&gt; в вашем проекте покажет диаграмму зависимостей &lt;code&gt;node_modules&lt;/code&gt;, их размер и связи&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://same.dev/&quot;&gt;same.dev&lt;/a&gt; — AI-тула, которая походит по сайту и сгенерит аналог (работает только на простеньких лендосах, но делает их сложно 😕)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если заходит речь про &lt;a href=&quot;https://allenpike.com/2025/javascript-fatigue-ssr&quot;&gt;выбор фронтового фреймворка&lt;/a&gt;, лучше выбирать что-то поскучнее и стабильнее, правда стабильных и скучных фреймворков маловато (Next.js вендорлочит, Astro про контент, React Router всё ещё в пучине перерождений)&lt;/li&gt;
&lt;li&gt;недавняя поддержка TS в Node &lt;a href=&quot;https://deno.com/blog/typescript-in-node-vs-deno&quot;&gt;вызывает улыбку на лице Ryan Dahl&lt;/a&gt;: в Deno TS не только тайпстрипается, но ещё и форматируется, компилируется, линтится и генерит документацию&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://advancedweb.hu/shorts/javascript-best-practice-use-return-await/&quot;&gt;паттерн возвращения&lt;/a&gt; &lt;code&gt;return await func()&lt;/code&gt; хорош тем, что дождётся выполнения кода, и если нужно поймать ошибку, то выбросит её, пока не произошёл выход из функции:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const helloWorld = async () =&amp;gt; {
  try {
    return await asyncHello(&quot;World&quot;);
  } catch (e) {
    return &quot;Whops&quot;;
  }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;а что если &lt;a href=&quot;https://dev.to/fedia/15kb-single-file-wiki-46a1&quot;&gt;«билдить» архив с вашими md-файлами просто в HTML&lt;/a&gt;? Навигацию можно сделать на CSS-селекторах &lt;code&gt;:target&lt;/code&gt;, HTML-файл скачивается один раз (offline-first), не нужен JS&lt;/li&gt;
&lt;li&gt;URL — идеальное место, чтобы &lt;a href=&quot;https://iamsahaj.xyz/blog/react-state-in-the-url/&quot;&gt;хранить сериализуемое состояние приложения&lt;/a&gt;, но есть ограничение: на 60-80к символов в URL браузер может загнуться&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cekrem.github.io/posts/beyond-react-memo-smarter-performance-optimization/&quot;&gt;база про перфоманс в React&lt;/a&gt;: отделяйте изменяющийся стейт рядом с тяжёлыми компонентами в отдельные компоненты для избежания ререндера&lt;/li&gt;
&lt;li&gt;явное лучше неявного на примере &lt;a href=&quot;https://www.trevorlasn.com/blog/explicit-is-better-than-implicit&quot;&gt;выделения данных или конфигов в коде&lt;/a&gt; в отдельные переменные&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://newsletter.daishikato.com/p/how-the-jotai-store-api-is-inspired-by-the-weakmap-api&quot;&gt;API стейт-менеджера Jotai&lt;/a&gt; вдохновлено &lt;code&gt;WeakMap&lt;/code&gt; + добавлена возможность подписки на мапу&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;если в вашем приложении есть отстраивание побочных цветов от основных цветов приложения (обводки, тени, градиенты, разделители, состояния UI-элементов, оттенки), то &lt;a href=&quot;https://ishadeed.com/article/css-relative-colors/&quot;&gt;в деле поможет relative color&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;в Chrome 135 нас ждёт появление двух CSS-функций &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/sign&quot;&gt;sign&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/abs&quot;&gt;abs&lt;/a&gt;: для получения знака выражения (-1 или 1) и модуля числа&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nerdy.dev/sibling-index&quot;&gt;в канарейке Chrome доступны&lt;/a&gt; функции &lt;a href=&quot;https://drafts.csswg.org/css-values-5/#tree-counting&quot;&gt;&lt;code&gt;sibling-index()&lt;/code&gt;&lt;/a&gt; и &lt;a href=&quot;https://drafts.csswg.org/css-values-5/#tree-counting&quot;&gt;&lt;code&gt;sibling-count()&lt;/code&gt;&lt;/a&gt; для получения индекса элемента и числа всех элементов на одном уровне в DOM&lt;/li&gt;
&lt;li&gt;полупрозрачное &lt;a href=&quot;https://frontendmasters.com/blog/chilled-out-text-underlines/&quot;&gt;«визуально спокойное» подчёркивание ссылок&lt;/a&gt; &lt;code&gt;text-decoration-color: color-mix(in srgb, currentColor, transparent 75%)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;существует специальное свойство &lt;a href=&quot;https://css-tip.com/infinite-logos-animation/&quot;&gt;для анимации движения элемента по SVG-пути&lt;/a&gt; — это &lt;code&gt;offset&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;с помощью &lt;code&gt;content-visibility&lt;/code&gt; и &lt;code&gt;contain&lt;/code&gt; &lt;a href=&quot;https://www.debugbear.com/blog/content-visibility-api&quot;&gt;можно указать браузеру&lt;/a&gt; не стилизовать, не строить лейаут или не отрисовывать определённый кусок интерфейса для улучшения перфоманса (наколеночная виртуализация)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://muffinman.io/blog/image-comparison-slider/&quot;&gt;интересная идея&lt;/a&gt; использовать для визуального «сравнивателя» картинок &lt;code&gt;&amp;lt;input type=&quot;range&quot;&amp;gt;&lt;/code&gt; в качестве управляющего элемента для задания кастомного свойства с шириной картинки&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;статья, где рассказывается про миграцию с одного тестового движка на другой (но это неважно), &lt;a href=&quot;https://open.nytimes.com/how-the-new-york-times-systematically-migrated-from-enzyme-into-react-testing-library-b3ea538d001c&quot;&gt;интересны три предлагаемых подхода к миграции&lt;/a&gt;: 1) бульдозер — мигрируем все файлы одним скопом, 2) консенсус — разделяем ответственность за каждый файл между конкретными людьми, 3) по частям — берём самый малозначительный файл, мигрируем, идём к следующему, повторяем, пока файлы не закончатся&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git switch -&lt;/code&gt; или &lt;code&gt;git checkout -&lt;/code&gt; (для староверов) &lt;a href=&quot;https://joshtronic.com/2025/03/09/switch-to-previous-checked-out-git-branch/&quot;&gt;переключает на прошлую ветку&lt;/a&gt; в гите&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 28.03.2025</title><link>https://juwain.github.io/web-platform/blog/2025-03-28/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-03-28/</guid><description>Новости веб-платформы</description><pubDate>Fri, 28 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в &lt;code&gt;@xstate/store@3.4.0&lt;/code&gt; (минималистичный стейт-менеджер под капотом &lt;code&gt;xstate&lt;/code&gt;, который можно использовать без полного обвеса), &lt;a href=&quot;https://github.com/statelyai/xstate/releases/tag/%40xstate%2Fstore%403.4.0&quot;&gt;добавили «атомарное» API&lt;/a&gt; &lt;code&gt;createAtom()&lt;/code&gt; с возможностью создавать атомарные хранилища, комбинировать их друг с другом и со сторами&lt;/li&gt;
&lt;li&gt;в техническом комитете Node.js &lt;a href=&quot;https://socket.dev/blog/node-js-tsc-votes-to-stop-distributing-corepack&quot;&gt;решили исключить&lt;/a&gt; &lt;code&gt;corepack&lt;/code&gt; из базовой поставки начиная с Node.js 25+ (в более ранних версиях он останется экспериментальной фичей), теперь нужно будет ставить отдельно &lt;code&gt;npm install -g corepack&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;библиотека для анимации &lt;a href=&quot;https://motion.dev/blog/introducing-motion-for-vue&quot;&gt;Motion портирована на Vue&lt;/a&gt;, теперь можно во так:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;motion.div
    :initial=&quot;{ opacity: 0, scale: 0 }&quot;
    :animate=&quot;{ opacity: 1, scale: 1 }&quot;
  /&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware&quot;&gt;в Next.js найдена уязвимость&lt;/a&gt; (больше похожая на бэкдор), позволяющая обходить мидлвары спец-заголовком &lt;code&gt;x-middleware-subrequest&lt;/code&gt;, то есть если у вас в мидлваре выполняется что-то важное, например, авторизация, то её сейчас можно скипнуть (если не обновить либу)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rsdoctor.dev/blog/release/release-note-1_0&quot;&gt;релизнулся Rsdoctor 1.0&lt;/a&gt;, webpack-совместимый анализатор бандла, аналог тулов  &lt;a href=&quot;https://github.com/webpack-contrib/webpack-bundle-analyzer&quot;&gt;webpack-bundle-analyzer&lt;/a&gt; и &lt;a href=&quot;https://github.com/statoscope/statoscope/&quot;&gt;Statoscope&lt;/a&gt;: с помощью него можно получить ответы на вопросы «почему билд медленный», «как лучше разбить бандл на чанки», «почему увеличился размер бандла»&lt;/li&gt;
&lt;li&gt;в Chrome 135 будут добавлены новые фишки:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/a-customizable-select&quot;&gt;кастомизируемый элемент &lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt;&lt;/a&gt; с помощью свойства &lt;code&gt;appearance: base-select&lt;/code&gt;, в который можно добавить произвольный HTML&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/blog/carousels-with-css&quot;&gt;псевдоэлементы&lt;/a&gt; &lt;code&gt;::scroll-button()&lt;/code&gt; и &lt;code&gt;::scroll-marker()&lt;/code&gt; для создания и стилизации «нативных» каруселей&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://valibot.dev/blog/valibot-v1-the-1-kb-schema-library/&quot;&gt;большое обновление Valibot v1.0.0&lt;/a&gt; (рантайм-валидатора схем) спустя 15 бет и 5 rc, много добавлений/изменений&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jdx/mise&quot;&gt;mise&lt;/a&gt; — мультитул для переключения версий node, python, ruby (как nvm) + переключения env-переменных (как direnv) + запуска тасков (как make)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kaluma-project/kaluma&quot;&gt;kaluma&lt;/a&gt; — мини-JS-рантайм для Raspberry Pi (вдумайтесь в параметры устройства: 300KB ROM, 64KB RAM)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/for-GET/http-decision-diagram&quot;&gt;http-decision-diagram&lt;/a&gt; — блок-схема принятия решения, какой HTTP-статус отдать клиенту&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/deoostfrees/Parvus&quot;&gt;Parvus&lt;/a&gt; — доступный лайтбокс без зависимостей на нативном &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;-е с интернализацией&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;а вы знали, что можно &lt;a href=&quot;https://leanrada.com/notes/inline-rendering-currentscript/&quot;&gt;обратиться к текущему выполняющемуся скрипту&lt;/a&gt; через  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Document/currentScript&quot;&gt;&lt;code&gt;document.currentScript&lt;/code&gt;&lt;/a&gt;? Это может быть полезно, чтобы, к примеру, динамически заменить скрипт на произвольный контент, получается такой дешёвый движок рантайм-шаблонов для всяких мелочей:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;Come on, it’s
&amp;lt;script&amp;gt;
  document.currentScript.replaceWith(new Date().getFullYear());
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tip.com/custom-progress/&quot;&gt;ещё один юзкейс&lt;/a&gt; для нового типизированного &lt;code&gt;attr()&lt;/code&gt;: прокидывание значений атрибутов &lt;code&gt;value&lt;/code&gt; и &lt;code&gt;max&lt;/code&gt; элемента &lt;code&gt;&amp;lt;progress&amp;gt;&lt;/code&gt; напрямую в CSS&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mask&lt;/code&gt; + &lt;code&gt;repeating-conic-gradient&lt;/code&gt; + немного тригонометрии = &lt;a href=&quot;https://css-tip.com/zig-zag-edge/&quot;&gt;зигзаг&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;если нужно что-то по-быстрому поправить в загруженном сайте без инспектора в дев-тулзах, можно использовать &lt;a href=&quot;https://www.smashingmagazine.com/2025/03/previewing-content-changes-work-documentdesignmode/&quot;&gt;дизайн-режим&lt;/a&gt; (ввести &lt;code&gt;document.designMode = &quot;on&quot;&lt;/code&gt; в консоли)&lt;/li&gt;
&lt;li&gt;а вот и &lt;a href=&quot;https://nerdy.dev/css-mixins-ready-for-experimentation&quot;&gt;миксины подвозят в канарейку Chrome&lt;/a&gt;, как обычно подождём 3 года и можно будет пользовать:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@mixin --box {
  aspect-ratio: 1;
  inline-size: 100px;
  block-size: 100px;
}

.box {
  @apply --box;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;полезные фичи &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt; &lt;a href=&quot;https://html-css-tip-of-the-week.netlify.app/tip/fieldset-and-legend/&quot;&gt;при создании форм&lt;/a&gt;: можно дизейблить целиком всю группу полей через атрибут &lt;code&gt;disabled&lt;/code&gt; у &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;, а также &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt; может находиться отдельно от &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; и быть связанным с формой атрибутом &lt;code&gt;form&lt;/code&gt; со значением &lt;code&gt;id&lt;/code&gt; формы&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;если вы игнорите сообщения консоли при запуске проекта &lt;code&gt;Browserslist: caniuse-lite is outdated&lt;/code&gt;, то у вас есть шанс &lt;a href=&quot;https://t.me/cherkashindev/311&quot;&gt;существенно уменьшить размер бандла&lt;/a&gt; с помощью команды &lt;code&gt;npx update-browserslist-db@latest&lt;/code&gt;, так как возможно уберётся много ненужной транспиляции&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 04.04.2025</title><link>https://juwain.github.io/web-platform/blog/2025-04-04/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-04-04/</guid><description>Новости веб-платформы</description><pubDate>Fri, 04 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/135&quot;&gt;вышел Chrome 135&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появились атрибуты &lt;code&gt;command&lt;/code&gt; и &lt;code&gt;commandfor&lt;/code&gt; для кнопок, чтобы декларативно описывать взаимодействие с поповерами и диалогами&lt;/li&gt;
&lt;li&gt;добавили псевдоэлементы &lt;code&gt;::scroll-button()&lt;/code&gt; и &lt;code&gt;::scroll-marker&lt;/code&gt; для «нативных» каруселей&lt;/li&gt;
&lt;li&gt;CSS-функция &lt;code&gt;shape()&lt;/code&gt; позволяет описывать в &lt;code&gt;clip-path&lt;/code&gt; параметрические SVG-like-формы&lt;/li&gt;
&lt;li&gt;добавлена возможность стилизации псевдоэлемента внутри псевдоэлемента &lt;code&gt;::before::marker&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержали &lt;a href=&quot;https://wicg.github.io/observable/&quot;&gt;Observable API&lt;/a&gt; и &lt;code&gt;fetchLater()&lt;/code&gt; для отложенного запуска &lt;code&gt;fetch&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/16574/webkit-features-in-safari-18-4/&quot;&gt;вышел Safari 18.4&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;внедрили новый декларативный формат Web Push&lt;/li&gt;
&lt;li&gt;также поддержали CSS-функцию &lt;code&gt;shape()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;обновили &lt;code&gt;&amp;lt;input type=&quot;color&quot; /&amp;gt;&lt;/code&gt;, теперь поддерживает атрибуты &lt;code&gt;alpha&lt;/code&gt; и &lt;code&gt;colorspace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержали &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Cookie_Store_API&quot;&gt;Cookie Store API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/137.0/releasenotes/&quot;&gt;вышел Firefox 137&lt;/a&gt;: из интересного только выкатили группировку табов, а в ночных сборках &lt;a href=&quot;https://www.omgubuntu.co.uk/2025/03/firefox-nightly-supports-web-apps-taskbar-tabs&quot;&gt;появляется поддержка PWA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/facebook/react/releases/tag/v19.1.0&quot;&gt;выпустили React 19.1.0&lt;/a&gt;: появилась фича Owner Stack для более детального отслеживания в дев-режиме иерархии рендера компонентов, а также подфиксили баги в React и React DOM&lt;/li&gt;
&lt;li&gt;вышел &lt;a href=&quot;https://expressjs.com/2025/03/31/v5-1-latest-release.html&quot;&gt;Express 5.1.0&lt;/a&gt;, эта версия становится LTS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v18.20.8&quot;&gt;поддержка Node.js 18&lt;/a&gt; заканчивается 30 апреля 2025, время обновить ваши &lt;code&gt;.nvmrc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mui.com/blog/material-ui-v7-is-here/&quot;&gt;выпущен Material UI v7&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;улучшилась поддержка ESM&lt;/li&gt;
&lt;li&gt;устаканилось API &lt;code&gt;slots&lt;/code&gt; и &lt;code&gt;slotProps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;впилили поддержку &lt;code&gt;@layer&lt;/code&gt; для упрощения интеграции с другими либами&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.monterail.com/stateofvue&quot;&gt;вышел отчёт State of Vue.js 2025&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;хотят по-прежнему дожать Vapor Mode с обратной совместимостью&lt;/li&gt;
&lt;li&gt;по популярности Vue всё ещё отстаёт от React, но количество сайтов на Vue явно больше Angular&lt;/li&gt;
&lt;li&gt;треть проектов всё ещё на Vue 2, хоть он больше и не поддерживается (миграция вызывает сложности)&lt;/li&gt;
&lt;li&gt;Pinia — доминирующий стейт-менеджер&lt;/li&gt;
&lt;li&gt;комьюнити не хватает библиотек компонентов (как MUI или Radix) под Vue&lt;/li&gt;
&lt;li&gt;Nuxt v4 уже неподалёку&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;со стороны WebKit &lt;a href=&quot;https://webkit.org/blog/16587/item-flow-part-1-a-new-unified-concept-for-layout/&quot;&gt;появилось предложение&lt;/a&gt; объединить пересекающиеся части flexbox и grid в новом семействе свойств &lt;code&gt;item-direction&lt;/code&gt;, &lt;code&gt;item-wrap&lt;/code&gt;, &lt;code&gt;item-pack&lt;/code&gt;, &lt;code&gt;item-slack&lt;/code&gt; (чтобы наконец перестать вспоминать каждый раз, что эти &lt;code&gt;align-smthng&lt;/code&gt; значат)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/loeffel-io/ls-lint&quot;&gt;ls-lint&lt;/a&gt; — линтер названий файлов и директорий в файловой системе&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bryanbraun.com/2025/03/29/breaking-down-circular-dependencies-javascript/&quot;&gt;кольцевые зависимости между модулями в JS&lt;/a&gt; не отлавливаются на уровне языка/среды, но они могут потенциально приводить к ошибкам типа &lt;code&gt;ReferenceError: Cannot access &apos;a&apos; before initialization&lt;/code&gt;, так как к содержимому из одного модуля может обращаться другой модуль до его инициализации и полного выполнения; беспорядочные кросс-импорты в «шареной» зоне проекта нуждаются в особом внимании, для этого есть сторонние либы для отслеживания корректности импортов &lt;a href=&quot;https://github.com/pahen/madge&quot;&gt;madge&lt;/a&gt; и &lt;a href=&quot;https://www.npmjs.com/package/eslint-plugin-import&quot;&gt;eslint-plugin-import&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cekrem.github.io/posts/react-memo-when-it-helps-when-it-hurts/&quot;&gt;мемоизация в React&lt;/a&gt; изначально спроектирована довольно хрупко: простое заворачивание пропсов в &lt;code&gt;useMemo&lt;/code&gt;/&lt;code&gt;useCallback&lt;/code&gt; не повлияет на ререндеры компонента, нужно ещё замемоизировать сам компонент в &lt;code&gt;React.memo&lt;/code&gt;, а также следить, что внутри нет спреда пропсов &lt;code&gt;&amp;lt;Child {...props} /&amp;gt;&lt;/code&gt;, нет немемоизированного прокидывания &lt;code&gt;{ children }&lt;/code&gt; (они пересоздаются каждый раз), нет дополнительных дочерних компонентов без мемоизации&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://adactio.com/notes/21812&quot;&gt;аутлайн&lt;/a&gt; по клавиатурному фокусу на ссылках никогда не повредит:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;a:focus-visible {
  outline-offset: 0.25em;
  outline-width: 0.25em;
  outline-color: currentColor;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/expanding-css-shadow-effects/&quot;&gt;про тени&lt;/a&gt;: три вида теней — &lt;code&gt;box-shadow&lt;/code&gt;, &lt;code&gt;filter: drop-shadow()&lt;/code&gt; и &lt;code&gt;text-shadow&lt;/code&gt; —могут не только статически применяться, но и анимироваться, причём благодаря &lt;code&gt;@property&lt;/code&gt; возможна анимация только одного из параметра тени, например, &lt;code&gt;box-shadow: inset 0 0 0 var(--l) var(--c)&lt;/code&gt;, что делает тени мощным декоративным элементом&lt;/li&gt;
&lt;li&gt;прикольный, но хрупкий &lt;a href=&quot;https://codepen.io/HejChristian/full/YPzLbYX&quot;&gt;голографический эффект на скролле&lt;/a&gt;, построенный на режимах наложения, &lt;code&gt;background-attachment: fixed&lt;/code&gt; и линейных градиентах&lt;/li&gt;
&lt;li&gt;а пока создатели CSS размышляют не схлопнуть ли flex и grid в единое свойство, разработчикам как-то нужно жить и решать, что использовать в каждом конкретном юзкейсе: вот у одного есть мнение, что в решении, что взять, нужно следовать в порядке &lt;a href=&quot;https://alex.party/posts/2025-03-23-grid-first-flex-third/&quot;&gt;grid/inline-grid → block → flex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;об анимации движения по линии с помощью &lt;code&gt;offset-path&lt;/code&gt; вы уже наверняка слышали, но тут &lt;a href=&quot;https://yuanchuan.dev/css-animation-with-offset-path&quot;&gt;идею развили поглубже&lt;/a&gt; и творят прям интересные экземпляры (правда с использованием &lt;a href=&quot;https://github.com/css-doodle/css-doodle&quot;&gt;css-doodle&lt;/a&gt;), так что есть чем вдохновиться&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.seangoedecke.com/vibe-coding/&quot;&gt;бездумный вайб-кодинг&lt;/a&gt; хорош для чего-то небольшого и одноразового, так как быстро раздувает количество кода и поддержка этого дела начинает упираться в комплексность; а самый хороший способ понять систему — вдумчиво её порефакторить&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 11.04.2025</title><link>https://juwain.github.io/web-platform/blog/2025-04-11/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-04-11/</guid><description>Новости веб-платформы</description><pubDate>Fri, 11 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2025/04.md&quot;&gt;на ближайшем заседании Ecma TC39&lt;/a&gt; будет обсуждаться в том числе &lt;a href=&quot;https://github.com/rbuckton/proposal-enum&quot;&gt;пропоузал ECMAScript enums&lt;/a&gt; (stage 1): кажется это хитрый план, как сделать enum-ы легальными в JS, и тогда не придётся их болезненно выпиливать из TS при будущем «встраивании» TS в браузеры&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://e18e.dev/blog/community-showcase-q1.html&quot;&gt;парни из e18e продолжают участвовать&lt;/a&gt; в улучшении фронтенд-экосистемы и напоминают о полезных проектах для авторов пакетов:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/arethetypeswrong/arethetypeswrong.github.io&quot;&gt;arethetypeswrong&lt;/a&gt; — анализирует пакет на предмет наличия проблем с конфигурацией TS-типов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/publint/publint&quot;&gt;publint&lt;/a&gt; — линтер &lt;code&gt;package.json&lt;/code&gt; в пакете&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://node-modules.dev/&quot;&gt;node-modules.dev&lt;/a&gt; — анализ зависимостей &lt;code&gt;node_modules&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/es-tooling/eslint-plugin-depend&quot;&gt;eslint-plugin-depend&lt;/a&gt; — плагин для eslint, находящий раздутые зависимости и ненужные полифиллы&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/idosal/git-mcp&quot;&gt;git-mcp&lt;/a&gt; — меняем урл github-репозитория (github.com/username/repo → gitmcp.io/username/repo) и получаем удалённый MCP-сервер, подключенный к этому репо «на лету»&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://googlechrome.github.io/lighthouse/scorecalc/&quot;&gt;Lighthouse Scoring Calculator&lt;/a&gt; — наглядный калькулятор того, как отдельные метрики влияют на очки в Lighthouse (самое большое влияние у CLS, TBT, LCP)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://piccalil.li/blog/simplify-sharing-with-built-in-apis-and-progressive-enhancement/&quot;&gt;напоминание&lt;/a&gt;, что помимо &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API&quot;&gt;Clipboard API&lt;/a&gt; существует ещё &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API&quot;&gt;Web Share API&lt;/a&gt; (которое пока недоступно в FF), но в режиме прогрессивного улучшение вполне сгодится&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://waspdev.com/articles/2025-04-06/features-that-every-js-developer-must-know-in-2025&quot;&gt;и ещё одно напоминание&lt;/a&gt; о полезных API, о которых постоянно забываешь:
&lt;ul&gt;
&lt;li&gt;в &lt;code&gt;&quot;&quot;.replace()&lt;/code&gt; и &lt;code&gt;&quot;&quot;.replaceAll()&lt;/code&gt; можно передавать колбек и модифицировать заматченный текст&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers&quot;&gt;Promise.withResolvers()&lt;/a&gt; позволяет «вытаскивать» наружу &lt;code&gt;resolve&lt;/code&gt; и &lt;code&gt;reject&lt;/code&gt; при создании промиса&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[10,20,30].at(-1)&lt;/code&gt; вернёт последний элемент массива&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;а также, как вы догадываетесь, &lt;a href=&quot;https://waspdev.com/articles/2025-04-09/features-that-every-js-developer-must-know-in-2025-part-2&quot;&gt;ещё одно напоминание&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy&quot;&gt;Object.groupBy()&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy&quot;&gt;Map.groupBy()&lt;/a&gt; сгруппируют элементы по переданному ключу&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry&quot;&gt;FinalizationRegistry&lt;/a&gt; стриггерит событие в момент, когда объект будет подчищен garbage collector-ом из памяти&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.frontendjoy.com/p/how-i-reduced-my-react-bundle-size-by-30-with-real-examples&quot;&gt;что можно сделать&lt;/a&gt;, чтобы уменьшить размер основного React-бандла:
&lt;ul&gt;
&lt;li&gt;прочекать файлы на сайд-эффекты (&lt;code&gt;window.someBadSideEffect = &apos;hello&apos;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;не импортировать объект/класс из внешних пакетов целиком, лучше отдельными функциями&lt;/li&gt;
&lt;li&gt;в React использовать &lt;a href=&quot;https://react.dev/reference/react/lazy&quot;&gt;React.lazy&lt;/a&gt; для ленивой подгрузки компонентов&lt;/li&gt;
&lt;li&gt;импортировать не нужные сразу либы динамически:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const Fuse = import(&quot;fuse.js&quot;).then((module) =&amp;gt; module.default);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;currentColor&lt;/code&gt; или даже &lt;code&gt;cUrrENtCoLOr&lt;/code&gt; хорошо подходит &lt;a href=&quot;https://frontendmasters.com/blog/using-currentcolor-in-2025/&quot;&gt;для проброса цвета внутрь инлайн-SVG&lt;/a&gt; (хотя то же можно сделать и кастомным свойством)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;nav {
  color: salmon;

  svg.icon {
    fill: currentColor;
    filter: drop-shadow(0 1px 0 oklch(from currentcolor calc(l - 0.25) c h));
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;свежеиспеченная функция &lt;code&gt;clip-path: shape()&lt;/code&gt; (поддерживается в Chrome и Safari) позволяет более декларативно и человекочитаемо &lt;a href=&quot;https://developer.chrome.com/blog/css-shape&quot;&gt;описывать формы&lt;/a&gt; по сравнению с &lt;code&gt;clip-path: path()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;трюк, &lt;a href=&quot;https://blog.jim-nielsen.com/2025/background-image-opacity-css/&quot;&gt;как сделать фоновые изображения полупрозрачными&lt;/a&gt;: если фон под изображением одноцветный и равномерный, то можно слить картинку через режимы наложения:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;background-image: url(image-one.jpg), url(image-two.jpg);
background-color: rgba(255, 255, 255, 0.6);
background-blend-mode: lighten;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://piccalil.li/links/ua-plus/&quot;&gt;не забываем&lt;/a&gt;, что если завернуть любой селектор в &lt;code&gt;:where()&lt;/code&gt;, то у него будет нулевая специфичность (годится для всяких ресетов) + годное свойство &lt;code&gt;text-decoration-skip-ink&lt;/code&gt; для тюна подчёркивания ссылок:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;:where(a:not([class])) {
  text-decoration-skip-ink: auto;
  color: currentColor;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;так как md поддерживает HTML внутри, то в него можно вставить тег &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; c &lt;a href=&quot;https://cassidoo.co/post/md-dark-light-imgs/&quot;&gt;разными вариантами картинки для тёмной/светлой темы&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
  &amp;lt;source media=&quot;(prefers-color-scheme: dark)&quot; srcset=&quot;dark-mode-image.png&quot; /&amp;gt;
  &amp;lt;source media=&quot;(prefers-color-scheme: light)&quot; srcset=&quot;light-mode-image.png&quot; /&amp;gt;
  &amp;lt;img src=&quot;default-image.png&quot; /&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://practica.dev/blog/about-the-sweet-and-powerful-use-case-code-pattern/&quot;&gt;незаслуженно забытый паттер проектирования Use-case&lt;/a&gt;, код читается как «история», вызов отдельных функций складывается в повествование:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const validatedorder = validateAndCoerceOrder (orderRequest);
const orderWithPricing = calculate0rderPricing(validated0rder);
const purchasingCustomer = await assertCustomerHasEnoughBalance (orderWithPricing);
...
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.cloudflare.com/yarn-test-suffers-strange-derailment/&quot;&gt;прикольная история&lt;/a&gt; про то, как падение тестов Jest привело разработчика к шуточной программе &lt;code&gt;sl&lt;/code&gt;, которая была создана для тех, кто напечатал команду &lt;code&gt;sl&lt;/code&gt; вместо &lt;code&gt;ls&lt;/code&gt; и выводит ASCII-паровоз в консоль (да уж, что только не прилетает вместе с &lt;code&gt;node_modules&lt;/code&gt; к вам в комп)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 18.04.2025</title><link>https://juwain.github.io/web-platform/blog/2025-04-18/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-04-18/</guid><description>Новости веб-платформы</description><pubDate>Fri, 18 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare продолжает свою экспансию: теперь &lt;a href=&quot;https://blog.cloudflare.com/full-stack-development-on-cloudflare-workers/&quot;&gt;на один Worker можно залить&lt;/a&gt; фронт, бэк и бд, кроме того поддерживаются все фронт-фреймворки и Vite, чтобы задеплоить одной кнопкой (для тех, кто смел и не боится блокировочек + стать завендорлоченным), а ещё выкатили &lt;a href=&quot;https://agents.cloudflare.com&quot;&gt;платформу для создания AI-агентов&lt;/a&gt; (козырное имя пакета &lt;code&gt;npm i agents&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v4.zod.dev/v4&quot;&gt;анонсирована Zod 4 beta&lt;/a&gt;: закрыты самые востребованные ишуи, стал быстрее отрабатывать &lt;code&gt;tsc&lt;/code&gt;, представлена тришейкабельная версия либы &lt;code&gt;@zod/mini&lt;/code&gt;, добавлено новое &lt;code&gt;z.interface()&lt;/code&gt; для вывода типа из схемы&lt;/li&gt;
&lt;li&gt;в ближайшее время в браузерах &lt;a href=&quot;https://developer.mozilla.org/en-US/blog/h1-element-styles/&quot;&gt;изменится подход&lt;/a&gt; к стилизации вложенных заголовков &lt;code&gt;h1&lt;/code&gt;: раньше в зависимости от глубины вложенных секций &lt;code&gt;h1&lt;/code&gt; по умолчанию становился всё меньше, теперь будут одного размера&lt;/li&gt;
&lt;li&gt;в Remix и React Router &lt;a href=&quot;https://zhero-web-sec.github.io/research-and-things/react-router-and-the-remixed-path&quot;&gt;найдена уязвимость&lt;/a&gt;, дающая возможность атаки cache poisoning — подмены закешированного ответа JSON-ом злоумышленника (если используете, нужно обновиться)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-570/&quot;&gt;обновился Astro до 5.7&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;выкатили экспериментальный Fonts API, чтобы из коробки управлять загрузкой шрифтов с CDN&lt;/li&gt;
&lt;li&gt;Sessions API и SVG Components теперь стабильные&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://spidermonkey.dev/blog/2025/04/11/shipping-temporal.html&quot;&gt;в Firefox 139&lt;/a&gt; будет включен по умолчанию Temporal, и FF станет первым поддержавшим браузером (FF получается становится такой экспериментальной площадкой до выкатки в Chrome)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wordpress.com/blog/2025/04/09/ai-website-builder/&quot;&gt;Wordpress выкатывает&lt;/a&gt; AI-генератор сайтов: no-code-конструкторы верстальщиков не одолели, посмотрит как справится AI&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/slopsquatting-how-ai-hallucinations-are-fueling-a-new-class-of-supply-chain-attacks&quot;&gt;новый тип уязвимости&lt;/a&gt;: нередко AI генерируют в коде зависимостей выдуманные названия пакетов, это в целом не проблема до тех пор, пока злоумышленники не начинают создавать под этими именами уже реальные пакеты с вредоносным кодом, которые попадают к вам в &lt;code&gt;node_modules&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://firebase.studio&quot;&gt;firebase.studio&lt;/a&gt; — в полку AI-редакторов прибыло со стороны Гугла: внутри работает Gemini, заявлена кросс-платформенность (веб, мобайл), деплой в гугловый хостинг&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://json5.org&quot;&gt;json5&lt;/a&gt; — JSON для людей (для ручного написания, например, конфигов): с trailing-запятыми, одиночными кавычками, переводом на новую строку, числами, комментами&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://typescript.guru/the-case-for-web-components-with-lit/&quot;&gt;юзкейс lit-веб-компонентов&lt;/a&gt; для создания кросс-фреймворчной библиотеки компонентов или дизайн-системы: не лочится на конкретный фреймворк, один источник правды&lt;/li&gt;
&lt;li&gt;юнион нескольких наборов свойств &lt;a href=&quot;https://timmarinin.net/2025/prefer-union-over-optional/&quot;&gt;лучше&lt;/a&gt; опциональных свойств в интерфейсе, так как добавляя возможность отсутствия свойства, вы создаёте больше возможных комбинаций свойств, часть их которых может быть невалидна:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;type NotificationProps =
  | { type: &quot;error&quot;; message: string }
  | {
      type: &quot;warning&quot;;
      message: string;
      buttonText: string;
    };

type NotificationProps = { message: string } &amp;amp; (
  | { type: &quot;error&quot; }
  | { type: &quot;warning&quot;; buttonText: string }
);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://2ality.com/2025/04/deploying-typescript-present-future.html&quot;&gt;интересное предположение&lt;/a&gt;, что развитие TS в сторону «вырезания» типов, в том числе и потенциальная поддержка «чистого» TS в браузерах, возможно приведёт к падению популярности JSX (в пользу &lt;a href=&quot;https://github.com/developit/htm&quot;&gt;htm&lt;/a&gt; и &lt;a href=&quot;https://lit.dev/docs/libraries/standalone-templates/&quot;&gt;lit-html&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://waspdev.com/articles/2025-04-16/what-i-dislike-in-javascript&quot;&gt;неприятные фишки JS&lt;/a&gt;, с которыми вы наверняка сталкивались: &lt;code&gt;typeof&lt;/code&gt;, сравнение двух &lt;code&gt;NaN&lt;/code&gt;, неочевидный порядок в &lt;code&gt;.sort()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leanrada.com/notes/simple-live-reload/&quot;&gt;наколеночный инжиниринг для livereload&lt;/a&gt;: через &lt;code&gt;PerformanceObserver&lt;/code&gt; следим за всеми загруженными ресурсами, поллим урл с запросом мета-данных, проверяем заголовки &lt;code&gt;Last-Modified&lt;/code&gt; и &lt;code&gt;ETag&lt;/code&gt;, в случае, если файл обновился — перезагружаемся&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/tailwinds-apply-feature-is-better-than-it-sounds/&quot;&gt;неправославное использование&lt;/a&gt; &lt;code&gt;tailwind&lt;/code&gt;, которое мне симпатизирует: применяем &lt;code&gt;@apply&lt;/code&gt; как миксин в обычном CSS вместо портянки атомарных классов в HTML, опционально используем название &lt;code&gt;@utility&lt;/code&gt; как отдельный CSS-класс&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/css-media-range-syntax&quot;&gt;напоминание&lt;/a&gt;, что Media Queries Range Syntax &lt;code&gt;@media (100px &amp;lt;= width &amp;lt;= 1900px)&lt;/code&gt; теперь доступен во всех браузерах&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flex-wrap: wrap&lt;/code&gt; не только переносит flex-элементы на новую строку, но и в целом включает &lt;a href=&quot;https://css-tip.com/flex-wrap/&quot;&gt;режим многострочного flex-контейнера&lt;/a&gt;, то есть &lt;code&gt;align-content&lt;/code&gt; становится можно применять даже случае одного элемента в контейнере&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:only-child&lt;/code&gt; хорошо сочетается с &lt;code&gt;:has&lt;/code&gt; — применяем &lt;a href=&quot;https://html-css-tip-of-the-week.netlify.app/tip/only-child/&quot;&gt;стили для элемента с единственным потомком&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;.card:has(&amp;gt; :only-child) {
  padding: 2rem;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;элемент &lt;code&gt;&amp;lt;noscript&amp;gt;&lt;/code&gt; можно &lt;a href=&quot;https://0xda.de/blog/2025/04/hiding-elements-that-require-javascript-without-javascript/&quot;&gt;использовать для задания фолбек-стилей&lt;/a&gt;, например, для сокрытия интерактивных элементов при отсутствии скриптов:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;noscript&amp;gt;
  &amp;lt;style&amp;gt;
    .d-js-required {
      display: none;
    }
  &amp;lt;/style&amp;gt;
&amp;lt;/noscript&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://techhub.iodigital.com/articles/interop-2025-which-browser-features-to-get-acquainted-with-this-year-and-why-you-should-care&quot;&gt;в Interop 2025 наш ждёт&lt;/a&gt;: Anchor positioning, улучшение &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;, &lt;code&gt;@scope&lt;/code&gt; (топ!), View transitions для SPA, багфиксы &lt;code&gt;backdrop-filter&lt;/code&gt;, событие &lt;code&gt;scrollend&lt;/code&gt;, мультисвойство &lt;code&gt;text-decoration&lt;/code&gt; (а где же мои Style Container Queries в FF?!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gatesnotes.com/home/home-page-topic/reader/microsoft-original-source-code&quot;&gt;рубрика дедовские мемуары&lt;/a&gt;: Билл Гейтс вспоминает, как они сотоварищи писали интерпретатор языка BASIC для процессора, которого у них самих не было, но они соврали, что есть&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.blog/open-source/git/git-turns-20-a-qa-with-linus-torvalds/&quot;&gt;продолжение рубрики от другого деда&lt;/a&gt;: Линус Торвальдс вспоминает, как 20 лет назад написал git лично для себя, и ему было начхать на окружающих&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lucianonooijen.com/blog/why-i-stopped-using-ai-code-editors/&quot;&gt;чувак убрал из своих редакторов AI-помощников&lt;/a&gt;, так как понял, что начал тупеть (я тоже так сделал, ни о чём не жалею), и пользуется LLM в отдельной модальности для подходящих задач&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 25.04.2025</title><link>https://juwain.github.io/web-platform/blog/2025-04-25/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-04-25/</guid><description>Новости веб-платформы</description><pubDate>Fri, 25 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;не Vitest единым: в параллельной Rust-песочнице &lt;a href=&quot;https://github.com/web-infra-dev/rstest&quot;&gt;начали готовить свой тестовый фреймворк на основе API Jest&lt;/a&gt;, обещают глубокую интеграцию с RS-экосистемой&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pnpm/pnpm/releases/tag/v10.9.0&quot;&gt;в новой версии pnpm 10.9&lt;/a&gt; поддержана установка JSR-пакетов &lt;code&gt;pnpm add jsr:&amp;lt;pkg_name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/blog/2025/04/21/react-compiler-rc&quot;&gt;вышел React Compiler RC&lt;/a&gt;: прошлый отдельный eslint-плагин смерджен в &lt;code&gt;eslint-plugin-react-hooks&lt;/code&gt;, начали двигаться в сторону поддержки в том числе Babel-free-сборки&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more#activity&quot;&gt;в React экспериментируют&lt;/a&gt; с &lt;code&gt;ViewTransitions&lt;/code&gt; — плавными переходами между компонентами, наборами данных, состояниями интерфейса, а также с &lt;code&gt;Activity&lt;/code&gt; — специальным API для анмаунта частей инфтерфейса, но с сохранением их состояния и низкоприоритетным продолжением рендера (для дальнейшего возможного показа этих частей)&lt;/li&gt;
&lt;li&gt;пропоузал Records and Tuples в ES был &lt;a href=&quot;https://github.com/tc39/proposal-record-tuple/issues/394&quot;&gt;официально отклонён TC39&lt;/a&gt; из-за нежелания добавлять новые примитивы в язык, в пользу добавления новых объектов (&lt;a href=&quot;https://github.com/tc39/proposal-composites/issues/15&quot;&gt;tc39/proposal-composites#15&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;JetBrains выкатили обновление &lt;a href=&quot;https://blog.jetbrains.com/webstorm/2025/04/webstorm-2025-1/&quot;&gt;WebStorm 2025.1&lt;/a&gt; с подпиской на возможность подключить AI-ассистента + агента&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://number-flow.barvian.me/&quot;&gt;number-flow&lt;/a&gt; — в последнее время распространился дизайн-паттерн, когда что-то печатается в браузере, и этот кросс-фреймворковый компонент для анимированного перехода между чисел может пригодиться&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/playwright-mcp&quot;&gt;playwright-mcp&lt;/a&gt; — вот к Playwright вслед за Puppeteer прикрутили MCP-интерфейс, так что теперь LLM смогут &lt;em&gt;невизуально&lt;/em&gt; взаимодействовать со страницами благодаря дереву доступности (погодите, но это же была тула для тестов?!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи и демки&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;в недавно вышедшем Chrome 135 &lt;a href=&quot;https://chromestatus.com/feature/4654499737632768&quot;&gt;появилась экспериментальная поддержка fetchLater&lt;/a&gt; — особого API для отправки beacon-запроса «в один конец»; замысел авторов — не отталкиваться больше от событий страницы (&lt;code&gt;unload&lt;/code&gt;/&lt;code&gt;beforeUnload&lt;/code&gt;, которые поддерживаются нестабильно), а перейти к регистрации разработчиками намерения отправить beacon-запрос, а браузер уже позаботится об остальном сам (хотя, в целом, целесообразность появления этого API не очень ясна, ведь недавно как раз везде поддержали &lt;code&gt;keepAlive&lt;/code&gt; у обычного &lt;code&gt;fetch&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;одна из причин, почему &lt;a href=&quot;https://plainvanillaweb.com/blog/articles/2025-04-21-attribute-property-duality/&quot;&gt;с веб-компонентами всё сложно&lt;/a&gt;: атрибут у HTML-элемента и значение свойства у JS-объекта этого элемента — это разные штуки: когда меняется свойство, значение атрибута не меняется, а вот смена значения атрибута чаще всего отзеркаливается в смене значения свойства, и в веб-компонентах как кастомных элементах с этим нужно разбираться вручную&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://simonsafar.com/2025/if_statements/&quot;&gt;замена ветвистых условий&lt;/a&gt; в функциях на плоскую структуру, где сначала идут early-returns, после идёт непоредственно функциональность, а затем обработка ошибок выполнения, обычно улучшает читаемость, и хочется меньше скипать код при его изучении&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://piccalil.li/blog/advanced-typescript-manipulation-features-for-the-real-world/&quot;&gt;разбор более сложных кейсов в TS&lt;/a&gt;: &lt;code&gt;as const&lt;/code&gt; для уточнения типа, indexed access types, mapped types:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const sendEvent = &amp;lt;E extends EventName&amp;gt;(event: E, payload: HomeEvents[E]) =&amp;gt; {
  /* ... */
};
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;type BooleanProperties&amp;lt;Type&amp;gt; = {
  [Key in keyof Type]: boolean;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fotis.xyz/posts/the-new-cookie-store-api/&quot;&gt;история про новенький Cookie Store API&lt;/a&gt;, который то ли уже появился в оставшемся FF, то ли всё таки ещё нет, и о том, как уже сейчас можно встроить его в React-приложение с фолбеком&lt;/li&gt;
&lt;li&gt;использование &lt;code&gt;useEffect&lt;/code&gt; для синхронизации нескольких состояний — &lt;a href=&quot;https://ondrejvelisek.github.io/avoid-state-synchronization-trap/&quot;&gt;не очень хорошая идея&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;сердечко с &lt;a href=&quot;https://css-tip.com/heart/&quot;&gt;новомодной функцией &lt;code&gt;shape()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;если вы не знаете, &lt;a href=&quot;https://adactio.com/journal/21853&quot;&gt;как подступиться к формату oklch&lt;/a&gt;, имея на руках макеты с rgb-цветами, то можно начать с «каста» rgb-цвета в oklch, а дальше уже тюнить lch-результат:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;--page-colour: oklch(from #49498d calc(l / 4) c h);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;помимо привычных браузеров Chrome, Firefox, Safari и Edge, которые в современном мире распространяются дефолтными установками в ОС, на базе их опенсорсных движков строят &lt;a href=&quot;https://frontendmasters.com/blog/newfangled-browser-alternatives/&quot;&gt;другие браузеры со своими фишками&lt;/a&gt;: где-то с переосмысленным UX (Arc, Horse, Zen, Wavebox, Surf, Shift), где-то с доп privacy (Orion, DuckDuckGo), где-то с доп функциями (Vivaldi), где-то с криптой (Brave), но отдельные смельчаки строят полностью свои движки (Ladybird, Flow, Servo)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cekrem.github.io/posts/coding-as-craft-going-back-to-the-old-gym/&quot;&gt;ещё один пойнт&lt;/a&gt; про осознанное применение AI в кодинге: делегируя AI-помощнику трудности решения проблем и нахождение решений, вы обкрадываете свой же опыт, благодаря которому нарабатывается экспертиза (преодоление «диких» условий без сторонней помощи закаляет), а также лишаете себя удовольствия от процесса (ведь кодинг это не только выдача готового кода, но и удовлетворение от становления лучшей версией себя в процессе его написания), а вот делегировать рутинные части, бойлерплейт и объяснение концепций — вполне ок для AI&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 02.05.2025</title><link>https://juwain.github.io/web-platform/blog/2025-05-02/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-05-02/</guid><description>Новости веб-платформы</description><pubDate>Fri, 02 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/138.0/releasenotes/&quot;&gt;зарелизился Firefox 138&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;в сам браузер добавили профили пользователей, а также раскатили на всех &lt;a href=&quot;https://blog.mozilla.org/en/firefox/tab-groups-community/&quot;&gt;группы табов&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;добавили поддержку &lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import/with&quot;&gt;Import Attributes&lt;/a&gt; (теперь поддерживается везде), а также &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/isError&quot;&gt;Error.isError&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;как и обещали, поправили дефолтную стилизацию вложенных элементов &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;а так же радостная новость: в &lt;a href=&quot;https://www.mozilla.org/en-US/firefox/140.0a1/releasenotes/#note-790833&quot;&gt;FF 139&lt;/a&gt; (уже есть в ночной сборке 140) появится поддержка View Transition API (теперь будет поддерживаться везде!)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nuxt.com/blog/v3-17&quot;&gt;вышел Nuxt 3.17&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;докрутили фетч данных: теперь при использовании &lt;code&gt;useAsyncData&lt;/code&gt; или &lt;code&gt;useFetch&lt;/code&gt; запросы будут шарить один и тот же реф на данные по одинаковому ключу между всеми компонентами&lt;/li&gt;
&lt;li&gt;в нескольких компонентах, использующих одинаковый источник данных, рефетч будет происходить только один раз при изменении зависимостей&lt;/li&gt;
&lt;li&gt;в качестве ключей в запросах теперь можно использовать реактивные примитивы (рефы, computed-ы или геттеры)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://storybook.js.org/blog/storybook-9-beta/&quot;&gt;вышла бета Storybook 9&lt;/a&gt;: в инструмент вовсю интегрируют запуск всевозможных тестов (UI, интерактивность, доступность, скриншоты), сынтегрировались с Vitest, поддержали React Native&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://privacysandbox.com/news/privacy-sandbox-next-steps/&quot;&gt;в Chrome передумали блокировать&lt;/a&gt; 3rd-party куки по умолчанию (не смогли со всеми договориться), всё останется как есть сейчас (можно вручную отказаться в настройках браузера), а также пообещали в Incognito-режиме добавить маскировку IP-адреса устройства&lt;/li&gt;
&lt;li&gt;и ещё про Chrome: в грядущей принудительной продаже браузера &lt;a href=&quot;https://arstechnica.com/ai/2025/04/chatgpt-head-tells-court-openai-is-interested-in-buying-chrome/&quot;&gt;покупателем может стать OpenAI&lt;/a&gt; (если так случится, то скорость изменения индустрии ещё больше ускорится)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gsap.com/blog/3-13/&quot;&gt;вышел GSAP 3.13&lt;/a&gt;: на удивление, фаундеры и ментейнеры до их покупки Webflow, никуда не ушли, а продолжают пилить проект; с этим релизом в GSAP сделали все ранее платные плагины бесплатными, а заодно и дропнули премиальный клуб GSAP&lt;/li&gt;
&lt;li&gt;со стороны Microsoft &lt;a href=&quot;https://blogs.windows.com/msedgedev/2025/04/22/contextual-logging-with-console-context/&quot;&gt;поступило предложение&lt;/a&gt; расширить &lt;code&gt;console&lt;/code&gt; методом &lt;code&gt;context()&lt;/code&gt;, чтобы иметь возможность группировать и стилизовать в консоли дев-тулзов портянку разносортных логов&lt;/li&gt;
&lt;li&gt;для V8 (начиная с Chrome 136) внутри JS-файлов &lt;a href=&quot;https://v8.dev/blog/explicit-compile-hints&quot;&gt;можно указывать спец-коммент&lt;/a&gt; для компилятора &lt;code&gt;//# allFunctionsCalledOnLoad&lt;/code&gt;, чтобы явно указать движку, что этот скрипт нужно распарсить и скомпилировать сразу же при первой встрече, а не тогда, когда потребуется выполнение определённой функции из этого скрипта&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kermit-font.com/&quot;&gt;kermit-font&lt;/a&gt; — прикольный «детский» шрифт в духе Comic Sans (поддерживается кириллица, есть вариативность)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://unbuilt.app&quot;&gt;unbuilt.app&lt;/a&gt; — реверс-сервис, находящий по артефактам в коде сайтов, какие технологии использовались для их создания&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://srvx.h3.dev/&quot;&gt;srvx&lt;/a&gt; — универсальный сервер с единым синтаксисом для Deno, Bun, Node.js&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/daviddarnes/component-template&quot;&gt;component-template&lt;/a&gt; — если уж теперь LLM расширяют наши возможности, почему бы не попробовать начать писать веб-компоненты? Вот как раз и стартовый шаблон подходящий нашелся.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;из всех способов &lt;a href=&quot;https://2ality.com/2025/04/stringification-javascript.html&quot;&gt;вывести &lt;em&gt;что-то&lt;/em&gt; как строку&lt;/a&gt;, менее подверженный ошибкам — &lt;code&gt;{}.toString.call(v)&lt;/code&gt;, но в большинстве случаев подойдёт &lt;code&gt;String(v)&lt;/code&gt;, но он, в свою очередь, не выведет содержимое объекта; для этого подходит &lt;code&gt;JSON.stringify()&lt;/code&gt;, но тоже со своими ограничениями&lt;/li&gt;
&lt;li&gt;возьмём дерево компонентов в React: &lt;a href=&quot;https://frontendmasters.com/blog/react-internals-which-useeffect-runs-first/&quot;&gt;обход и рендер&lt;/a&gt; происходит начиная с родителей «вглубь» детей, а применение эффектов (&lt;code&gt;useEffect&lt;/code&gt;) — на «обратном» пути обхода, «вверх» от детей к родителям&lt;/li&gt;
&lt;li&gt;если вам &lt;a href=&quot;https://antfu.me/posts/categorize-deps&quot;&gt;для управления зависимостями&lt;/a&gt; в &lt;code&gt;package.json&lt;/code&gt; недостаточно &lt;code&gt;dependencies&lt;/code&gt; и &lt;code&gt;devDependencies&lt;/code&gt; и хочется добавить категории, можно использовать &lt;a href=&quot;https://pnpm.io/catalogs&quot;&gt;PNPM Catalogs&lt;/a&gt; для группировки: хоть фича изначально для монореп, но она помогает разделить пакеты и внутри одного репо по категориям (&lt;code&gt;test&lt;/code&gt;, &lt;code&gt;frontend&lt;/code&gt;, &lt;code&gt;types&lt;/code&gt;, &lt;code&gt;lint&lt;/code&gt;…)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-irl.info/creating-css-variables-from-a-js-file/&quot;&gt;рецепт&lt;/a&gt;, как просто на коленке, без сторонних зависимостей хранить дизайн-токены в JSON, а транслировать в CSS в виде переменных в &lt;code&gt;:root {}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/add-jsr-with-pnpm-yarn&quot;&gt;устанавливать пакеты из JSR&lt;/a&gt; вместо npm, уже умеет pnpm 10.9+ и yarn 4.9.0+&lt;/li&gt;
&lt;li&gt;рубрика «что хотел сказать автор» от Дэна Абрамова &lt;a href=&quot;https://overreacted.io/what-does-use-client-do/&quot;&gt;про RSC&lt;/a&gt; продолжается: директива &lt;code&gt;&apos;use client&apos;&lt;/code&gt; делает компонент доступным серверу через &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, чтобы он мог его предвыполнить, а &lt;code&gt;&apos;use server&apos;&lt;/code&gt; экспортирует серверные функции на клиент, чтобы их можно было вызвать асинхронно в RPC-стиле&lt;/li&gt;
&lt;li&gt;все эти ваши сайты — это для людей, а для машин достаточно склеенной текстовой портянки (&lt;a href=&quot;https://bun.sh/llms-full.txt&quot;&gt;пример от Bun&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kxlaa.com/articles/when-you-might-need-to-override-the-defaults-in-tanstack-query&quot;&gt;парочка кандидатов на переопределение&lt;/a&gt; в дефолтных настройках TanStack Query:
&lt;ul&gt;
&lt;li&gt;количество ретраев по умолчанию равно 3, что не всегда ок, например, если используется внутри тестов ошибок (увеличивается время выполнения тестов) → меняем число ретраев на 0&lt;/li&gt;
&lt;li&gt;время инвалидации кеша по умолчанию небольшое, часто происходит бесполезные перезапросы, а если вы уверены, что ответ от внешнего сервиса точно не будет меняться, перезапросов можно избежать → &lt;code&gt;staleTime: Number.POSITIVE_INFINITY&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://emilkowal.ski/ui/good-vs-great-animations&quot;&gt;как подтюнить анимации&lt;/a&gt;, чтобы они из просто хороших стали великолепными:
&lt;ul&gt;
&lt;li&gt;не забыть настроить &lt;code&gt;transform-origin&lt;/code&gt; с той стороны, откуда анимация визуально начинается&lt;/li&gt;
&lt;li&gt;подобрать более натуральный изинг: хотя бы &lt;code&gt;ease-out&lt;/code&gt;, а лучше кастомную «пружинную» функцию&lt;/li&gt;
&lt;li&gt;при реализации динамического выделения табов лучше применить &lt;code&gt;clip-path&lt;/code&gt;, чем просто менять цвет текста и заливки&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/16831/line-height-units/&quot;&gt;единица измерения &lt;code&gt;lh&lt;/code&gt;&lt;/a&gt; хороший (и доступный с 2023 года везде) способ не мучиться с &lt;code&gt;em&lt;/code&gt; для задания межстрочных отступов:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;p {
  margin-block: 1lh;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;скруглённые углы в CSS есть уже давно, но их по-прежнему может не хватать для &lt;em&gt;непрямоугольных&lt;/em&gt; форм, тогда в дело вступает &lt;a href=&quot;https://frontendmasters.com/blog/curved-box-cutouts-in-css/&quot;&gt;давно забытое искусство&lt;/a&gt; подставления скруглённых уголочков на фон блока (только вместо png-картинок выступают радиальные градиенты)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/revisiting-image-maps/&quot;&gt;для реализации кликабельной картинки-карты&lt;/a&gt; с интерактивными областями может подойти древняя пара тегов &lt;code&gt;&amp;lt;map&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;area&amp;gt;&lt;/code&gt;, но могут быть проблемы с респонсивом, поэтому то же можно реализовать в чистом SVG (ведь внутрь групп в качестве обёртки для форм в SVG можно включать ссылки &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://addyo.substack.com/p/avoiding-skill-atrophy-in-the-age&quot;&gt;ещё один тейк, на этот раз от Addy Osmani&lt;/a&gt;, про деградацию скиллов при неразумном использовании AI-тулов: самое плохое — отваливается критическое мышление, не менее неприятное — общения между разработчиками становится меньше&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://til.jakelazaroff.com/git/add-a-global-gitignore/&quot;&gt;для гита можно настроить&lt;/a&gt; глобальный игнор-конфиг для всей системы, на маке/линуксе лежит в &lt;code&gt;~/.config/git/ignore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;чтобы при табе &lt;a href=&quot;https://www.tempertemper.net/blog/focus-priming&quot;&gt;появление фокуса&lt;/a&gt; происходило на инпутах не с левого верхнего угла экрана, а на определённом месте, нужно просто перед табом кликнуть где-то неподалёку&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 09.05.2025</title><link>https://juwain.github.io/web-platform/blog/2025-05-09/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-05-09/</guid><description>Новости веб-платформы</description><pubDate>Fri, 09 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/blog/release/v24.0.0&quot;&gt;вышла Node v24.0.0&lt;/a&gt; с обновлённым V8 и npm, теперь это версия Current (она &lt;a href=&quot;https://nodejs.org/en/about/previous-releases&quot;&gt;станет LTS&lt;/a&gt; в октябре)&lt;/li&gt;
&lt;li&gt;судебное разбирательство с Google помимо продажи Chrome &lt;a href=&quot;https://www.omgubuntu.co.uk/2025/05/mozilla-says-google-search-deal-vital-to-firefoxs-survival&quot;&gt;грозит лишить Firefox и Safari заработка&lt;/a&gt;, так как Google сейчас оплачивает выставленный в пользу Chrome поиск в этих браузерах по умолчанию (и если прекратит это делать, то лишит Mozilla 3/4 дохода); парадоксальная и грустная ситуация, что более здоровые конкурентные рыночные условия добьют FF&lt;/li&gt;
&lt;li&gt;в Figma &lt;a href=&quot;https://www.config.new&quot;&gt;анонсировали и выкатили новые фичи&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://help.figma.com/hc/en-us/articles/31289469907863-Use-the-grid-auto-layout-flow&quot;&gt;внедрили гриды&lt;/a&gt; с растягиванием ячеек, гэпами и выравниванием&lt;/li&gt;
&lt;li&gt;добавили &lt;a href=&quot;https://www.figma.com/draw/&quot;&gt;новые инструменты&lt;/a&gt; для рисования вектора (кисти, заливки, формы)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.figma.com/sites/&quot;&gt;добавили конвертацию макета в код&lt;/a&gt; и публикацию сайта прямо из Figma (но пока что &lt;a href=&quot;https://adrianroselli.com/2025/05/do-not-publish-your-designs-on-the-web-with-figma-sites.html&quot;&gt;есть вопросики к доступности&lt;/a&gt; получаемого результата)&lt;/li&gt;
&lt;li&gt;ну и конечно &lt;a href=&quot;https://www.figma.com/make/&quot;&gt;появилась генерация в макете&lt;/a&gt; «чего угодно» с AI&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://deepwiki.com&quot;&gt;deepwiki&lt;/a&gt; — проект, позволяющий для любого публичного репозитория сгенерировать с помощью AI документацию по исходному коду (создаются даже схемы и диаграммы): например, дока &lt;a href=&quot;https://deepwiki.com/mobxjs/mobx&quot;&gt;mobx&lt;/a&gt;, &lt;a href=&quot;https://deepwiki.com/facebook/react&quot;&gt;react&lt;/a&gt;, &lt;a href=&quot;https://deepwiki.com/torvalds/linux&quot;&gt;linux&lt;/a&gt;; изучать новые либы стало ещё интереснее и проще&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.joshwcomeau.com/operator-lookup/&quot;&gt;operator-lookup&lt;/a&gt; — интерактивный туториал по операторам JS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pyodide.org/en/stable/&quot;&gt;pyodide&lt;/a&gt; — порт CPython на WebAssembly/&lt;a href=&quot;https://emscripten.org/&quot;&gt;Emscripten&lt;/a&gt;, позволяющий запускать код на питоне в браузере/Node.js&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/stevedylandev/bhvr&quot;&gt;bhvr&lt;/a&gt; — а вот и попытка сделать просто работающий фуллстек-React-фреймворк, в который не нужно долго вкуривать, и он не залочен под конкретного вендора: под капотом &lt;strong&gt;B&lt;/strong&gt;un, &lt;strong&gt;H&lt;/strong&gt;ono, &lt;strong&gt;V&lt;/strong&gt;ite, &lt;strong&gt;R&lt;/strong&gt;eact&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Temzasse/react-modal-sheet&quot;&gt;react-modal-sheet&lt;/a&gt; — неплохой UI-элемент выезжающей шторки под React&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/color-js/color.js&quot;&gt;color.js&lt;/a&gt; — либа для манипуляции с цветами от авторов спек (Lea Verou, Chris Lilley) и других уважаемых людей&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@sergio.a.soria/composing-micro-frontends-with-astros-server-islands-88a02728436c&quot;&gt;как организовать микрофронтенды с помощью Astro&lt;/a&gt;: каждый микрофронтенд организуется как отдельный Astro-сервер, с урлов всех микрофронтов получается HTML, а затем с помощью &lt;a href=&quot;https://docs.astro.build/en/guides/server-islands/&quot;&gt;Server Islands&lt;/a&gt; организуется отложенная загрузка динамики каждого фронта (&lt;a href=&quot;https://github.com/sasoria/astro-microfrontends-ssr-distributed/tree/main&quot;&gt;пример&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;и снова рубрика «что хотел сказать автор» от Дэна Абрамова, &lt;a href=&quot;https://overreacted.io/rsc-for-astro-developers/&quot;&gt;и снова про RSC&lt;/a&gt;: на примере того, как организован серверный и клиентский код в Astro, поясняется, что и как организовано в React; проблем сходу вижу две:
&lt;ul&gt;
&lt;li&gt;в Astro разделение на сервер/клиент сходу понятное и простое как палка&lt;/li&gt;
&lt;li&gt;в React надо ещё уложить в голове, что компоненты по-умолчанию серверные, а могут быть клиентские, а на самом деле могут быть и такими, и такими&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;пара человеческих статей о том, как по-разному устроена работа эвент лупа &lt;a href=&quot;https://www.deepintodev.com/blog/how-javascript-works-behind-the-scenes&quot;&gt;в браузерном JS&lt;/a&gt; и в &lt;a href=&quot;https://www.deepintodev.com/blog/how-nodejs-works-behind-the-scenes&quot;&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://waspdev.com/articles/2025-05-07/how-to-sanitize-html-without-libraries&quot;&gt;как примерно устроен санитайзер HTML&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;берём сырой HTML,&lt;/li&gt;
&lt;li&gt;вставляем его в новый неактивный документ через &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/DOMParser&quot;&gt;DOMParser&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;затем пробегаемся рекурсивно по дочерним нодам, смотрим на соответствие их списку допустимых тегов, а также на &lt;em&gt;нессылки&lt;/em&gt; в урлах ссылок или картинок,&lt;/li&gt;
&lt;li&gt;берём проверенные ноды, отбрасываем не прошедшие проверку&lt;/li&gt;
&lt;li&gt;возвращаем отфильтрованные ноды&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/shape-a-new-powerful-drawing-syntax-in-css/&quot;&gt;сборник юзкейсов&lt;/a&gt; новой функции &lt;code&gt;shape()&lt;/code&gt; (ждём только &lt;a href=&quot;https://caniuse.com/mdn-css_types_basic-shape_shape&quot;&gt;FF в 141 версии&lt;/a&gt;), и заодно &lt;a href=&quot;https://webkit.org/blog/16794/the-css-shape-function/&quot;&gt;интро&lt;/a&gt; в блоге webkit: самый сок этой функции — это человекочитаемые команды внутри и возможность использовать переменные, чтобы делать формы респонсивными&lt;/li&gt;
&lt;li&gt;хорошая фича &lt;a href=&quot;https://webkit.org/blog/16854/margin-trim/&quot;&gt;margin-trim&lt;/a&gt;, которая подрезает лишние отступы детей, выезжающие за родителя, но поддерживается только в Safari, печаль&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gomakethings.com/an-aspect-ratio-css-utility-class/&quot;&gt;утилитарный класс&lt;/a&gt; для установки &lt;code&gt;aspect-ratio&lt;/code&gt; у картинок/видео, само соотношение сторон в переменной, чтобы задать извне:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;[class*=&quot;aspect-ratio&quot;] {
  --ratio: auto;
  object-fit: cover;
  aspect-ratio: var(--ratio);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;подход к решению задачи показа/сокрытия боковых фейдов при скролле (в начале скролла фейд скрыт со стороны начала скролл-контейнера, в конце — со стороны конца контейнера): обычно это решается через JS, но &lt;a href=&quot;https://css-tricks.com/modern-scroll-shadows-using-scroll-driven-animations/&quot;&gt;здесь приводится решение через скролл-анимации&lt;/a&gt;, когда в зависимости от кейфрейма, переменная обнуляется или задаётся значением:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@keyframes scrollfade {
  0% {
    --left-fade: 0;
  }
  10%,
  100% {
    --left-fade: 3rem;
  }
  0%,
  90% {
    --right-fade: 3rem;
  }
  100% {
    --right-fade: 0;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;вот уже &lt;a href=&quot;https://thenewstack.io/frontends-next-evolution-ai-powered-state-management/&quot;&gt;пошли первые фантазии&lt;/a&gt; на тему AI-мидлвар в стейт-менеджерах на фронте: типа вместо написания конкретной логики делегируем разрешение конфликтов, мемоизацию и префетч умной плослойке в виде AI-модели (уходим от кодоцентричной разработки к описанию поведения на естественном языке)&lt;/li&gt;
&lt;li&gt;часто &lt;a href=&quot;https://cekrem.github.io/posts/psychology-of-clean-code/&quot;&gt;мы не пишем чистый код&lt;/a&gt;, потому что торопимся успеть до дедлайна, перегружены или не хотим трогать, чтобы не поломалось; но в целом, если устраивать «партизанский» рефакторинг, ревьюить самого себя до отправки на общественное ревью и представлять, что скажет «будущий я» по поводу этого кода, то код точно станет получше&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 16.05.2025</title><link>https://juwain.github.io/web-platform/blog/2025-05-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-05-16/</guid><description>Новости веб-платформы</description><pubDate>Fri, 16 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в Chrome 136 &lt;a href=&quot;https://developer.chrome.com/blog/visited-links&quot;&gt;обезопасили хранение истории посещения ссылок&lt;/a&gt;: с помощью безобидного селектора &lt;code&gt;:visited&lt;/code&gt; с вредоносного сайта можно прочекать вашу историю посещения ссылок, так как она применяется к ссылкам сразу на всех сайтах; теперь же история посещения ссылок будет ограничена только конкретным сайтом, и со стороннего сайта вынуть из CSS её будет нельзя&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/16923/webkit-features-in-safari-18-5/&quot;&gt;Safari обновился до 18.5&lt;/a&gt;: добавили поддержку Declarative Web Push, который работает без Service Worker&lt;/li&gt;
&lt;li&gt;а в версии Safari Technology Preview &lt;a href=&quot;https://webkit.org/blog/16929/contrast-color/&quot;&gt;допилили функцию&lt;/a&gt; &lt;code&gt;contrast-color()&lt;/code&gt;, которая для переданного цвета автоматом подбирает контрастный чёрный или белый:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;color: contrast-color(purple);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;в Edge &lt;a href=&quot;https://blogs.windows.com/msedgedev/2025/05/05/creating-a-more-accessible-web-with-aria-notify/&quot;&gt;пробуют новое API ARIA Notify&lt;/a&gt; с помощью которого можно программно вызвать произнесение сообщения для определённой DOM-ноды скринридером:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;document.querySelector(&quot;#text-editor&quot;).ariaNotify(&quot;Selected text is bold&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mozilla-firefox/firefox&quot;&gt;исходники Firefox иронично завезли&lt;/a&gt; на майкрософтовский Github, видимо уже готовятся сдавать в музэй&lt;/li&gt;
&lt;li&gt;оказывается для &lt;a href=&quot;https://www.oddbird.net/2025/05/06/polyfill-updates/&quot;&gt;popover-ов и anchor positioning&lt;/a&gt; есть прям «официальные» полифиллы &lt;a href=&quot;https://github.com/oddbird/popover-polyfill/tree/v0.6.0&quot;&gt;@oddbird/popover-polyfill&lt;/a&gt; и &lt;a href=&quot;https://github.com/oddbird/css-anchor-positioning&quot;&gt;@oddbird/css-anchor-positioning&lt;/a&gt;, так что если вы не использовали их по причине нераспостранённости в браузерах, то это не проблема&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://parceljs.org/blog/v2-15-0&quot;&gt;вышел Parcel v2.15.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;движок переписан на Rust&lt;/li&gt;
&lt;li&gt;внутри начали использовать другой HTML-парсер, &lt;a href=&quot;https://github.com/servo/html5ever&quot;&gt;html5ever&lt;/a&gt; из движка Servo&lt;/li&gt;
&lt;li&gt;с SVGO перешли на Rust-аналог — &lt;a href=&quot;https://github.com/noahbald/oxvg&quot;&gt;OXVG&lt;/a&gt; (работает &lt;a href=&quot;https://github.com/noahbald/oxvg/wiki/Benchmarks&quot;&gt;в разы быстрее&lt;/a&gt;, чем JS; хотя уход с JS-решений, как по мне, в долгую ухудшает поддерживаемость тулов в угоду сиюминутному ускорению)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wanasit/chrono&quot;&gt;chrono&lt;/a&gt; — парсер даты из строки на человеческом языке в машиночитаемый формат&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;chrono.parseDate(&quot;An appointment on Sep 12-13&quot;);
// Fri Sep 12 2014 12:00:00 GMT-0500 (CDT)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/voideditor/void&quot;&gt;void&lt;/a&gt; — опенсорсный аналог Cursor (на самом деле ещё один пока ещё бесплатный форк VS Code)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-generators.com/svg-to-css/&quot;&gt;svg-to-css&lt;/a&gt; — транслятор нечитаемой SVG-формы в более читаемый CSS-синтаксис &lt;code&gt;clip-path: shape()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leptos.dev&quot;&gt;leptos&lt;/a&gt; — React-подобный фреймворк на Rust со знакомыми паттернами (реактивные сигналы, подобие JSX, компоненты)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://basecoatui.com/&quot;&gt;basecoatui&lt;/a&gt; — shadcn/ui, портированный с React в чистый HTML/CSS&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/NickvanDyke/eslint-plugin-react-you-might-not-need-an-effect&quot;&gt;eslint-plugin-react-you-might-not-need-an-effect&lt;/a&gt; — плагин для ESLint, подсвечивающий &lt;a href=&quot;https://react.dev/learn/you-might-not-need-an-effect&quot;&gt;лишнее использование &lt;code&gt;useEffect&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;эволюция альтернативного минималистичного генератора статических сайтов &lt;a href=&quot;https://github.com/nuejs/nue/tree/master/packages/nuejs&quot;&gt;Nue JS&lt;/a&gt; привела к &lt;a href=&quot;https://nuejs.org/blog/introducing-hyper/&quot;&gt;ребредингу в Hyper&lt;/a&gt; — также минималистичный, но уже полноценный headless view layer, которым изначально и планировался React, но потом что-то пошло не так&lt;/li&gt;
&lt;li&gt;если вы не уверены точно, какой будет лог у следующего кода, то есть &lt;a href=&quot;https://www.deepintodev.com/blog/how-promises-work-in-javascript&quot;&gt;подробное объяснение о работе промисов&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;new Promise((resolve) =&amp;gt; {
  console.log(&quot;Deep&quot;);
  resolve(&quot;12&quot;);
}).then((result) =&amp;gt; console.log(result));

console.log(25);
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;если ваш проект с JS/TS, JSX/TSX, CSS, у вас нет желания мигрировать на новый ESLint (или же надоело дружить между собой Pretier и ESLint), зато есть желание куда-то съехать, то вот &lt;a href=&quot;https://blog.appsignal.com/2025/05/07/migrating-a-javascript-project-from-prettier-and-eslint-to-biomejs.html&quot;&gt;гайдик по переезду на Biome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;противоречие Rust- и JS-тулингов &lt;a href=&quot;https://github.com/oxc-project/oxc/issues/10048&quot;&gt;даёт о себе знать&lt;/a&gt;: React Compiler — JS-тула, использует Babel, и не работает с Rust-тулченами типа SWC и OXC&lt;/li&gt;
&lt;li&gt;пример &lt;a href=&quot;https://cekrem.github.io/posts/dependency-inversion-in-react/&quot;&gt;реализации простой Dependency Inversion в React&lt;/a&gt;, когда отделяется слой работы с данными и подтягивается в компонент как зависимость&lt;/li&gt;
&lt;li&gt;Дэн не унимается и &lt;a href=&quot;https://overreacted.io/static-as-a-server/&quot;&gt;продолжает толкать свою телегу&lt;/a&gt;: на этот раз напоминание, что RSC могут рендериться в билд-тайме в статичный HTML вовсе без использования «серверных» функций&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://julesblom.com/writing/parent-owners-context&quot;&gt;тонкость работы с контекстом в React&lt;/a&gt;: если вынести контекст-провайдер в отдельную обёртку и прокидывать содержимое в него через &lt;code&gt;children&lt;/code&gt;, то при изменении стейта внутри этой обёртки можно избавиться от лишних ререндеров &lt;code&gt;children&lt;/code&gt;, так как они не меняются (и &lt;a href=&quot;https://blacksheepcode.com/posts/no_react_context_is_not_causing_too_many_renders&quot;&gt;ещё одна статейка&lt;/a&gt; про этот же подход, но с более обширным объяснением)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.totaltypescript.com/books/total-typescript-essentials&quot;&gt;новая книга по основам TS «Total TypeScript Essentials»&lt;/a&gt; от Matt Pocock: пока не читал, но одобряю не глядя&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;как с помощью CSS-анимаций делать &lt;a href=&quot;https://www.smashingmagazine.com/2025/05/smashing-animations-part-1-classic-cartoons-inspire-css/&quot;&gt;простую «ретро»-мультипликацию&lt;/a&gt;: когда &lt;code&gt;@keyframes&lt;/code&gt; используются буквально по прямому назначению, декорации движутся, показываются и скрываются, а в итоге всё кажется живым&lt;/li&gt;
&lt;li&gt;реализация &lt;a href=&quot;https://dev.to/madsstoumann/guitar-chords-in-css-3hk8&quot;&gt;схем гитарных аккордов&lt;/a&gt; на гридах, фукнции &lt;code&gt;attr()&lt;/code&gt;, градиентах и container-queries (Chrome only)&lt;/li&gt;
&lt;li&gt;так, тут &lt;a href=&quot;https://css-tricks.com/scroll-driven-animations-inside-a-css-carousel/&quot;&gt;опасная и экспериментальная CSS-магия&lt;/a&gt;: берём scroll animations, добавляем новенькие CSS-карусели и вишенкой на торте — scroll snaps: так можно в карусельке реализовать динамическую высоту слайдов в зависимости от скролла (Chrome only)&lt;/li&gt;
&lt;li&gt;псевдоэлементом &lt;code&gt;::first-letter&lt;/code&gt; можно стилизовать не только обычную букву, но и любой символ, &lt;a href=&quot;https://frontendmasters.com/blog/initial-letter-with-emoji/&quot;&gt;к примеру, emoji&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;li&amp;gt;🍎 &amp;lt;strong&amp;gt;Apple&amp;lt;/strong&amp;gt; Text&amp;lt;/li&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;li::first-letter {
  initial-letter: 3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;тема &lt;code&gt;height: 100%&lt;/code&gt; &lt;a href=&quot;https://www.joshwcomeau.com/css/height-enigma/&quot;&gt;неочевидно работает в CSS&lt;/a&gt; из-за двух противоречащих друг другу механизмов: 1) по умолчанию во Flow layout родитель принимает минимально необходимую высоту для показа дочерних элементов; 2) высота ребёнка, заданная в % расчитывается относительно родителя. Поэтому для корректной работы процентной высоты во Flow layout она должна быть выставлена в &lt;code&gt;100%&lt;/code&gt; для всех возможных родителей (&lt;code&gt;#root&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt;, &lt;code&gt;html&lt;/code&gt;). Или же можно не заморачиваться и использовать другой контекст форматирования — Grid layout, в котором не родитель схлопывается под высоту ребёнка, а наоборот дети растягиваются на высоту родителя&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;как узнать, &lt;a href=&quot;https://gomakethings.com/how-to-tell-if-your-site-is-gzipped/&quot;&gt;используется ли на вашем сервере gzip&lt;/a&gt; или другое сжатие: в девтулзах во вкладке Network смотрим на выполненный запрос, в колонке Size сверху отображается transferred size и пониже actual size; если transferred &amp;lt; actual, значит сжатие есть&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 23.05.2025</title><link>https://juwain.github.io/web-platform/blog/2025-05-23/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-05-23/</guid><description>Новости веб-платформы</description><pubDate>Fri, 23 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;команда TS выкатила &lt;a href=&quot;https://devblogs.microsoft.com/typescript/announcing-typescript-native-previews/&quot;&gt;превью нативного TS на Go&lt;/a&gt;, можно попробовать в терминале &lt;code&gt;npm install -D @typescript/native-preview&lt;/code&gt; или в &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=TypeScriptTeam.native-preview&quot;&gt;VS Code в виде расширения&lt;/a&gt;: оно живое (!) и по ощущениям LSP в VS Code шевелится побыстрее&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/blogs/2025/05/19/openSourceAIEditor&quot;&gt;Microsoft заопенсорсит расширение Copilot-чата&lt;/a&gt;, тем самым видимо планируя прикрыть зоопарк форков VS Code с AI-панельками; также Copilot Chat будет поддержан в вебе и &lt;a href=&quot;https://github.com/microsoft/vscode/issues/248627&quot;&gt;существенно доработан&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;и тему VS Code продолжает новость, что в редакторах HTML и CSS в подсказках будет выдаваться инфа о Baseline-поддержке свойств, тегов и атрибутов (а также не только в VS Code, но и в других редакторах, которые используют &lt;a href=&quot;https://github.com/microsoft/vscode#readme&quot;&gt;опенсорсные наработки Code - OSS&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amitmerchant.com/the-pipe-operator-php-85/&quot;&gt;в PHP 8.5 появится pipe-оператор&lt;/a&gt; (ноябрь 2025), а вот &lt;a href=&quot;https://github.com/tc39/proposal-pipeline-operator&quot;&gt;подзаброшенный пропоузал в JS&lt;/a&gt; уже вряд ли вскоре оживёт&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://devclass.com/2025/05/13/stack-overflow-seeks-rebrand-as-traffic-continues-to-plummet-which-is-bad-news-for-developers/&quot;&gt;Stackoverflow стремительно теряет активных пользователей&lt;/a&gt; (и не потому что на все вопросы уже ответили, а потому что узнавать ответы стали в других местах), поэтому компания думает о ребрендинге и перефокусировке с только Q&amp;amp;A ещё на сообщество и построение карьеры; что ж, такие времена, или адаптируйся под AI, или умри&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.mozilla.org/en/mozilla/internet-policy/amicus_brief/&quot;&gt;Mozilla просит суд&lt;/a&gt; не перекрывать «денежный» кислород от Google в антимонопольном деле; такой вот парадокс: чтобы поддержать хоть какую-то конкуренцию, нужно продолжать делать «нерыночные» вливания за поиск Google по умолчанию в FF&lt;/li&gt;
&lt;li&gt;ESLint в добавок к JSON, md и CSS, теперь умеет линтить HTML &lt;a href=&quot;https://eslint.org/blog/2025/05/eslint-html-plugin/&quot;&gt;с помощью плагина html-eslint&lt;/a&gt;; как и в прошлых случаях из коробки сразу идут многие базовые правила, которые не надо дополнительно настраивать&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://guybedford.com/hot-reloading-es-module-shims-2.5&quot;&gt;вышли ES Module Shims 2.5&lt;/a&gt; (это те, которые уже в версии 2.0 давали возможность запускать type-erasable-код на TS прямиком в браузере, без компиляции):
&lt;ul&gt;
&lt;li&gt;позволяют использовать нативные импорты CSS- и JSON-модулей: &lt;code&gt;import style from &apos;./style.css&apos; with { type: &apos;css&apos; };&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;нативный TS теперь просто работает, без доп настроек&lt;/li&gt;
&lt;li&gt;появилась возможность замутить «нативный» hot reload через &lt;code&gt;import.meta.hot&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;в Deno начали тыкать палочкой, типа их фреймворк Fresh что-то уже не особо-то и fresh (протух-с), поэтому &lt;a href=&quot;https://deno.com/blog/an-update-on-fresh&quot;&gt;вышел пост&lt;/a&gt;, что Fresh 2.0 уже на подходе, под капотом будут Express/Hono-like API, позволяющие без лишнего бойлерплейта писать сервер, организовать мидлвари и другие плюшки&lt;/li&gt;
&lt;li&gt;в семействе Rs- &lt;a href=&quot;https://lib.rsbuild.dev/blog/introducing-rslib&quot;&gt;вышла новая либа для создателей либ — Rslib&lt;/a&gt;: внутри уже предустановленные конфиги для беспроблемной сборки (в том числе стилей) и публикации либ в разных форматах (ESM, CJS, UMD, Module Federation)&lt;/li&gt;
&lt;li&gt;а в семействе TanStack &lt;a href=&quot;https://github.com/TanStack/db&quot;&gt;вышла клиентская БД/стор — db&lt;/a&gt;, которая держит данные на клиенте, позволяет делать выборки (query) из этой БД и синкается с любым бэком&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://code2tutorial.com&quot;&gt;code2tutorial&lt;/a&gt; — ещё один проект, составляющий документацию-туториал по репозиторию (аналог &lt;a href=&quot;https://deepwiki.com&quot;&gt;deepwiki&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/humanwhocodes/crosspost/&quot;&gt;crosspost&lt;/a&gt; — JS-либа для кросспостов в соц сети; тут хочется подсветить не фичи либы, а её API — чистый паттерн Strategy (о котором &lt;a href=&quot;/web-platform/trainers/design-patterns-js/12-strategy-theory/&quot;&gt;рассказывал в тренажёре&lt;/a&gt;), зацените&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;для работы с буфером обмена можно использовать методы &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Clipboard/writeText&quot;&gt;&lt;code&gt;navigator.clipboard.writeText()&lt;/code&gt;&lt;/a&gt; для обычного текста или &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Clipboard/write&quot;&gt;&lt;code&gt;navigator.clipboard.write()&lt;/code&gt;&lt;/a&gt; для всех остальных форматов типа картинок, текстового контента и HTML; а проверить браузер на умение вставлять определённый формат (без выброса исключения) можно с помощью &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/ClipboardItem/supports_static&quot;&gt;&lt;code&gt;ClipboardItem.supports()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;а собственно &lt;a href=&quot;https://web.dev/articles/async-clipboard&quot;&gt;Async Clipboard API&lt;/a&gt; поддерживает помимо стандартных &lt;code&gt;text/plain&lt;/code&gt;, &lt;code&gt;text/html&lt;/code&gt; и &lt;code&gt;image/png&lt;/code&gt; ещё и кастомные форматы: для этого при создании &lt;code&gt;new ClipboardItem&lt;/code&gt; нужно указать в названии типа префикс &lt;code&gt;web &lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;const clipboardItem = new ClipboardItem({
  [`web ${jpegBlob.type}`]: jpegBlob,
  [`web ${gifBlob.type}`]: gifBlob,
});
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://macarthur.me/posts/generators/&quot;&gt;юзкейсы генераторов в JS&lt;/a&gt; обычно довольно специфические, но если свести к сути, то они подходят для любой условно «бесконечной» серии действий: перебора элементов, генерации наборов, обработки асинхронных сообщений; неочевидный пример:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;function* getElements(tagName = &quot;div&quot;) {
  while (true) yield document.createElement(tagName);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;alt-текст, который показывается, если изображение не загрузилось, &lt;a href=&quot;https://piccalil.li/blog/you-can-style-alt-text-like-any-other-text/&quot;&gt;тоже можно стилизовать&lt;/a&gt;: для этого к &lt;code&gt;img {}&lt;/code&gt; просто применяются текстовые стили, можно дополнительно проставить в JS data-атрибут для картинок на колбеке &lt;code&gt;onerror&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;для нативных &lt;code&gt;&amp;lt;input type=&quot;date&quot;&amp;gt;&lt;/code&gt; и &lt;code&gt;&amp;lt;input type=&quot;time&quot;&amp;gt;&lt;/code&gt; в &lt;em&gt;некоторых хромиум-браузерах&lt;/em&gt; показываются иконки часов и календаря, для &lt;a href=&quot;https://cassidoo.co/post/input-type-date/&quot;&gt;их стилизации&lt;/a&gt; подходит псевдокласс &lt;code&gt;::-webkit-calendar-picker-indicator&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;если решение работает, это не значит, что оно оптимальное; так ответ на StackOverflow может быть устаревшим, хоть и популярным, и чат-бот также может взять популярное устаревшее решение из поискового топа; вот к примеру &lt;a href=&quot;https://frontendmasters.com/blog/chatgpt-and-old-and-broken-code/&quot;&gt;для анимированного градиента текста&lt;/a&gt; достаточно таких стилей:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;.gradient-text {
  background: linear-gradient(90deg, #00f, #0ff, #00f) -100%/ 200%;
  color: transparent;
  animation: shimmer 2s linear infinite;
  -webkit-background-clip: text;
  background-clip: text;
}

@keyframes shimmer {
  to {
    background-position: 100%;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;новую функцию &lt;code&gt;shape()&lt;/code&gt; можно использовать не только в связке с &lt;code&gt;clip-path()&lt;/code&gt; для рисования фигур, но и с &lt;code&gt;offset-path&lt;/code&gt; &lt;a href=&quot;https://frontendmasters.com/blog/move-modal-in-on-a-shape/&quot;&gt;для задания формы движения&lt;/a&gt;: вместо &lt;code&gt;offset-path: path(&quot;&quot;)&lt;/code&gt; более читаемый &lt;code&gt;offset-path: shape()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://adactio.com/journal/21896&quot;&gt;некоторые CSS-сниппеты&lt;/a&gt; разной степени полезности: точно подтвержу, что если делаете какой-то общий компонент со стилизацией, которая может внезапно стать «глобальной» (стилизация по тегам &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt;…), то её точно полезно завернуть в &lt;code&gt;@layer {}&lt;/code&gt;, чтобы у потребителя не возникло необходимости переопределять ваши «глобальные» стили, так как они будут применяться раньше по каскаду&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nerdy.dev/3-unintuitive-layout-solutions&quot;&gt;неинтуитивные решения для лейаута&lt;/a&gt;, например, по умолчанию минимальная ширина grid- и flex-детей — &lt;code&gt;auto&lt;/code&gt;, что не всегда удобно, и её можно сбросить:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;.wat {
  min-height: 0;
  min-width: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;тег &lt;code&gt;&amp;lt;datalist&amp;gt;&lt;/code&gt; можно использовать &lt;a href=&quot;https://html-css-tip-of-the-week.netlify.app/tip/datalist/&quot;&gt;не только для «выпадашки» текстовых значений&lt;/a&gt;, таргет-элементом листа может быть, например, &lt;code&gt;&amp;lt;input type=&quot;color&quot;&amp;gt;&lt;/code&gt;, а элементами листа, соответственно, цвета:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;datalist&amp;gt;
  &amp;lt;option value=&quot;#ff0000&quot;&amp;gt;Red&amp;lt;/option&amp;gt;
  &amp;lt;option value=&quot;#00ff00&quot;&amp;gt;Green&amp;lt;/option&amp;gt;
&amp;lt;/datalist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/document/d/1BDJMsMmgSciLUGSC0e9os5gPhp8Dc0Q-E0BLq4z1rWw/edit?tab=t.0&quot;&gt;памятка&lt;/a&gt; по проверке доступности сайта/приложения с клавиатуры и из скринридера (NVDA, TalkBack, VoiceOver)&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 30.05.2025</title><link>https://juwain.github.io/web-platform/blog/2025-05-30/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-05-30/</guid><description>Новости веб-платформы</description><pubDate>Fri, 30 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://browsercompany.substack.com/p/letter-to-arc-members-2025&quot;&gt;закрывается браузер Arc&lt;/a&gt;: создатели переключились на другой браузер (с AI) Dia, под капотом тоже Chromium и проприетарная платформа для создания браузеров, которую опенсорсить не собираются&lt;/li&gt;
&lt;li&gt;также &lt;a href=&quot;https://blog.glitch.com/post/changes-are-coming-to-glitch/&quot;&gt;закрывается проект Glitch&lt;/a&gt; (браузерный редактор веб-приложений + хостинг) после 10 лет работы&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://eslint.org/blog/2025/05/eslint-v9.0.0-retrospective/&quot;&gt;в ESLint провели ретроспективу&lt;/a&gt; выкатки flat-config-а с 2019 по 2024, выявили основные ошибки: слишком много ломающий изменений за раз, слишком много документации и отсутствие тулинга автомиграции, медленное впитывание новой версии экосистемой, отказ от двойных конфигов (надо было поддержать, востребовано авторами плагинов)&lt;/li&gt;
&lt;li&gt;господа из React Router &lt;a href=&quot;https://remix.run/blog/rsc-preview&quot;&gt;поддержали в RR React Server Components&lt;/a&gt;, а также &lt;a href=&quot;https://remix.run/blog/wake-up-remix&quot;&gt;решили воскресить Remix&lt;/a&gt; (в лучших традициях рестлинга) да не просто так, а сделать его полностью независимым, даже от React (внутри будет форк Preact): теперь стало понятно, что этот проект — экспериментальная площадка, чтобы проверять крейзи-фичи и затем интегрировать их в «стабильный» RR&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/137&quot;&gt;вышел Chrome 137&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддержали функцию &lt;code&gt;if()&lt;/code&gt; в CSS: &lt;code&gt;background-color: if(style(--color: white): black; else: white)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;внедрили свойства &lt;code&gt;reading-flow&lt;/code&gt;, &lt;code&gt;reading-order&lt;/code&gt; для указания порядка чтения элементов скринридерами в флекс-/грид-лейаутах&lt;/li&gt;
&lt;li&gt;заработала функция &lt;code&gt;shape()&lt;/code&gt; для указания направления в свойстве &lt;code&gt;offset-path&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;для SVG-элементов теперь можно управлять трансформацией через атрибут &lt;code&gt;transform&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавили значение &lt;code&gt;view-transition-name: match-element&lt;/code&gt;, чтобы автогенерировать название вью-транзишна вместо хардкода или задания из JS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/139.0/releasenotes/&quot;&gt;вышел Firefox 139.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;из коробки работает Temporal proposal (прикол в том, что для движка SpiderMonkey &lt;a href=&quot;https://spidermonkey.dev/blog/2025/04/11/shipping-temporal.html&quot;&gt;поддержку реализовал&lt;/a&gt; один чел, опенсорсный контрибьютор, который не работает в Mozilla)&lt;/li&gt;
&lt;li&gt;поддержали атрибут &lt;code&gt;hidden=until-found&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;в экспериментальных фигах за флагом приехали: View Transition API, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/yield&quot;&gt;&lt;code&gt;scheduler.yield()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bun.sh/blog/bun-v1.2.14&quot;&gt;вышла новая версия Bun v1.2.14&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;позаимствовали фичу &lt;code&gt;catalogs:&lt;/code&gt; из pnpm для создания алиасов для группы зависимостей&lt;/li&gt;
&lt;li&gt;добавили флаг &lt;code&gt;bun init --react&lt;/code&gt; для быстрого разворачивания шаблона React-проекта и дев-сервером на Bun&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jspm.org/jspm-4.0-release&quot;&gt;вышла новая версия JSPM 4.0&lt;/a&gt; (import map package manager): внутри команды для безконфиговой сборки и сервинга проекта, поддержка нативного TS «со стриппингом», импортмапы средствами браузера — звучит знакомо? да, потому что контрибьютор JSPM и &lt;a href=&quot;https://github.com/guybedford/es-module-shims&quot;&gt;ES Module Shims&lt;/a&gt; — один и тот же человек, Guy Bedford&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.angular.dev/announcing-angular-v20-b5c9c06cf301&quot;&gt;вышел Angular 20&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;стабилизированы реактивные фичи &lt;code&gt;effect&lt;/code&gt;, &lt;code&gt;linkedSignal&lt;/code&gt; и &lt;code&gt;toSignal&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавлена экспериментальная поддержка фетчера &lt;code&gt;httpResource()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;причёсан SSR&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/spaansba/ForesightJS&quot;&gt;ForesightJS&lt;/a&gt; — либа для предсказания действия пользователя по движению курсора (префетч ресурсов по ховеру — слишком поздно, а по вьюпорту — запрашивается лишнее; с этой либой можно префетчить раньше и более точечно)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zumerlab/snapdom&quot;&gt;snapdom&lt;/a&gt; — либа для снятие скриншота с DOM-ноды, как в дев-тулзах, только отдельной либой (и без папеттира внутри)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/pqoqubbw/icons&quot;&gt;icons&lt;/a&gt; — бесплатные анимированные SVG-иконки для React с использованием motion&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://beraliv.com/snippets/enum-converter&quot;&gt;enum-converter&lt;/a&gt; — пример работы  &lt;a href=&quot;https://github.com/itsdouges/typescript-transformer-handbook&quot;&gt;TypeScript Transform API&lt;/a&gt; — конвертер Enum в type alias&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;реактовский &lt;code&gt;useSyncExternalStore&lt;/code&gt; можно использовать не только для хранения каких-то бизнес-данных (типичный стор), но и &lt;a href=&quot;https://www.epicreact.dev/use-sync-external-store-demystified-for-practical-react-development-w5ac0&quot;&gt;для «UI»-информации&lt;/a&gt;, например, данных о &lt;code&gt;window.matchMedia&lt;/code&gt;: подписываемся на &lt;code&gt;&apos;change&apos;&lt;/code&gt; состояния экрана, записываем в «стор», в React-компоненте юзаем этот стор&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://amorgunov.com/posts/2025-05-20-how-solve-cross-imports/&quot;&gt;как избегать проблемы циклических импортов&lt;/a&gt; между компонентами с помощью здравого смысла, а также инверсии зависимостей (меняем прямое использование на пропы) на примере методологии FSD&lt;/li&gt;
&lt;li&gt;в связи с начавшейся раскаткой Temporal в браузерах (FF — первый) &lt;a href=&quot;https://waspdev.com/articles/2025-05-24/temporal-api&quot;&gt;пора знакомиться&lt;/a&gt;, если ещё не, тем более, есть &lt;a href=&quot;https://www.npmjs.com/package/temporal-polyfill&quot;&gt;полифилл&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://deno.com/blog/history-of-javascript&quot;&gt;краткая история JS&lt;/a&gt; с уклоном в Райана Даля, Node и Deno: в 2025 JS исполнилось 30 лет, JSDoc — 26 лет, JSON — 24, Safari — 22, MDN — 20, jQuery — 19, Chrome — 17, CommonJS, Node.js, CoffeeScript — 16, npm, AngularJS, Backbone — 15, Webpack, TypeScript — 13, React — 12, ES6 — 10, Next.js — 9, Bun — 2&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;помимо именования view-transions с ними есть &lt;a href=&quot;https://benfrain.com/first-adventures-in-view-transitions/&quot;&gt;ещё одна проблема&lt;/a&gt;: так как транзишн применяется к &lt;code&gt;document&lt;/code&gt;, одновременно может выполняться только один транзишн, поэтому невозможно запустить конкурентные транзишны + есть проблема с &lt;code&gt;z-index&lt;/code&gt;, когда транзишнящийся элемент перекрывает всё вокруг; решение — &lt;a href=&quot;https://github.com/WICG/view-transitions/blob/main/scoped-transitions.md&quot;&gt;будущий Scoped View Transitions&lt;/a&gt;, то есть возможность запуска транзишна на конкретном элементе &lt;code&gt;element.startViewTransition()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/css-spotlight-effect/&quot;&gt;эффект «фонарика в темноте»&lt;/a&gt;: что прикольно, так это, что можно задавать любую форму светлому участку благодаря &lt;code&gt;filter&lt;/code&gt; или &lt;code&gt;mix-blend-mode&lt;/code&gt;, например, «решётка» из градиентов сильно смазанная и переконтращенная &lt;code&gt;filter: blur(1em) contrast(100)&lt;/code&gt; становится движущейся «кляксой»&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 06.06.2025</title><link>https://juwain.github.io/web-platform/blog/2025-06-06/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-06-06/</guid><description>Новости веб-платформы</description><pubDate>Fri, 06 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;в Chrome 138 (&lt;a href=&quot;https://developer.chrome.com/blog/chrome-138-beta&quot;&gt;сейчас уже в бете&lt;/a&gt;) будут доступны CSS-функции &lt;code&gt;sibling-index()&lt;/code&gt; и &lt;code&gt;sibling-count()&lt;/code&gt;, которые отдают интежер с позицией элемента среди собратьев и общее число детей, будет работать внутри &lt;code&gt;calc()&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;li {
  animation-delay: calc(0.1s * sibling-index());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://voidzero.dev/posts/announcing-rolldown-vite&quot;&gt;выпущен tech preview&lt;/a&gt; «растифицированного» Vite — Rolldown-Vite: под капотом заменили связку Rollup + esbuild на собственные Rolldown + Oxc, чем существенно ускорили сборку по времени и памяти; заодно решили, что раз оно теперь работает быстро, то можно и для дев-сервера сделать не лёгкую ESM-сборку, а полноценную, и в будущем в Vite будет доступен режим full-bundle mode&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vitest.dev/blog/vitest-3-2.html&quot;&gt;обновился Vitest до версии 3.2&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;задепрекейтили настройку &lt;code&gt;workspace&lt;/code&gt; в пользу &lt;code&gt;projects&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавили аннотации в выполнение тестов, которые будут выводиться в консоль, и кастомные цвета для &lt;code&gt;projects&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;добавили возможность раcширения встроенных &lt;code&gt;locators&lt;/code&gt; собственными методами&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://starwind.dev&quot;&gt;starwind&lt;/a&gt; — тейлвиндовые компоненты для Astro (не shadcn/ui единым)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/livestorejs/livestore&quot;&gt;livestore&lt;/a&gt; — решение для стораджа данных на клиенте в SQLite c реал-тайм-синхронизацией всех клиентов и бэка&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://udm14.com/&quot;&gt;udm14&lt;/a&gt; — если добавить параметр &lt;code&gt;&amp;amp;udm=14&lt;/code&gt; к поисковой строке гугла, то он внезапно откроется без AI-обвеса, суммаризаторов и тд&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mathiasbynens/small&quot;&gt;small&lt;/a&gt; — минимально возможные синтаксически валидные файлы на всех языках (например, в JSON-файлах — минимальное содержимое &lt;code&gt;0&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;природа языка JS такова, что при «кидании» в throw можно бросить не только объект ошибки &lt;code&gt;Error&lt;/code&gt;, но и строку, число, объект, и это создаёт проблемы с тем, что и в каком формате ожидать в &lt;code&gt;catch&lt;/code&gt;; TypeScript тут особо не помогает, исключения в TS не тайпчекаются, поэтому &lt;a href=&quot;https://www.haydenbleasel.com/blog/on-javascript-errors&quot;&gt;рекомендуется&lt;/a&gt; при обработке исключения проверять его тип&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;export const parseError = (error: unknown) =&amp;gt; {
	if (typeof error === &apos;string&apos;) {
		return error;
	}

	if (error instanceof Error) {
		return error.message;
	}

	return &apos;An error occurred&apos;;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;если вы приводите строку к дате &lt;code&gt;new Date(&apos;2025-05-28&apos;)&lt;/code&gt; и &lt;code&gt;new Date(&apos;2025/05/28&apos;)&lt;/code&gt;, то &lt;a href=&quot;https://brandondong.github.io/blog/javascript_dates/&quot;&gt;результаты могут быть разные&lt;/a&gt;: в первом случае браузер воспринимает строку как неполный формат записи даты-времени &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601&lt;/a&gt; и дополняет её на своё усмотрение (так, что может даже открутить часами дату до предыдущего дня, если устройство находится в удачной таймзоне)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;flushSync&lt;/code&gt; — метод в React, который позволяет минуя батчинг &lt;a href=&quot;https://www.epicreact.dev/mastering-focus-management-in-react-with-flush-sync-f5b38&quot;&gt;императивно и синхронно запустить обновление UI в нужный момент&lt;/a&gt;, например, чтоб корректно установить фокус в инпут, который только что показался с помощью сеттера из &lt;code&gt;useState&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;есть такой тип данных &lt;code&gt;Uint8Array&lt;/code&gt;, который как обычный массив, но каждый элемент в нём гарантировано размером 1 байт; так вот, в V8 на больших размерах массивов (&amp;gt; 150) &lt;code&gt;Uint8Array&lt;/code&gt; &lt;a href=&quot;https://evanhahn.com/v8-array-vs-uint8array-memory-usage/&quot;&gt;занимает меньше места в памяти, чем обычный массив&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/firstchild-can-be-white-space/&quot;&gt;дежурное напоминание&lt;/a&gt;: в свойстве &lt;code&gt;firstChild&lt;/code&gt; может оказаться не нужный DOM-элемент (тег), а текстовая нода с переносом строки &quot;\n &quot; (зависит от форматирования HTML-кода), поэтому лучше использовать &lt;code&gt;.children[0]&lt;/code&gt; (при этом &lt;code&gt;:first-child&lt;/code&gt; в CSS и через &lt;code&gt;querySelector&lt;/code&gt; вернёт корректного потомка, не текстовую ноду)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;у нативного элемента &lt;code&gt;dialog&lt;/code&gt; есть браузерный элемент подложки, который стилизуется через &lt;code&gt;::backdrop&lt;/code&gt;, обычно его делают полупрозрачным (и сам он по умолчанию тоже полупрозрачный); так вот, к нему можно при желании &lt;a href=&quot;https://css-tricks.com/getting-creative-with-html-dialog/&quot;&gt;применить фоновое изображение&lt;/a&gt;, чтобы сделать подложку непрозрачной и модалку перекрывающей нижний слой&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benjaminaster.com/css-minecraft/&quot;&gt;полностью CSS-ный редактор в стиле Майнкрафт&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;все блоки уже заранее построены, но скрыты и показываются благодаря старому трюку с чекбоксами/радиокнопками и соответствующими лейблами&lt;/li&gt;
&lt;li&gt;анимации тоже заранее запущены, но поставлены на паузу, а нажатие контролов (&lt;code&gt;:active&lt;/code&gt;) их снимает с паузы&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://agenticweb.nearestnabors.com/p/ai-future-web&quot;&gt;мрачноватый рисунок образа будущего&lt;/a&gt;: Chrome превращается в новый IE6, так как Google с одной стороны заставляют его продать, с другой — с приходом LLM поиск, а следом и веб-браузинг как таковой, а следом и процесс развития стандартов существенно меняется&lt;/li&gt;
&lt;li&gt;разработка ПО породила собственную субкультуру &lt;a href=&quot;https://blog.codinghorror.com/new-programming-jargon/&quot;&gt;с чисто разработческим жаргоном&lt;/a&gt;: Yoda Conditions, Stringly Typed, Rubber Ducking, Jenga Code и другие знакомые по разработческим будням явления&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 13.06.2025</title><link>https://juwain.github.io/web-platform/blog/2025-06-13/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-06-13/</guid><description>Новости веб-платформы</description><pubDate>Fri, 13 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cursor.com/changelog/1-0&quot;&gt;обновился редактор Cursor 1.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;главное — появилась настройка в 1 клик MCP-серверов&lt;/li&gt;
&lt;li&gt;также из интересного появилась бета-фича Memories: редактор может запоминать факты из диалогов и ссылаться на них в будущем&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/tc39-advances-9-proposals&quot;&gt;последние обновления ES от TC39&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Array.fromAsync&lt;/code&gt; перешёл на Stage 4 (доступен везде)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Error.isError&lt;/code&gt; перешёл на Stage 4 (доступен везде)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;using&lt;/code&gt; перешёл на Stage 4 (Chrome only)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tc39/proposal-seeded-random&quot;&gt;Seeded Pseudo Random Numbers&lt;/a&gt; от Tab Atkins перешёл на Stage 2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-590/&quot;&gt;обновился Astro 5.9&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появилась экспериментальная встроенная поддержка &lt;code&gt;Content-Security-Policy&lt;/code&gt; посредством встраивания тега &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; с нужными хэшами используемых файлов (также загружаемых динамически)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;недавно анонсировали &lt;a href=&quot;https://github.com/platformatic/php-node&quot;&gt;&lt;code&gt;@platformatic/php-node&lt;/code&gt;&lt;/a&gt; — официальный модуль Node.js с возможностью процессить PHP внутри Node.js-рантайма; главный вопрос был «зочем?», и вот &lt;a href=&quot;https://blog.platformatic.dev/seamlessly-blend-php-with-nodejs&quot;&gt;выпустили статью&lt;/a&gt;, где рассказали юзкейсы: миграция PHP-прил на Node.js, гибридные приложения (Node.js сервисы с кусочками PHP-процессинга)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://remix.run/blog/rr-governance&quot;&gt;React Router пообещали сделать стабильнее&lt;/a&gt; через перевод процесса разработки на процесс &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;TC39 Process&lt;/a&gt; (проход по стейджам + публичные обсуждения)&lt;/li&gt;
&lt;li&gt;команда Edge завезла в будущий Chrome 139 &lt;a href=&quot;https://developer.chrome.com/blog/gap-decorations&quot;&gt;стилизацию gap-ов в гридах/флексбоксах&lt;/a&gt; посредством новых свойств &lt;code&gt;column-rule-*&lt;/code&gt; и &lt;code&gt;row-rule-*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://voidzero.dev/posts/announcing-oxlint-1-stable&quot;&gt;релизнули первый стабильный Oxlint&lt;/a&gt; (линтер на Rust от Evan You сотоварищи):
&lt;ul&gt;
&lt;li&gt;за счёт мультипоточности быстрее ESLint в 50-100x&lt;/li&gt;
&lt;li&gt;есть автомиграция flat-config-а ESLint в &lt;code&gt;.oxlintrc.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;сразу включает &amp;gt; 500 правил из самого ESLint и популярных плагинов + собственные правила&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/control-apps-using-mcp-server&quot;&gt;DigitalOcean выпустили MCP-сервер&lt;/a&gt;, чтобы деплоить на платформу сразу из редактора без лишних конфигов&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/16993/news-from-wwdc25-web-technology-coming-this-fall-in-safari-26-beta/&quot;&gt;анонсировали бету Safari 26&lt;/a&gt;, да, Safari 19 не будет, будет сразу 26, следуя за числом года (что будет после 2099 года видимо уже неважно):
&lt;ul&gt;
&lt;li&gt;наконец-то будут SVG-favicon-ки&lt;/li&gt;
&lt;li&gt;тег &lt;code&gt;&amp;lt;model&amp;gt;&lt;/code&gt; для показа 3d-моделей в браузере (с фолбеком в обычную картинку)&lt;/li&gt;
&lt;li&gt;в CSS поддержаны Anchor Positioning, Scroll-driven Animations, &lt;code&gt;contrast-color()&lt;/code&gt;, &lt;code&gt;progress()&lt;/code&gt;, &lt;code&gt;margin-trim&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;из API поддержаны &lt;code&gt;URLPattern&lt;/code&gt;, &lt;code&gt;scrollMargin&lt;/code&gt; в &lt;code&gt;IntersectionObserver&lt;/code&gt;, &lt;code&gt;File System WritableStream&lt;/code&gt;,  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Modifier&quot;&gt;Pattern Modifiers&lt;/a&gt; в &lt;code&gt;RegExp&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.canidev.tools/&quot;&gt;canidev.tools&lt;/a&gt; — CanIUse для фич девтулзов в движках&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/achtaitaipai/odyc&quot;&gt;odyc&lt;/a&gt; — забавная либа для создания простых нарративных игр прям из конфига, такие вайбы «языка» Scratch&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lingo.dev/en/compiler&quot;&gt;lingo.dev compiler&lt;/a&gt; — мультиязычная поддержка в React-прилах через слой перевода с помощью LLM: думаю, такую тенденцию будем наблюдать и дальше — воткни LLM-слой в сборку для какой-то понятной ограниченной задачи и всё просто заработает&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://macarthur.me/posts/current-script/&quot;&gt;с помощью &lt;code&gt;document.currentScript&lt;/code&gt;&lt;/a&gt; можно пробросить через тег &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; внутрь скрипта data-атрибуты, чекать обычные атрибуты (типа, что скрипту обязательно проставлен &lt;code&gt;defer&lt;/code&gt;) или же порядок следования скрипта в разметке (только в начале &lt;code&gt;body&lt;/code&gt; или после определённого элемента)&lt;/li&gt;
&lt;li&gt;Tanner Linsley убеждает, что &lt;a href=&quot;https://tanstack.com/blog/search-params-are-state&quot;&gt;URL как хранилище стейта недооценено&lt;/a&gt; из-за проблем с парсингом, типизацией и отсутствия связи с роутингом напрямую и рекомендует использовать TanStack Router, чтобы порешать все эти проблемы и наслаждаться рантайм-валидацией роутов с безопасным сохранением стейта в URL&lt;/li&gt;
&lt;li&gt;в отличие от директив (типа &lt;code&gt;use strict&lt;/code&gt;) магические комменты в начале файлов вроде &lt;code&gt;/** @aPragma */&lt;/code&gt; или &lt;code&gt;//# aMagicComment&lt;/code&gt;, влияющие на процесс интерпретации и транспиляции JS-файлов, &lt;a href=&quot;https://macwright.com/2025/04/29/directive-prologues-and-javascript-dark-matter&quot;&gt;нестандартны и мало задокументированы&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://frontendmasters.com/blog/scroll-driven-letter-grid/&quot;&gt;напоминание&lt;/a&gt;, что у вариативных шрифтов можно анимировать &lt;code&gt;font-weight&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/viewport-unit-variants/&quot;&gt;ещё одно напоминание&lt;/a&gt;: вьюпорт-ориентированные динамические единицы измерения &lt;code&gt;sv*&lt;/code&gt;, &lt;code&gt;lv*&lt;/code&gt;, &lt;code&gt;dv*&lt;/code&gt; с нами уже с 2022 года, то есть сейчас уже считаются широко распространёнными&lt;/li&gt;
&lt;li&gt;анимация до не фиксированного, а &lt;a href=&quot;https://www.joshwcomeau.com/animation/partial-keyframes/&quot;&gt;динамического значения&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;@keyframes oscillate {
  from {
    transform: translateX(calc(var(--amount) * -1));
  }
  to {
    transform: translateX(var(--amount));
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1fr 1fr&lt;/code&gt; vs &lt;code&gt;auto auto&lt;/code&gt; vs &lt;code&gt;50% 50%&lt;/code&gt;, &lt;a href=&quot;https://frontendmasters.com/blog/1fr-1fr-vs-auto-auto-vs-50-50/&quot;&gt;что выбрать, если нужно разделить на две равные части&lt;/a&gt;: в итоге лучше будет воспользоваться гридовым &lt;code&gt;minmax(0, 1fr)&lt;/code&gt; для возможности работы &lt;code&gt;overflow&lt;/code&gt; при переполнении&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;элемент &lt;code&gt;&amp;lt;output&amp;gt;&lt;/code&gt; &lt;a href=&quot;https://html-css-tip-of-the-week.netlify.app/tip/output/&quot;&gt;задуман для отображения результата вычисления&lt;/a&gt;, значение задаётся как для элемента формы (через &lt;code&gt;value&lt;/code&gt;), но при этом находясь внутри &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; элемент не сабмитится, то есть служит чисто для визуализации&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;задумывались ли вы &lt;a href=&quot;https://adrianroselli.com/2025/06/where-to-put-focus-when-opening-a-modal-dialog.html&quot;&gt;куда следует ставить фокус при открытии модалки&lt;/a&gt;: в инпут, на кнопку закрытия, на заголовок, на кнопку ключевого действия в модалке? Однозначного ответа на этот вопрос нет, зато есть набор вопросов, которые можно себе задать, чтобы выбрать подходящий вариант для вашего конкретного случая&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 20.06.2025</title><link>https://juwain.github.io/web-platform/blog/2025-06-20/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-06-20/</guid><description>Новости веб-платформы</description><pubDate>Fri, 20 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://socket.dev/blog/pnpm-introduces-global-virtual-store-and-expanded-version-catalogs&quot;&gt;вышел релиз pnpm 10.12.1&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;выкатили экспериментальную поддержку global virtual stores — теперь в &lt;code&gt;node_modules&lt;/code&gt; хранятся не сами пакеты, а только симлинки на центральное хранилище в файловой системе, которое может переиспользоваться сразу всеми проектам; поэтому теперь установка пакетов может быть очень быстрой за счёт установленных ранее и закешированных в хранилище пакетов&lt;/li&gt;
&lt;li&gt;добавили в настройки режим &lt;code&gt;catalogMode&lt;/code&gt; для управления установкой пакетов для монореп&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Node.js 18 уже достигла End-Of-Life, и мигрировать рекомендуется &lt;a href=&quot;https://nodejs.org/en/blog/announcements/node-18-eol-support&quot;&gt;сразу на текущую активную 22 версию&lt;/a&gt;, чтобы в следующий раз нескоро переезжать (апрель 2027)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/blog/2025/06/04/jest-30&quot;&gt;выпущен Jest 30&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;поддерживает &lt;code&gt;.mts&lt;/code&gt; и &lt;code&gt;.cts&lt;/code&gt; файлы по умолчанию&lt;/li&gt;
&lt;li&gt;удалили алиасы &lt;code&gt;expect&lt;/code&gt;, для миграции добавили eslint-плагин с автофиксером&lt;/li&gt;
&lt;li&gt;обновили поддержку &lt;code&gt;jsdom&lt;/code&gt;, дропнули поддержку Node 14, 16, 19 и 21, TS &amp;lt; 5.4&lt;/li&gt;
&lt;li&gt;так как Гугл задепрекейтил домен &lt;code&gt;goo.gl&lt;/code&gt;, который использовался для хранения снепшотов, то придётся их все переделать&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;для &lt;a href=&quot;https://community.vercel.com/t/introducing-design-mode-on-v0/13225&quot;&gt;v0 сделали режим Design Mode&lt;/a&gt;, чтобы править параметры в UI без залезания в код (пока поддерживается Tailwind и shadcn/ui)&lt;/li&gt;
&lt;li&gt;в Chromium 138, Firefox 140 и Safari 26 Beta &lt;a href=&quot;https://developer.chrome.com/blog/escape-attributes&quot;&gt;изменится принцип&lt;/a&gt; декодирования символов &lt;code&gt;&amp;lt;&lt;/code&gt; и &lt;code&gt;&amp;gt;&lt;/code&gt; в атрибутах элемента с помощью методов &lt;code&gt;innerHTML&lt;/code&gt; и &lt;code&gt;outerHTML&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div data-content=&quot;&amp;lt;u&amp;gt;hello&amp;lt;/u&amp;gt;&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;div.outerHTML;
// раньше было &amp;lt;div data-content=&quot;&amp;lt;u&amp;gt;hello&amp;lt;/u&amp;gt;&quot;&amp;gt;&amp;lt;/div&amp;gt;
// теперь будет &amp;lt;div data-content=&quot;&amp;amp;lt;u&amp;amp;gt;hello&amp;amp;lt;/u&amp;amp;gt;&quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://biomejs.dev/blog/biome-v2/&quot;&gt;вышел Biome v2&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;линтинг типов теперь не завязан на &lt;code&gt;tsc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;поддержаны вложенные конфиги&lt;/li&gt;
&lt;li&gt;для того, чтобы линтинг мог завязываться не только на один файл, выпущен специальный сканер файлов, который находит вложенные конфиги и индексирует файлы&lt;/li&gt;
&lt;li&gt;появилась первая ограниченная поддержка плагинов и HTML-форматтер&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zed.dev/blog/debugger&quot;&gt;в редакторе Zed появился встроенный Debugger&lt;/a&gt; (имплементирован &lt;a href=&quot;https://microsoft.github.io/debug-adapter-protocol/&quot;&gt;Debug Adapter Protocol (DAP)&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://h3.dev/blog/v2-beta&quot;&gt;вышла H3 v2 beta&lt;/a&gt;: быстрый сервер, который работает в разных райнтаймах (Node.js, Deno, Bun), но при этом основывается на стандартных API вроде &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Request&quot;&gt;Request&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Response&quot;&gt;Response&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/URL&quot;&gt;URL&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Headers&quot;&gt;Headers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mysticatea.github.io/eslint-plugin-eslint-comments/rules/no-restricted-disable.html&quot;&gt;eslint-plugin-eslint-comments&lt;/a&gt; — плагин для ESLint, который линтит комменты ESLint, чтобы, например, &lt;a href=&quot;https://mysticatea.github.io/eslint-plugin-eslint-comments/rules/no-restricted-disable.html&quot;&gt;запретить выключение правил линтинга&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.isquaredsoftware.com/2025/06/react-community-2025/&quot;&gt;как сейчас дела в React&lt;/a&gt; и экосистеме билд-тулов и фреймворков: по скачиваниям Vite-плагин растёт и догоняет Next, а CRA после депрейката расти перестал; среди остальных React-специфичных фреймворков больше всего скачиваний у React Router, а Astro, Expo и Gatsby существенно отстают&lt;/li&gt;
&lt;li&gt;import-maps изначально не позволяли загружать любые модули до загрузки самого import-map-а, а также всего на страницу мог быть только один import-map: это ограничение усложнило применение технологии у инженеров Shopify и они совместно с вендорами браузеров &lt;a href=&quot;https://shopify.engineering/resilient-import-maps&quot;&gt;проработали изменение в спецификации и внедрили в Chromium и WebKit&lt;/a&gt;; теперь import-map-ов может быть несколько, и они мерджатся в один, а также любой модуль может загружаться до или после загрузки самого map-а&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.totaltypescript.com/concepts/the-prettify-helper&quot;&gt;утилитарный тип Prettify&lt;/a&gt;, которого пока нет в стандартной поставке TS, улучшает читаемость «сборных» типов:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;type Prettify&amp;lt;T&amp;gt; = {
  [K in keyof T]: T[K];
} &amp;amp; {};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://allthingssmitty.com/2025/06/16/using-await-at-the-top-level-in-es-modules/&quot;&gt;юзкейсы top-level &lt;code&gt;await&lt;/code&gt; в браузере и Node.js&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;запрос конфига на старте приложения &lt;code&gt;const config = await fetch(&apos;/config.json&apos;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;динамический импорт другого модуля &lt;code&gt;const dbDriver = await import(&apos;./drivers/postgres.js&apos;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;ожидание инициализации (в момент выполнения top-level &lt;code&gt;await&lt;/code&gt; выполнение модуля становится на паузу)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;обзёрверы в JS (ResizeObserver, MutationObserver…) имеют примерное одинаковое API (и одинаково не очень удобное), поэтому автор &lt;a href=&quot;https://css-tricks.com/a-better-api-for-the-resize-observer/&quot;&gt;предлагает использовать функцию-обёртку&lt;/a&gt;, которая принимает DOM-элемент и коллбек на вход, инкапсулирует создание обзёрвера и возвращает функции &lt;code&gt;unobserve&lt;/code&gt; и &lt;code&gt;disconnect&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;пока встроенная функция нахождения контрастного цвета текста &lt;code&gt;contrast-color()&lt;/code&gt; ещё нигде не работает, можно &lt;a href=&quot;https://blog.damato.design/posts/css-only-contrast/&quot;&gt;использовать математическую магию&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;{
	color:
    color(
      from var(--color) xyz
      round(up, min(1, max(0, 0.18 - y)))
      round(up, min(1, max(0, 0.18 - y)))
      round(up, min(1, max(0, 0.18 - y)))
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://jakearchibald.com/2025/animating-zooming/&quot;&gt;в комбинированных анимациях&lt;/a&gt;, где используются &lt;code&gt;scale&lt;/code&gt; и &lt;code&gt;translate&lt;/code&gt; одновременно, важен порядок написания свойств: если &lt;code&gt;scale&lt;/code&gt; писать перед &lt;code&gt;translate&lt;/code&gt;, то тогда &lt;code&gt;translate&lt;/code&gt; будет выполняться неравномерно, так как &lt;code&gt;scale&lt;/code&gt; будет «умножать» значения &lt;code&gt;translate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;есть такая функция &lt;code&gt;filter()&lt;/code&gt; (не путать со свойством &lt;code&gt;filter&lt;/code&gt;), которая &lt;a href=&quot;https://frontendmasters.com/blog/grainy-gradients/&quot;&gt;позволяет создать комбинированный фильтр&lt;/a&gt;, например, из градиента и SVG; всё бы хорошо, но она работает только в Safari, а если хочется кроссбраузерно сделать на градиентной картинке, к примеру, зернёный фильтр, то нужно отдельно задать всему блоку свойство &lt;code&gt;filter&lt;/code&gt; и градиент наслоить на зерно&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;HTML&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ausi.github.io/respimagelint/docs.html&quot;&gt;чеклист&lt;/a&gt; для проверки правильности синтаксиса респонсив-изображений (&lt;code&gt;srcset&lt;/code&gt;, &lt;code&gt;sizes&lt;/code&gt;) с примерами правильно/неправильно&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nicchan.me/blog/youre-not-a-front-end-developer-until-youve/&quot;&gt;квиз с 32 ситуациями&lt;/a&gt;, с которыми вы уже сталкивались или ещё столкнётесь в своей карьере фронтендера: выполнение всех пунктов сделает вас почтенным пенсионером разработки&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Пульс веб-платформы 27.06.2025</title><link>https://juwain.github.io/web-platform/blog/2025-06-27/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-06-27/</guid><description>Новости веб-платформы</description><pubDate>Fri, 27 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;Новости&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/release-notes/138&quot;&gt;вышел Chrome 138&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появились функции &lt;code&gt;sibling-index()&lt;/code&gt; и &lt;code&gt;sibling-count()&lt;/code&gt;, которые возвращают индекс элемента среди собратьев и общее число детей&lt;/li&gt;
&lt;li&gt;значение &lt;code&gt;stretch&lt;/code&gt; (префиксная версия &lt;code&gt;-webkit-fill-available&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;математические функции &lt;code&gt;abs()&lt;/code&gt;, &lt;code&gt;sign()&lt;/code&gt;, &lt;code&gt;progress()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;группа встроенных AI-API: Translator API, Language Detector API, Summarizer API&lt;/li&gt;
&lt;li&gt;эскейп символов &lt;code&gt;&amp;lt;&lt;/code&gt; и &lt;code&gt;&amp;gt;&lt;/code&gt; в значениях атрибутов DOM-нод&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mozilla.org/en-US/firefox/140.0/releasenotes/&quot;&gt;выпущен Firefox 140&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;в браузере появились вертикальные табы на боковой панели (также можно вручную выгружать табы из памяти)&lt;/li&gt;
&lt;li&gt;поддержан &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/CookieStore&quot;&gt;CookieStore API&lt;/a&gt; и &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/CSS_Custom_Highlight_API&quot;&gt;Custom Highlight API&lt;/a&gt;, теперь есть во всех браузерах!&lt;/li&gt;
&lt;li&gt;вслед за Chrome тоже теперь эскейпируют символы &lt;code&gt;&amp;lt;&lt;/code&gt; и &lt;code&gt;&amp;gt;&lt;/code&gt; в атрибутах и применяют сквозные стили по умолчанию к &lt;code&gt;h1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astro.build/blog/astro-5100/&quot;&gt;в Astro 5.10&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;появились live-контентные коллекции, которые извлекаются в рантайме вместо билд-тайма&lt;/li&gt;
&lt;li&gt;стабилизированы встроенные респонсив-картинки&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prettier.io/blog/2025/06/23/3.6.0&quot;&gt;в Prettier 3.6&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;под флагом вышел новый CLI&lt;/li&gt;
&lt;li&gt;зарелижены плагины &lt;a href=&quot;https://github.com/prettier/prettier/tree/main/packages/plugin-oxc&quot;&gt;&lt;code&gt;@prettier/plugin-oxc&lt;/code&gt;&lt;/a&gt; и &lt;a href=&quot;https://github.com/prettier/prettier/tree/main/packages/plugin-hermes&quot;&gt;&lt;code&gt;@prettier/plugin-hermes&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vite.dev/blog/announcing-vite7.html&quot;&gt;вышел Vite 7.0&lt;/a&gt;, в котором дропнута поддержка Node.js 18 и изменены дефолтные таргет-версии браузеров&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/svg/svgo/releases/tag/v4.0.0&quot;&gt;выпустили SVGO v4.0.0&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;дропнули поддержку Node.js 14&lt;/li&gt;
&lt;li&gt;появились новые дефолтные плагины&lt;/li&gt;
&lt;li&gt;теперь поставляется в виде dual-пакета: ESM + CJS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Проекты&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/andreruffert/syntax-highlight-element&quot;&gt;syntax-highlight-element&lt;/a&gt; — а вот подъехал и веб-компонент для подсветки синтаксиса на свежеподдержаном &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API&quot;&gt;Custom Highlight API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/filipsobol/sonda&quot;&gt;sonda&lt;/a&gt; — универсальный визуализатор и анализатор JS и CSS-бандлов, совместимый с основными сборщиками и фреймворками&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cferdinandi/kelp/&quot;&gt;kelp&lt;/a&gt; — новый CSS-фреймворк в 2025 наверное звучит уже иронично, использовать его вы вряд ли будете, но покопать для нахождения интересных фишек никогда нелишне, например, селектор &lt;code&gt;:where(:root)&lt;/code&gt; или &lt;a href=&quot;https://github.com/cferdinandi/kelp/blob/main/css/tokens/color.css&quot;&gt;слоистая структура отдельных модулей CSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Статьи, мнения, туториалы&lt;/h3&gt;
&lt;h4&gt;JS/TS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ckeditor.com/blog/how-we-reduced-ckeditor-bundle-size/&quot;&gt;очередная история&lt;/a&gt; про уменьшение раздутого бандла; если вы сталкиваетесь с такой же проблемой:
&lt;ul&gt;
&lt;li&gt;проверьте, хорошо ли работает тришейкинг: возможно придётся убрать barrel-импорты, где-то вручную добавить магический коммент &lt;code&gt;/* #__PURE__ */&lt;/code&gt; и настроить секцию &lt;code&gt;sideEffects&lt;/code&gt; в &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;смените таргет-версию ES хотя бы до es2022&lt;/li&gt;
&lt;li&gt;обновите зависимости&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;наверняка вы сталкивались &lt;a href=&quot;https://2ality.com/2025/06/checking-map-keys-array-indices-typescript.html&quot;&gt;с ситуацией в TS&lt;/a&gt;, когда из-за ветки проверки ключей Map или индексов массивов в тип значения добавляется &lt;code&gt;undefined&lt;/code&gt;, например, &lt;code&gt;undefined | string&lt;/code&gt;, из-за этого приходится дополнительно явно проверять значение на &lt;code&gt;undefined&lt;/code&gt; либо ещё вариант пропатчить тип метода &lt;code&gt;has()&lt;/code&gt; у &lt;code&gt;Map&lt;/code&gt; или же просто проставить &lt;code&gt;!&lt;/code&gt; там, где вы точно уверены в результате&lt;/li&gt;
&lt;li&gt;комитет одобрил ES2025, &lt;a href=&quot;https://2ality.com/2025/06/ecmascript-2025.html&quot;&gt;что нового появилось в языке&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;Import attributes &lt;code&gt;with { type: &apos;json&apos; }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Iterator helper methods (filter, map, find…)&lt;/li&gt;
&lt;li&gt;новые методы Set()&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RegExp.escape()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Promise.try()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CSS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.smashingmagazine.com/2025/06/css-cascade-layers-bem-utility-classes-specificity-control/&quot;&gt;каскадные слои в CSS&lt;/a&gt; — хорошая тема, даже если вы используете подход с атомарными стилями; особенно может быть полезно на больших проектах со старой кодовой базой или внешними стилями, а также если планируется долго развивать комплексное приложение&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webkit.org/blog/17101/a-guide-to-scroll-driven-animations-with-just-css/&quot;&gt;скролл-анимации&lt;/a&gt; хоть ещё и поддерживаются только chromium-браузерах, но уже появились в превью-версиях Safari и за флагом в FF, так что для каких-то простеньких и не влияющих сильно на UX интерфейсных решений, вполне применимы (например, анимированный индикатор скролла страницы)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Платформа&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;если вы приступаете к разработке чего-то связанного с датой-временем (особенно в мировых масштабах) с мыслью «Что может быть проще времени?», то без использования спец либ вы наверняка столкнётесь с массой проблем (иногда даже их не заметив), вот &lt;a href=&quot;https://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b923ca&quot;&gt;список потенциальных проблем&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;чел вёл статистику столкновения с хитрыми багами с 2002 года и &lt;a href=&quot;https://henrikwarne.com/2025/06/15/lessons-from-9-more-years-of-tricky-bugs/&quot;&gt;подвёл итоги&lt;/a&gt;; часто проблемы возникают:
&lt;ul&gt;
&lt;li&gt;с обработкой пустых значений (забывается ставить проверку на пустоту)&lt;/li&gt;
&lt;li&gt;с днями (временем, в целом)&lt;/li&gt;
&lt;li&gt;с устаревшими форматами данных&lt;/li&gt;
&lt;li&gt;дубликатами словарей&lt;/li&gt;
&lt;li&gt;незапушенными локальными изменениями&lt;/li&gt;
&lt;li&gt;некорректными правами доступа&lt;/li&gt;
&lt;li&gt;некорректным использованием фич пользователями&lt;/li&gt;
&lt;li&gt;неполной тестовой средой по сравнению с продом&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Проблемы во фронтовых проектах и их решения</title><link>https://juwain.github.io/web-platform/blog/2025-11-21/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-11-21/</guid><description>Проблемы во фронтовых проектах и их решения</description><pubDate>Fri, 21 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Подсобрал список типовых проблем и их решений, с которыми неизбежно сталкиваются разросшиеся фронтовые монорепы или семейства проектов, если заранее не позаботиться о решениях.&lt;/p&gt;
&lt;p&gt;⚠️ Неудобная локальная разработка, зоопарк технологий/подходов, сложно вкатываться в существующие проекты.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Решения:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Переход на единую типовую сборку (Vite, Webpack…) с общим конфигом, общий инструментарий для монореп (workspaces, turbo, lerna…).&lt;/li&gt;
&lt;li&gt;Создание единого шаблона для старта нового приложения.&lt;/li&gt;
&lt;li&gt;Выработка единообразного стека:
&lt;ol&gt;
&lt;li&gt;система: node/bun, TS, фреймворк (React, Vue, Next…)&lt;/li&gt;
&lt;li&gt;зависимости:
&lt;ul&gt;
&lt;li&gt;пакетный менеджер (yarn/npm/pnpm, для консистентности лок-файлов)&lt;/li&gt;
&lt;li&gt;стейт-менеджер (или его отсутствие =&amp;gt; Tanstack Query)&lt;/li&gt;
&lt;li&gt;роутер&lt;/li&gt;
&lt;li&gt;инструменты для работы с формами (хуки, валидация, маски для инпутов…) и валидатор схем&lt;/li&gt;
&lt;li&gt;стилизация (CSS Modules, SASS, Styled-подобные, ваниль), использование единообразного UI-kit (Storybook)&lt;/li&gt;
&lt;li&gt;утилиты (работа с датами, общие либы типа lodash)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Процесс регулярных обновлений зависимостей.&lt;/li&gt;
&lt;li&gt;Единообразная структура проекта/проектов, приведение к единому виду (FSD…).&lt;/li&gt;
&lt;li&gt;Архитектурные соглашения по выносу шаренных кусочков в микрофронты, связь между «отдельными кусочками» приложений в рамках общих приложений.&lt;/li&gt;
&lt;li&gt;Общий/стандартизированный CI/CD.&lt;/li&gt;
&lt;li&gt;Общий подход к проксированию запросов на бэк, к развёртыванию проекта локально.&lt;/li&gt;
&lt;li&gt;Общий код-стайл и линтинг (ESLint, Prettier, Biome…).&lt;/li&gt;
&lt;li&gt;Общий подход к логированию аналитики.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;⚠️ Долгая разработка, необходимость частых ресерчей&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Решения:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Централизованное внедрение AI-инструментов для помощи в написании кода (выбор единых агентов, генерация вспомогательных артефактов типа &lt;code&gt;claude.md&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Создание бойлерплейта для документации и внедрение AI-генерации документации. Хранение документации в самих проектах и регулярная перегенерация.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;⚠️ Дублирования кода, велосипеды&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Решение:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Вынос повторяющихся пакетов в шареное хранилище переиспользуемых решений, хостинг в приватном npm-реестре, поддержка.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;⚠️ Большое количество багов, уязвимостей и неконтролируемый/плохой перф и UX&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Решения:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Внедрение мониторинга ошибок (Sentry), настройка алертов в чаты/дашбордов на ошибки (Grafana).&lt;/li&gt;
&lt;li&gt;Подключение измерения метрик перфа в рантайме у пользователей (Vitals, TTVC и подобные), а также на CI/CD («бюджет» на перф в пулреквестах).&lt;/li&gt;
&lt;li&gt;Интеграция в CI/CD инструментов для поиска уязвимостей в коде.&lt;/li&gt;
&lt;li&gt;Процесс регулярного пополнения и разгребания бэклога техдолга (баги, уязвимости, оптимизации).&lt;/li&gt;
&lt;li&gt;Внедрение среды для тестов/автотестов, написание/генерация юнит-тестов и e2e-тестов, регрессионное тестирование, запуск на CI/CD.&lt;/li&gt;
&lt;li&gt;Выработка плавил работы со статикой (картинки на CDN, автоматизированное сжатие, ленивая загрузка).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;⚠️ Несогласованная командная работа&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Решения:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Использование контрактов (Open API) на бэке/фронте, кодогенерации типов и API-клиентов, клиент-серверных фреймворков (trpc).&lt;/li&gt;
&lt;li&gt;Внедрение автоматизации в код-ревью (автоназначение ревьюеров, выработка правил мерджа в master, AI-генерация описаний пулреквестов и ревью).&lt;/li&gt;
&lt;li&gt;Договорённости в единообразном именовании коммитов (conventional commits), веток, пулреквестов; единые подходы к организации дев/стейдж/релиз-веток; семантическое версионирование релизов.&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Про микрофронты на коленке. Iframe</title><link>https://juwain.github.io/web-platform/blog/2025-12-03/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2025-12-03/</guid><description>Про микрофронты на коленке. Iframe</description><pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Мне в работе попадалась реализация микрофронтов на основе &lt;code&gt;iframe&lt;/code&gt;. В целом, это вариант, когда надо «дёшево и сердито». Обычно такое используется, когда хост-приложение не одно и в каждом внутри своеобразная сборка, то есть федерацией модулей или монорепой всех проблем не решить.&lt;/p&gt;
&lt;p&gt;Как это работает: по определённому адресу хостится мини-приложение, например, по урлу &lt;code&gt;example.com/header&lt;/code&gt; грузится общее приложение хедера для всех возможных хост-сред. Во все хост-приложения хедер встраивается через &lt;code&gt;iframe&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;iframe src=&quot;/header&quot;&amp;gt;&amp;lt;/iframe&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Важный момент: чтобы не возникало проблем с CORS, при таком подходе приложения должны находиться на одном домене, а также полностью должны совпадать порт и протокол.&lt;/p&gt;
&lt;p&gt;Редко когда такое мини-приложение живёт само по себе. Обычно нужно, чтобы оно как-то общалось со внешним миром. Для этого есть система двунаправленных событий, которые отправляются с помощью метода &lt;code&gt;postMessage&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;window.parent.postMessage&lt;/code&gt; — отправляет сообщение изнутри  фрейма наружу, в родителя.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;iframe.contentWindow.postMessage&lt;/code&gt; — отправляет сообщение снаружи, от родителя, внутрь фрейма.&lt;/p&gt;
&lt;p&gt;Получаются отправленные события подпиской на &lt;code&gt;message&lt;/code&gt; (как изнутри &lt;code&gt;iframe&lt;/code&gt;, так и в родительском приложении снаружи):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;parent.html:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;iframe id=&quot;myFrame&quot; src=&quot;/child&quot;&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;script&amp;gt;
const iframe = document.getElementById(&apos;myFrame&apos;);

// Отправка сообщения во фрейм
iframe.addEventListener(&apos;load&apos;, () =&amp;gt; {
    iframe.contentWindow.postMessage({ type: &apos;fromParent&apos;, payload: &apos;Привет!&apos; }, &apos;*&apos;);
});

// Получение сообщения от фрейма
window.addEventListener(&apos;message&apos;, (event) =&amp;gt; {
    if (event.data.type === &apos;fromChild&apos;) {
        console.log(&apos;Получено от фрейма:&apos;, event.data.payload);
    }
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;child.html:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;
// Отправка сообщения родителю
window.parent.postMessage({ type: &apos;fromChild&apos;, payload: &apos;Ответ!&apos; }, &apos;*&apos;);

// Получение сообщения от родителя
window.addEventListener(&apos;message&apos;, (event) =&amp;gt; {
    if (event.data.type === &apos;fromParent&apos;) {
        console.log(&apos;Получено от родителя:&apos;, event.data.payload);
    }
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Эту идею можно раскрутить и дальше. Например, если одни и те же данные с сервера нужны в нескольких микрофронтах, то это может привести к дублированию запросов. Один из выходов — перенести этот дублирующийся запрос в хост-приложение и шарить его с фреймами. Ещё один вариант — сделать отдельный &lt;code&gt;iframe&lt;/code&gt;, в котором визуально ничего нет (его можно даже скрыть), но есть данные. Данные этот стор-iframe может шарить наружу всем желающим, тоже через &lt;code&gt;postMessage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Также помимо общения через &lt;code&gt;postMessage&lt;/code&gt; шаринг данных между контекстами можно построить на &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API&quot;&gt;Broadcast Channel API&lt;/a&gt; или &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API&quot;&gt;Channel Messaging API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Broadcast Channel обеспечивает широковещательную связь между всеми контекстами одного origin, а Channel Messaging создает секьюрный двусторонний канал связи между двумя конкретными контекстами.&lt;/p&gt;
&lt;p&gt;То есть этот самый «стор с шаренными данными» при получении данных может в зависимости от цели пулять данные или на всех, или точечно в конкретное место. Работают оба способа тоже на похожих &lt;code&gt;postMessage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;В случае с Broadcast Channel надо как-то пошарить между потребителями созданный объект самого канала:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Создание канала
const bc = new BroadcastChannel(&quot;test_channel&quot;);

// Отправка сообщения в канал
bc.postMessage(&quot;This is a test message.&quot;);

// Приём сообщения
bc.onmessage = (event) =&amp;gt; {
  console.log(event);
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В случае с Channel Messaging параметры для связи двух контекстов передаются в доп параметрах &lt;code&gt;postMessage&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;main-page:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const channel = new MessageChannel();
const port1 = channel.port1;

// Подписка на загрузку iframe
iframe.addEventListener(&quot;load&quot;, onLoad);

function onLoad() {
  // Слушание входящих сообщений на port1
  port1.onmessage = onMessage;
  
  // Отправка исходящего сообщения на port1
  port1.postMessage(input.value);

  // Отправка port2 в iframe
  iframe.contentWindow.postMessage(&quot;init&quot;, &quot;*&quot;, [channel.port2]);
}

// Обработка сообщений на port1
function onMessage(e) {
  console.log(e.data);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;child-page:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let port2;

// Слушание события инициализации
window.addEventListener(&quot;message&quot;, initPort);

// Настройка порта
function initPort(e) {
  port2 = e.ports[0];
  port2.onmessage = onMessage;
}

// Обработка сообщений на port2
function onMessage(e) {
  port2.postMessage(`Message received by IFrame: &quot;${e.data}&quot;`);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Отдельно отмечу наличие атрибута &lt;code&gt;loading=lazy&lt;/code&gt; у &lt;code&gt;iframe&lt;/code&gt;. Это чтобы не подгружать те &lt;code&gt;iframe&lt;/code&gt;, которые находятся вне вьюпорта, для экономии ресурсов.&lt;/p&gt;
&lt;p&gt;Также дополнительно подсвечу, что в хромиум-браузерах все &lt;code&gt;iframe&lt;/code&gt; на одном домене будут обрабатываться в одном потоке, то есть могут потенциально блокировать друг друга, даже если не блокируют родителя (лайфхак: если нет нужды держать их на одном домене, то выносом на другой домен можно «распараллелить потоки»).&lt;/p&gt;
</content:encoded></item><item><title>Время пробовать pnpm?</title><link>https://juwain.github.io/web-platform/blog/2026-01-14/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-01-14/</guid><description>Время попробовать pnpm?</description><pubDate>Wed, 14 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;А вы заметили, что со всеми этими ии-движухами как-то морально проще стало экспериментировать с новым софтом и подходами в работе. Раньше ну узнаешь, что какая-то там либа вышла, ну подумаешь, что надо когда-нибудь попробовать, и всё на том. Ну максимум на свежем проекте или новом компе что-то свежее ставишь, пробуешь.&lt;/p&gt;
&lt;p&gt;А теперь как-то реально попроще со всем этим стало: узнаёшь, сразу пробуешь, профит (наверное это можно назвать таблеткой от FOMO, правда хоть это и купирует приступы, но провоцирует повторные 😁).&lt;/p&gt;
&lt;p&gt;Возможно на такой волне стоит присмотреться и к остальной экосистеме. Например, вот в pnpm &lt;a href=&quot;https://pnpm.io/blog/2025/12/29/pnpm-in-2025&quot;&gt;подвели итоги прошлого года&lt;/a&gt;. В v10 много всего интересного.&lt;/p&gt;
&lt;p&gt;Самое важное — pnpm перестал доверять всем пакетам. Раньше &lt;code&gt;pnpm install&lt;/code&gt; давал любому пакету в дереве зависимостей запускать произвольный код (preinstall, postinstall). Это само собой создавало вектор атак через supply chain.&lt;/p&gt;
&lt;p&gt;В v10 lifecycle scripts блокируются по умолчанию. Никакого preinstall/postinstall без явного разрешения.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;allowBuilds:
  esbuild: true
  nx@21.6.4: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ещё одна фишка pnpm — content-addressable store (дедупликация файлов). В v10.12 сделали ещё шаг дальше — глобальное виртуальное хранилище.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm-workspace.yaml
enableGlobalVirtualStore: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Раньше каждый проект имел свой &lt;code&gt;node_modules&lt;/code&gt;. Теперь общие зависимости линкуются один раз глобально. А это:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Экономия диска — одинаковые графы зависимостей шарятся между проектами.&lt;/li&gt;
&lt;li&gt;Быстрые установки — если 10 проектов используют &lt;code&gt;react@19&lt;/code&gt;, pnpm линкует его один раз из глобального хранилища на машине.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Для монорепозиториев и сложных настроек есть конфиги зависимостей. Это позволяет &lt;a href=&quot;https://pnpm.io/config-dependencies&quot;&gt;шарить конфиги pnpm&lt;/a&gt; (хуки, патчи, разрешения на билды) между проектами.&lt;/p&gt;
&lt;p&gt;Конфиги зависимостей устанавливаются в &lt;code&gt;node_modules/.pnpm-config&lt;/code&gt; до основного графа зависимостей.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# pnpm-workspace.yaml
configDependencies:
  pnpm-plugin-my-company: &quot;1.0.0+sha512-...&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Это помогает шарить &lt;code&gt;.pnpmfile.cjs&lt;/code&gt; хуки между репозиториями, централизовать патчи для &lt;code&gt;patchedDependencies&lt;/code&gt;, поддерживать список пакетов, которым разрешено запускать build скрипты.&lt;/p&gt;
&lt;p&gt;Кроме того, pnpm давно умеет &lt;a href=&quot;https://pnpm.io/package_json#devenginesruntime&quot;&gt;переключать версию Node.js для рантайма&lt;/a&gt; (не нужен nvm). В 2025 добавили Deno и Bun.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// package.json
{
  &quot;devEngines&quot;: {
    &quot;runtime&quot;: {
      &quot;name&quot;: &quot;node&quot;,
      &quot;version&quot;: &quot;24.6.0&quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pnpm сам скачает и будет использовать указанную версию для скриптов.&lt;/p&gt;
&lt;p&gt;Поддержка JSR — тоже прикольно, но пока что не особо актуально, как я вижу.&lt;/p&gt;
&lt;p&gt;Кроме того, ещё от себя добавлю, что в pnpm есть &lt;code&gt;catalogs&lt;/code&gt;-алиасы (чтобы один раз в конфиге объявить набор зависимостей), &lt;code&gt;workspaces&lt;/code&gt; (для организации монореп), возможность патчить зависимости (&lt;code&gt;pnpm patch&lt;/code&gt;) и проверять их на актуальность (&lt;code&gt;pnpm outdated&lt;/code&gt;)&lt;/p&gt;
</content:encoded></item><item><title>CSS и HTML фичи в Baseline 2025</title><link>https://juwain.github.io/web-platform/blog/2026-02-04/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-02-04/</guid><description>Ключевые CSS и HTML фичи веб-платформы, достигшие статуса Baseline Widely Available</description><pubDate>Wed, 04 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В прошлом году (+ в январе 2026) довольно много платформенных фич достигли статуса Baseline Widely Available — это значит, что они поддерживаются во всех основных браузерах уже 30 месяцев! А это повод &lt;s&gt;бескомпромиссно тащить их в прод&lt;/s&gt; проверить аналитику по пользовательским устройствам и браузерам в вашем проекте (скорее всего ваши пользователи уже обзавелись браузером, которые эти фичи поддерживают).&lt;/p&gt;
&lt;p&gt;Собрал списком все фичи с кратким описанием и моими комментами к их использованию.&lt;/p&gt;
&lt;h3&gt;CSS&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/container-queries/&quot;&gt;Container Queries&lt;/a&gt;&lt;/strong&gt; — применение стилей на основе размеров родительского контейнера, а не viewport. Позволяет создавать адаптивные компоненты, которые реагируют на свой контейнер.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card {
  container-type: inline-size;
}

@container (min-width: 300px) {
  .card { background-color: lightblue; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 5 из 5, но требует перестроить майндсет в целом при работе с UI (то есть не только вам как разработчику, но ещё из дизайнеру). Хорошо ложится на UI-киты и разработку изолированных компонентов.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/individual-transforms/&quot;&gt;Individual Transform Properties&lt;/a&gt;&lt;/strong&gt; — отдельные свойства &lt;code&gt;translate&lt;/code&gt;, &lt;code&gt;scale&lt;/code&gt;, &lt;code&gt;rotate&lt;/code&gt; вместо одного &lt;code&gt;transform&lt;/code&gt;. Упрощает анимации и улучшает читаемость кода.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  translate: 20px 10px;
  scale: 0.8;
  rotate: 90deg;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 3 из 5, приятный сахар, помогает сократить повторящийся код при написании трансформов, легко внедрить.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/motion-path/&quot;&gt;Motion Path&lt;/a&gt;&lt;/strong&gt; — анимация элементов вдоль заданного пути с помощью &lt;code&gt;offset-path&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  offset-path: path(&apos;M10 10 L 100 100&apos;);
  animation: move 2s linear infinite;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 2 из 5, специфичная, но прикольная фича, но если появится подходящая задача и вовремя вспомнить, можно избежать использования JS для анимации движения элемента по траектории.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/grid-animation/&quot;&gt;Grid Animation&lt;/a&gt;&lt;/strong&gt; — анимация свойств &lt;code&gt;grid-template-columns&lt;/code&gt; и &lt;code&gt;grid-template-rows&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  transition: grid-template-columns 0.3s;
}
.grid:hover {
  grid-template-columns: 1fr 2fr;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 2 из 5, в целом прикольная фича для разъезжающихся динамических лейаутов, но применимость нечастая.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/animation-composition/&quot;&gt;animation-composition&lt;/a&gt;&lt;/strong&gt; — выбор способа комбинирования анимаций, влияющих на одно свойство.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  animation-composition: add; /* replace, add, accumulate */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 2 из 5, если делаете руками CSS-анимации, может пригодиться, иначе не будет полезно.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/color-mix/&quot;&gt;color-mix()&lt;/a&gt;&lt;/strong&gt; — смешивание двух цветов в заданном цветовом пространстве. Полезно для создания светлых/тёмных оттенков.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  background: color-mix(in srgb, red 50%, white 50%);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, чрезвычайно мощная штука, если настраиваете собственную дизайн-систему, стайлгайд или UI-кит в проекте.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/color-function/&quot;&gt;color()&lt;/a&gt;&lt;/strong&gt; — выбор цвета из указанного цветового пространства. Поддерживает wide-gamut пространства вроде &lt;code&gt;display-p3&lt;/code&gt; для более насыщенных цветов.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  color: color(display-p3 0.5 0.2 0.8);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, аналогично мнению про &lt;code&gt;color-mix()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/lab/&quot;&gt;Lab и LCH&lt;/a&gt;&lt;/strong&gt; — цветовые пространства с перцептивной равномерностью. Lab использует прямоугольные координаты, LCH — полярные.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/oklab/&quot;&gt;Oklab и OkLCh&lt;/a&gt;&lt;/strong&gt; — цветовые пространства, разработанные для лучшего соответствия человеческому восприятию цвета. OkLCh — полярный вариант Oklab.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  color: lab(50% 20 -30);
  background: lch(60% 50 150);
  color: oklab(0.5 0.2 -0.1);
  background: oklch(0.6 0.5 120);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, формат &lt;code&gt;oklch&lt;/code&gt; может также пригодиться для гибкой настройки цветовой палитры и её производных в проекте.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/viewport-unit-variants/&quot;&gt;Small, Large, Dynamic Viewport Units&lt;/a&gt;&lt;/strong&gt; — единицы &lt;code&gt;dvh&lt;/code&gt;, &lt;code&gt;svh&lt;/code&gt;, &lt;code&gt;lvh&lt;/code&gt; для учёта UI мобильных браузеров. &lt;code&gt;sv*&lt;/code&gt; — минимальный размер, &lt;code&gt;lv*&lt;/code&gt; — максимальный, &lt;code&gt;dv*&lt;/code&gt; — динамический.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  height: 100svh; /* 100% минимального viewport height */
  width: 100dvw;  /* 100% динамического viewport width */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, если вы когда-нибудь боролись с fullscreen-высотой в вёрстке на мобилках, то в следующий раз присмотритесь к этим значениям, могут пригодиться.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/two-value-display/&quot;&gt;Two-value display property&lt;/a&gt;&lt;/strong&gt; — свойство &lt;code&gt;display&lt;/code&gt; теперь принимает два значения для явного указания внешнего и внутреннего режима layouts. Например, &lt;code&gt;inline flex&lt;/code&gt; или &lt;code&gt;block flow&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card {
  display: inline flex;
}
.container {
  display: block flow;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 2 из 5, любопытно, но не более.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/overflow-clip/&quot;&gt;overflow: clip&lt;/a&gt;&lt;/strong&gt; — обрезка содержимого без создания скроллов, с возможностью обрезки только по одной стороне&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.nav-bar {
  overflow-x: clip;
  overflow-y: visible;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, полезно, если нужно включить скролл по одно стороне + также это значение overflow, в котром не создаётся новый formatting context.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/overscroll-behavior/&quot;&gt;overscroll-behavior&lt;/a&gt;&lt;/strong&gt; — управление поведением при прокрутке за границы.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container {
  overscroll-behavior: contain;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, очень узкоспециализированная фича, но может быть крайне полезна для управлением мульти-скроллом.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/outline/&quot;&gt;outline&lt;/a&gt;&lt;/strong&gt; — свойства для стилизации линии вокруг элемента вне border, не влияющие на layout.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  outline: 2px dashed red;
  outline-offset: 5px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 3 из 5, фича-то старая, но был баг в Safari, который починили в 03.2023.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/nth-child-of/&quot;&gt;&lt;code&gt;:nth-child() of &amp;lt;selector&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; — более точный выбор элементов с фильтром по селектору.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;li:nth-child(odd of .active) {
  background: yellow;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, прикольная штука для условной стилизации, полезно помнить перед реализацией на JS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/media-query-range-syntax/&quot;&gt;Media Query Range Syntax&lt;/a&gt;&lt;/strong&gt; — новый синтаксис для медиа-запросов с диапазонами.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media (400px &amp;lt;= width &amp;lt;= 800px) {
  /* стили */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 4 из 5, синтаксический сахар, нравится, что наконец не нужно каждый раз вспоминать и перебирать варианты min/max-width.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/resolution/&quot;&gt;Resolution Media Query&lt;/a&gt;&lt;/strong&gt; — медиа-запрос для применения стилей на основе плотности пикселей устройства.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@media (min-resolution: 2dppx) {
  /* стили для high-DPI экранов */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 2 из 5, узкоспециализированная фича, но может пригодиться для детальной стилизации для разных мобильных устройств.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/trig-functions/&quot;&gt;Trigonometric Functions&lt;/a&gt;&lt;/strong&gt; — &lt;code&gt;sin()&lt;/code&gt;, &lt;code&gt;cos()&lt;/code&gt;, &lt;code&gt;tan()&lt;/code&gt; в CSS для математических вычислений.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  transform: rotate(calc(sin(45deg) * 1turn));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 2 из 5, любопытно, но слишком хардкорно, малоприменимо в реальной жизни.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/calc-constants/&quot;&gt;calc() Keywords&lt;/a&gt;&lt;/strong&gt; — математические константы &lt;code&gt;e&lt;/code&gt;, &lt;code&gt;pi&lt;/code&gt;, &lt;code&gt;infinity&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt; в CSS math функциях.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  font-size: calc(var(--base-size) * pi);
  height: calc(100vh * sin(pi / 2));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 1 из 5, не могу придумать, где это применить.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/font-palette/&quot;&gt;font-palette&lt;/a&gt;&lt;/strong&gt; — выбор цветовой палитры из шрифта, с возможностью переопределения отдельных цветов через &lt;code&gt;@font-palette-values&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.element {
  font-palette: alternate;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 1 из 5, малополезная фича, применимая только для &quot;цветных&quot; шрифтов, не стоит внимания&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/contain-style/&quot;&gt;Style Containment&lt;/a&gt;&lt;/strong&gt; и &lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/contain-inline-size/&quot;&gt;Inline-size Containment&lt;/a&gt;&lt;/strong&gt; — изоляция стилей элемента. &lt;code&gt;style&lt;/code&gt; ограничивает расчёт счётчиков и кавычек внутри элемента, а &lt;code&gt;inline-size&lt;/code&gt; предотвращает установку inline-размеров элемента его содержимым, ускоряя рендеринг.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.widget {
  contain: style;
}

.container {
  contain: inline-size;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 1 из 5, мелкие малополезные фичи, &lt;code&gt;style&lt;/code&gt; может пригодиться разве что в нестандартных нумерованных списках; &lt;code&gt;inline-size&lt;/code&gt;, могу только в теории представить, что может быть полезно в разного рода wysiwyg-ах.&lt;/p&gt;
&lt;h3&gt;HTML / DOM&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web-platform-dx.github.io/web-features-explorer/features/inert/&quot;&gt;inert&lt;/a&gt;&lt;/strong&gt; — атрибут для отключения элементов от взаимодействия и accessibility tree. Элементы не получают фокус и не реагируют на клики.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div inert&amp;gt;
  &amp;lt;button&amp;gt;Неактивная кнопка&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Мнение&lt;/em&gt;: 3 из 5, мощная и простая фича, хороший юзкейс для ограничения пределов фокуса при показе модальных окон: модалка работает, body под ней за inert-ом.&lt;/p&gt;
</content:encoded></item><item><title>Playwright CLI</title><link>https://juwain.github.io/web-platform/blog/2026-02-09/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-02-09/</guid><description>Эргономичный CLI для запуска безголового Playwright — автоматизация действий в браузере без MCP</description><pubDate>Mon, 09 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Тут вышел &lt;a href=&quot;https://github.com/microsoft/playwright-cli&quot;&gt;https://github.com/microsoft/playwright-cli&lt;/a&gt;, более эргономичный, чем MCP, способ запускать ботом безголового playwright для выполнения действий в браузере.&lt;/p&gt;
&lt;p&gt;Да, собственно, не обязательно ботом, можно просто в рамках CLI-API написать скрипт для автоматизации действия в браузере:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;playwright-cli open https://demo.playwright.dev/todomvc/ --headed
playwright-cli type &quot;Buy groceries&quot;
playwright-cli press Enter
playwright-cli type &quot;Water flowers&quot;
playwright-cli press Enter
playwright-cli check e21
playwright-cli check e35
playwright-cli screenshot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Вот эти вот e21 и e35 — это наименования DOM-нод в открытом сайте. Командой &lt;code&gt;open&lt;/code&gt; сайт открывается и записывается его снепшот в виде yaml-файла. Каждая нода помечается своим айдишником.&lt;/p&gt;
&lt;p&gt;По необходимости можно вызывать playwright &quot;с головой&quot;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;playwright-cli open https://playwright.dev --headed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Для ботов прописаны доки для выполнения рутинных задач:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Request mocking&lt;/strong&gt; — перехват и мок запросов&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running Playwright code&lt;/strong&gt; — выполнение playwright-скриптов&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Browser session management&lt;/strong&gt; — управление браузерными сессиями&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Storage state (cookies, localStorage)&lt;/strong&gt; — запись и чтение из браузерного хранилища&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test generation&lt;/strong&gt; — генерация тестов после взаимодействия с сайтом&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracing&lt;/strong&gt; — запись трейсов&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Video recording&lt;/strong&gt; — запись видео&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>react-best-practices</title><link>https://juwain.github.io/web-platform/blog/2026-01-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-01-16/</guid><description>react-best-practices</description><pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Тут Vercel подогнали &lt;s&gt;мозгов для ваших frontend-агентов&lt;/s&gt; &lt;a href=&quot;https://vercel.com/blog/introducing-react-best-practices&quot;&gt;набор бестпрактисов и антипаттернов по React&lt;/a&gt;, можно установить в виде скиллов в ваш любимый агент или просто почитать. Темы, рассматриваемые внутри: устранение вотерфоллов, оптимизация размера бандла, SSR, дата-фетчинг на клиенте (жаль, что без tanstack, а только swr), оптимизация ререндеров, перфоманс рендеринга и JS, а также ещё немного мелочей.&lt;/p&gt;
</content:encoded></item><item><title>npm lifecycle scripts</title><link>https://juwain.github.io/web-platform/blog/2026-02-16/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-02-16/</guid><description>TIL: в npm есть lifecycle scripts — хуки pre и post для стандартных команд dev, build, test</description><pubDate>Mon, 16 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TIL, что в npm есть lifecycle scripts. Перед и после стандартных команд типа &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt; есть &quot;хуки&quot;, на которые можно подцепить нужные дополнительные команды.&lt;/p&gt;
&lt;p&gt;| &lt;code&gt;npm run dev&lt;/code&gt; | &lt;code&gt;predev&lt;/code&gt; → &lt;code&gt;dev&lt;/code&gt; → &lt;code&gt;postdev&lt;/code&gt; |
| &lt;code&gt;npm run build&lt;/code&gt; | &lt;code&gt;prebuild&lt;/code&gt; → &lt;code&gt;build&lt;/code&gt; → &lt;code&gt;postbuild&lt;/code&gt; |
| &lt;code&gt;npm test&lt;/code&gt; | &lt;code&gt;pretest&lt;/code&gt; → &lt;code&gt;test&lt;/code&gt; → &lt;code&gt;posttest&lt;/code&gt; |&lt;/p&gt;
&lt;p&gt;Добавляете в &lt;code&gt;package.json&lt;/code&gt; скрипт с префиксом &lt;code&gt;pre&lt;/code&gt; или &lt;code&gt;post&lt;/code&gt; — npm запустит их с соответствующем порядке:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;scripts&quot;: {
    &quot;build:client&quot;: &quot;node esbuild.client.mjs&quot;,
    &quot;predev&quot;: &quot;npm run build:client&quot;
    &quot;dev&quot;: &quot;tsx src/server/index.ts&quot;,
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Сначала &lt;code&gt;predev&lt;/code&gt; соберёт клиент, &lt;code&gt;dev&lt;/code&gt; → запустит сервер.&lt;/p&gt;
&lt;p&gt;Полезно, когда перед запуском надо что-то подготовить — собрать ассеты, проверить типы, создать папки.&lt;/p&gt;
&lt;p&gt;Что можно с этим сделать:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prepublishOnly&lt;/code&gt; — проверки перед публикацией пакета в npm&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prebuild&lt;/code&gt; — генерация кода или очистка папки dist&lt;/li&gt;
&lt;li&gt;&lt;code&gt;postinstall&lt;/code&gt; — автоматические действия после &lt;code&gt;npm install&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Подробнее: &lt;a href=&quot;https://docs.npmjs.com/cli/v10/using-npm/scripts#pre--post-scripts&quot;&gt;docs.npmjs.com/cli/v10/using-npm/scripts&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>End-to-end разработчик</title><link>https://juwain.github.io/web-platform/blog/2026-03-01/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-03-01/</guid><description>Деление на фронтенд и бэкенд теряет смысл — приходит эпоха полнофункционального разработчика</description><pubDate>Sun, 01 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Деление на фронтенд и бэкенд никогда не было про технику. Это было больше про бизнес-процессы и найм: в индустрии удобнее искать заменяемых специалистов на узкий скоуп. Фронтендер имплементит &quot;клиентскую&quot; логику, бэкендер — API и &quot;серверную&quot; логику. Но по сути это единое целое и деление, если посмотреть свежим взглядом, весьма условное. Я прекрасно помню времена, когда фреймворки не затачивались конкретно на фронт/бэк, а были про веб-разработку проекта целиком.&lt;/p&gt;
&lt;p&gt;И сейчас это деление начинает терять смысл. ИИшки привносят собой инфляцию ценности навыков (и стоимости строк кода). Уметь писать код стоит меньше, чем год назад. И будет стоить ещё меньше через год. Причём стоит меньше и в деньгах, и в самой ценности навыка: знания становятся все более и более общедоступны и легкодоступны, и само понятие конкретного навыка — это теперь не что-то труднодостигаемое и &quot;выстрадываемое&quot; потом и кровью.&lt;/p&gt;
&lt;p&gt;Приходит эпоха полнофункционального разработчика (олды тут? привет, вебмастера). Это как бы «фуллстек» в старом понимании (например, в связке React + Node) + одновременно, который понимает систему целиком от и до, может и обозревать верхнеуровнево, и &quot;зумиться&quot; до детальной имплементации, настраивает инфраструктуру, валидирует, что и как система делает, а главное — следит, как система соотносится бизнесом, насколько качественно решает его проблемы. End-to-end-разработчик.&lt;/p&gt;
&lt;p&gt;Карьерный путь становится короче и интенсивнее. &quot;Junior&quot; в привычном смысле исчезает — вместо него &quot;junior senior&quot;: человек приходит уже с наработанным опытом через пет-проекты, симуляционные окружения. С образованием вообще всё просто небывало круто. Как никогда раньше обучение может быть безостановочным процессом и не привязанным к конкретному обучающему вендору — селф-обучение выходит на первый план, а бизнесы напрямую предоставляют свою инфру для специализации в нужном контексте.&lt;/p&gt;
&lt;p&gt;Реагировать на происходящее можно по-разному. Отрицать, игнорировать, плыть по течению или против. Но если хочется сохранить привычные заработки и скорость их роста, в обозримом будущем все пути ведут к тому, чтобы брать на себя бо́льшую ответственность. Для разработчика это или уходить в пипл-менеджмент, или же расширять и углублять технику. Я за свою карьеру два раза проходит цикл &quot;разраб -&amp;gt; тимлид -&amp;gt; разраб&quot; и понял, что не хочу закапываться в менеджмент дальше. Поэтому сейчас отзываясь на вызовы нового времени выбираю второе.&lt;/p&gt;
&lt;p&gt;Так что буду уделять больше своего времени частям веб-разработки и платформы, которые выходят за пределы интерфейса в браузере: инфраструктуре, &quot;серверу&quot;, инструментам сборки и доставки, проектированию систем. И вникать в зарождающуюся роль e2e-разработчика — теперь больше &quot;пчеловода&quot;, чем &quot;собирателя&quot;.&lt;/p&gt;
&lt;p&gt;Думаю, это также отразится и на содержании блога.&lt;/p&gt;
&lt;p&gt;Stay tuned!&lt;/p&gt;
</content:encoded></item><item><title>Визуальное регрессионное тестирование в Docker</title><link>https://juwain.github.io/web-platform/blog/2026-03-17/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-03-17/</guid><description>Настраиваем скриншотные тесты React-компонентов через Playwright, Storybook и Docker для детерминированного рендеринга в CI</description><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В нескольких проектах, где я работал, пробовали внедрить скриншот-тестирование компонентов. Принцип работы такой:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;меняем компонент&lt;/li&gt;
&lt;li&gt;делаем эталонный скриншот, сохраняем в репе&lt;/li&gt;
&lt;li&gt;повторяем на всех компонентах&lt;/li&gt;
&lt;li&gt;при повторных изменениях запускаем тесты, в которых сравниваются эталонные скриншоты и текущее отображение компонентов&lt;/li&gt;
&lt;li&gt;если все расхождения запланированные, меняем эталонные скрины; если есть незапланированные расхождения, поздравляю, тесты нашли регресс!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Такие тесты хорошо подходят для теста вёрстки элементов ui-kit-а (многочисленные состояниях ховера, фокуса, разные режимы компонента) или же каких-то критичных компонентов (форма логина, чекаут), которые никак нельзя случайно поломать.&lt;/p&gt;
&lt;p&gt;Снепшотные тесты, юниты, e2e тут не помогут, нужно именно сравнение скринов.
Звучит хорошо, но есть одно НО. Во всех случаях на моей практике дело упиралось в то, что скриншоты снимаются разными разработчиками на разных машинах с разными ОС. И в зависимости от этого скриншоты начинают расходиться. Шрифты другие. Субпиксельный рендеринг другой. Антиалиасинг другой. Также отличаются элементы форм. MacOS рендерит шрифты и формы иначе, чем Ubuntu. И тест падает, хотя визуально всё ок. Вместо помощи тесты начинают мешать и бесить.&lt;/p&gt;
&lt;p&gt;Логично было бы предположить делать скриншоты на одной машине, например, вынести этот процесс на CI/CD или на отдельный сервер, но обычно с этим в компаниях сложно, нужно всё согласовывать, заводить, что есть заморочь.&lt;/p&gt;
&lt;p&gt;И тут изучая Docker открыл для себя идеально подходящую под кейс фичу! Через Docker можно связать файловую систему хоста (ваша машина) с файловой системой запущенного контейнера. То есть храним скрины по прежнему в репо (развёрнутом у каждого разработчика), монтируем папку с ними внутрь Docker-контейнера, снимаем скриншоты, сравниваем, при необходимости обновляем. Внутри контейнера один и тот же образ с фиксированной ОС, фиксированной версией браузера, фиксированными шрифтами. И соотвественно таким же макаром запускается в CI.&lt;/p&gt;
&lt;p&gt;Собрал пруф оф концепт — &lt;a href=&quot;https://github.com/juwain/playwright-docker-screenshot-testing&quot;&gt;github.com/juwain/playwright-docker-screenshot-testing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Что там вкратце, происходит: &lt;strong&gt;Storybook&lt;/strong&gt; изолирует компоненты, &lt;strong&gt;Playwright&lt;/strong&gt; делает скриншоты, &lt;strong&gt;Docker&lt;/strong&gt; обеспечивает одинаковый рендеринг.&lt;/p&gt;
&lt;p&gt;Оркестрация через &lt;code&gt;docker-compose.yml&lt;/code&gt; (именно там указывается, какие локальные папки монтируются в контейнер):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  visual-tests:
    build: .
    volumes:
      # Persist screenshots - accessible from host
      - ./__screenshots__:/app/__screenshots__
      # HTML report for visual diff
      - ./html-report:/app/html-report
      # Test results (traces, screenshots on failure)
      - ./test-results:/app/test-results
      # Source files for quick iteration (read-only)
      - ./src:/app/src:ro
    environment:
      - CI=true
    command: sh -c &quot;npm run storybook -- --host 0.0.0.0 &amp;amp; sleep 15 &amp;amp;&amp;amp; npx playwright test --project=visual&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Docker-образ с Playwright официальный от Microsoft уже содержит браузеры и все зависимости.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM mcr.microsoft.com/playwright:v1.48.0-noble
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Каждый визуальный тест — это три действия: открыть стори, дождаться рендера, сравнить скриншот. Storybook рендерит в статическом режиме каждый отдельный компонент по адресу &lt;code&gt;/iframe.html?id=${storyId}&amp;amp;viewMode=story&lt;/code&gt;, ждём пока загрузятся картинки и шрифты, можно снимать скриншот Playwright-ом и сравнивать тоже им.&lt;/p&gt;
&lt;p&gt;Пример теста кнопки:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;test.describe(&apos;Button&apos;, () =&amp;gt; {
  test(&apos;hover&apos;, async ({ page }) =&amp;gt; {
    const component = await gotoStory(page, &apos;design-system-button--primary&apos;);
    const button = component.locator(&apos;button.button&apos;).first();
    await button.hover();
    await expect(component).toHaveScreenshot();
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Особенности настройки Playwright: можно оставить небольшой задел на случайные расхождения, выключить анимации, спрятать каретку в инпутах.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;toHaveScreenshot: {
  maxDiffPixels: 100,
  animations: &quot;disabled&quot;,
  caret: &quot;hide&quot;,
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;После прогона тестов формируется HTML-репорт: интерактивный diff, где можно посмотреть, что именно изменилось, без установки сторонних инструментов (приложил скрин, как это выглядит в комментах).&lt;/p&gt;
&lt;p&gt;Отдельными cli-командами скрины апрувятся и обновляются.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;scripts&quot;: {
    &quot;test:visual&quot;: &quot;docker compose up --build&quot;,
    &quot;test:visual:update&quot;: &quot;playwright test --project=visual --update-snapshots&quot;,
    &quot;test:visual:approve&quot;: &quot;playwright test --project=visual --last-failed --update-snapshots&quot;,
    &quot;test:visual:report&quot;: &quot;playwright show-report html-report&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Как superset.sh привёл меня к собственной теме для Zed</title><link>https://juwain.github.io/web-platform/blog/2026-04-30/</link><guid isPermaLink="true">https://juwain.github.io/web-platform/blog/2026-04-30/</guid><description>Сначала про систему цветовых токенов и визуальных решений в superset.sh, а затем — что меняется, когда те же идеи переносишь в тему для редактора</description><pubDate>Thu, 30 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;В последнее время моя ежедневная работа всё больеш смещается в терминал. Когда параллельно открыто несколько проектов и у каждого по несколько вкладок в терминале, обычный плоский список табов (у меня терминал iTerm) слишком скукоживается.&lt;/p&gt;
&lt;p&gt;Не хватает ещё одного измерения: горизонтально — вкладки внутри одного проекта, вертикально — сами проекты.&lt;/p&gt;
&lt;p&gt;Потом узнал про &lt;a href=&quot;https://superset.sh/&quot;&gt;&lt;code&gt;superset.sh&lt;/code&gt;&lt;/a&gt;, и он мне зашёл. Получается такой 2D-терминал: слева список проектов, внутри каждого свои табы.&lt;/p&gt;
&lt;p&gt;Параллельно с увеличением количества времени проводимого в терминале меняется и роль редактора кода. Если раньше IDE была главным рабочим местом, то в агентоцентричной разработке &quot;редактор&quot; больше нужен для просмотра diff, точечных правок и удобной навигации по файлам.&lt;/p&gt;
&lt;p&gt;У меня эту роль уже около года выполняет Zed: быстрый, легковесный и менее прожорливый по ресурсам, чем VS Code.&lt;/p&gt;
&lt;p&gt;Теперь про смену контекста между режимом &quot;терминала&quot; и &quot;редактора&quot;.&lt;/p&gt;
&lt;p&gt;В &lt;code&gt;superset.sh&lt;/code&gt; мне очень понравилась тёмная тема по умолчанию, а при переходе в Zed была другая тёмная тема, о которую спотыкается глаз, когда много раз за день прыгаешь между &quot;менеджером терминалов&quot; и &quot;редактором для проверки изменений&quot;.&lt;/p&gt;
&lt;p&gt;В общем, я собрал тему для Zed на основе темы superset. В целом, нужно было экспортнуть тему из superset и сопоставить с токенами темы в Zed.&lt;/p&gt;
&lt;p&gt;Так как это всё таки немного разные контексты, пришлось подтюнить тему в течение нескольких недель, пока окончательно не привык.&lt;/p&gt;
&lt;p&gt;В СПБ сейчас начинаются белые ночи, поэтому больше счас сижу в светлой теме днём (на основной работе) и в тёмной после заката (на пет-проектах).&lt;/p&gt;
&lt;p&gt;Тему для Zed я опубликовал здесь &lt;a href=&quot;https://github.com/juwain/superset-zed-theme&quot;&gt;github.com/juwain/superset-zed-theme&lt;/a&gt;.&lt;/p&gt;
</content:encoded></item></channel></rss>