do-webp
v2.0.0
Published
Convert images to WebP via npx do-webp
Maintainers
Readme
do-webp
Утилита командной строки для конвертации изображений в формат WebP с сохранением исходной структуры папок или размещением результатов рядом с оригиналами.
!!! AI POWERED
Всё было проверено только на шиндоус.
Возможности
- Конвертация отдельных файлов или целых папок (рекурсивно по умолчанию)
- Поддержка форматов: .jpg, .jpeg, .png, .tiff, .bmp, .svg
- Настраиваемое качество WebP (1–100) и режим без потерь
- Изменение размера результата: в пикселях (
--width/--height) или в процентах (--scale) - Два режима работы:
- без параметра
-d– WebP-файлы создаются рядом с исходными (в тех же папках) - с параметром
-d– все результаты сохраняются в указанную выходную папку с сохранением вложенной структуры
- без параметра
- Возможность отключить рекурсивный обход подпапок (
--no-recursive)
Требования и зависимости
- Node.js 22.12 или новее
- Пакеты
sharpиcommanderставятся автоматически
Установка
Глобальная установка из NPM
npm install -g do-webpЛокальная установка
git clone https://github.com/Manshooo/do-webp
cd do-webp
npm install
npm run build
npm linkВызов без установки
npx do-webp -s ./images -d ./webpили
do-webp -s ./imagesИспользование
do-webp -s <путь> [options]Параметры
| Параметр | Описание |
|------------------------------|---------------------------------------------------------------------------|
| -s, --source <path> | Исходный файл или папка (обязательный) |
| -d, --dist <path> | Выходная папка. Если не указана, WebP-файлы создаются рядом с оригиналами |
| -q, --quality <number> | Качество сжатия от 1 до 100 (по умолчанию 80) |
| -w, --width <px> | Ширина результата в пикселях |
| --height <px> | Высота результата в пикселях |
| --scale <percent> | Масштаб в процентах от исходного размера: 50 или 150% |
| --fit <mode> | Как вписывать в заданные размеры (по умолчанию inside) |
| --lossless | Сжатие без потерь: файл крупнее, но без артефактов |
| --no-recursive | Отключить рекурсивную обработку подпапок (по умолчанию рекурсия включена) |
| -c, --concurrency <number> | Количество параллельных потоков (по умолчанию 4) |
| -V, --version | Показать версию |
| -h, --help | Показать справку |
Размер результата
Размер задаётся одним из двух способов, вместе они не работают:
- В пикселях —
--widthи/или--height. Если указать только одну сторону, вторая считается сама по пропорциям. - В процентах —
--scale. Считается от исходного размера файла, поэтому в папке с разными картинками каждая масштабируется от своего размера.
# фиксированная ширина, высота по пропорциям
do-webp -s logo.svg --width 512
# уменьшить вдвое
do-webp -s photo.jpg --scale 50
# увеличить в полтора раза (проценты можно писать со знаком)
do-webp -s photo.jpg --scale 150%Режимы --fit
Нужны только когда заданы обе стороны сразу. Значения те же, что у sharp:
| Режим | Что делает |
|-----------|--------------------------------------------------------------------------|
| inside | Вписывает целиком, пропорции сохраняются, результат может быть меньше заданного (по умолчанию) |
| cover | Заполняет прямоугольник целиком и обрезает лишнее |
| contain | Вписывает целиком и дополняет до нужного размера полями |
| fill | Растягивает до точного размера, пропорции нарушаются |
| outside | Вписывает так, чтобы покрыть прямоугольник, без обрезки |
# впишется в 200x200, реальный размер, например, 200x133
do-webp -s photo.jpg --width 200 --height 200
# ровно 200x200 с обрезкой по краям
do-webp -s photo.jpg --width 200 --height 200 --fit coverПро SVG
SVG растеризуется в размер, записанный в самом файле — в атрибутах width и height,
а если их нет, то в размер из viewBox. Именно поэтому иконка с viewBox="0 0 64 64"
без width/height превращается в WebP 64×64 и выглядит пиксельной, сколько ни поднимай -q.
Лечится указанием размера — тогда картинка перерисовывается из вектора сразу в нужное разрешение, а не растягивается после отрисовки:
do-webp -s favicon.svg --width 512Для иконок и логотипов с плоскими заливками имеет смысл добавить --lossless: файл
получится крупнее, но без «грязи» вокруг контуров и текста.
do-webp -s favicon.svg --width 512 --losslessПримеры
Конвертация всех изображений в папке
photosс сохранением результатов в той же папке (структура сохраняется):do-webp -s ./photosКонвертация папки
photosс сохранением всех WebP-файлов в папкуwebp(структура вложенных папок сохраняется):do-webp -s ./photos -d ./webpКонвертация одного файла:
do-webp -s avatar.pngРезультат:
avatar.webpрядом сavatar.png.Конвертация с качеством 90 и отключением рекурсии (обрабатываются только файлы в корне
photos):do-webp -s ./photos -q 90 --no-recursiveКонвертация файла в указанную выходную папку:
do-webp -s image.jpg -d ./convertedПревью для галереи: всё в папке уменьшается до ширины 400 пикселей и складывается отдельно:
do-webp -s ./photos -d ./thumbs --width 400
Что стоит знать
- Ориентация фотографий. Поворот из EXIF применяется к картинке при конвертации, потому что WebP этот тег не хранит. Снятые вертикально фотографии не ложатся набок.
- Совпадение имён.
logo.pngиlogo.svgв одной папке дают один и тот жеlogo.webp. Второй файл пропускается с предупреждением, а не затирает первый молча — переименуйте исходник или разложите файлы по разным папкам. - Код возврата.
0, если сконвертировались все файлы.1, если хоть один файл не удалось обработать или пришлось пропустить из-за совпадения имён — так ошибку видно в скриптах и CI. - Прогресс. Первые три файла печатаются построчно, дальше идёт счётчик. При выводе в файл или пайп счётчик не печатается, чтобы не засорять лог.
Что изменилось в 2.0
Ломающие изменения:
- Node.js 22.12 или новее вместо 14. Подтянулось за
sharp0.35 иcommander15. sharpобновлён с 0.33 до 0.35 — в 0.33 остались незакрытые уязвимости libvips.-q 0больше не принимается, минимум1: нуля WebP всё равно не понимает.- Ненулевой код возврата при ошибках конвертации и пропущенных файлах. Раньше
всегда возвращался
0, даже когда не сконвертировалось ничего. - Совпадение имён не приводит к перезаписи — лишний файл пропускается.
- Точка входа переехала с
bin/do-webp.jsнаdist/cli.js. Черезdo-webpиnpxразницы нет, но прямой запуск файла изnode_modulesпридётся поправить.
Остальное:
- Исходники переписаны на TypeScript, в пакет уезжает собранный JavaScript.
- Появились
--width,--height,--scale,--fitи--lossless. - Исправлен разбор
-qи-c: раньше любое значение превращалось вNaN. photo.PNGбольше не даётphoto.PNG.webp.
Разработка
npm install
npm test # проверка типов + сборка + тесты
npm run build # только сборка в dist/
npm run typecheck # только проверка типов, включая тестыСтруктура:
| Файл | За что отвечает |
|---------------------|-------------------------------------------------------|
| src/cli.ts | Разбор аргументов, оркестрация, вывод итогов |
| src/options.ts | Типы опций, парсеры значений, проверка сочетаний |
| src/files.ts | Обход дерева, имена результатов, совпадения имён |
| src/convert.ts | Расчёт размера и конвейер sharp |
| src/pool.ts | Ограничение параллелизма |
| src/logger.ts | Вывод в консоль и строка прогресса |
Исходники написаны так, чтобы node мог запускать .ts напрямую своей вырезкой типов —
без сборки, когда нужно быстро проверить правку:
node src/cli.ts -s ./photos --width 400Тесты в test/ делятся на два вида: юнит-тесты берут функции прямо из src/,
а cli.test.ts запускает собранный dist/cli.js отдельным процессом и проверяет
настоящие файлы на диске.
Выпуск версии
Версия поднимается только через workflow Release, руками её править не нужно:
- Actions → Release → Run workflow
- Выбрать, что сделать с версией
- Run workflow
Дальше всё делается само: прогоняются тесты, версия записывается в package.json,
пакет уезжает в npm, появляются коммит, тег и релиз на GitHub. Разойтись тег
и package.json не могут — их ставит один и тот же шаг.
Значения поля «Что сделать с версией»:
| Значение | Что делает |
|-------------------------|-------------------------------------------------------------------|
| none (по умолчанию) | Выпускает версию, которая уже записана в package.json |
| patch minor major | Поднимает соответствующую часть версии перед публикацией |
Ниже есть поле для точной версии — если его заполнить, выбор выше игнорируется.
По умолчанию стоит none, чтобы случайный запуск не поднял версию молча:
такой прогон просто упрётся в проверку «эта версия уже в npm» и остановится.
Если релиз упал
Смотря на каком шаге. Всё до публикации — тесты, расчёт версии, проверки — происходит внутри раннера и в репозиторий не попадает: ни лишнего тега, ни поднятой версии не остаётся, можно просто запустить workflow заново с теми же параметрами.
Публикация в npm — точка невозврата. Если она прошла, а коммит с тегом запушить не удалось (например, из-за защиты ветки), версия в npm уже есть. Тогда остаётся поправить причину и проставить коммит с тегом руками — повторный запуск не поможет, он упрётся в проверку «уже опубликовано».
Настройка публикации в npm (делается один раз)
Публикация идёт по OIDC через доверенного издателя, без токенов в секретах.
Пока издатель не настроен, npm publish падает с ENEEDAUTH — прав id-token: write
в workflow для этого недостаточно, npm должен со своей стороны знать, какому
репозиторию доверять.
- Зайти на npmjs.com под владельцем пакета
- Открыть страницу пакета
do-webp→ Settings - Найти раздел Trusted publisher и выбрать GitHub Actions
- Заполнить:
- Organization or user:
Manshooo - Repository:
do-webp - Workflow filename:
release.yml - Environment: оставить пустым
- Organization or user:
- Сохранить
Значения должны совпадать с репозиторием буква в букву, включая регистр. Если позже переименовать файл workflow, издателя нужно будет поправить.
Запасной вариант, если доверенный издатель по каким-то причинам не подходит:
создать в npm гранулярный токен с правом публикации, положить его в секреты
репозитория как NPM_TOKEN и добавить в шаг setup-node параметр
registry-url: "https://registry.npmjs.org", а в шаг публикации —
env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}. Такие токены живут максимум
90 дней, так что менять их придётся регулярно.
