playwright-cli
Тут вышел https://github.com/microsoft/playwright-cli, более эргономичный, чем MCP, способ запускать ботом безголового playwright для выполнения действий в браузере.
Да, собственно, не обязательно ботом, можно просто в рамках CLI-API написать скрипт для автоматизации действия в браузере:
Вот эти вот e21 и e35 — это наименования DOM-нод в открытом сайте. Командой
По необходимости можно вызывать playwright "с головой":
Для ботов прописаны доки для выполнения рутинных задач:
- Request mocking — перехват и мок запросов
- Running Playwright code — выполнение playwright-скриптов
- Browser session management — управление браузерными сессиями
- Storage state (cookies, localStorage) — запись и чтение из браузерного хранилища
- Test generation — генерация тестов после взаимодействия с сайтом
- Tracing — запись трейсов
- Video recording — запись видео
Тут вышел https://github.com/microsoft/playwright-cli, более эргономичный, чем MCP, способ запускать ботом безголового playwright для выполнения действий в браузере.
Да, собственно, не обязательно ботом, можно просто в рамках CLI-API написать скрипт для автоматизации действия в браузере:
playwright-cli open https://demo.playwright.dev/todomvc/ --headed
playwright-cli type "Buy groceries"
playwright-cli press Enter
playwright-cli type "Water flowers"
playwright-cli press Enter
playwright-cli check e21
playwright-cli check e35
playwright-cli screenshot
Вот эти вот e21 и e35 — это наименования DOM-нод в открытом сайте. Командой
open сайт открывается и записывается его снепшот в виде yaml-файла. Каждая нода помечается своим айдишником.По необходимости можно вызывать playwright "с головой":
playwright-cli open https://playwright.dev --headed
Для ботов прописаны доки для выполнения рутинных задач:
- Request mocking — перехват и мок запросов
- Running Playwright code — выполнение playwright-скриптов
- Browser session management — управление браузерными сессиями
- Storage state (cookies, localStorage) — запись и чтение из браузерного хранилища
- Test generation — генерация тестов после взаимодействия с сайтом
- Tracing — запись трейсов
- Video recording — запись видео
🔥14❤2
Что нового Baseline Widely Available, часть 3
...продолжение
JavaScript
Array findLast() и findLastIndex() — поиск в массиве в обратном порядке.
Мнение: 3 из 5, хорошо, когда удаётся утилиты заменять на встроенные методы, так что мелочь, а приятно.
—
Array by Copy — методы
Мнение: 3 из 5, это вот из разряда "теперь надо запомнить, что так делать можно", а то по привычке спредишь массив перед любой мутацией
—
Import Maps — декларативное управление импортами через JSON.
Мнение: 4 из 5, вот это, кстати, довольно важная непроходная фича, по сути позволяющая на ES-модулях построить проект без особой сборки, чтобы само собиралось в рантайме (но пригодно, на мой взгляд, в небольших проектах).
—
JavaScript Modules in Workers — использование ES-модулей в Web Workers с
Мнение: 2 из 5, с одной стороны, да, появилась возможность импортировать ES-модули, с другой — в этом режиме они импортируются под CORS-ом, а в классических воркерах доступен и `no-cors`-режим; в общем годная тема, ещё больше можно вынести в воркер.
—
requestAnimationFrame() in Workers — анимации в Web Workers.
Мнение: 2 из 5, тоже плюсом к предыдущему пункту, если работаете с воркерами, то можно более плавно встраивать результат вычисления обратно в основной поток.
—
Compression Streams — API для сжатия/распаковки данных в формате gzip или deflate.
Мнение: 3 из 5, может быть полезно для сжатия пользовательских файлов или распаковки полученных сжатых файлов, приятно, что заехало прям в платформу, можно не использовать доп либы.
—
Constructed Stylesheets — программное создание стилей через
Мнение: 2 из 5, более навороченный способ добавлять динамически новые стили, хз, может будет полезно авторам runtime-стилизационных библиотек.
продолжение следует...
#Пульс_веб_платформы
@web_platform | Поддержать платформу⭐️
...продолжение
JavaScript
Array findLast() и findLastIndex() — поиск в массиве в обратном порядке.
const array = [5, 12, 8, 130, 44];
const isLargeNumber = (element) => element > 100;
console.log(array.findLast(isLargeNumber)); // 130
console.log(array.findLastIndex(isLargeNumber)); // 3
Мнение: 3 из 5, хорошо, когда удаётся утилиты заменять на встроенные методы, так что мелочь, а приятно.
—
Array by Copy — методы
toSorted(), toReversed(), toSpliced(), возвращающие новый массив без изменения оригинала.
const arr = [1, 2, 3];
const sorted = arr.toSorted();
const reversed = arr.toReversed();
Мнение: 3 из 5, это вот из разряда "теперь надо запомнить, что так делать можно", а то по привычке спредишь массив перед любой мутацией
—
Import Maps — декларативное управление импортами через JSON.
<script type="importmap">
{
"imports": {
"lodash": "/node_modules/lodash-es/lodash.js",
"utils": "/src/utils.js"
}
}
</script>
Мнение: 4 из 5, вот это, кстати, довольно важная непроходная фича, по сути позволяющая на ES-модулях построить проект без особой сборки, чтобы само собиралось в рантайме (но пригодно, на мой взгляд, в небольших проектах).
—
JavaScript Modules in Workers — использование ES-модулей в Web Workers с
{ type: "module" }.
// worker.js
import { processData } from './utils.js';
self.onmessage = (e) => {
const result = processData(e.data);
self.postMessage(result);
};
Мнение: 2 из 5, с одной стороны, да, появилась возможность импортировать ES-модули, с другой — в этом режиме они импортируются под CORS-ом, а в классических воркерах доступен и `no-cors`-режим; в общем годная тема, ещё больше можно вынести в воркер.
—
requestAnimationFrame() in Workers — анимации в Web Workers.
// worker.js
function animate() {
// логика анимации
requestAnimationFrame(animate);
}
animate();
Мнение: 2 из 5, тоже плюсом к предыдущему пункту, если работаете с воркерами, то можно более плавно встраивать результат вычисления обратно в основной поток.
—
Compression Streams — API для сжатия/распаковки данных в формате gzip или deflate.
const compressed = readableStream
.pipeThrough(new CompressionStream('gzip'));
Мнение: 3 из 5, может быть полезно для сжатия пользовательских файлов или распаковки полученных сжатых файлов, приятно, что заехало прям в платформу, можно не использовать доп либы.
—
Constructed Stylesheets — программное создание стилей через
CSSStyleSheet и их совместное использование через adoptedStyleSheets.
const sheet = new CSSStyleSheet();
sheet.replaceSync('.my-class { color: blue; }');
document.adoptedStyleSheets = [sheet];
Мнение: 2 из 5, более навороченный способ добавлять динамически новые стили, хз, может будет полезно авторам runtime-стилизационных библиотек.
продолжение следует...
#Пульс_веб_платформы
@web_platform | Поддержать платформу
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥6❤4
Что нового Baseline Widely Available, часть 4
...продолжение
Web APIs
Offscreen Canvas — рендеринг canvas в отдельном потоке без зависимостей от DOM.
Мнение: 4 из 5, по идее довольно мощная возможность для оптимизации, опять же в связке с web worker-ом, куда можно кинуть "внеэкранную канву" для рендера чего-либо тяжёлого.
—
Screen Orientation — API для управления ориентацией экрана.
Мнение: 4 из 5, мастхэв для работы с мобилками, пригождалось.
—
Server Timing — API для получения информации о таймингах запросов с сервера.
Мнение: 4 из 5, это мощное дополнение к Web Performance API, правда требует настройки и бэка/сервера, чтобы отправлялись нужные заголовки.
—
Push Messages — API для push-уведомлений.
Мнение: 5 из 5, о, думаю, появлению этого API на iOS для PWA очень порадовались банки и другие выпиленные из сторов компании; всему, что убирает монополию вендоров в пользу веб-платформы ставим пятюню.
—
MathML — разметка математических формул без картинок и JS-библиотек.
Мнение: 4 из 5, вот это очень хоть и узкоспециализировано, но на мой взгляд тоже круто, так как позволяет latex-у и подобным инструментам, избавиться от доп кода для рендера формул.
#Пульс_веб_платформы
@web_platform | Поддержать платформу⭐️
...продолжение
Web APIs
Offscreen Canvas — рендеринг canvas в отдельном потоке без зависимостей от DOM.
const offscreen = canvas.transferControlToOffscreen();
worker.postMessage({ canvas: offscreen }, [offscreen]);
Мнение: 4 из 5, по идее довольно мощная возможность для оптимизации, опять же в связке с web worker-ом, куда можно кинуть "внеэкранную канву" для рендера чего-либо тяжёлого.
—
Screen Orientation — API для управления ориентацией экрана.
await screen.orientation.lock('landscape');
Мнение: 4 из 5, мастхэв для работы с мобилками, пригождалось.
—
Server Timing — API для получения информации о таймингах запросов с сервера.
const entries = performance.getEntriesByType('navigation');
const serverTiming = entries[0].serverTiming;
Мнение: 4 из 5, это мощное дополнение к Web Performance API, правда требует настройки и бэка/сервера, чтобы отправлялись нужные заголовки.
—
Push Messages — API для push-уведомлений.
const subscription = await pushManager.subscribe();
Мнение: 5 из 5, о, думаю, появлению этого API на iOS для PWA очень порадовались банки и другие выпиленные из сторов компании; всему, что убирает монополию вендоров в пользу веб-платформы ставим пятюню.
—
MathML — разметка математических формул без картинок и JS-библиотек.
<p>
The fraction
<math>
<mfrac>
<mn>1</mn>
<mn>3</mn>
</mfrac>
</math>
is not a decimal number.
</p>
Мнение: 4 из 5, вот это очень хоть и узкоспециализировано, но на мой взгляд тоже круто, так как позволяет latex-у и подобным инструментам, избавиться от доп кода для рендера формул.
#Пульс_веб_платформы
@web_platform | Поддержать платформу
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥8❤7
npm lifecycle scripts
TIL, что в npm есть lifecycle scripts. Перед и после стандартных команд типа
Добавляете в
Сначала
Полезно, когда перед запуском надо что-то подготовить — собрать ассеты, проверить типы, создать папки.
Что можно с этим сделать:
-
-
-
Дока
#Лаборатория_веб_платформы
@web_platform | Поддержать платформу💕
TIL, что в npm есть lifecycle scripts. Перед и после стандартных команд типа
dev, build, test есть "хуки", на которые можно подцепить нужные дополнительные команды.
npm run dev | predev → dev → postdev
npm run build | prebuild → build → postbuild
npm test | pretest → test → posttest
Добавляете в
package.json скрипт с префиксом pre или post — npm запустит их с соответствующем порядке:
{
"scripts": {
"build:client": "node esbuild.client.mjs",
"predev": "npm run build:client"
"dev": "tsx src/server/index.ts",
}
}
Сначала
predev соберёт клиент, dev запустит сервер.Полезно, когда перед запуском надо что-то подготовить — собрать ассеты, проверить типы, создать папки.
Что можно с этим сделать:
-
prepublishOnly — проверки перед публикацией пакета в npm-
prebuild — генерация кода или очистка папки dist-
postinstall — автоматические действия после npm installДока
#Лаборатория_веб_платформы
@web_platform | Поддержать платформу
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤6🤓3
End-to-end разработчик
Деление на фронтенд и бэкенд никогда не было про технику. Это было больше про бизнес-процессы и найм: в индустрии удобнее искать заменяемых специалистов на узкий скоуп. Фронтендер имплементит "клиентскую" логику, бэкендер — API и "серверную" логику. Но по сути это единое целое и деление, если посмотреть свежим взглядом, весьма условное. Я прекрасно помню времена, когда фреймворки не затачивались конкретно на фронт/бэк, а были про веб-разработку проекта целиком.
И сейчас это деление начинает терять смысл. ИИшки привносят собой инфляцию ценности навыков (и стоимости строк кода). Уметь писать код стоит меньше, чем год назад. И будет стоить ещё меньше через год. Причём стоит меньше и в деньгах, и в самой ценности навыка: знания становятся все более и более общедоступны и легкодоступны, и само понятие конкретного навыка — это теперь не что-то труднодостигаемое и "выстрадываемое" потом и кровью.
Приходит эпоха полнофункционального разработчика (олды тут? привет, вебмастера). Это как бы «фуллстек» в старом понимании (например, в связке React + Node) + одновременно, который понимает систему целиком от и до, может и обозревать верхнеуровнево, и "зумиться" до детальной имплементации, настраивает инфраструктуру, валидирует, что и как система делает, а главное — следит, как система соотносится с бизнесом, насколько качественно решает его проблемы. End-to-end-разработчик.
Карьерный путь становится короче и интенсивнее. "Junior" в привычном смысле исчезает — вместо него "junior senior": человек приходит уже с наработанным опытом через пет-проекты, симуляционные окружения. С образованием вообще всё просто небывало круто. Как никогда раньше обучение может быть безостановочным процессом и не привязанным к конкретному обучающему вендору — селф-обучение выходит на первый план, а бизнесы напрямую предоставляют свою инфру для специализации в нужном контексте.
Реагировать на происходящее можно по-разному. Отрицать, игнорировать, плыть по течению или против. Но если хочется сохранить привычные заработки и скорость их роста, в обозримом будущем все пути ведут к тому, чтобы брать на себя бо́льшую ответственность. Для разработчика это или уходить в пипл-менеджмент, или же расширять и углублять технику. Я за свою карьеру два раза проходит цикл "разраб -> тимлид -> разраб" и понял, что не хочу копать в менеджмент дальше. Поэтому сейчас отзываясь на вызовы нового времени выбираю второе.
Так что буду уделять больше своего времени частям веб-разработки и платформы, которые выходят за пределы интерфейса в браузере: инфраструктуре, "серверу", инструментам сборки и доставки, проектированию систем. И вникать в зарождающуюся роль e2e-разработчика — теперь больше "пчеловода", чем "собирателя".
Думаю, это также отразится и на содержании блога.
Всем послушных пчёл!👁️
#Фикшн_веб_платформы
@web_platform | Поддержать платформу
Деление на фронтенд и бэкенд никогда не было про технику. Это было больше про бизнес-процессы и найм: в индустрии удобнее искать заменяемых специалистов на узкий скоуп. Фронтендер имплементит "клиентскую" логику, бэкендер — API и "серверную" логику. Но по сути это единое целое и деление, если посмотреть свежим взглядом, весьма условное. Я прекрасно помню времена, когда фреймворки не затачивались конкретно на фронт/бэк, а были про веб-разработку проекта целиком.
И сейчас это деление начинает терять смысл. ИИшки привносят собой инфляцию ценности навыков (и стоимости строк кода). Уметь писать код стоит меньше, чем год назад. И будет стоить ещё меньше через год. Причём стоит меньше и в деньгах, и в самой ценности навыка: знания становятся все более и более общедоступны и легкодоступны, и само понятие конкретного навыка — это теперь не что-то труднодостигаемое и "выстрадываемое" потом и кровью.
Приходит эпоха полнофункционального разработчика (олды тут? привет, вебмастера). Это как бы «фуллстек» в старом понимании (например, в связке React + Node) + одновременно, который понимает систему целиком от и до, может и обозревать верхнеуровнево, и "зумиться" до детальной имплементации, настраивает инфраструктуру, валидирует, что и как система делает, а главное — следит, как система соотносится с бизнесом, насколько качественно решает его проблемы. End-to-end-разработчик.
Карьерный путь становится короче и интенсивнее. "Junior" в привычном смысле исчезает — вместо него "junior senior": человек приходит уже с наработанным опытом через пет-проекты, симуляционные окружения. С образованием вообще всё просто небывало круто. Как никогда раньше обучение может быть безостановочным процессом и не привязанным к конкретному обучающему вендору — селф-обучение выходит на первый план, а бизнесы напрямую предоставляют свою инфру для специализации в нужном контексте.
Реагировать на происходящее можно по-разному. Отрицать, игнорировать, плыть по течению или против. Но если хочется сохранить привычные заработки и скорость их роста, в обозримом будущем все пути ведут к тому, чтобы брать на себя бо́льшую ответственность. Для разработчика это или уходить в пипл-менеджмент, или же расширять и углублять технику. Я за свою карьеру два раза проходит цикл "разраб -> тимлид -> разраб" и понял, что не хочу копать в менеджмент дальше. Поэтому сейчас отзываясь на вызовы нового времени выбираю второе.
Так что буду уделять больше своего времени частям веб-разработки и платформы, которые выходят за пределы интерфейса в браузере: инфраструктуре, "серверу", инструментам сборки и доставки, проектированию систем. И вникать в зарождающуюся роль e2e-разработчика — теперь больше "пчеловода", чем "собирателя".
Думаю, это также отразится и на содержании блога.
Всем послушных пчёл!
#Фикшн_веб_платформы
@web_platform | Поддержать платформу
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21🔥9👎4❤3⚡2💊2
Скриншот-тестирование компонентов в Docker
В нескольких проектах, где я работал, пробовали внедрить скриншот-тестирование компонентов. Принцип работы такой:
1) меняем компонент
2) делаем эталонный скриншот, сохраняем в репе
3) повторяем на всех компонентах
4) при повторных изменениях запускаем тесты, в которых сравниваются эталонные скриншоты и текущее отображение компонентов
5) если все расхождения запланированные, меняем эталонные скрины; если есть незапланированные расхождения, поздравляю, тесты нашли регресс!
Такие тесты хорошо подходят для теста вёрстки элементов ui-kit-а (многочисленные состояниях ховера, фокуса, разные режимы компонента) или же каких-то критичных компонентов (форма логина, чекаут), которые никак нельзя случайно поломать.
Снепшотные тесты, юниты, e2e тут не помогут, нужно именно сравнение скринов.
Звучит хорошо, но есть одно НО. Во всех случаях на моей практике дело упиралось в то, что скриншоты снимаются разными разработчиками на разных машинах с разными ОС. И в зависимости от этого скриншоты начинают расходиться. Шрифты другие. Субпиксельный рендеринг другой. Антиалиасинг другой. Также отличаются элементы форм. И тест падает, хотя визуально всё ок. Вместо помощи тесты начинают мешать и бесить.
Логично было бы предположить делать скриншоты на одной машине, например, вынести этот процесс на CI/CD или на отдельный сервер, но обычно с этим в компаниях сложно, нужно всё согласовывать, заводить, что есть заморочь.
И тут изучая Docker открыл для себя идеально подходящую под кейс фичу! Через Docker можно связать файловую систему хоста (ваша машина) с файловой системой запущенного контейнера. То есть храним скрины по прежнему в репо (развёрнутом у каждого разработчика), монтируем папку с ними внутрь Docker-контейнера, снимаем скриншоты, сравниваем, при необходимости обновляем. Внутри контейнера один и тот же образ с фиксированной ОС, фиксированной версией браузера, фиксированными шрифтами. И соотвественно таким же макаром запускается в CI.
Собрал пруф оф концепт.
Что там вкратце, происходит: Storybook изолирует компоненты, Playwright делает скриншоты, Docker обеспечивает одинаковый рендеринг.
Оркестрация через
Docker-образ с Playwright официальный от Microsoft уже содержит браузеры и все зависимости.
Каждый визуальный тест — это три действия: открыть стори, дождаться рендера, сравнить скриншот. Storybook рендерит в статическом режиме каждый отдельный компонент по адресу
Пример теста кнопки:
Особенности настройки Playwright: можно оставить небольшой задел на случайные расхождения, выключить анимации, спрятать каретку в инпутах.
После прогона тестов формируется HTML-репорт: интерактивный diff, где можно посмотреть, что именно изменилось (приложил скрин, как это выглядит в комментах).
#Лаборатория_веб_платформы
@web_platform | Поддержать платформу⭐️
В нескольких проектах, где я работал, пробовали внедрить скриншот-тестирование компонентов. Принцип работы такой:
1) меняем компонент
2) делаем эталонный скриншот, сохраняем в репе
3) повторяем на всех компонентах
4) при повторных изменениях запускаем тесты, в которых сравниваются эталонные скриншоты и текущее отображение компонентов
5) если все расхождения запланированные, меняем эталонные скрины; если есть незапланированные расхождения, поздравляю, тесты нашли регресс!
Такие тесты хорошо подходят для теста вёрстки элементов ui-kit-а (многочисленные состояниях ховера, фокуса, разные режимы компонента) или же каких-то критичных компонентов (форма логина, чекаут), которые никак нельзя случайно поломать.
Снепшотные тесты, юниты, e2e тут не помогут, нужно именно сравнение скринов.
Звучит хорошо, но есть одно НО. Во всех случаях на моей практике дело упиралось в то, что скриншоты снимаются разными разработчиками на разных машинах с разными ОС. И в зависимости от этого скриншоты начинают расходиться. Шрифты другие. Субпиксельный рендеринг другой. Антиалиасинг другой. Также отличаются элементы форм. И тест падает, хотя визуально всё ок. Вместо помощи тесты начинают мешать и бесить.
Логично было бы предположить делать скриншоты на одной машине, например, вынести этот процесс на CI/CD или на отдельный сервер, но обычно с этим в компаниях сложно, нужно всё согласовывать, заводить, что есть заморочь.
И тут изучая Docker открыл для себя идеально подходящую под кейс фичу! Через Docker можно связать файловую систему хоста (ваша машина) с файловой системой запущенного контейнера. То есть храним скрины по прежнему в репо (развёрнутом у каждого разработчика), монтируем папку с ними внутрь Docker-контейнера, снимаем скриншоты, сравниваем, при необходимости обновляем. Внутри контейнера один и тот же образ с фиксированной ОС, фиксированной версией браузера, фиксированными шрифтами. И соотвественно таким же макаром запускается в CI.
Собрал пруф оф концепт.
Что там вкратце, происходит: Storybook изолирует компоненты, Playwright делает скриншоты, Docker обеспечивает одинаковый рендеринг.
Оркестрация через
docker-compose.yml (именно там указывается, какие локальные папки монтируются в контейнер):
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 "npm run storybook -- --host 0.0.0.0 & sleep 15 && npx playwright test --project=visual"
Docker-образ с Playwright официальный от Microsoft уже содержит браузеры и все зависимости.
FROM mcr.microsoft.com/playwright:v1.48.0-noble
Каждый визуальный тест — это три действия: открыть стори, дождаться рендера, сравнить скриншот. Storybook рендерит в статическом режиме каждый отдельный компонент по адресу
/iframe.html?id=${storyId}&viewMode=story, ждём пока загрузятся картинки и шрифты, можно снимать скриншот Playwright-ом и сравнивать тоже им.Пример теста кнопки:
test.describe('Button', () => {
test('hover', async ({ page }) => {
const component = await gotoStory(page, 'design-system-button--primary');
const button = component.locator('button.button').first();
await button.hover();
await expect(component).toHaveScreenshot();
});
});
Особенности настройки Playwright: можно оставить небольшой задел на случайные расхождения, выключить анимации, спрятать каретку в инпутах.
toHaveScreenshot: {
maxDiffPixels: 100,
animations: "disabled",
caret: "hide",
},
После прогона тестов формируется HTML-репорт: интерактивный diff, где можно посмотреть, что именно изменилось (приложил скрин, как это выглядит в комментах).
#Лаборатория_веб_платформы
@web_platform | Поддержать платформу
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20🔥9❤2🥰1
Не теряемся
Раньше я составлял и публиковал дайжесты #Пульс_веб_платформы. Дело это было довольно муторное и меня хватило на выпуск где-то примерно 80 еженедельных дайджестов. В процессе я каждый четверг пропускал через себя несколько других дайджестов, около сотни тг-каналов и примерно столько же отдельных RSS-блогов.
С момент последнего выпуска прошло около 10 месяцев, одно время я совсем бросил что-то читать, но потом интерес вернулся. Попробовал собрать несколько дайджестов, но мозг сразу сказал, что заниматься написанием дайджестов больше не будет. Но читать дайджесты при этом хочется!
И я решил построить автоматизированный пайплайн сборки дайджестов (прежде всего для себя, но может быть и вам зайдёт).
В общем,дождался блокировки телеги и вынес дайджест в отдельного бота @web_platform_pulse_bot.
В нём ежедневно утром бот публикует примерно 10 ссылок с самым интересным, что произошло в индустрии за прошлые сутки. Аннотации пишу уже не я, а модель, поэтому в душевности дайджест, конечно, потерял. Но в информативности, пожалуй, даже прибавил, так как посты стали ежедневными вместо еженедельных, и покрывают большее число материалов. Если хочется за пару минут понять, что там произошло в целом, достаточно краткой сводки утром по диагонали вместо чтения объёмных рассылок.
Я умышленно отделил авторский контент блога от генерёжки дайджеста, поэтому он будет именно в отдельном боте @web_platform_pulse_bot.
Помимо бота дайджест публикуется на сайт https://juwain.github.io/web-platform/pulse/ и в RSS https://juwain.github.io/web-platform/pulse/rss.xml.
Основной веблог тоже перевёз на gh pages https://juwain.github.io/web-platform/blog/ и в RSS https://juwain.github.io/web-platform/rss.xml (на очередную оплату домена webplatform.tech блог, увы, не заработал).
Отдельно настроил публикацию в зеркало на статику яндексовского sourcecraft. Там ресурсы доступны даже на парковке, так как Яндекс в белых списках.
Вот зеркало дайджеста https://juwain.sourcecraft.site/web-platform/pulse/ и его RSS https://juwain.sourcecraft.site/web-platform/pulse/rss.xml.
А также зеркало основного блога https://juwain.sourcecraft.site/web-platform/blog/ и его RSS https://juwain.sourcecraft.site/web-platform/rss.xml.
Если интересны технические детали реализации, поставьте реакций, я тогда позже напишу отдельный пост, как эта фиговина работает в более-менее автономном режиме и в лучшем случае требует от меня поревьюить подготовленные тексты через интерфейс TG.
В комментах приложу пару примеров дайджестов за прошлые дни.
#Лаборатория_веб_платформы
@web_platform | Поддержать платформу🌟
Раньше я составлял и публиковал дайжесты #Пульс_веб_платформы. Дело это было довольно муторное и меня хватило на выпуск где-то примерно 80 еженедельных дайджестов. В процессе я каждый четверг пропускал через себя несколько других дайджестов, около сотни тг-каналов и примерно столько же отдельных RSS-блогов.
С момент последнего выпуска прошло около 10 месяцев, одно время я совсем бросил что-то читать, но потом интерес вернулся. Попробовал собрать несколько дайджестов, но мозг сразу сказал, что заниматься написанием дайджестов больше не будет. Но читать дайджесты при этом хочется!
И я решил построить автоматизированный пайплайн сборки дайджестов (прежде всего для себя, но может быть и вам зайдёт).
В общем,
В нём ежедневно утром бот публикует примерно 10 ссылок с самым интересным, что произошло в индустрии за прошлые сутки. Аннотации пишу уже не я, а модель, поэтому в душевности дайджест, конечно, потерял. Но в информативности, пожалуй, даже прибавил, так как посты стали ежедневными вместо еженедельных, и покрывают большее число материалов. Если хочется за пару минут понять, что там произошло в целом, достаточно краткой сводки утром по диагонали вместо чтения объёмных рассылок.
Я умышленно отделил авторский контент блога от генерёжки дайджеста, поэтому он будет именно в отдельном боте @web_platform_pulse_bot.
Помимо бота дайджест публикуется на сайт https://juwain.github.io/web-platform/pulse/ и в RSS https://juwain.github.io/web-platform/pulse/rss.xml.
Основной веблог тоже перевёз на gh pages https://juwain.github.io/web-platform/blog/ и в RSS https://juwain.github.io/web-platform/rss.xml (на очередную оплату домена webplatform.tech блог, увы, не заработал).
Отдельно настроил публикацию в зеркало на статику яндексовского sourcecraft. Там ресурсы доступны даже на парковке, так как Яндекс в белых списках.
Вот зеркало дайджеста https://juwain.sourcecraft.site/web-platform/pulse/ и его RSS https://juwain.sourcecraft.site/web-platform/pulse/rss.xml.
А также зеркало основного блога https://juwain.sourcecraft.site/web-platform/blog/ и его RSS https://juwain.sourcecraft.site/web-platform/rss.xml.
Если интересны технические детали реализации, поставьте реакций, я тогда позже напишу отдельный пост, как эта фиговина работает в более-менее автономном режиме и в лучшем случае требует от меня поревьюить подготовленные тексты через интерфейс TG.
В комментах приложу пару примеров дайджестов за прошлые дни.
#Лаборатория_веб_платформы
@web_platform | Поддержать платформу
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤16🔥5🤔2
Как superset.sh привёл меня к собственной теме для Zed
В последнее время моя ежедневная работа всё больше смещается в терминал. Когда параллельно открыто несколько проектов и у каждого по несколько вкладок в терминале, обычный плоский список табов терминала (у меня iTerm) слишком скукоживается.
Не хватает ещё одного измерения: горизонтально — вкладки внутри одного проекта, вертикально — сами проекты.
И тут узнал про superset.sh, и он мне зашёл. Получается такой 2D-терминал: слева список проектов, внутри каждого свои табы.
Параллельно с увеличением количества времени проводимого в терминале меняется и роль редактора кода. Если раньше IDE была главным рабочим местом, то в агентоцентричной разработке "редактор" больше нужен для просмотра diff, точечных правок и удобной навигации по файлам.
У меня эту роль уже около года выполняет Zed: быстрый, легковесный и менее прожорливый по ресурсам, чем VS Code.
Теперь про смену контекста между режимом "терминала" и "редактора".
В superset-е мне очень понравилась тёмная тема по умолчанию (такая тёплая ламповая), а при переходе в Zed была другая тёмная тема, о которую спотыкается глаз, когда много раз за день прыгаешь между "менеджером терминалов" и "редактором для проверки изменений".
В общем, я собрал тему для Zed на основе темы superset.
В целом, нужно было экспортнуть тему из superset и сопоставить с токенами темы в Zed. Так как это всё таки немного разные контексты, пришлось подтюнить тему в течение пары недель использования, пока окончательно не привык.
В СПб сейчас начинаются белые ночи, поэтому больше счас сижу в светлой теме днём (на основной работе) и в тёмной после заката (на пет-проектах).
Тему для Zed я опубликовал здесь https://github.com/juwain/superset-zed-theme.
Скрины в комментах.
#Лаборатория_веб_платформы
@web_platform | Поддержать блог💙
В последнее время моя ежедневная работа всё больше смещается в терминал. Когда параллельно открыто несколько проектов и у каждого по несколько вкладок в терминале, обычный плоский список табов терминала (у меня iTerm) слишком скукоживается.
Не хватает ещё одного измерения: горизонтально — вкладки внутри одного проекта, вертикально — сами проекты.
И тут узнал про superset.sh, и он мне зашёл. Получается такой 2D-терминал: слева список проектов, внутри каждого свои табы.
Параллельно с увеличением количества времени проводимого в терминале меняется и роль редактора кода. Если раньше IDE была главным рабочим местом, то в агентоцентричной разработке "редактор" больше нужен для просмотра diff, точечных правок и удобной навигации по файлам.
У меня эту роль уже около года выполняет Zed: быстрый, легковесный и менее прожорливый по ресурсам, чем VS Code.
Теперь про смену контекста между режимом "терминала" и "редактора".
В superset-е мне очень понравилась тёмная тема по умолчанию (такая тёплая ламповая), а при переходе в Zed была другая тёмная тема, о которую спотыкается глаз, когда много раз за день прыгаешь между "менеджером терминалов" и "редактором для проверки изменений".
В общем, я собрал тему для Zed на основе темы superset.
В целом, нужно было экспортнуть тему из superset и сопоставить с токенами темы в Zed. Так как это всё таки немного разные контексты, пришлось подтюнить тему в течение пары недель использования, пока окончательно не привык.
В СПб сейчас начинаются белые ночи, поэтому больше счас сижу в светлой теме днём (на основной работе) и в тёмной после заката (на пет-проектах).
Тему для Zed я опубликовал здесь https://github.com/juwain/superset-zed-theme.
Скрины в комментах.
#Лаборатория_веб_платформы
@web_platform | Поддержать блог
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🤣1😇1
Виталий и Платформа
#Лаборатория_веб_платформы Look Ma, это я в 2025 пишу фича-флаги прямо в CSS! /* обычные стили */ /* ... */ @container style(--wow-such-a-feature: true) { /* стили за фича-флагом */ /* ... */ } @container style(--wow-such-an-another…
Ну ошибся на годик, с кем не бывает.
Там в FF 151, наконец, завезли 🥳
Там в FF 151, наконец, завезли 🥳
The @container CSS at-rule supports style() queries
🔥9👍3😁2
Как пошарить системное видео/аудио в расширение браузера
Недавно увидел в одном расширении в Chrome интересное решение, расковырял исходники, решил поделиться.
Функциональность расширения — запись звука, сохранение в файл и дальнейшая отправка его в сервис транскрибации.
Так вот интересный момент как именно расширение получает аудио. Допустим вы открываете во браузере Google Meet, десктопный Zoom или любой другой апп для созвонов. Начинаете созвон, приложение/браузер стримит туда-сюда звук и видео. И этот поток направляется в браузерное расширение. В Chrome при этом надо дать явное разрешение и затем появляется уведомление, что происходит шаринг вкладки или всей системы в расширение (аналогичным образом вы обычно шарите свой экран в веб-приложение, а тут веб-приложением выступает браузерное расширение).
Как это работает под капотом. Там Manifest V3 приложение. Микрофон получается через
Потом два независимых потока, микрофон и собеседник, нужно свести в один. И делается это Web Audio API:
То есть по сути Web Audio используется как микшер. В процессе там заодно можно что-то дополнительно обработать, например, усилить микрофон, а на выходе получить единый поток.
Ок, поток получили, теперь задача его записать. Для этого используется MediaStream Recording API и интерфейс MediaRecorder. Пишется не одним куском в конце, а порциями:
То есть кратенько: Media Capture and Streams и Screen Capture добывают
И ещё один интересный момент уже про само браузерное расширение. Вообще оно работает в service worker, у которого нет доступа к DOM и всем веб-API. И чтоб это обойти используется Chrome-специфичное chrome.offscreen, которое создаёт полноценную "невидимую" страницу, где и выполняется код.
#Лаборатория_веб_платформы
@web_platform | Поддержать блог💙
Недавно увидел в одном расширении в Chrome интересное решение, расковырял исходники, решил поделиться.
Функциональность расширения — запись звука, сохранение в файл и дальнейшая отправка его в сервис транскрибации.
Так вот интересный момент как именно расширение получает аудио. Допустим вы открываете во браузере Google Meet, десктопный Zoom или любой другой апп для созвонов. Начинаете созвон, приложение/браузер стримит туда-сюда звук и видео. И этот поток направляется в браузерное расширение. В Chrome при этом надо дать явное разрешение и затем появляется уведомление, что происходит шаринг вкладки или всей системы в расширение (аналогичным образом вы обычно шарите свой экран в веб-приложение, а тут веб-приложением выступает браузерное расширение).
Как это работает под капотом. Там Manifest V3 приложение. Микрофон получается через
getUserMedia из (Media Capture and Streams API). А вот звук стрима берётся через getDisplayMedia — это уже Screen Capture API, в рамках которой браузер показывает системный диалог "чем поделиться". Таким образом и получается что угодно шарить в браузерное расширение.Потом два независимых потока, микрофон и собеседник, нужно свести в один. И делается это Web Audio API:
const ctx = new AudioContext();
const mix = ctx.createMediaStreamDestination();
ctx.createMediaStreamSource(micStream).connect(micGain).connect(mix);
ctx.createMediaStreamSource(tabStream).connect(tabGain).connect(mix);
const combined = mix.stream; // снова обычный MediaStream, его и пишем
То есть по сути Web Audio используется как микшер. В процессе там заодно можно что-то дополнительно обработать, например, усилить микрофон, а на выходе получить единый поток.
Ок, поток получили, теперь задача его записать. Для этого используется MediaStream Recording API и интерфейс MediaRecorder. Пишется не одним куском в конце, а порциями:
start(timeslice) отдаёт данные кусками по ходу записи, и если что-то пойдёт не так на втором часу разговора, то всё не будет потеряно. У WebM при этом есть давняя болячка — MediaRecorder не проставляет длительность в заголовок, и готовый файл выглядит «бесконечным» для плееров и сервера. Лечится это пост-обработкой блоба, дописыванием правильных метаданных уже после остановки.То есть кратенько: Media Capture and Streams и Screen Capture добывают
MediaStream (с устройств или с экрана), Web Audio умеет этот поток обрабатывать и микшировать, а MediaStream Recording берёт готовый MediaStream на вход и сериализует его в сжатые байты — Blob в webm/mp4/ogg, которые уже можно сохранить на устройство или отправить в какой-то внешний сервис дальше.И ещё один интересный момент уже про само браузерное расширение. Вообще оно работает в service worker, у которого нет доступа к DOM и всем веб-API. И чтоб это обойти используется Chrome-специфичное chrome.offscreen, которое создаёт полноценную "невидимую" страницу, где и выполняется код.
#Лаборатория_веб_платформы
@web_platform | Поддержать блог
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍2❤1
Виталий и Платформа
Как superset.sh привёл меня к собственной теме для Zed В последнее время моя ежедневная работа всё больше смещается в терминал. Когда параллельно открыто несколько проектов и у каждого по несколько вкладок в терминале, обычный плоский список табов терминала…
4 мая -> 20 июня, столько провисел мой pr в zed до мерджа
зато теперь тема superset доступна через сам zed https://zed.dev/extensions/superset-theme👍
зато теперь тема superset доступна через сам zed https://zed.dev/extensions/superset-theme
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🗿2
Виталий и Платформа
4 мая -> 20 июня, столько провисел мой pr в zed до мерджа зато теперь тема superset доступна через сам zed https://zed.dev/extensions/superset-theme 👍
btw там интересная система в репе, используются git submodules: в
SHA коммита в
а в
.gitmodules указывается источник субмодуля (внешний реп):
[submodule "extensions/superset-theme"]
path = extensions/superset-theme
url = https://github.com/juwain/superset-zed-theme.git
SHA коммита в
.gitmodules не хранится, она лежит в самом git-дереве реестра (специальная запись с режимом 160000 (gitlink)). По пути extensions/superset-theme в дереве лежит не папка с файлами, а запись типа commit = aa134f47….а в
extensions.toml указывается, что публиковать:
[superset-theme]
submodule = "extensions/superset-theme"
version = "0.0.1"
👨💻3