#новость дня
Котаны, языку JavaScript сегодня исполнилось 29 лет!
4 декабря 1995 года после фееричных 10 дней разработки Брендан Эйх представил компании Netscape язык LiveScript, предназначавшийся для встраивания в их всё ещё свежий и самый популярный в мире браузер.
Но яйцеголовые маркетологи были уже тогда, потому язык быстренько обозвали JavaScript и выкинули на рынок как есть. Да, история немного сложнее и они реально собирались создать упрощённый вариант Java и JVM, но уж получилось как получилось.
Продавать это всё равно решили как простое решение для добавления интерактива на веб-страницы используя ваши существующие ресурсы в виде программистов на Java.
В итоге, JavaScript прошёл все круги издевательств, особенно от Microsoft. Был стандартизирован как EcmaScript, а году так в 2008 его даже называли СНЯП: Самый Недооценённый Язык Программирования.
Ну в 2024 году мы с вами точно можем сказать, что если кого и недооценили — то это точно не JS.
В общем, дальнейшего джаваскрипту развития, котаны! Всё только начинается.
#js #jscript #ecmascript #бородач
Котаны, языку JavaScript сегодня исполнилось 29 лет!
4 декабря 1995 года после фееричных 10 дней разработки Брендан Эйх представил компании Netscape язык LiveScript, предназначавшийся для встраивания в их всё ещё свежий и самый популярный в мире браузер.
Но яйцеголовые маркетологи были уже тогда, потому язык быстренько обозвали JavaScript и выкинули на рынок как есть. Да, история немного сложнее и они реально собирались создать упрощённый вариант Java и JVM, но уж получилось как получилось.
Продавать это всё равно решили как простое решение для добавления интерактива на веб-страницы используя ваши существующие ресурсы в виде программистов на Java.
В итоге, JavaScript прошёл все круги издевательств, особенно от Microsoft. Был стандартизирован как EcmaScript, а году так в 2008 его даже называли СНЯП: Самый Недооценённый Язык Программирования.
Ну в 2024 году мы с вами точно можем сказать, что если кого и недооценили — то это точно не JS.
В общем, дальнейшего джаваскрипту развития, котаны! Всё только начинается.
#js #jscript #ecmascript #бородач
👍18❤7🤩2
#такое дня
Прежде чем волноваться о плохо пройденном собесе, помни: некий разработчик Facebook прошёл алгоритмы, лайвкодинг, калча фит... и всё ради того, чтобы при каждом нажатии клавиши в поле ввода поста прогонять регулярку на поиск ссылок по всему тексту.
Да, вы не ослышались. В итоге, на сообщение в 10000 символов задержка может составить две-три секунды.
Не надо так, котаны.
Ссылка на тред: тут. В треде народ развлекается разным профайлингом, очень интересно: React Scan, Chrome Profile, немного реверс-инжиниринга...
Как же решать такую задачу? Ну, например, debounce или throttle, зависит от условий. Или предсказание по первому символу.
#js #react
Прежде чем волноваться о плохо пройденном собесе, помни: некий разработчик Facebook прошёл алгоритмы, лайвкодинг, калча фит... и всё ради того, чтобы при каждом нажатии клавиши в поле ввода поста прогонять регулярку на поиск ссылок по всему тексту.
Да, вы не ослышались. В итоге, на сообщение в 10000 символов задержка может составить две-три секунды.
Не надо так, котаны.
Ссылка на тред: тут. В треде народ развлекается разным профайлингом, очень интересно: React Scan, Chrome Profile, немного реверс-инжиниринга...
Как же решать такую задачу? Ну, например, debounce или throttle, зависит от условий. Или предсказание по первому символу.
#js #react
🤡14❤3👍2
#инструмент дня
Примерно пять раз в секунду где-то в мире очередному разработчику приходит в голову идея: «А что если я этот виджет сделаю независимо от основного приложения, на каком-нибудь миниатюрном фреймворке, чтобы быломодно, молодежно переносимо?»
Когда такая идея приходила мне, я взял Preact, а потом Van. А тут недавно на собеседовании кандидат рассказал, что тоже сталкивался с подобной задачей и решил её через µhtml.
Микрохатээмэль
Сразу ссылка: https://github.com/WebReflection/uhtml
JSX там нет, вся работа через шаблонные литералы. Что, впрочем, выглядит вполне нормально:
И да, ваши глаза вас не обманывают: сигналы! И SSR.
В общем, глаза кандидата так светились, что мне тоже надо будет попробовать.
А ваши варианты, котаны?
#uhtml #js #framework
Примерно пять раз в секунду где-то в мире очередному разработчику приходит в голову идея: «А что если я этот виджет сделаю независимо от основного приложения, на каком-нибудь миниатюрном фреймворке, чтобы было
Когда такая идея приходила мне, я взял Preact, а потом Van. А тут недавно на собеседовании кандидат рассказал, что тоже сталкивался с подобной задачей и решил её через µhtml.
Микрохатээмэль
Сразу ссылка: https://github.com/WebReflection/uhtml
JSX там нет, вся работа через шаблонные литералы. Что, впрочем, выглядит вполне нормально:
import { render, html, signal, detach } from 'uhtml/preactive';
const count = signal(0);
render(document.body, () => html`
<button onclick=${() => { count.value++ }}>
Clicks: ${count.value}
</button>
`);
// stop reacting to signals in the future
setTimeout(() => {
detach(document.body);
}, 10000);И да, ваши глаза вас не обманывают: сигналы! И SSR.
В общем, глаза кандидата так светились, что мне тоже надо будет попробовать.
А ваши варианты, котаны?
#uhtml #js #framework
👍7❤2
This media is not supported in your browser
VIEW IN TELEGRAM
#проект дня
Помните, когда я описывал библиотеку powerglitch, я сказал, что хотел бы сделать свой маленький плеер, где обложка глючила бы в такт?
Ну что же, я сделал!
Идея показалась интересной, особенно с перспективой в будущем генерировать глитч-видео на основе ритма. Но реализация оказалась не такой простой, как я думал.
Основные этапы разработки:
1. Загрузка аудиофайлов — обработка mp3-файлов и их воспроизведение в браузере.
2. Извлечение обложки — получаем картинку из метаданных трека.
3. Анализ аудиопотока — детектируем ритм и биты разными методами.
4. Генерация глитч-эффектов — синхронизируем глитчи с музыкой.
Для реализации я использовал:
- powerglitch — библиотека для создания глитч-эффектов.
- WebAudio API — анализ аудиопотока в браузере.
- music-metadata — для извлечения метаданных, в том числе обложек, из mp3.
Проблема с обложкой
На этапе парсинга метаданных и отображения обложки неожиданно возникла проблема: maximum stack size exceeded.
Всё оказалось просто: обложки были тупо слишком большими, поэтому я выходил за пределы максимального размера блока. А он всего 64 килобайта, которых хватит всем.
Нужно было обрабатывать данные поблочно.
Решилось всё использованием библиотеки uint8array-extras, хотя, если честно, решение лежало на поверхности. С другой стороны, есть нюанс с Юникодом.
И, к сожалению, библиотека powerglitch просто не позволяет менять настройки глитча на лету. Но она оказалась достаточно производительной, чтобы просто пересоздавать.
Методы детектирования ритма
Я добавил несколько способов анализа:
- Spectral Flux — анализ изменений спектральной энергии.
- Zero Crossing Rate — количество пересечений нуля в сигнале.
- Beat Tracking — поиск ударов в аудиопотоке.
- Energy Detection — резкие скачки громкости.
- Peak Detection — анализ пиков сигнала.
Сейчас плеер работает, но хочется добавить больше визуальных эффектов и попробовать другие алгоритмы анализа. Впрочем, на драмэндбассе любой сравнительно хорошо работает. Хотя надо бы ещё ручки покрутить.
Жаль, браузеры не могут записывать видео с самих себя... Но это мы решим :)
Ах, да. Посмотреть можно вот тут: https://bekharsky.github.io/GlitchBeat/
И репка: https://github.com/bekharsky/glitchbeat
Пощёлкайте разные виды определения ритма. Там очень далеко от идеала, но иногда получается прям хорошо.
#js #audio #glitch #effect #music
Помните, когда я описывал библиотеку powerglitch, я сказал, что хотел бы сделать свой маленький плеер, где обложка глючила бы в такт?
Ну что же, я сделал!
Идея показалась интересной, особенно с перспективой в будущем генерировать глитч-видео на основе ритма. Но реализация оказалась не такой простой, как я думал.
Основные этапы разработки:
1. Загрузка аудиофайлов — обработка mp3-файлов и их воспроизведение в браузере.
2. Извлечение обложки — получаем картинку из метаданных трека.
3. Анализ аудиопотока — детектируем ритм и биты разными методами.
4. Генерация глитч-эффектов — синхронизируем глитчи с музыкой.
Для реализации я использовал:
- powerglitch — библиотека для создания глитч-эффектов.
- WebAudio API — анализ аудиопотока в браузере.
- music-metadata — для извлечения метаданных, в том числе обложек, из mp3.
Проблема с обложкой
На этапе парсинга метаданных и отображения обложки неожиданно возникла проблема: maximum stack size exceeded.
Всё оказалось просто: обложки были тупо слишком большими, поэтому я выходил за пределы максимального размера блока. А он всего 64 килобайта, которых хватит всем.
Нужно было обрабатывать данные поблочно.
Решилось всё использованием библиотеки uint8array-extras, хотя, если честно, решение лежало на поверхности. С другой стороны, есть нюанс с Юникодом.
И, к сожалению, библиотека powerglitch просто не позволяет менять настройки глитча на лету. Но она оказалась достаточно производительной, чтобы просто пересоздавать.
Методы детектирования ритма
Я добавил несколько способов анализа:
- Spectral Flux — анализ изменений спектральной энергии.
- Zero Crossing Rate — количество пересечений нуля в сигнале.
- Beat Tracking — поиск ударов в аудиопотоке.
- Energy Detection — резкие скачки громкости.
- Peak Detection — анализ пиков сигнала.
Сейчас плеер работает, но хочется добавить больше визуальных эффектов и попробовать другие алгоритмы анализа. Впрочем, на драмэндбассе любой сравнительно хорошо работает. Хотя надо бы ещё ручки покрутить.
Жаль, браузеры не могут записывать видео с самих себя... Но это мы решим :)
Ах, да. Посмотреть можно вот тут: https://bekharsky.github.io/GlitchBeat/
И репка: https://github.com/bekharsky/glitchbeat
Пощёлкайте разные виды определения ритма. Там очень далеко от идеала, но иногда получается прям хорошо.
#js #audio #glitch #effect #music
👍19❤4🤩1
#заметка дня
Как мы все знаем, в JavaScript есть две формы «пустоты»:
Но почти весь современный фронтенд давно выбрал сторону.
Почему
Разные API возвращают то null, то undefined, то оба.
Это неясно, это ошибки.
✅ TypeScript-гайд от Microsoft прямо говорит: используйте undefined, избегайте
✅ В TSLint null запрещён по умолчанию (`no-null-keyword`).
✅ Правила ESLint Unicorn (да, название неслучайное) — тоже пропагандируют борьбу с
✅ В крупных экосистемах, например, как у Prisma,
✅
✅
а
В реальных системах это даёт выигрыш в размере и читаемости. Пример из продакшена: объект с миллионом
❌ Да, из-за того, что множество систем до сих пор оперирует
Кстати, даже столь любимый мной Effector ещё не так давно пропагандировал
Итак,
Пора выбрать сторону 🦄
P. S. человек, который заставил меня принять сторону сейчас, наверное, сидит и хихикает. Но в целом, единственное, что у меня есть в защиту
#js #ts #eslint #null
Как мы все знаем, в JavaScript есть две формы «пустоты»:
undefined и null.Но почти весь современный фронтенд давно выбрал сторону.
null — это ошибка на миллиард долларов, о которой пожалел даже его создатель, Тони Хоар. Он добавляет путаницу, ломает API и заставляет писать лишние проверки.Почему
null — плохая идея:Разные API возвращают то null, то undefined, то оба.
Это неясно, это ошибки.
✅ TypeScript-гайд от Microsoft прямо говорит: используйте undefined, избегайте
null.✅ В TSLint null запрещён по умолчанию (`no-null-keyword`).
✅ Правила ESLint Unicorn (да, название неслучайное) — тоже пропагандируют борьбу с
null в пользу чистого, предсказуемого кода.✅ В крупных экосистемах, например, как у Prisma,
null создаёт баги и недопонимание в API (issue #572)✅
undefined — поведение по умолчанию в JS для необъявленных свойств и пустых объектов.✅
undefined выигрывает даже в JSON. Когда ты сериализуешь данные:null остаётся в объекте:
{ "a": null }
а
undefined просто исчезает:
{ "a": undefined } → { }
В реальных системах это даёт выигрыш в размере и читаемости. Пример из продакшена: объект с миллионом
null весил 13.9 MB, а с undefined — всего 21 байт. И если ты работаешь с Node.js и хорошо контролируешь свои API — undefined тебе только на руку.❌ Да, из-за того, что множество систем до сих пор оперирует
null, и даже DOM API возвратит null при отсутствии элемента (ноды), выбор становится не настолько простым. К счастью, мы можем использовать optional chaining (?.) и nullish coalescing (??) чтобы снизить вероятность конфуза.Кстати, даже столь любимый мной Effector ещё не так давно пропагандировал
null для пустых сторов, но с недавнего времени разрешил undefined (в своей манере, там сложная концепция).Итак,
null — это рудимент. Он создаёт больше проблем, чем решает. undefined уже делает всё, что нужно — чище, предсказуемей и легче.Пора выбрать сторону 🦄
P. S. человек, который заставил меня принять сторону сейчас, наверное, сидит и хихикает. Но в целом, единственное, что у меня есть в защиту
null — это наш бакенд на PHP и MySQL 🤷 #js #ts #eslint #null
👍29👎9🤩5
#заметка дня
Вчерашний день начался с лёгкой тряски из-за неспособности некоторых разработчиков правильно обрабатывать такую простую вещь, как аналитику ссылок:
Собственно, код вы видите на иллюстрации. Прекрасно видно, что поведение по-умолчанию уничтожено, взамен ничего не предложено. При этом я всё ещё могу кликнуть по ссылке правой кнопкой мыши и выбрать "Открыть в новой вкладке".
Спасибо хотя бы на этом.
Итак, но намерения-то ясны: хотят получить аналитику. HSCO — это неймспейс компании, а DataLayer это — ну кто бы мог подумать — буквально Google Analytics gtag.
Впрочем, эту же аналитику они теряют, если я кликаю правой кнопкой мыши.
Чем же заменить подобное? Ну, во-первых, а надо ли вам это делать? Чем проход по ссылке и событие "select item" там отличается от непосредственного клика? Ведь чтение referrer никто не отменял. И, очевидно, для SPA и островных приложений это вообще проблемой не является.
Но если очень надо собирать данные именно в момент клика куда-то на странице, можно воспользоваться navigator.sendBeacon().
Да, нужно будет настроить Measurement API в Google Analytics, но в итоге всё сведётся к простой функции:
Собрать данные можно в момент клика или по наведению мыши на ссылку, чтобы минимизировать потери во время чтения атрибутов, а уже отправить их — как в обработчике клика, так и по событию visibilitychange документа.
А ещё вы почти всегда можете отправить дополнительные параметры запроса и считать их по факту. Таким образом, не потеряли бы ни клик, ни открытие в новой вкладке, ни шаринг.
В общем, вряд ли был какой-то злой умысел, скорее, банальный skill issue. Но честное слово, не надо так. Не ломайте дефолтное поведение элементов, пожалуйста.
#analytics #js
Вчерашний день начался с лёгкой тряски из-за неспособности некоторых разработчиков правильно обрабатывать такую простую вещь, как аналитику ссылок:
Каждый веб-разработчик, который блокирует открытие ссылки в новой вкладке по нажатию Ctrl/Cmd или средней кнопкой мышки — мой личный враг. Этому нет ни единого разумного объяснения.
Собственно, код вы видите на иллюстрации. Прекрасно видно, что поведение по-умолчанию уничтожено, взамен ничего не предложено. При этом я всё ещё могу кликнуть по ссылке правой кнопкой мыши и выбрать "Открыть в новой вкладке".
Спасибо хотя бы на этом.
Итак, но намерения-то ясны: хотят получить аналитику. HSCO — это неймспейс компании, а DataLayer это — ну кто бы мог подумать — буквально Google Analytics gtag.
Впрочем, эту же аналитику они теряют, если я кликаю правой кнопкой мыши.
Чем же заменить подобное? Ну, во-первых, а надо ли вам это делать? Чем проход по ссылке и событие "select item" там отличается от непосредственного клика? Ведь чтение referrer никто не отменял. И, очевидно, для SPA и островных приложений это вообще проблемой не является.
Но если очень надо собирать данные именно в момент клика куда-то на странице, можно воспользоваться navigator.sendBeacon().
Да, нужно будет настроить Measurement API в Google Analytics, но в итоге всё сведётся к простой функции:
function trackEventWithBeacon(eventName, params = {}) {
const measurementId = 'G-XXXXXXX'; // ← замени на свой GA4 ID
const apiSecret = 'YOUR_API_SECRET'; // ← замени на свой API Secret
const clientId = getClientId(); // читаем из _ga cookie
const payload = {
client_id: clientId,
events: [{
name: eventName,
params
}]
};
const url = `https://www.google-analytics.com/mp/collect?measurement_id=${measurementId}&api_secret=${apiSecret}`;
const blob = new Blob([JSON.stringify(payload)], { type: 'application/json' });
navigator.sendBeacon(url, blob);
}
Собрать данные можно в момент клика или по наведению мыши на ссылку, чтобы минимизировать потери во время чтения атрибутов, а уже отправить их — как в обработчике клика, так и по событию visibilitychange документа.
А ещё вы почти всегда можете отправить дополнительные параметры запроса и считать их по факту. Таким образом, не потеряли бы ни клик, ни открытие в новой вкладке, ни шаринг.
В общем, вряд ли был какой-то злой умысел, скорее, банальный skill issue. Но честное слово, не надо так. Не ломайте дефолтное поведение элементов, пожалуйста.
#analytics #js
👍24❤5
#игра дня
Давненько не было чего-то необычного.
Впрочем, если вы не фанат Dwarf Fortress, конечно.
Untrusted — это игра, в которой вам предлагают не просто пройти уровень, а сначала починить его. Или, если точнее, подправить JavaScript-код, который за него отвечает. Персонаж — профессор Эвал — застрял в виртуальной реальности, и единственный способ выбраться оттуда — лезть в исходники и аккуратно, а иногда и не очень, их переписывать.
Каждый уровень — это кусок JS-кода, который можно и нужно менять: отключить ловушку, переписать поведение врагов, добавить себе проход в стене — пожалуйста. Главное — чтобы заработало.
Игру сложно назвать обучающей, но если вы когда-то писали на JavaScript и у вас осталась эта мышечная память
🎮 https://untrustedgame.com/ 📂 https://github.com/AlexNisnevich/untrusted
#game #js
Давненько не было чего-то необычного.
Впрочем, если вы не фанат Dwarf Fortress, конечно.
Untrusted — это игра, в которой вам предлагают не просто пройти уровень, а сначала починить его. Или, если точнее, подправить JavaScript-код, который за него отвечает. Персонаж — профессор Эвал — застрял в виртуальной реальности, и единственный способ выбраться оттуда — лезть в исходники и аккуратно, а иногда и не очень, их переписывать.
Каждый уровень — это кусок JS-кода, который можно и нужно менять: отключить ловушку, переписать поведение врагов, добавить себе проход в стене — пожалуйста. Главное — чтобы заработало.
Игру сложно назвать обучающей, но если вы когда-то писали на JavaScript и у вас осталась эта мышечная память
for (var i = 0; i < ...), будет ощущение, что вы просто продолжаете работу, только теперь в компании ASCII-графики и странного профессора.🎮 https://untrustedgame.com/ 📂 https://github.com/AlexNisnevich/untrusted
#game #js
🤩13❤7
#фишка дня
Понадобилось мне тут создать список полей для функции
Но дело в том, что поля в форме сгруппированы по одному из параметров. Ну, условно:
А
А тут нам поможет flatMap! Это как map, но любой возвращённый массив развернёт и включит в состав возвращаемого.
Удобно? Удобно.
#js #map #flatMap #бородач
Понадобилось мне тут создать список полей для функции
watch (обозреватель введенных значений) в react-hook-form. Но дело в том, что поля в форме сгруппированы по одному из параметров. Ну, условно:
feature1[goods], feature1[variants], feature2[goods], feature2[variants]. А
watch на вход принимает одномерный массив строк. Так что же делать? А тут нам поможет flatMap! Это как map, но любой возвращённый массив развернёт и включит в состав возвращаемого.
Удобно? Удобно.
#js #map #flatMap #бородач
🫡4❤3👍1
#такое дня
Никак не мог вчера понять, почему в части проекта аутентификационные попапы отрабатывают нормально, а в другой — нет.
Флоу-то классический, тяжёлый, надёжный как швейцарские часы:
1. Кликнули по кнопке
2. Открылся попап аутентификации
3. Пока пользователь проходит процесс, ждём закрытия окна (а точнее, проверяем свойство closed по интервалу)
4. Как только окно закрылось — обновляем список токенов.
Так вот в некоторых проектах пункт 3 отваливался. Терялся контекст окна и всё тут. Хотя флоу и инструменты везде одни и те же.
Как оказалось, аддон koa-helmet для Koa.js когда-то давно в патч-версию вкинул заголовки CORS и COOP. И врубил их по-умолчанию.
Что такое CORS знают, в общем, все. А что такое COOP?
Это сравнительно новая штука и она устанавливает правила общения с окном, открытым через window.open. И в случае same-origin, достучаться до свойства closed уже не выйдет.
Есть
Ну и в какой-то момент старую версию Koa обновили до поновее и получили упс.
Менять поведение в патч-версиях — это мерзко. Но мы уже не в первый раз такое наблюдаем.
#koa #js #backend #popup #coop
Никак не мог вчера понять, почему в части проекта аутентификационные попапы отрабатывают нормально, а в другой — нет.
Флоу-то классический, тяжёлый, надёжный как швейцарские часы:
1. Кликнули по кнопке
2. Открылся попап аутентификации
3. Пока пользователь проходит процесс, ждём закрытия окна (а точнее, проверяем свойство closed по интервалу)
4. Как только окно закрылось — обновляем список токенов.
Так вот в некоторых проектах пункт 3 отваливался. Терялся контекст окна и всё тут. Хотя флоу и инструменты везде одни и те же.
Как оказалось, аддон koa-helmet для Koa.js когда-то давно в патч-версию вкинул заголовки CORS и COOP. И врубил их по-умолчанию.
Что такое CORS знают, в общем, все. А что такое COOP?
Это сравнительно новая штука и она устанавливает правила общения с окном, открытым через window.open. И в случае same-origin, достучаться до свойства closed уже не выйдет.
Есть
same-origin-allow-popups, но оно совсем новое и мало где поддерживается.Ну и в какой-то момент старую версию Koa обновили до поновее и получили упс.
Менять поведение в патч-версиях — это мерзко. Но мы уже не в первый раз такое наблюдаем.
#koa #js #backend #popup #coop
❤14👍3🤩2🫡2🤬1
#такое дня
Кто хочет поорать на монитор?
На меня не смотрите, я уже поорал.
Итак, насколько хорошо ты понимаешь даты в JavaScript?
Кто сказал Temporal API? Выйди вон из класса, дедушки разговаривают.
Итак, вашему вниманию квиз на пограничные условия в JS Date API.
Вперёд, делитесь результатами: https://jsdate.wtf/
У меня всё очень плохо🫠
#js #date #wtf
Кто хочет поорать на монитор?
На меня не смотрите, я уже поорал.
Итак, насколько хорошо ты понимаешь даты в JavaScript?
Кто сказал Temporal API? Выйди вон из класса, дедушки разговаривают.
Итак, вашему вниманию квиз на пограничные условия в JS Date API.
Вперёд, делитесь результатами: https://jsdate.wtf/
У меня всё очень плохо
#js #date #wtf
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🤩4🤡3
#фишка дня
Вот как вы думаете, что может преследовать разработчика веб-браузера во сне? Может, это разбор дерева DOM? А может, реализация всех новых атрибутов элементов?
Нет! Это поддержка легаси! Например, как вам такое сообщение в PR браузера Ladybird:
Вы всё правильно поняли. Получение базового URL-адреса сборки ведётся путём выбрасывания исключения и поиска адреса в нём. Я такое делал на AppsScript чтобы получить стек, но прям в продакшене да чтобы для реального использования...
Пруф: https://github.com/LadybirdBrowser/ladybird/pull/5678
Дальше — больше. Не только разработчики Atlassian (Jira, Trello) используют подобное, тем же самым славится и любимый многими Parcel: https://github.com/parcel-bundler/parcel/pull/2534/files#diff-39112519f42223a8e331d0dac27d01f8a70db6fe3d515ad8016856931a6ccbda
Стало быть, фишкой дня объявляется:
И, получается, ничего лучше же у нас так-то и нет. Если нет двери — используем окно.
А подробнее о браузере Ladybird я рассказывал в нескольких постах. Например, тут: https://t.iss.one/htmlshit/2935
#js #hack
Вот как вы думаете, что может преследовать разработчика веб-браузера во сне? Может, это разбор дерева DOM? А может, реализация всех новых атрибутов элементов?
Нет! Это поддержка легаси! Например, как вам такое сообщение в PR браузера Ladybird:
Atlassian login gets the base URL for its module scripts by throwing an error and pulling out the current script's URL from error.stack with regex.
Вы всё правильно поняли. Получение базового URL-адреса сборки ведётся путём выбрасывания исключения и поиска адреса в нём. Я такое делал на AppsScript чтобы получить стек, но прям в продакшене да чтобы для реального использования...
Пруф: https://github.com/LadybirdBrowser/ladybird/pull/5678
Дальше — больше. Не только разработчики Atlassian (Jira, Trello) используют подобное, тем же самым славится и любимый многими Parcel: https://github.com/parcel-bundler/parcel/pull/2534/files#diff-39112519f42223a8e331d0dac27d01f8a70db6fe3d515ad8016856931a6ccbda
Стало быть, фишкой дня объявляется:
function getBundleURL() {
// Attempt to find the URL of the current script and use that as the base URL
try {
throw new Error();
} catch (err) {
var matches = ('' + err.stack).match(/(https?|file|ftp):\/\/[^)\n]+/g);
if (matches) {
return getBaseURL(matches[0]);
}
}
И, получается, ничего лучше же у нас так-то и нет. Если нет двери — используем окно.
А подробнее о браузере Ladybird я рассказывал в нескольких постах. Например, тут: https://t.iss.one/htmlshit/2935
#js #hack
❤5🤩4
Media is too big
VIEW IN TELEGRAM
#заметка дня
Тут в нашем чатике aka @htmlshitchat человек задал вопрос: «Как заставить событие произойти только после долгого нажатия на кнопку?»
И, вроде, очевидный ответ: ставь таймаут да отменяй его:
Осторожно,псевдокод jQuery
Но это было бы скучно и недостаточно для поста, не правда ли?
И тут я вспомнил, что в 2017 году уже делал нечто подобное. Тогда не обошлось без погружения в Three.js и математику шестиугольников. Я об этом уже рассказывал: https://t.iss.one/htmlshit/2639
Немного покопавшись в вебархиве, я нашёл тот проект. Итак, что же мы делали?
А вот на видео видно.
Анимация была оформлена на Tween.js, который всё ещё очень и очень популярен. Правда, название их последнего релиза ну прям удручает. End of the end — серьёзно?
С 2017 года API их, конечно же, поменялся. Мне хотелось одновременно и последний вариант API вам показать, и сетку заставить работать... как хорошо, что мы в вебе, где можно вообще всё!
Итак, кодпен: https://codepen.io/alinaki/pen/KwPwVPr?editors=1100
Весь современный код упихан в секцию с HTML, в script type="module", где импортированы нужные модули и константы из ESM-версии Tween.js, он же является нашим скоупом.
Это вообще очень удобный паттерн чтобы быстро накидать пример без бандлинга.
По зажатию кнопки мыши запускаем анимацию forward, по отпусканию кнопки — запускаем reverse. Из breaking changes — раньше можно было просто вызвать start(), а теперь нужно вызывать startFromCurrentValues(), иначе красоты не получится.
Достаточно просто и эффектно.
#js #animation #tween #бородач
Тут в нашем чатике aka @htmlshitchat человек задал вопрос: «Как заставить событие произойти только после долгого нажатия на кнопку?»
И, вроде, очевидный ответ: ставь таймаут да отменяй его:
Осторожно,
let r = null;
$button.on("mousedown", function(e) {
e.preventDefault();
e.stopPropagation();
r = window.setTimeout(function() {
$button.html('Clicked');
}, 3000);
});
$button.on("mouseup", function() {
$button.html('Hold me');
window.clearTimeout(r);
});
Но это было бы скучно и недостаточно для поста, не правда ли?
И тут я вспомнил, что в 2017 году уже делал нечто подобное. Тогда не обошлось без погружения в Three.js и математику шестиугольников. Я об этом уже рассказывал: https://t.iss.one/htmlshit/2639
Немного покопавшись в вебархиве, я нашёл тот проект. Итак, что же мы делали?
А вот на видео видно.
Анимация была оформлена на Tween.js, который всё ещё очень и очень популярен. Правда, название их последнего релиза ну прям удручает. End of the end — серьёзно?
С 2017 года API их, конечно же, поменялся. Мне хотелось одновременно и последний вариант API вам показать, и сетку заставить работать... как хорошо, что мы в вебе, где можно вообще всё!
Итак, кодпен: https://codepen.io/alinaki/pen/KwPwVPr?editors=1100
Весь современный код упихан в секцию с HTML, в script type="module", где импортированы нужные модули и константы из ESM-версии Tween.js, он же является нашим скоупом.
Это вообще очень удобный паттерн чтобы быстро накидать пример без бандлинга.
По зажатию кнопки мыши запускаем анимацию forward, по отпусканию кнопки — запускаем reverse. Из breaking changes — раньше можно было просто вызвать start(), а теперь нужно вызывать startFromCurrentValues(), иначе красоты не получится.
function forward() {
tween.stop().to({
value: 2000
}, 3000).startFromCurrentValues();
}
function reverse() {
tween.stop().to({
value: 1000
}, 3000).startFromCurrentValues();
}
Достаточно просто и эффектно.
#js #animation #tween #бородач
❤9👍4🤩3
This media is not supported in your browser
VIEW IN TELEGRAM
#инструмент дня
Одной из самых популярных задач по работе с изображениями было и остаётся удаление фона с картинок. Вокруг этого развелось какое-то невероятное число сервисов.
И все хотят денег.
Но мы же с вами понимаем, что даже достаточно сложную нейронку можно запустить прямо в браузере, правда? Мощностей вашего компьютера в совокупности с возможностями WebGPU более чем хватит, чтобы работать с моделями разной направленности.
Итак, вашему вниманию — Transformers.js, как средство работы с моделями, и одно из самых наглядных его применений — удаление фона с фото прямо в вашем браузере: https://github.com/huggingface/transformers.js-examples/pull/4/files
Демо: https://huggingface.co/spaces/webml-community/remove-background-webgpu
Бесплатно, без SMS.
Конечно, Transformers.js могут и не такое, была бы натренированная модель: анализ эмоциональной окраски текста, распознавание речи, получение выжимки из текста... Впрочем, ребята и их предоставляют, в огромном количестве.
Огонь? Огонь!🔥
#js #ml #бородач
Одной из самых популярных задач по работе с изображениями было и остаётся удаление фона с картинок. Вокруг этого развелось какое-то невероятное число сервисов.
И все хотят денег.
Но мы же с вами понимаем, что даже достаточно сложную нейронку можно запустить прямо в браузере, правда? Мощностей вашего компьютера в совокупности с возможностями WebGPU более чем хватит, чтобы работать с моделями разной направленности.
Итак, вашему вниманию — Transformers.js, как средство работы с моделями, и одно из самых наглядных его применений — удаление фона с фото прямо в вашем браузере: https://github.com/huggingface/transformers.js-examples/pull/4/files
Демо: https://huggingface.co/spaces/webml-community/remove-background-webgpu
Бесплатно, без SMS.
Конечно, Transformers.js могут и не такое, была бы натренированная модель: анализ эмоциональной окраски текста, распознавание речи, получение выжимки из текста... Впрочем, ребята и их предоставляют, в огромном количестве.
Огонь? Огонь!
#js #ml #бородач
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14🤩2🫡1
#фишка дня
Вот вы знали, что в слушатель события можно передать AbortSignal и не выкаблучиваться с именованными функциями и вообще перестать слушать много событий разом, если надо?
А вот можно! Как в этом примере от Мэтта Покока.
И больше таких приятных современных вещей описано в статье Марка Грабански. Крайне рекомендую к ознакомлению.
#js #event #abortsignal #бородач
Вот вы знали, что в слушатель события можно передать AbortSignal и не выкаблучиваться с именованными функциями и вообще перестать слушать много событий разом, если надо?
А вот можно! Как в этом примере от Мэтта Покока.
И больше таких приятных современных вещей описано в статье Марка Грабански. Крайне рекомендую к ознакомлению.
#js #event #abortsignal #бородач
1❤8🤩7👍6🫡2
#дайджест недели
1️⃣ Понедельник
Flexbox можно выровнять «по-безопасному» с помощью align-items: safe center;. В узком контейнере элементы не обрезаются и доступны при скролле. Поддержка: Chrome 115+, Firefox 63+, Safari 17.6.
https://t.iss.one/htmlshit/3789
2️⃣ Вторник
Аттлассиан и Parcel используют хак: бросают исключение и вытаскивают URL из error.stack.
https://t.iss.one/htmlshit/3790
FlexBox Labs — конструктор раскладок под флекс (есть и экспериментальный грид). Работает онлайн и локально.
https://t.iss.one/htmlshit/3792
3️⃣ Среда
В Chrome DevTools появился MCP — протокол для подключения внешних инструментов и данных к ИИ-моделям.
https://t.iss.one/htmlshit/3793
При анимации цвета в CSS всё сводится к RGB, из-за чего появляются серые провалы. Решения: filter: hue-rotate() или анимация угла оттенка в переменной.
https://t.iss.one/htmlshit/3794
5️⃣ Четверг
Реализация долгого нажатия с анимацией через Tween.js.
https://t.iss.one/htmlshit/3796
Удаление фона прямо в браузере: Transformers.js + WebGPU. Бесплатное демо от HuggingFace.
https://t.iss.one/htmlshit/3797
5️⃣ Пятница
В addEventListener можно передавать AbortSignal и удобно управлять отпиской от событий.
https://t.iss.one/htmlshit/3799
Jest Preview визуализирует тесты в браузере.
https://t.iss.one/htmlshit/3800
6️⃣ Суббота
Slack тестирует локализацию с помощью «белиберды», чтобы легко находить непереведённые строки. Переводы хранят в ICU MessageFormat.
https://t.iss.one/htmlshit/3802
GRID TYPE — редактор модульных шрифтов, вдохновлённый Баухаузом. Можно собирать буквы и орнаменты, экспортировать в шрифтовые файлы. Поддерживается кириллица.
https://t.iss.one/htmlshit/3803
#css #js #tools #animation #i18n #fonts
Flexbox можно выровнять «по-безопасному» с помощью align-items: safe center;. В узком контейнере элементы не обрезаются и доступны при скролле. Поддержка: Chrome 115+, Firefox 63+, Safari 17.6.
https://t.iss.one/htmlshit/3789
Аттлассиан и Parcel используют хак: бросают исключение и вытаскивают URL из error.stack.
https://t.iss.one/htmlshit/3790
FlexBox Labs — конструктор раскладок под флекс (есть и экспериментальный грид). Работает онлайн и локально.
https://t.iss.one/htmlshit/3792
В Chrome DevTools появился MCP — протокол для подключения внешних инструментов и данных к ИИ-моделям.
https://t.iss.one/htmlshit/3793
При анимации цвета в CSS всё сводится к RGB, из-за чего появляются серые провалы. Решения: filter: hue-rotate() или анимация угла оттенка в переменной.
https://t.iss.one/htmlshit/3794
Реализация долгого нажатия с анимацией через Tween.js.
https://t.iss.one/htmlshit/3796
Удаление фона прямо в браузере: Transformers.js + WebGPU. Бесплатное демо от HuggingFace.
https://t.iss.one/htmlshit/3797
В addEventListener можно передавать AbortSignal и удобно управлять отпиской от событий.
https://t.iss.one/htmlshit/3799
Jest Preview визуализирует тесты в браузере.
https://t.iss.one/htmlshit/3800
Slack тестирует локализацию с помощью «белиберды», чтобы легко находить непереведённые строки. Переводы хранят в ICU MessageFormat.
https://t.iss.one/htmlshit/3802
GRID TYPE — редактор модульных шрифтов, вдохновлённый Баухаузом. Можно собирать буквы и орнаменты, экспортировать в шрифтовые файлы. Поддерживается кириллица.
https://t.iss.one/htmlshit/3803
#css #js #tools #animation #i18n #fonts
Please open Telegram to view this post
VIEW IN TELEGRAM
103👍22❤2
#дайджест недели
1️⃣ Понедельник
100 способов отцентрировать элемент
https://t.iss.one/htmlshit/3806
Оказывается, в
https://t.iss.one/htmlshit/3808
2️⃣ Вторник
Классная статья по Big O — визуально и интерактивно объясняет сложность алгоритмов. Есть перевод, но лучше идти сразу к оригиналу — там интерактив
https://t.iss.one/htmlshit/3809
Команда Motion перешла с TypeScript на .NET / C#. CI-проверки в TS занимали 20+ минут, а компилятор часто падал
https://t.iss.one/htmlshit/3811
3️⃣ Среда
У FFmpeg есть логотип — и он основан на алгоритме DCT, лежащем в основе JPEG
https://t.iss.one/htmlshit/3813
Simon Gellner сделал идеальный пример кружка статуса через
https://t.iss.one/htmlshit/3815
5️⃣ Четверг
Если парсинг JSON стал постоянным источником боли — попробуй jsonrepair. Он чинит незакрытые кавычки, лишние запятые и другую питонячесть вроде
https://t.iss.one/htmlshit/3817
5️⃣ Пятница
Фронтенд-разработка выматывает сильнее, чем кажется
https://t.iss.one/htmlshit/3818
#css #js #tools #animation #bigo #typescript #dotnet #json #frontend
100 способов отцентрировать элемент
https://t.iss.one/htmlshit/3806
Оказывается, в
content-е псевдоэлементов можно использовать переменные. Это позволяет делать, например, анимированные бейджики или уведомления.https://t.iss.one/htmlshit/3808
Классная статья по Big O — визуально и интерактивно объясняет сложность алгоритмов. Есть перевод, но лучше идти сразу к оригиналу — там интерактив
https://t.iss.one/htmlshit/3809
Команда Motion перешла с TypeScript на .NET / C#. CI-проверки в TS занимали 20+ минут, а компилятор часто падал
https://t.iss.one/htmlshit/3811
У FFmpeg есть логотип — и он основан на алгоритме DCT, лежащем в основе JPEG
https://t.iss.one/htmlshit/3813
Simon Gellner сделал идеальный пример кружка статуса через
clip-path и маску. Всё настраивается CSS-переменными, а ещё там используется любопытный API DiceBear для генерации аватарокhttps://t.iss.one/htmlshit/3815
Если парсинг JSON стал постоянным источником боли — попробуй jsonrepair. Он чинит незакрытые кавычки, лишние запятые и другую питонячесть вроде
Truehttps://t.iss.one/htmlshit/3817
Фронтенд-разработка выматывает сильнее, чем кажется
https://t.iss.one/htmlshit/3818
#css #js #tools #animation #bigo #typescript #dotnet #json #frontend
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12
#дайджест недели
1️⃣ Понедельник
CSS Scroll Snap теперь умеет делать автопрокрутку чата вниз без костылей на JS.
Есть пример прямо в спецификации и демо от Брамуса. Старый баг с Chrome уже пофиксили.
https://t.iss.one/htmlshit/3823
2️⃣ Вторник
Линус Торвальдс ругает rustfmt за «эвристику», которая ломает историю коммитов.
https://t.iss.one/htmlshit/3824
Как уменьшить вариативный шрифт с 785 до 58 КБ.
https://t.iss.one/htmlshit/3826
3️⃣ Среда
› 'wtf' instanceof String — false
› typeof 'wtf' — 'string'
https://t.iss.one/htmlshit/3827
5️⃣ Четверг
git-absorb автоматизирует fixup-коммиты.
Сам находит, что вы правили, и создаёт нужные fixup! перед rebase.
https://t.iss.one/htmlshit/3829
Вышла документалка о Vite. Любовные сцены сняты прекрасно:
https://t.iss.one/htmlshit/3831
5️⃣ Пятница
Evil Martians показали, как сделать офлайн-поиск в Astro без бэкенда.
JSON-индекс на сборке, MiniSearch в браузере — и всё работает мгновенно.
https://t.iss.one/htmlshit/3832
— Это код, он не может сделать больно!
Код:
https://t.iss.one/htmlshit/3838
6️⃣ Суббота
Что происходит, когда вы посещаете сайт — пошагово от DNS до рендеринга.
И бонусом — крестики-нолики на чистом CSS и без HTML.
https://t.iss.one/htmlshit/3839
#js #css #git
CSS Scroll Snap теперь умеет делать автопрокрутку чата вниз без костылей на JS.
Есть пример прямо в спецификации и демо от Брамуса. Старый баг с Chrome уже пофиксили.
https://t.iss.one/htmlshit/3823
Линус Торвальдс ругает rustfmt за «эвристику», которая ломает историю коммитов.
https://t.iss.one/htmlshit/3824
Как уменьшить вариативный шрифт с 785 до 58 КБ.
https://t.iss.one/htmlshit/3826
› 'wtf' instanceof String — false
› typeof 'wtf' — 'string'
https://t.iss.one/htmlshit/3827
git-absorb автоматизирует fixup-коммиты.
Сам находит, что вы правили, и создаёт нужные fixup! перед rebase.
https://t.iss.one/htmlshit/3829
Вышла документалка о Vite. Любовные сцены сняты прекрасно:
https://t.iss.one/htmlshit/3831
Evil Martians показали, как сделать офлайн-поиск в Astro без бэкенда.
JSON-индекс на сборке, MiniSearch в браузере — и всё работает мгновенно.
https://t.iss.one/htmlshit/3832
— Это код, он не может сделать больно!
Код:
https://t.iss.one/htmlshit/3838
Что происходит, когда вы посещаете сайт — пошагово от DNS до рендеринга.
И бонусом — крестики-нолики на чистом CSS и без HTML.
https://t.iss.one/htmlshit/3839
#js #css #git
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6
#инструмент дня
Ох что я вам нашёл! Просто пушка.
Как вам отладка на мобильных устройствах? Ну только честно. По-моему — мучение.
Да, можно подключить телефон кабелем к компьютеру и пользоваться консолью настольного браузера. Можно купить доступ к Browserstack или аналогам и разруливать косяки на десятках устройств. Ах да, можно ещё воспользоваться эмулятором!
Но почему бы просто не воспользоваться девтулзами? Ну потому что в мобильных браузерах их нет.
Зато есть Eruda! Встраиваемая консоль для мобильных браузеров: https://github.com/liriliri/eruda
Демо: https://eruda.liriliri.io/
В принципе, выглядит как сильно упрощённая копия хромовых вебтулзов и вполне себе может помочь в отладке, особенно учитывая количество всяческих официальных и не очень плагинов от визуализации касаний до пиксель-пёрфект подложки.
В общем, забавная вещь! В какой-то момент может и выручить.
#js #devtools #mobile #бородач
Ох что я вам нашёл! Просто пушка.
Как вам отладка на мобильных устройствах? Ну только честно. По-моему — мучение.
Да, можно подключить телефон кабелем к компьютеру и пользоваться консолью настольного браузера. Можно купить доступ к Browserstack или аналогам и разруливать косяки на десятках устройств. Ах да, можно ещё воспользоваться эмулятором!
Но почему бы просто не воспользоваться девтулзами? Ну потому что в мобильных браузерах их нет.
Зато есть Eruda! Встраиваемая консоль для мобильных браузеров: https://github.com/liriliri/eruda
Демо: https://eruda.liriliri.io/
В принципе, выглядит как сильно упрощённая копия хромовых вебтулзов и вполне себе может помочь в отладке, особенно учитывая количество всяческих официальных и не очень плагинов от визуализации касаний до пиксель-пёрфект подложки.
В общем, забавная вещь! В какой-то момент может и выручить.
#js #devtools #mobile #бородач
👍13🤩1
#фишка дня
Как сделать вывод консоли красивеньким?
Очень просто, использовать спецификаторы преобразования!
Прямо как sprintf в Си, ну как вы можете этого не знать?
Короче, всё внимание на иллюстрацию. Adobe настолько оборзели, что свой логотип даже вам в консоль пихают, если у вас получится открыть девтулзы на веб-версии Фотошопа.
А делается это буквально так: https://codepen.io/alinaki/pen/PoXrejX
Для тех, кто по ссылкам не ходит, сокращённая версия:
Как можно догадаться, %c это спецификатор, указывающий, что сюда надо подставить CSS, переданный соответствующим аргументом.
Полный список спецификаторов есть на MDN.
Красота спасёт мир, котаны!
#console #js #sprintf #бородач
Как сделать вывод консоли красивеньким?
Очень просто, использовать спецификаторы преобразования!
Прямо как sprintf в Си, ну как вы можете этого не знать?
Короче, всё внимание на иллюстрацию. Adobe настолько оборзели, что свой логотип даже вам в консоль пихают, если у вас получится открыть девтулзы на веб-версии Фотошопа.
А делается это буквально так: https://codepen.io/alinaki/pen/PoXrejX
Для тех, кто по ссылкам не ходит, сокращённая версия:
console.info(
"%c %cAdobe %cPhotoshop Web%c %c2023.20.0.0%c %c1bba617e276",
"padding-left: 36px; line-height: 36px; background-image: url('data:image/gif;base64,R0lGODlhIAAgAPEBAAAAAPw==');"
)
Как можно догадаться, %c это спецификатор, указывающий, что сюда надо подставить CSS, переданный соответствующим аргументом.
Полный список спецификаторов есть на MDN.
Красота спасёт мир, котаны!
#console #js #sprintf #бородач
👍8❤3
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня
Таблица до сих пор превосходит все попытки её имитировать по очень простой причине:
если скопировать её из браузера, она спокойно вставится в Excel или Google Sheets как нормальный диапазон.
Но вот обратное направление не работает. Скопировал диапазон из Sheets — а в браузере всё рассыпалось в текст, будто ничего и не было.
Иногда это мешает: есть форма с табличкой на сайте, есть данные в Google Sheets, и единственное желание — просто вставить их туда, не перепечатывая по ячейке. Чтобы привычный Ctrl+V вёл себя так же естественно, как в Excel.
Для таких случаев можно сделать маленькую, но удобную вещь — ловить событие вставки и парсить табличные данные из буфера, распределяя их по нужным полям:
Так можно взять диапазон в Google Sheets, нажать Ctrl+V в браузере — и данные разложатся по ячейкам формы, словно это штатная функция.
Я пример забыл, а вы и молчите: https://codepen.io/alinaki/pen/KwzvEeX
#js #table
Таблица до сих пор превосходит все попытки её имитировать по очень простой причине:
если скопировать её из браузера, она спокойно вставится в Excel или Google Sheets как нормальный диапазон.
Но вот обратное направление не работает. Скопировал диапазон из Sheets — а в браузере всё рассыпалось в текст, будто ничего и не было.
Иногда это мешает: есть форма с табличкой на сайте, есть данные в Google Sheets, и единственное желание — просто вставить их туда, не перепечатывая по ячейке. Чтобы привычный Ctrl+V вёл себя так же естественно, как в Excel.
Для таких случаев можно сделать маленькую, но удобную вещь — ловить событие вставки и парсить табличные данные из буфера, распределяя их по нужным полям:
document.addEventListener("paste", function (e) {
const text = e.clipboardData.getData("text");
const rows = text.trim().split(/\r?\n/).map(r => r.split("\t"));
const inputs = [...document.querySelectorAll("input")];
let index = 0;
for (const row of rows) {
for (const cell of row) {
if (inputs[index]) {
inputs[index].value = cell;
index++;
}
}
}
e.preventDefault();
});
Так можно взять диапазон в Google Sheets, нажать Ctrl+V в браузере — и данные разложатся по ячейкам формы, словно это штатная функция.
Я пример забыл, а вы и молчите: https://codepen.io/alinaki/pen/KwzvEeX
#js #table
1👍20❤1