Будни разработчика
14.6K subscribers
1.36K photos
398 videos
8 files
2.28K links
Download Telegram
#заметка дня

Итак, на работе выдали новые ноутбуки тем, чьи машины в лизинге уже три года и более.

Вот только есть нюанс. Мой побитый M2 Pro нём на борту 32 Гб оперативной памяти, а новенький M5 Pro — только 24. Как-то нехорошо.

У компании, конечно, свои интересы в ограничении максимальной конфигурации, но получили что получили. Людям, работающим с тяжёлыми задачами выдали модели на 48 Гб, то есть, возможность что-то доказать имеется.

Но я сюда не ныть пришёл, хотя очень хочется. Любые ограничения это повод пересмотреть работу. И одним из таких пересмотров, конечно же, стала сборка Webpack, которая в пике сжирает 11 гигабайт. Планирую заменить на Rspack, хоть там есть и свои нюансы.

Самый главный нюанс — продать это стафф-инженеру.

Но поговорить я даже не об этом хотел. У коллеги новый такой же ноутбук резко начал выть кулерами, и причина была не очень ясна. Потребление памяти в пике всё ещё не упирается в лимит, свопится не очень сильно. А воет.

А воет, потому что процесс rg — знаменитый инструмент поиска ripgrep — забивал 8 ядер процессора под завязку и останавливаться не собирался.

Попросил коллегу показать мне её расширения для Cursor (VS Code). И там, конечно, было очень красиво. 34 расширения с её учебных дней, от разных иконок и сниппетов до подсветки классов.

Запустили Extensions Bisect — я писал об этой встроенной в VS Code утилите не так давно, она позволяет найти расширение, которое вызывает глюки редактора или прочие странные эффекты — вот вроде пожирания ресурсов ripgrep-ом.

И такое расширение нашлось! Им оказалось популярное IntelliSense for CSS class names in HTML.

Что заставило его сожрать все ресурсы и почему это не проявлялось на предыдущей машине — вопрос остаётся открытым. Да и не нужно оно в большинстве случаев.

В общем, я рад тишине в офисе, наконец.

#rg #vscode
👍18🔥52👏1
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня

Вы когда-нибудь пытались анимировать смену цвета и сталкивались с тем, что в какой-то момент всё превращается в уныло-серое? Джош Комо как раз разбирает эту проблему.

Дело в том, что даже если мы задаём разные цвета через разные цветовые модели, браузер всё равно интерполирует их в RGB-пространстве. А оно ограниченное, и на кривой перехода иногда выпадает серый — как с градиентами (https://xn--r1a.website/htmlshit/806), только теперь в анимации.

Казалось бы, решение простое: крутим hue в HSL, и серого не будет. Но на практике CSS-анимации всё равно сводятся к RGB, и мы снова получаем неожиданный результат. И более того, анимация от 0 до 360 (полный оборот) вообще не будет анимирована. Оптимизация!

Есть два способа это обойти:

1. Использовать filter: hue-rotate(), чтобы прокручивать оттенки напрямую.
2. Хранить угол оттенка в CSS-переменной и анимировать именно её, а не цвет в целом.

В итоге получается ровная и предсказуемая смена цвета без серых провалов.

Статья: https://www.joshwcomeau.com/animation/color-shifting/

#css #color #animation #бородач
7👍2
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня

Таблица до сих пор превосходит все попытки её имитировать по очень простой причине:
если скопировать её из браузера, она спокойно вставится в 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 #бородач
👍141
Проект от подписчика!

Напоминаю, что я выкачу любую статью или проект от вас, не стесняйтесь писать.

Презентация? Выступили на митапе? Хотите поделиться интересной статьёй — добро пожаловать!


Всем привет! Меня зовут Роман, я фуллстек-разработчик, 5+ лет в вебе — фриланс и работа в команде, в основном фронтенд. Давно читаю «Будни разработчика», так что вдвойне приятно оказаться здесь уже со своим материалом. Хочу рассказать про инструмент, который сделал под собственную боль и которым теперь пользуюсь сам каждый день.

Когда верстаешь адаптив, постоянно скачешь между десктопом и мобильной версией: то DevTools в режиме устройства, то ресайз окна, то открыть на телефоне. Десктоп и мобайл при этом никогда не видны вместе — один прячется, когда смотришь на другой. А показывать заказчику «узкое окно браузера» по видеосвязи — так себе демонстрация.

Готовые симуляторы есть (Mobile First, U-eyes и другие — со своей задачей справляются). Но почти все открывают превью в отдельном окне или своей области. Мне же нужно было другое: рамка телефона прямо поверх десктопной страницы, на той же вкладке, одновременно с ней. Не нашёл такого — сделал сам.

🟣 Как устроено (коротко по технике)

Страница внутри себя. Очевидный путь — iframe с тем же URL, сужённый до ширины телефона. Но большинство сайтов отдают X-Frame-Options и CSP: frame-ancestors, и iframe просто не грузится. Через declarativeNetRequest (MV3) динамически срезаю X-Frame-Options, вырезаю только директиву frame-ancestors из CSP (остальной CSP не трогаю) и подменяю User-Agent на мобильный. Правило живёт только пока открыто превью, привязано к конкретной вкладке, ничего не блокируется и не отправляется — меняются лишь заголовки ответа.

Изоляция стилей. Весь UI оверлея (рамка, панель, кнопки) — в Shadow DOM, чтобы CSS сайта и расширения не ломали друг друга.

Синхронизация. Скролл, клики и ввод проксируются между десктопом и превью — заполняешь форму на десктопе, видишь, как она заполняется в телефоне. Самое муторное — маппинг элементов и защита от бесконечных циклов событий.

🟣 Скриншоты снимаются и обрезаются локально, сохраняются файлом — ничего никуда не грузится.

🟣 Запись экрана. Честно про текущее состояние: в опубликованной версии работает штатным путём — через диалог захвата экрана браузера, видео кодируется локально (WebM и MP4, MP4 пока тестово). Параллельно допиливаю бесшовный вариант без промпта на расшаривание (chrome.tabCapture + getUserMedia в offscreen, перекодирование через WebCodecs + mp4/webm-muxer) — но это пока в разработке.

🟣 Приватность как ограничение архитектуры. Нет бэкенда, аналитики и удалённого кода. Настройки — в chrome.storage.local, не покидают устройство. Разрешения в манифесте — ровно под задачу.

Итог: Mobile View — десктоп и мобайл одновременно на вкладке, синхронизация, скриншоты, запись. Бесплатно, лежит в Chrome Web Store.

Буду рад любому фидбэку. И если найдёте баги на своей ОС/версии браузера — напишите подробно, по возможности со скрином или записью: веду проект в одиночку, так баги фиксятся куда быстрее.

Chrome Web Store: https://chromewebstore.google.com/detail/mobile-view-%E2%80%94-mobile-simu/hocbjiaeeijekejepphjihbpogikmofh
Сайт: https://mobileview.app
Статья на Хабре: https://habr.com/ru/articles/1047354/
6🔥19👍21🫡1
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня

Команда Chrome предложила довольно необычное API для частичного обновления HTML. В разметке можно оставить специальный маркер:


<div>
<?marker name="placeholder">
</div>


Браузер игнорирует <?marker>, поэтому такой код уже сейчас работает как обычный HTML.

Позже, когда данные будут готовы, достаточно добавить:


<template for="placeholder">
Here is some <em>HTML content</em>!
</template>


После этого содержимое шаблона автоматически займёт место маркера.

На практике это означает, что сервер может начать отдавать страницу ещё до того, как готовы все данные. Не нужно искать элементы по id, не нужно писать код для замены заглушек, не нужно придумывать собственный протокол поверх HTML.

Несколько лет назад стриминг HTML ассоциировался почти только с React. Штош.

Самое приятное, что <?marker> — не какой-то новый синтаксис. Processing instructions существуют ещё со времён XML, а браузеры уже умеют спокойно пропускать их в HTML. Поэтому использовать такую разметку можно хоть сегодня. Для старых браузеров есть полифилл от Google Chrome Labs.

Статья:
https://developer.chrome.com/blog/declarative-partial-updates

Полифилл:
https://github.com/GoogleChromeLabs/template-for-polyfill

#html
👍14👏3🤩21
Как правильно работать с резервным копированием в облаке?

25 июня приглашаем на бесплатный вебинар от MWS Cloud Platform всех, кто работает с облаками.

Развеем мифы, разберём лучшие современные подходы и инструменты.

Обсудим интеграцию в процессы, консистентность, точечное восстановление и безопасность. Поговорим о плюсах нативных облачных инструментов.

Проведём демо в MWS Cloud Platform и ответим на ваши вопросы.

Зарегистрируйтесь, чтобы не пропустить!

25 июня в 14:00 (мск)

Зарегистрироваться
Please open Telegram to view this post
VIEW IN TELEGRAM
#новость дня

В HTTP появился (точнее, вот-вот появится, только RFC приняли) новый метод QUERY.

Примерно такой:


QUERY /search
Content-Type: application/json

{
"q": "foo",
"limit": 10,
"sort": "-published"
}


И самое интересное тут даже не то, что теперь можно отправлять сложный поисковый запрос в теле HTTP-запроса. Самый интересный вопрос: а разве мы не могли делать это через GET?

Могли. Иногда даже делали.


GET /search
Content-Type: application/json

{
"q": "foo",
"limit": 10,
"sort": "-published"
}


На уровне HTTP-сообщения тело у GET возможно. Протокол не развалится только потому, что после заголовков пришёл body.

Проблема в другом: у тела GET нет нормальной общей семантики.

Стандарт не говорит: «тело GET — это параметры запроса». Сервер и клиент могут между собой так договориться, но для остальной инфраструктуры это будет частная магия. Прокси, CDN, кэши, балансировщики, библиотеки и браузерные API не обязаны понимать такой договор.

Поэтому GET с body — это поведение из серии “может работать в нашей связке”. Где-то пройдёт, где-то тело проигнорируют, где-то запрос завернут, а где-то его вообще нельзя будет отправить. Например, браузерный fetch не разрешает body у GET и HEAD.

QUERY как раз стандартизирует этот сценарий.


QUERY /search
Content-Type: application/json

{
"q": "foo",
"limit": 10,
"sort": "-published"
}


Смысл метода: это запрос на чтение, но параметры запроса лежат в теле. То есть больше не нужно притворяться, что сложный фильтр — это короткая строка query-параметров, и не нужно использовать POST там, где состояние на сервере не меняется.

От POST отличие тоже важное. POST для HTTP-инфраструктуры выглядит как метод с возможными побочными эффектами. QUERY, наоборот, описан как safe и idempotent: его можно повторить, не ожидая, что повтор сам по себе что-то создаст или изменит.

Получается, QUERY — это не «GET с body», а нормальный стандартный способ сказать: тело запроса важно, оно описывает выборку, и сам запрос при этом остаётся запросом на чтение.

#http
👍195
#такое дня

Как выбесить коллег одной строкой?

А сейчас я покажу вам...

Автор

#бородач #js
🤩17🤬4👍3🤡1
#ссылка дня

Когда-то давным давно поддержки кастомных шрифтов в браузерах толком не было, а желание сделать красиво — было.

Как же обходились? Ну, например, генерировали картинки, используя библиотеки FreeType и (для PHP) GD2/Imagemagick.

К слову, это до сих пор валидный кейс, соответствующие плагины для популярных CMS вполне себе поддерживаются: https://www.drupal.org/project/textimage

Просто зачастую нет никакого смысла тащить целый шрифт на фронт ради пары заголовков. Да и даже его часть — тоже.

Естественно, всегда можно резать набор глифов (символов) на лету... например, утилитами вроде https://opentype.js.org/ или FontForge в командном режиме, но каждый ли проект в этом нуждается?

А, ну и как же, нельзя забывать о вкладе Adobe Flash в поддержку кастомных шрифтов! Была технология sIFR, которая генерировала маленькие Flash-апплеты на месте, где должен был располагаться ваш заголовок.

Или аналогичная — Cufon, но уже на связке JS/SVG или VRML (векторный язык в IE).

Забавное было время, конечно, но иногда лучше и правда сгенерировать картинку, чем тащить весь шрифт целиком.

#font #old #бородач
5
Media is too big
VIEW IN TELEGRAM
Вышел anime.js 4.5.0.

Anime.js — это JavaScript-библиотека для анимаций. Её часто используют для DOM, CSS-свойств, SVG, таймлайнов и обычных JS-объектов: когда нужна не одна transition, а нормальное управление движением, задержками, easing’ами и последовательностями.

В 4.5.0 появился API адаптеров. Если коротко, теперь anime.js можно научить работать с объектами, которые устроены не как DOM-элементы.

Главный пример в этом релизе — встроенный адаптер для Three.js.

В Three.js анимация часто требует писать во вложенные свойства объекта:


mesh.position.x = 100
mesh.rotation.y = Math.PI / 4
mesh.material.opacity = 0.5
mesh.material.color.set('#ff8844')


С адаптером это можно описывать прямо в animate():


animate(mesh, {
x: 100,
rotateY: 45,
opacity: 0.5,
color: '#ff8844',
})


Адаптер сам сопоставляет параметры с position, rotation, material, цветом и другими свойствами Three.js.

Появился и более привычный для фронтендера синтаксис 3D-трансформаций: rotateX, rotateY, rotateZ, scale, transformOrigin, плюс skewX, skewY, skewZ.

Материалы тоже стало анимировать проще. Цвет можно передавать строкой — hex, rgb, hsl или CSS-переменной — без ручного перекладывания в THREE.Color.

Ещё одна хорошая часть — instanced mesh. Объекты, которые в Three.js обычно используются для большого количества одинаковой геометрии, теперь можно анимировать почти как обычные меши. Для сцен с сетками, частицами, волнами и кучей повторяющихся элементов это сильно сокращает ручной код.

В stagger() добавили поддержку 3D: теперь задержки можно раскладывать не только по x и y, но и по z. Плюс появились jitter и seed, чтобы делать разброс в движении, но при этом получать повторяемый результат.

Остальные изменения — в changelog: фиксы timeline, keyframes, seek, reversed loops, render engine, работа с цветами и разные мелкие правки.

Важная деталь: сайт anime.js теперь тоже портирован на новый API с Three.js-адаптером. То есть это не просто пример в документации, а уже основа для собственного сайта проекта.

Получился релиз, после которого anime.js заметно лучше ложится на 3D-сцены. Да здравствуют описания анимаций без постоянного ручного прохода по position, rotation, material и прочим внутренним полям.

#animejs #animation #threejs
13
Media is too big
VIEW IN TELEGRAM
#статья дня

Не так давно в чате канала проскочил вопрос, как правильно делать контейнеры, которые могут вылезать за визуальные границы.

Например, основной контент находится посредине и занимает в ширину 80-120 приятных для чтения глазу символов, а вот картинки хотелось бы разнести до краёв.

Техника называется full bleed. Я не знаю, как точно перевести.

Если посмотрите видео, то виден ещё один вариант использования, когда галерея выходит за пределы экрана лишь с одной стороны, но дальше тем не менее границы игнорирует.

Вот так: https://codepen.io/hexagoncircle/pen/gOWjwme

Альтернативный вариант: https://codepen.io/maartenbruggink/full/eYWjxae

Раньше такое делалось жонглированием полями, теперь же у нас есть гриды.

И у небезызвестного Джоша Комо есть статья как раз об этом: https://www.joshwcomeau.com/css/full-bleed/

Тем не менее, я рекомендую посмотреть приложенные кодпены, поскольку в них зоны грида именуются и становится понятнее, что к чему.

Всем full bleed, котаны!

#css #fullbleed #gallery #бородач
110🫡1
This media is not supported in your browser
VIEW IN TELEGRAM
#библиотека дня

Есть небольшая библиотека для undo/redo в JavaScript: async-history-stack.

Она интересна не тем, что «умеет откатывать состояние». Это как раз самый простой случай. Интереснее другое: в историю можно складывать действия, у которых есть асинхронные операции и побочные эффекты.

Например, пользователь удаляет картинку из галереи. В реальном приложении это может быть не один setState, а целая цепочка: уйти со страницы картинки, отправить запрос на удаление, убрать ссылку из локального состояния, обновить интерфейс.

А при undo надо сделать обратное: восстановить картинку, вернуть ссылку в состояние и снова открыть страницу этой картинки.

async-history-stack предлагает описывать такие действия через push: функция сразу выполняет изменение и возвращает функцию, которая умеет это изменение откатить.


await historyStack.push(async () => {
await applyChanges()

return async () => {
await revertChanges()
}
})


То есть в историю кладётся не снимок объекта, а переход туда-обратно. Благодаря этому undo/redo может быть не привязан к конкретному стору и нормально покрывает навигацию, RPC, работу с файлами и другие асинхронные штуки.

В библиотеке есть undo, redo, clear, size, timestamp, лимит истории, отмена через signal и merge, чтобы склеивать несколько изменений в одну запись. Например, когда много мелких действий должны откатываться одним undo.

Я набросал демо: галерея, удаление карточки, имитация асинхронного RPC, лог операций, undo/redo и восстановление маршрута. Ну и да, вместо обычных заглушек там процедурно генерируются SVG-паркеты, потому что почему бы и нет.

Ссылка на библиотеку:
https://github.com/kettanaito/async-history-stack

Демо:
https://codepen.io/editor/alinaki/pen/019f1263-8e38-73da-a864-9854b6093cee

Всем undo, котаны!

#history #undo #library #svg #tile
13🔥4🫡1
#ссылка дня

Когда технологии стареют, это почти незаметно — пока не становится поздно. Вроде всё работает, но обновлений безопасности больше нет, старые зависимости перестают собираться, а новые версии библиотек ломают совместимость. Так проект постепенно превращается в мину замедленного действия.

Чтобы не попадать в такие ситуации, существует проект endoflife.date. Он показывает, когда заканчивается поддержка языков, библиотек, фреймворков и систем. Вводишь, например, Node.js или Ubuntu — и сразу видно, какие версии ещё живы, а какие пора обновлять. У них даже есть открытое API, так что можно встроить проверку прямо в CI и получать напоминания автоматически.

Но обновляться стоит с умом. Иногда новая версия приносит несовместимые изменения и кучу головной боли. Поэтому существуют LTS-версии — стабильные ветки, которые поддерживаются дольше обычных и меняются не так резко. На них удобно сидеть, если важна предсказуемость и стабильность.

Простая идея, но в долгосрочной перспективе экономит много времени и нервов.

#lts #support #бородач
6🫡2
#инструмент дня

Я уже один раз потерял ссылку на этот сервис, потому на правах закладки.

Встречайте, Cobalt: https://cobalt.tools/

Это сервис с открытым исходным кодом (GitHub), предназначенный для скачивания видео с большой кучи разнообразных сервисов: вк, ютуб, рутуб, тикток, твиттер, инстаграм и так далее и тому подобное. Полный список тут.

Никакой рекламы и занудства. Разве только UI на мобиле подглючивает — у меня не всегда правильно определяется безопасная зона "чёлки".

В общем, рекомендация.

#video #download #бородач
14🔥4🤡2
Соскучились по рождественским календарям для программистов?

У CodeRun тут получился Advent of Code посреди лета, только с более олимпиадной составляющей: 15 задач, которые выкатываются пачками по 5 штук каждые 5 дней до 17 июля, общий зачёт и отдельные лидерборды по 11 языкам.

Главная механика — не просто «решил / не решил». Быстрый и экономный код даёт больше баллов, так что после первого accepted всё только начинается: можно переписывать решение, смотреть на время, память, крайние случаи и пытаться выжать из него ещё немного.

Я знаю людей, которые реально встают на час раньше, чтобы перед работой прорешать очередной LeetCode. Я не уверен, что сам готов к такой дисциплине, но понимаю, зачем они это делают: алгоритмы быстро ржавеют, если их не трогать. А здесь примерно тот же формат тренировки, только не в одиночном режиме и с таблицей, где сразу видно, насколько твоё «и так нормально» на самом деле нормально.

Призы тоже есть: топ-1 по каждому из 11 языков получает мерч-пак CodeRun, топ-3 общего зачёта — коллекционный лего-набор, а топ-200 общего зачёта — скип контеста и пробное интервью в Яндекс.

Последний пункт, кстати, довольно практичный. Даже если не относиться к этому как к спорту, такой челлендж можно использовать как понятный способ размяться перед алгоритмическими интервью: задачи, ограничения, дедлайн, сравнение решений и болезненное напоминание, что O(n²) иногда всё ещё O(n²).
🔥32👍2
Media is too big
VIEW IN TELEGRAM
#фишка дня

Когда я наткнулся на этот твит в обсуждении утилиты работы с цветами Андрея Ситника, я не сразу примерил его на себя. Но, как оказалось, стоило бы.

Итак, давайте поясню для тех, кто по ссылкам не ходит.

В азиатских иероглифических языках почти весь ввод с клавиатуры происходит в аккордном режиме или же в режиме т. н. композитинга, общее название — Input Method Editor.

TL;DR: На экране всплывает окошко с символами или их группами и пользователь может что-то выбрать.

На каких-то ОС оно вызывается долгим зажатием клавиши, где-то — по хоткею, а где-то — автоматически и сразу.

Так вот, одно дело азиатские языки (я очень рекомендую посмотреть сам твит), а другое — разные европейские. И речь о диакритических знаках: умляуты, акуты, ударения, птички и шапочки.

Так вот, я не имею финской раскладки, потому буквы ä, å и ö ввожу как раз в режиме композитинга, долгим зажатием «материнской» клавиши.

Собственно, так база для азиатских языков проникла и в мою жизнь.

Кстати, выбор Emoji из всплывающего окошка — туда же.

В JavaScript-событиях для этого режима имеется флаг isComposing. Поэтому если вы, как и я в примере на видео, решили реализовать ввод групп символов подобным образом — циклически перебирая поля ввода — стоит об этом подумать :)

Собственно, давайте и пример: https://codepen.io/alinaki/pen/MWMpdvO?editors=1010

И напишите в комментариях, как вы решаете проблему редкого ввода букв с диакритикой у себя в системе. Например, я не помню, как это происходит в Windows, а в Linux я использую клавишу Compose, она работает чуть иначе.

#javascript #composing #event #бородач
🔥5
#инструмент дня

Появился Nub — новый «всё-в-одном» тулкит для JavaScript. Название, конечно, опасное: любой пост про него автоматически звучит как обращение к аудитории.

GitHub: https://github.com/nubjs/nub
Site: https://nubjs.com/

Кто уже догадался, откуда у названия ноги растут?

Да, оттуда.

Но есть нюанс: Nub не пытается заменить Node.js.

Смысл такой: дать разработчику всё приятное, что люди обычно хвалят в Bun — быстрый запуск, TypeScript из коробки, меньше зоопарка CLI, — но оставить выполнение кода на старом добром Node.js.

Nub — это один Rust-бинарник поверх обычного Node.js. Он умеет:

— запускать TypeScript/TSX/JSX без отдельного build step
— автоматически подхватывать tsconfig paths
— грузить .env
— импортировать YAML/TOML/JSONC/JSON5
— работать как быстрый runner для package.json scripts
— заменять npx/pnpm exec
— ставить зависимости
— управлять версиями Node
— делать watch mode

То есть вместо набора из tsx, ts-node, dotenv, tsconfig-paths, nvm, pnpm run, npx и пары заклинаний из README вашего монорепо — один nub.

Главный selling point не «мы быстрее всех, потому что переписали мир на Zig, потом по-ковбойски переписали его на Rust с помощью ИИ, а теперь давайте все сделаем вид, что это нормальный жизненный цикл инфраструктурного рантайма».

Код в итоге выполняет обычный Node.js. Nub просто добавляет слой удобства: транспиляцию через oxc, хуки резолвинга, полифиллы и быстрые команды вокруг проекта.

На сайте, конечно, бенчмарки красивые:

nub run — сильно быстрее npm run / pnpm run
nubx — сильно быстрее npx
nub install — быстрее pnpm и, по их тестам, даже чуть быстрее bun install
nub index.ts — примерно как обычный node по старту и быстрее tsx

Плюс отдельно упирают в supply-chain безопасность: build scripts по умолчанию не запускаются, свежие подозрительные релизы можно придерживать, вредоносные пакеты проверяются через OSV.

Выглядит как очень понятная реакция на последние годы JS tooling: всем понравилось, что Bun быстрый и удобный, но не всем хочется тащить в прод ещё один почти-Node, который иногда внезапно оказывается «почти», а потом ещё и внезапно оказывается почти переписанным.

Nub говорит: а давайте оставим Node, но перестанем страдать от того, что вокруг него исторически вырос целый огород одноразовых CLI.

Пока штука свежая, я бы не тащил её сразу в критичный CI без проверки, но для внутренних тулов, dev-скриптов и монореп — очень интересно.

#node #bun #typescript #oxc #rust
👍13🔥3🫡21
#уязвимость дня

У браузеров новый жанр: сайт может косвенно смотреть, что вы делаете на компьютере, по задержкам SSD.

Исследователи из Graz University of Technology показали атаку FROST. Схема примерно такая: сайт заводит себе большой файл в локальном хранилище браузера через Origin Private File System и постоянно читает его маленькими кусками. Пока SSD занят только этим — задержки одни. Открыли другой сайт или приложение — нагрузка на диск изменилась, задержки тоже. По этим микросдвигам можно попытаться понять, что ещё запущено на компьютере.

В эксперименте сайты угадывались примерно с точностью 89%, приложения — около 96%.

Отдельно хороша реакция браузеров. По пересказу Ars Technica и Tom’s Hardware, Google не считает fingerprinting уязвимостью безопасности. Apple, судя по статье, отправила в сторону будущих privacy-защит. Mozilla проблему признала, но фикса пока нет.

Получилось как обычно: API добавляли для нормальных вещей — локального хранения, офлайн-работы, быстрых приложений. А потом выяснилось, что из этого же API можно собрать ещё один датчик состояния машины.

Закрывать лишние вкладки теперь можно не из-за RAM, а для своей же приватности.

#ssd #vulnerability
9👎1👏1🤬1
#игра дня

Среда — это маленькая пятница! Время сыграть в... Carmageddon!

Его как Никита Аксёнов портировал в браузер :) Точнее, не оригинальную игру, а движок Deathrace, целью которого является реверс-инжиниринг оригинального движка.

Естественно, чтобы играть локально нужны ассеты игры, но по ссылке — всё работает прекрасно: https://retrogamescenter.ru/ports/carmaweb/index.html

В отличие от нативного Carmageddon, управление тут перенесено на стрелки, а не работает на Numpad. Я всё ещё помню, насколько это было ублюдочно.

Я стар. Я суперстар.

Жаль, мультиплеер не пашет пока :)

#game #old
10👍1🤡1
Media is too big
VIEW IN TELEGRAM
#инструмент дня

После Scratch в обучении программированию часто начинается пробел.

Сначала ребёнок собирает игру из блоков: персонаж ходит, говорит, что-то собирает. Всё живое и понятное. А потом ему внезапно дают VS Code, JavaScript, Canvas, npm и объясняют, что теперь надо быть взрослым.

Roblox Studio и Minecraft MakeCode этот пробел частично закрывают, но по-своему. Они хорошо отвечают на вопрос «зачем мне вообще кодить»: чтобы сделать свой мир, карту, режим, предмет или механику. Но как следующий шаг после Scratch они не всегда мягкие. Roblox Studio быстро превращается в отдельную IDE с Luau, сценой, объектами и клиент-серверной моделью. Minecraft — в редстоун, команды, datapacks, моды и свою специфическую экосистему.

Odyc.js интересен тем, что он меньше.

Это маленький JavaScript-движок для пиксельных narrative games: карта, персонаж, диалоги, звуки, взаимодействия. Игру можно собрать буквально в одном файле, без большого геймдев-цирка и обряда посвящения через инфраструктуру. У него есть песочница, где можно сразу ковырять игру в браузере.

Для обучения это хороший масштаб: уже не блоки, но ещё не Unity. Ребёнок пишет настоящий код, видит объекты, строки, координаты, условия и события — и всё это сразу превращается не в абстрактный прямоугольник, а в комнату, дверь, ключ, NPC и диалог.

Scratch учит: программирование — это поведение.

Minecraft и Roblox показывают: кодом можно менять миры.

Odyc аккуратно вставляется между ними: теперь то же самое, но буквами — и пока в масштабе, который можно удержать в голове.

#game #js
👍7🫡3