This media is not supported in your browser
VIEW IN TELEGRAM
#автор дня
Сегодня у моей дочки день рождения — целых три года :)
Потому сил моих хватает только познакомить вас с замечательным автором — Тиффани Чонг и её потрясающим анимешным CSS-артом: https://codepen.io/tiffachoo/pens/public
Кажется, будто можно составить из этих персонажей целую игру, милота зашкаливает.
Не кукситесь, котаны :)
#css #art
Сегодня у моей дочки день рождения — целых три года :)
Потому сил моих хватает только познакомить вас с замечательным автором — Тиффани Чонг и её потрясающим анимешным CSS-артом: https://codepen.io/tiffachoo/pens/public
Кажется, будто можно составить из этих персонажей целую игру, милота зашкаливает.
Не кукситесь, котаны :)
#css #art
👍42🤩16❤11
This media is not supported in your browser
VIEW IN TELEGRAM
#баг дня
Сегодня Chrome 125 принёс шикарное.
В погоне за поддержкой CSS Popup Anchor Positioning API они совсем позабыли о, собственно, правильном назначении этих самых якорей.
Вспоминаем, что видеоплеер работает в Shadow DOM и получаем поведение с иллюстрации.
Ссылка: https://issues.chromium.org/issues/341741271
Скоро поправят в Canary. Надеюсь, будет бэкпорт.
#css #popup
Сегодня Chrome 125 принёс шикарное.
В погоне за поддержкой CSS Popup Anchor Positioning API они совсем позабыли о, собственно, правильном назначении этих самых якорей.
Вспоминаем, что видеоплеер работает в Shadow DOM и получаем поведение с иллюстрации.
Ссылка: https://issues.chromium.org/issues/341741271
Скоро поправят в Canary. Надеюсь, будет бэкпорт.
#css #popup
🤩9👍2
#заметка дня
Рубрика "Вы не спрашивали, но я всё равно отвечу!"
На самом деле, разговор произошёл в Твиттере, и я посчитал разумным, вынести его сюда.
Итак, вопрос:
Что бы убедиться: использование testid в end-2-end тестах для выборки элементов это анти-паттерн, верно? Следует тестировать с точки зрения пользователя: искать кнопку с неким текстом, например.
Знаете ли вы статьи или доклады, которые подкрепляют эту точку зрения?
Отвечаю:
Это не то чтобы антипаттерн, это просто бестолковое использование ресурсов, потому и продвигается как антипаттерн.
1. Надо тестировать то, что видит юзер
2. Если что-то не видит, значит, всё плохо
3. Если там иконка или нужен результат — искать надо по a11y атрибутам.
Сразу поясню за "бестолковость".
Когда ты что-то тестируешь, тесты становятся твоей документацией. Значит, в тестах закрепляется текущее поведение проекта. Даже строки не стоит импортировать (если ты только не тестируешь систему перевода).
А это значит, если кто-то случайно сломает систему перевода или неправильно переведёт строку без информирования остальных — тесты упадут и это правильно.
Дальше, решая проблему через ARIA-атрибуты, ты заодно решаешь вопрос доступности. Бесплатно. Поэтому data-testid и названы бестолковым использованием ресурсов.
Это же, кстати, касается систем трекинга вроде Datadog RUM.
Смысл фронтенда в том, чтобы пользователь мог с продуктом взаимодействовать. Для этого необходима визуальная и когнитивная поддержка. Кнопка может быть и видна, но на кнопке — упс — может не быть текста. Или она будет цвета фона (потому скриншот-тесты ещё не вымерли).
Подобный подход к тестировани применяется как в E2E, так и в юнит- и интеграционном тестировании. Вот, например, поясняющая статья от Testing Library, которая нынче стандарт де-факто для тестирования в вебе.
Тестируйте, котаны!
#web #testing #e2e
Рубрика "Вы не спрашивали, но я всё равно отвечу!"
На самом деле, разговор произошёл в Твиттере, и я посчитал разумным, вынести его сюда.
Итак, вопрос:
Что бы убедиться: использование testid в end-2-end тестах для выборки элементов это анти-паттерн, верно? Следует тестировать с точки зрения пользователя: искать кнопку с неким текстом, например.
Знаете ли вы статьи или доклады, которые подкрепляют эту точку зрения?
Отвечаю:
Это не то чтобы антипаттерн, это просто бестолковое использование ресурсов, потому и продвигается как антипаттерн.
1. Надо тестировать то, что видит юзер
2. Если что-то не видит, значит, всё плохо
3. Если там иконка или нужен результат — искать надо по a11y атрибутам.
Сразу поясню за "бестолковость".
Когда ты что-то тестируешь, тесты становятся твоей документацией. Значит, в тестах закрепляется текущее поведение проекта. Даже строки не стоит импортировать (если ты только не тестируешь систему перевода).
А это значит, если кто-то случайно сломает систему перевода или неправильно переведёт строку без информирования остальных — тесты упадут и это правильно.
Дальше, решая проблему через ARIA-атрибуты, ты заодно решаешь вопрос доступности. Бесплатно. Поэтому data-testid и названы бестолковым использованием ресурсов.
Это же, кстати, касается систем трекинга вроде Datadog RUM.
Смысл фронтенда в том, чтобы пользователь мог с продуктом взаимодействовать. Для этого необходима визуальная и когнитивная поддержка. Кнопка может быть и видна, но на кнопке — упс — может не быть текста. Или она будет цвета фона (потому скриншот-тесты ещё не вымерли).
Подобный подход к тестировани применяется как в E2E, так и в юнит- и интеграционном тестировании. Вот, например, поясняющая статья от Testing Library, которая нынче стандарт де-факто для тестирования в вебе.
Тестируйте, котаны!
#web #testing #e2e
Testing-Library
React Testing Library | Testing Library
React Testing Library builds on top of DOM Testing Library by adding
👍16❤1
#ссылка дня
Итак, в чатике пару дней назадподнялся срачик состоялось некоторое обсуждение.
Темой этого самого обсуждения стало автоматическое воспроизведение видео со звуком на сайтах. Насколько нам всем известно, это с некоторых пор практически невозможно: только после явного действия пользователя.
Но коллега утверждал, что можно и в доказательство приводил Reddit. Естественно, никто повторить не мог.
Пришлось — кто бы мог подумать — обратиться к документации!
Итак, смотрим: https://developer.chrome.com/blog/autoplay
И что же это мы такое видим?
— On desktop, the user's Media Engagement Index threshold has been crossed, meaning the user has previously played video with sound.
Что ещё за индекс вовлечённости такой?!
Это что же получается, я смотрю недостаточно мемов на реддите?!
И таки да, внизу имеется расшифровка. Самый простой способ посмотреть её результаты — это открыть страницу about://media-engagement в Chrome.
В общем, когда очередной заказчик вашего очередного проекта возмутится тем, что музыка в его прекрасном промо-видео не играет, расскажите ему о том, что его проект просто неинтересен людям. Вот так просто.
#chrome #media #sound
Итак, в чатике пару дней назад
Темой этого самого обсуждения стало автоматическое воспроизведение видео со звуком на сайтах. Насколько нам всем известно, это с некоторых пор практически невозможно: только после явного действия пользователя.
Но коллега утверждал, что можно и в доказательство приводил Reddit. Естественно, никто повторить не мог.
Пришлось — кто бы мог подумать — обратиться к документации!
Итак, смотрим: https://developer.chrome.com/blog/autoplay
И что же это мы такое видим?
— On desktop, the user's Media Engagement Index threshold has been crossed, meaning the user has previously played video with sound.
Что ещё за индекс вовлечённости такой?!
Это что же получается, я смотрю недостаточно мемов на реддите?!
И таки да, внизу имеется расшифровка. Самый простой способ посмотреть её результаты — это открыть страницу about://media-engagement в Chrome.
В общем, когда очередной заказчик вашего очередного проекта возмутится тем, что музыка в его прекрасном промо-видео не играет, расскажите ему о том, что его проект просто неинтересен людям. Вот так просто.
#chrome #media #sound
👍26🤡2🤩1
#заметка дня
В чате вопрос возник: «А при каких условиях и на что нужно ставить role=“button”?»
Вопрос весьма разумный, ведь вроде как кнопка она и есть кнопка, button. Вот только не всё так просто.
Для начала давайте определимся раз и навсегда: ссылки вместо кнопок не используются никогда.
Ссылка – это или переход к якорю на этой же странице, или же переход на другую страницу и только. Никаких a[href=“#”] с onClick, забудьте.
Остаются button, input[type=“button”] и input[type=“submit”].
Последние потомков внутри не предполагают и являются замещаемыми. Это значит, псевдо-элементов у нас тоже там нет. Впрочем, они вполне себе неплохо оформляются и как вещь в себе работают сносно: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/button
И вот, button. Что же с ним может быть не так, что нам потребуется нечто с role=“button”?
Давайте с очевидного: валидатор запрещает иметь div внутри button.
Выражаясь языком спецификации, button ожидает фразовый контент, а не потоковый: https://caninclude.glitch.me/can/include/?child=div&parent=button
То есть речь идёт не только о div, а ещё о десятке тегов. В итоге официально вкладывать можно практически один лишь span. Наверное, это не всем и не всегда удобно.
Впрочем, браузеры такой трюк позволяют.
Но если вам не всё равно — добавьте role=“button” и tabindex на любой удобный вам элемент, чтобы превратить его в интерактивный. Валидатор и скринридеры будут довольны. А ещё старые Safari, которые не умеют во flexbox на кнопках.
Мы у себя в дизайн-системе назвали такой компонент PlainButton, вот иногда ну надо.
Второй же случай посложнее.
Есть такой вид кнопок, toggle-кнопки. Переключатели. Это не checkbox, это не switch. Это просто что-то, что можно «зажать» сейчас и «отжать» потом. Например, кнопки в текстовом редакторе.
Они или находятся в зажатом положении (текст по центру, полужирный и т. д.), или в отжатом. Переключаем, в общем.
Почему это не чекбоксы? Потому что это не волеизъявление (согласие на что-то) как таковое, это просто некое действие, влияющее на что-то в приложении. Почему не свитчи? Потому что мы ничего не включаем физически. Кажется, об этих концептах стоит потом подробнее написать 😅
В общем, если вы подменяете логику работы кнопки с моментальной реакции на что-то иное вроде toggle, вам необходимо отдельно указать как минимум два необходимых атрибута: role=“button” и aria-pressed. Это же касается, например, кнопок открытия аккордеонов. Вот только вместо pressed нужно будет устанавливать expanded: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role
Да, это всё поначалу кажется ненужным усложнением, но поверьте: в большом приложении информация лишней не бывает. Особенно если она поможет кому-то вашим приложением пользоваться. А заодно легче отлаживать и хранить состояние.
#button #a11y #role #toggle #бородач
В чате вопрос возник: «А при каких условиях и на что нужно ставить role=“button”?»
Вопрос весьма разумный, ведь вроде как кнопка она и есть кнопка, button. Вот только не всё так просто.
Для начала давайте определимся раз и навсегда: ссылки вместо кнопок не используются никогда.
Ссылка – это или переход к якорю на этой же странице, или же переход на другую страницу и только. Никаких a[href=“#”] с onClick, забудьте.
Остаются button, input[type=“button”] и input[type=“submit”].
Последние потомков внутри не предполагают и являются замещаемыми. Это значит, псевдо-элементов у нас тоже там нет. Впрочем, они вполне себе неплохо оформляются и как вещь в себе работают сносно: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/button
И вот, button. Что же с ним может быть не так, что нам потребуется нечто с role=“button”?
Давайте с очевидного: валидатор запрещает иметь div внутри button.
Выражаясь языком спецификации, button ожидает фразовый контент, а не потоковый: https://caninclude.glitch.me/can/include/?child=div&parent=button
То есть речь идёт не только о div, а ещё о десятке тегов. В итоге официально вкладывать можно практически один лишь span. Наверное, это не всем и не всегда удобно.
Впрочем, браузеры такой трюк позволяют.
Но если вам не всё равно — добавьте role=“button” и tabindex на любой удобный вам элемент, чтобы превратить его в интерактивный. Валидатор и скринридеры будут довольны. А ещё старые Safari, которые не умеют во flexbox на кнопках.
Мы у себя в дизайн-системе назвали такой компонент PlainButton, вот иногда ну надо.
Второй же случай посложнее.
Есть такой вид кнопок, toggle-кнопки. Переключатели. Это не checkbox, это не switch. Это просто что-то, что можно «зажать» сейчас и «отжать» потом. Например, кнопки в текстовом редакторе.
Они или находятся в зажатом положении (текст по центру, полужирный и т. д.), или в отжатом. Переключаем, в общем.
Почему это не чекбоксы? Потому что это не волеизъявление (согласие на что-то) как таковое, это просто некое действие, влияющее на что-то в приложении. Почему не свитчи? Потому что мы ничего не включаем физически. Кажется, об этих концептах стоит потом подробнее написать 😅
В общем, если вы подменяете логику работы кнопки с моментальной реакции на что-то иное вроде toggle, вам необходимо отдельно указать как минимум два необходимых атрибута: role=“button” и aria-pressed. Это же касается, например, кнопок открытия аккордеонов. Вот только вместо pressed нужно будет устанавливать expanded: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role
Да, это всё поначалу кажется ненужным усложнением, но поверьте: в большом приложении информация лишней не бывает. Особенно если она поможет кому-то вашим приложением пользоваться. А заодно легче отлаживать и хранить состояние.
#button #a11y #role #toggle #бородач
👍27
#автор дня
Итак, я не так давно, буквально пару месяцев назад, выкладывал репозиторий Сергея Ufocoder'а, посвящённый утечкам памяти в JavaScript. Ну, вот же, положила: https://t.me/htmlshit/2668
Думаю, сегодня можно выложить кое-что ещё :)
Некоторое время Сергей занимается разработкой простого FPS. И пришло время показать первые результаты!
Собственно, перед нами однопользовательская игра в стиле Wolfenstein 3D.
Использует подход к отрисовке графике из 1990-х, в частности алгоритм raycasting (все графические вычисления происходят на CPU).
Написана с нуля, то есть без использования сторонних библиотек.
В игре несколько уровней и очень простой искусственный интеллект, есть возможность подбирать патроны и убегать от зомби, используя мини карту.
Если появится желание улучшить игру, то ее исходники находятся в открытом виде и автор приветствует любые улучшения и исправления.
Репозиторий: https://github.com/ufocoder/fps
Играть: https://ufocoder.github.io/fps/
Если вы, котаны, задались целью понять, как работают 3D-движки на базовом уровне — это вот самое то :)
P. S. а 15 июня у него будет стрим про разработку этой самой игры
#game #fps
Итак, я не так давно, буквально пару месяцев назад, выкладывал репозиторий Сергея Ufocoder'а, посвящённый утечкам памяти в JavaScript. Ну, вот же, положила: https://t.me/htmlshit/2668
Думаю, сегодня можно выложить кое-что ещё :)
Некоторое время Сергей занимается разработкой простого FPS. И пришло время показать первые результаты!
Собственно, перед нами однопользовательская игра в стиле Wolfenstein 3D.
Использует подход к отрисовке графике из 1990-х, в частности алгоритм raycasting (все графические вычисления происходят на CPU).
Написана с нуля, то есть без использования сторонних библиотек.
В игре несколько уровней и очень простой искусственный интеллект, есть возможность подбирать патроны и убегать от зомби, используя мини карту.
Если появится желание улучшить игру, то ее исходники находятся в открытом виде и автор приветствует любые улучшения и исправления.
Репозиторий: https://github.com/ufocoder/fps
Играть: https://ufocoder.github.io/fps/
Если вы, котаны, задались целью понять, как работают 3D-движки на базовом уровне — это вот самое то :)
P. S. а 15 июня у него будет стрим про разработку этой самой игры
#game #fps
👍18❤4
This media is not supported in your browser
VIEW IN TELEGRAM
#инструмент дня
React Compiler, говорите...
А что если я скажу вам, что есть инструмент, конвертирующий ваши JSX-компоненты во... во все остальные?
Буквально: JSX/Svelte в: React, Svelte, Vue, Angular, Qwik, Lit, Solid, Preact...
Давайте просто сразу дам ссылку на песочницу: https://mitosis.builder.io/playground/
Если уж и не для практического применения, но если вдруг надо срочно пересесть на другой фреймворк — то понять принципы можно с лёгкостью.
Знаешь JSX или Svelte — пишешь на всех :)
#framework #tool
React Compiler, говорите...
А что если я скажу вам, что есть инструмент, конвертирующий ваши JSX-компоненты во... во все остальные?
Буквально: JSX/Svelte в: React, Svelte, Vue, Angular, Qwik, Lit, Solid, Preact...
Давайте просто сразу дам ссылку на песочницу: https://mitosis.builder.io/playground/
Если уж и не для практического применения, но если вдруг надо срочно пересесть на другой фреймворк — то понять принципы можно с лёгкостью.
Знаешь JSX или Svelte — пишешь на всех :)
#framework #tool
👍12🤩4
#такое дня
Я знаю, вы любите стыдный контент.
После трёх релизов подряд, в которых не было ничего, кроме исправления z-index (не спрашивайте), проверяющий мои PRы бакендщик (остальные в отпуске), заметил:
— Я-то хотя бы жисоны перекладываю...
Давайте ваши свежие стыдные истории, котаны.
Я знаю, вы любите стыдный контент.
После трёх релизов подряд, в которых не было ничего, кроме исправления z-index (не спрашивайте), проверяющий мои PRы бакендщик (остальные в отпуске), заметил:
— Я-то хотя бы жисоны перекладываю...
Давайте ваши свежие стыдные истории, котаны.
🤩14👍6❤4👎1
#статья дня
Я много раз начинал и забрасывал статью о том, как справляться с рутиной. Но писать статью — это не в чате «деда» включать. Всё-таки важная штука — аудитория.
Впрочем, здесь мне помогут Александр Беспоясов, Вадим Юмадилов и Андрей Романов. Фамилия Беспоясова должна быть вам знакома – он отметился в Солидбуке.
Итак, какие вопросы разбираются в их лонгриде Фронтенд — это не больно:
— Как решать задачи, а не писать код
— Как не умереть в пиксель-перфекте
— Как вести диалог с дизайнерами
Можно, конечно, просто посоветовать перестать ныть и начать вникать, но это будет слишком грубым описанием этой прекрасной работы.
И обязательно обратите внимание на прикреплённые к статье материалы. В них есть всё.
#work #frontend #psychology #бородач
Я много раз начинал и забрасывал статью о том, как справляться с рутиной. Но писать статью — это не в чате «деда» включать. Всё-таки важная штука — аудитория.
Впрочем, здесь мне помогут Александр Беспоясов, Вадим Юмадилов и Андрей Романов. Фамилия Беспоясова должна быть вам знакома – он отметился в Солидбуке.
Итак, какие вопросы разбираются в их лонгриде Фронтенд — это не больно:
— Как решать задачи, а не писать код
— Как не умереть в пиксель-перфекте
— Как вести диалог с дизайнерами
Можно, конечно, просто посоветовать перестать ныть и начать вникать, но это будет слишком грубым описанием этой прекрасной работы.
И обязательно обратите внимание на прикреплённые к статье материалы. В них есть всё.
#work #frontend #psychology #бородач
👍12
#фишка дня
Иногда встаёт задача не просто проиллюстрировать статью, но обрезать (кропнуть) исходное изображение. И желательно так, чтобы результат был адаптивен и адекватно реагировал на масштабирование.
Джейк Арчибальд предлагает решение на SVG и foreignObject: https://codepen.io/alinaki/pen/KKLXvwz
Вообще, весьма красиво. Да, можно генерировать кропы на сервере, но это, как минимум, лишние телодвижения. А тут – одна картинка, чистый и понятный код.
#svg #img #foreignObject #crop
Иногда встаёт задача не просто проиллюстрировать статью, но обрезать (кропнуть) исходное изображение. И желательно так, чтобы результат был адаптивен и адекватно реагировал на масштабирование.
Джейк Арчибальд предлагает решение на SVG и foreignObject: https://codepen.io/alinaki/pen/KKLXvwz
Вообще, весьма красиво. Да, можно генерировать кропы на сервере, но это, как минимум, лишние телодвижения. А тут – одна картинка, чистый и понятный код.
#svg #img #foreignObject #crop
👍11
#такое дня
Не, не могу молчать. Андрей Ситник снова пошёл священной претензией на сообщество фронтенда.
И снова с Линуксом.
Итак, суть подачи: «Во фронтенде бесит, что люди так много говорят про diversity и адаптивность к разным системам, а все сидят на Маках».
Начнём с того, что не все сидят на маках, но все, кто выступает на конференциях 🙂 Ошибка выжившего как она есть.
А дальше... давайте сначала ваше мнение, котаны. Выше — опрос про вашу ОС для работы.
Если вам будет интересно — напишу свой путь и выбор инструментов.
Не, не могу молчать. Андрей Ситник снова пошёл священной претензией на сообщество фронтенда.
И снова с Линуксом.
Итак, суть подачи: «Во фронтенде бесит, что люди так много говорят про diversity и адаптивность к разным системам, а все сидят на Маках».
Начнём с того, что не все сидят на маках, но все, кто выступает на конференциях 🙂 Ошибка выжившего как она есть.
А дальше... давайте сначала ваше мнение, котаны. Выше — опрос про вашу ОС для работы.
Если вам будет интересно — напишу свой путь и выбор инструментов.
👍3🤩1
#ретро дня
В комментариях к предыдущему посту встал вопрос: "А как тестировать Safari в Windows и Linux?"
Что ж, на этот вопрос есть частичный ответ. И пару лет назад я делал серию постов, посвящённую этой проблеме.
TL;DR: Safari не единственный браузер на WebKit, есть ещё Epiphany aka GNOME Web. И если на Linux он вполне себе нативно запускается, то на Windows нужно немного плясок.
Собственно, посты из серии:
Краткая история Safari: https://t.me/htmlshit/704
Установка GNOME Web на Windows WSL2: https://t.me/htmlshit/709
Использование WebKit Demo Browser через Playwright: https://t.me/htmlshit/714
Просто готовая сборка WebKit: https://t.me/htmlshit/715
Если кто попробует и дополнит инструкцию — я буду очень рад🥺
P. S. там же есть инфа, как получить бесплатный доступ к сервису Browserstack: https://t.me/htmlshit/718
В комментариях к предыдущему посту встал вопрос: "А как тестировать Safari в Windows и Linux?"
Что ж, на этот вопрос есть частичный ответ. И пару лет назад я делал серию постов, посвящённую этой проблеме.
TL;DR: Safari не единственный браузер на WebKit, есть ещё Epiphany aka GNOME Web. И если на Linux он вполне себе нативно запускается, то на Windows нужно немного плясок.
Собственно, посты из серии:
Краткая история Safari: https://t.me/htmlshit/704
Установка GNOME Web на Windows WSL2: https://t.me/htmlshit/709
Использование WebKit Demo Browser через Playwright: https://t.me/htmlshit/714
Просто готовая сборка WebKit: https://t.me/htmlshit/715
Если кто попробует и дополнит инструкцию — я буду очень рад
P. S. там же есть инфа, как получить бесплатный доступ к сервису Browserstack: https://t.me/htmlshit/718
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
#заметка дня
Тут Иван Акулов из Framer поделился, как они доставляют AVIF-изображения, добиваясь ещё большей, чем WEBP, экономии трафика.
Да, я в курсе, что многие генерируют картинки при сборке, кто-то использует сервисы и так далее, но давайте не забывать, что:
1. Есть пользовательский контент
2. Облака могут встать дорого
Итак, в чём же проблема? А в том что AVIF ну очень долго кодируется, что не есть хорошо. Там, где на генерацию WEBP уйдёт 100-300 мс, на AVIF — 1-3 секунды.
В итоге, если генерировать изображения по запросу и сохранять на CDN (тем же nginx, например), будет не очень вежливо заставлять посетителя ждать.
Поэтому было решено применять подход, знакомый нам как stale-while-revalidate.
1. С первым запросом генерируем WEBP-картинку, но устанавливаем кеширующие заголовки как Cache-Control to max-age=0, stale-while-revalidate=31536000.
2. Поскольку max-age выставлен в 0, картинка моментально "протухнет", CDN с этим не согласится и отправит второй запрос, чтобы, собственно, закешировать.
3. И вот тут уже начинаем генерировать AVIF.
4. И отправляем его с max-age=31536000, ну, почти навсегда.
Ну и общая статья на тему: https://www.framer.com/help/articles/how-are-images-optimized-in-framer/
Я тут пока готовил этот обзор, хотел найти свой конфиг nginx для генерации и кропа картинок на лету, но... потерял. Кажется, пришло время потренироваться и написать обновлённый, по мотивам.
А как вы доставляете картинки, котаны?
#image #optimization
Тут Иван Акулов из Framer поделился, как они доставляют AVIF-изображения, добиваясь ещё большей, чем WEBP, экономии трафика.
Да, я в курсе, что многие генерируют картинки при сборке, кто-то использует сервисы и так далее, но давайте не забывать, что:
1. Есть пользовательский контент
2. Облака могут встать дорого
Итак, в чём же проблема? А в том что AVIF ну очень долго кодируется, что не есть хорошо. Там, где на генерацию WEBP уйдёт 100-300 мс, на AVIF — 1-3 секунды.
В итоге, если генерировать изображения по запросу и сохранять на CDN (тем же nginx, например), будет не очень вежливо заставлять посетителя ждать.
Поэтому было решено применять подход, знакомый нам как stale-while-revalidate.
1. С первым запросом генерируем WEBP-картинку, но устанавливаем кеширующие заголовки как Cache-Control to max-age=0, stale-while-revalidate=31536000.
2. Поскольку max-age выставлен в 0, картинка моментально "протухнет", CDN с этим не согласится и отправит второй запрос, чтобы, собственно, закешировать.
3. И вот тут уже начинаем генерировать AVIF.
4. И отправляем его с max-age=31536000, ну, почти навсегда.
Ну и общая статья на тему: https://www.framer.com/help/articles/how-are-images-optimized-in-framer/
Я тут пока готовил этот обзор, хотел найти свой конфиг nginx для генерации и кропа картинок на лету, но... потерял. Кажется, пришло время потренироваться и написать обновлённый, по мотивам.
А как вы доставляете картинки, котаны?
#image #optimization
👍10❤6
#такое дня
Олды тут?
Волновало ли вас мнение разработчиков-зумеров о вашем подходе к работе?
Спойлер: нет.
А вот Gergely Orosz (я боюсь это транслитерировать) решил собрать мнение обеих сторон, и людей старшего поколения о молодом, и наоборот.
И выпустил две огромные статьи:
GenZ глазами миллениалов и GenX
https://newsletter.pragmaticengineer.com/p/genz
Миллениалы и GenX глазами GenZ:
https://newsletter.pragmaticengineer.com/p/genz-part-2
Поскольку мне аж 36 лет, и я смотрел доклад 36 два раза, иллюстрацией к этому посту я выбрал именно выводы из второй части.
Поиграем в бинго, олды? У меня пять из шести.
По-моему, в целом, весь спор поколений немного переоценён, но некоторые общности имеют место быть. И их приходится учитывать и в бизнесе, и в общении.
Впрочем, гораздо большую роль, на мой взгляд, играет культурный бэкграунд.
#life
Олды тут?
Волновало ли вас мнение разработчиков-зумеров о вашем подходе к работе?
Спойлер: нет.
А вот Gergely Orosz (я боюсь это транслитерировать) решил собрать мнение обеих сторон, и людей старшего поколения о молодом, и наоборот.
И выпустил две огромные статьи:
GenZ глазами миллениалов и GenX
https://newsletter.pragmaticengineer.com/p/genz
Миллениалы и GenX глазами GenZ:
https://newsletter.pragmaticengineer.com/p/genz-part-2
Поскольку мне аж 36 лет, и я смотрел доклад 36 два раза, иллюстрацией к этому посту я выбрал именно выводы из второй части.
Поиграем в бинго, олды? У меня пять из шести.
По-моему, в целом, весь спор поколений немного переоценён, но некоторые общности имеют место быть. И их приходится учитывать и в бизнесе, и в общении.
Впрочем, гораздо большую роль, на мой взгляд, играет культурный бэкграунд.
#life
👍4
#статья дня
Давай сегодня тему пошире. Если ты работаешь с проектами крупнее одного лендинга за раз, или более того — с продуктами, резко встаёт вопрос целесообразности внедрения той или иной фишки.
Просто «потому что хочется» работает на самых первых этапах, ведь проекты создаются для того, чтоб решить какую-то конкретную боль клиента. Иногда клиент — основатель стартапа.
А вот потом начинается производственный ад. Виной которому менеджеры продукта.
Ну конечно же не они, но именно они будут отвечать за ведение проекта и внедрение результатов. И за аналитику на первом этапе, конечно же. Так как же с ними договариваться и как они будут принимать это решение? Ну или, как минимум, приоритизировать задачи?
в один пост не вместилось, далее… ⏭
Давай сегодня тему пошире. Если ты работаешь с проектами крупнее одного лендинга за раз, или более того — с продуктами, резко встаёт вопрос целесообразности внедрения той или иной фишки.
Просто «потому что хочется» работает на самых первых этапах, ведь проекты создаются для того, чтоб решить какую-то конкретную боль клиента. Иногда клиент — основатель стартапа.
А вот потом начинается производственный ад. Виной которому менеджеры продукта.
Ну конечно же не они, но именно они будут отвечать за ведение проекта и внедрение результатов. И за аналитику на первом этапе, конечно же. Так как же с ними договариваться и как они будут принимать это решение? Ну или, как минимум, приоритизировать задачи?
в один пост не вместилось, далее… ⏭
А формула проста, и имя ей RICE-фреймворк.
Берём коэффициенты:
Reach: сколько людей будет затронуто, число
Impact: насколько сильно,0.25, 0.5, 1, 2, 3
Confidence: степень уверенности в этом, в процентах
Effort: сколько сил потребуется, любое положительное число, сторипоинты, человеко-месяцы, часы; что угодно используемое в конторе
И считаем:
А вот что такое готовность и успех можно поговорить позже.
Правда это всё не включает Developer’s Enjoyment 🥲
Подробнее тут: https://hello.ducalis.io/knowledge-base/rice-scoring-prioritization-framework
Берём коэффициенты:
Reach: сколько людей будет затронуто, число
Impact: насколько сильно,0.25, 0.5, 1, 2, 3
Confidence: степень уверенности в этом, в процентах
Effort: сколько сил потребуется, любое положительное число, сторипоинты, человеко-месяцы, часы; что угодно используемое в конторе
И считаем:
(R*I*C)/E
. Больше число — больше уверенности в успехе. Или как минимум в целесообразности начала разработки. А вот что такое готовность и успех можно поговорить позже.
Правда это всё не включает Developer’s Enjoyment 🥲
Подробнее тут: https://hello.ducalis.io/knowledge-base/rice-scoring-prioritization-framework
Ducalis.io
RICE Framework: (Reach * Impact * Confidence) / Effort - Ducalis.io
Learn to use the RICE Framework formula to prioritize your projects, calculate the score, and understand its meaning in a simple way. Download a free template!
👍4
#ссылка дня
Когда-то мы обсуждали новость о том, что ESLint хочет перейти на новый, плоский формат конфига в своей 9 версии.
Естественно, я случайно грохнул старый чат с комментариям, но — поверьте — обсуждали.
Это, казалось бы, удобное нововведение вызвало бурю негодования. Кто-то решил остаться на восьмой версии, кто-то нашёл это идеальным поводом чтобы уйти на какой-нибудь Biome.
Но... ESLint нас услышал! И они выкатили инструмент для миграции конфигов: https://eslint.org/blog/2024/05/eslint-configuration-migrator/
Естественно, не без ограничений (основное — поддерживается только корневая директория), но всё же.
Буду пробовать и сообщу. Я тут осознал, что вообще до сих пор на седьмом...
#eslint #tool
Когда-то мы обсуждали новость о том, что ESLint хочет перейти на новый, плоский формат конфига в своей 9 версии.
Естественно, я случайно грохнул старый чат с комментариям, но — поверьте — обсуждали.
Это, казалось бы, удобное нововведение вызвало бурю негодования. Кто-то решил остаться на восьмой версии, кто-то нашёл это идеальным поводом чтобы уйти на какой-нибудь Biome.
Но... ESLint нас услышал! И они выкатили инструмент для миграции конфигов: https://eslint.org/blog/2024/05/eslint-configuration-migrator/
Естественно, не без ограничений (основное — поддерживается только корневая директория), но всё же.
Буду пробовать и сообщу. Я тут осознал, что вообще до сих пор на седьмом...
#eslint #tool
👍12
#такое дня
Продолбал вечер пятницы из-за одного довольно тупого решения почти годичной давности.
Итак, на проекте используются react-hook-form и кастомный селект на базе Downshift (useSelect). К
В октябре прошлого года по причине, которую никто уже не помнит, мы закрепили react-hook-form на версии 7.47.0.
Ну и всё шло гладко, пока мне не потребовалось прокидывать disabled-состояние на те самые селекты. Казалось бы, однозначный код:
...но вот при изменении состояния
И... это поведение было исправлено буквально через 3 месяца от момента, как мы закрепили версию.
Не то чтобы закрепление версии само по себе плохая практика, скорее, наоборот, но такие решения надо документировать. Я бы не потерял столько времени, пытаясь понять, что же я делаю не так 🙁
P.S. Ладно, самое тупое в том, что мне в итоге не понадобился
Я решил просто не показывать контролируемые селекты, если нужная секция не отмечена. Таким образом, поле ввода снимается с регистрации в React Hook Form и значения не приходится фильтровать.
#form #react
Продолбал вечер пятницы из-за одного довольно тупого решения почти годичной давности.
Итак, на проекте используются react-hook-form и кастомный селект на базе Downshift (useSelect). К
react-hook-form
, по причине контролируемой реализации виджета, он подключается через Controller.В октябре прошлого года по причине, которую никто уже не помнит, мы закрепили react-hook-form на версии 7.47.0.
Ну и всё шло гладко, пока мне не потребовалось прокидывать disabled-состояние на те самые селекты. Казалось бы, однозначный код:
<Controller
name={name}
control={control}
disabled={disabled}
defaultValue={options[0].value}
shouldUnregister={true}
render={({ field: { onChange, value } }) => (
<Select
options={options}
defaultValue={value}
onChange={({ value }) => {
onChange(value);
}}
/>
)}
/>
...но вот при изменении состояния
disabled
, значение контроллера по-умолчанию точно так же никуда не передавалось.И... это поведение было исправлено буквально через 3 месяца от момента, как мы закрепили версию.
Не то чтобы закрепление версии само по себе плохая практика, скорее, наоборот, но такие решения надо документировать. Я бы не потерял столько времени, пытаясь понять, что же я делаю не так 🙁
P.S. Ладно, самое тупое в том, что мне в итоге не понадобился
disabled
. Вообще.Я решил просто не показывать контролируемые селекты, если нужная секция не отмечена. Таким образом, поле ввода снимается с регистрации в React Hook Form и значения не приходится фильтровать.
#form #react
React-Hook-Form
React Hook Form - performant, flexible and extensible form library
Performant, flexible and extensible forms with easy-to-use validation.
👍13