Что ж, потирание вручную сжатого изображения TinyPng WebpackPlugin тоже SoEasy

JavaScript Webpack
Что ж, потирание вручную сжатого изображения TinyPng WebpackPlugin тоже SoEasy

автор:JowayYoung
склад:Github,CodePen
Блог:Официальный сайт,Наггетс,думаю нет,Знай почти
Нет публики:Интерфейс IQ
Специальное: оригинал не просто, или скопирован без разрешения не должен быть воспроизведен, для перепечатки, пожалуйста, свяжитесь с автором авторизации

предисловие

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

Если вы часто обращаете внимание на тему оптимизации производительности, то можете найти无论怎样对代码做最好的优化也不及对一张图片做一次压缩好. Таким образом, сжатие изображений стало наиболее распространенной операцией при оптимизации производительности.Будь то ручное сжатие изображений или автоматическое сжатие изображений, оно должно выполняться в процессе разработки проекта.

Автоматическое сжатие изображения обычноwebpackДоступ к некоторым третьим сторонам при создании проектаLoader&Pluginобрабатывать. ОткрытьGithub,поискwebpack imageОжидание ключевых слов, Звезда не болееimage-webpack-loaderа такжеimagemin-webpack-pluginэти двоеLoader&Plugin. Многие студенты могут выбрать их, поскольку они удобны, быстры, просты в использовании и имеют простой доступ.

Однако эти дваLoader&PluginЕсть некоторые особые проблемы, все они основаны наimageminразвивающийся.imageminНекоторые зависимости размещены на внешних серверах, вnpm i xxxУстановите их по умолчаниюGitHub ReleasesЕсли у вас нет стандартного доступа в Интернет, вы не сможете его установить, и даже если вы сможете стандартизировать доступ в Интернет, вы не сможете его установить. Поэтому автор опубликовал статью об обработке зеркал NPM.«Поговорим об опасных ямах зеркалирования NPM», специально для решения этих проблем, связанных с сбоем установки из-за сетевого окружения. Помимо этой проблемы с установкой,imageminЕсть еще одна большая проблема, то есть потеря текстуры сжатия серьезно.Чем больше размер изображения, тем это более очевидно.Всегда есть несколько сжатых изображений, которые искажены, и общая степень сжатия не очень высока. Таким образом, когда проект будет сдан, его может поймать осторожная сестра QA, как это может быть четко не сравнимо с чертежом дизайна!

инструмент

инструмент сжатия изображений

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

工具集合

инструмент Открытый исходный код потери API Бесплатная пробная версия
QuickPicture ✖️ ✔️ ✖️ Есть много сжимаемых типов, текстура сжатия лучше, есть ограничения по объему, а есть ограничения по количеству
ShrinkMe ✖️ ✖️ ✖️ Есть много сжимаемых типов, текстура сжатия общая, нет ограничения по количеству и есть ограничение по объему.
Squoosh ✔️ ✖️ ✔️ Есть несколько сжимаемых типов, текстура сжатия общая, нет ограничения по количеству и есть ограничение по объему.
TinyJpg ✖️ ✔️ ✔️ Типов сжимаемых мало, текстура сжатия очень хорошая, есть ограничения по количеству, есть ограничения по объему
TinyPng ✖️ ✔️ ✔️ Типов сжимаемых мало, текстура сжатия очень хорошая, есть ограничения по количеству, есть ограничения по объему
Zhitu ✖️ ✖️ ✖️ Сжимаемый тип является общим, текстура сжатия является общей, существуют ограничения по количеству и объему.

Как видно из приведенного сравнения таблиц, свободный опыт будет существовать体积限制, это и понятно, даже если заряд одинаков, ведь все заливают одну картинку больше 10 М, какой сервер это выдержит. тогда есть数量限制,вы можете загружать только 20 изображений за раз.Кажется есть правило.Если качество сжатия хорошее,количество будет ограничено.В противном случае количество не будет ограничено.Конечно после зарядки ограничений не будет . тогда есть可压缩类型, тип изображения обычноjpg,png,gif,svgа такжеwebp,gifКак правило, он будет искажен после сжатия.svgОбычно используется на векторных иконках и редко используется на изображениях сцен,webpСжатие возможно из-за редко используемых проблем совместимостиjpgа такжеpngБудет достаточно. Конечно压缩质感Это лучшее соображение. Таким образом, большинство студентов выберутTinyJpgа такжеTinyPng, по сути они братья, от одного производителя.

Было запущено простое голосование в группе обсуждения WeChat официального аккаунта автора, и, наконец,TinyJpgа такжеTinyPngпобедить.

工具投票

Проблема с TinyJpg/TinyPng
  • загружать и скачивать手动
  • только сжатыйjpgа такжеpng
  • сжимать только за один раз20открытым
  • Максимальный размер каждого листа не может превышать5M
  • Информация о визуальной обработке не является особенно полной
Принцип сжатия TinyJpg/TinyPng

TinyJpg/TinyPngИспользуйте интеллектуальную технологию сжатия с потерями, чтобы уменьшить размер изображения, выборочно уменьшить количество похожих цветов в изображении и сохранить данные всего несколькими байтами. Визуальное воздействие почти незаметно, но разница в размере файла большая. при использовании智能有损压缩技术называетсяколичественно.

TinyJpg/TinyPngпри сжатииpng文件эффект более выражен. Сканируйте изображения на наличие похожих цветов и комбинируйте их, уменьшая количество цветов.24位png文件Преобразовать в меньший размер8位png文件, отбрасывая все ненужные метаданные.

наиболееpng文件имеют50%~70%Степень сжатия трудно различить даже при хорошем зрении. Использование оптимизированных изображений снижает нагрузку на полосу пропускания и время загрузки, а изображения, используемые на сайте,TinyJpg/TinyPngСжав его один раз, эффект заключается в том, что никакая оптимизация кода не может наверстать упущенное.

熊猫

API разработки TinyJpg/TinyPng

Ознакомьтесь с соответствующей информацией и найдитеTinyJpg/TinyPngЕго алгоритм сжатия еще не открыт, но предоставляется API, подходящий для разработчиков. Заинтересованные студенты могут перейти кРазрабатывать документацию по APIПроверьте это.

существуетNodeаспект,TinyJpg/TinyPngофициально предоставленtinifyЯвляясь основной библиотекой JS для сжатия изображений, она очень проста в использовании, см.ДокументацияБар. Однако, если вы перейдете на API разработки, вы все равно не сможете избежать платы. Хотите ежемесячную подписку или бесплатно? Если вы хотите быть свободным, продолжайте смотреть вниз, местные тираны свободны!

工具价格

выполнить

я тоже часто пользуюсьTinyJpg/TinyPngПрограммист не может брать плату. Поиск прорывов и решение проблем — самые основные качества программиста.我们需明确什么问题,需解决什么问题.

анализировать

Из вышеизложенного необходимо толькоTinyJpg/TinyPngИсходная функция была преобразована в следующие функции.

  • Автоматическая загрузка и загрузка
  • сжимаемыйjpgа такжеpng
  • без ограничений по количеству
  • Существует ограничение громкости, максимальная громкость не может превышать5M
  • Успешное сжатие или не вывод подробной информации

автоматическая обработка

Для фронтенд-разработчиков эта безмозглая операция загрузки и выгрузки должна быть автоматизирована, что избавит от проблем и усилий. Но эту операцию надо совмещатьwebpackиметь дело, в конце концов превращается вLoaderещеPlugin, который будет проанализирован позже. Однако внимательные учащиеся узнают, как с этим справиться, прочитав заголовок.

Тип сжатия

gifКак правило, он будет искажен после сжатия.svgОбычно используется на векторных иконках и редко используется на изображениях сцен,webpСжатие возможно из-за редко используемых проблем совместимостиjpgа такжеpngБудет достаточно. При фильтрации изображений используйтеpath模块Определите, является ли тип файлаjpgа такжеpng, если да, продолжить обработку, иначе не обрабатывать.

Количественные ограничения

Конечно, ограничения по количеству быть не может.Если в проекте более 20 картинок, то это не пакетный пакетный процесс.Такого быть не может. Для такого веб-сайта, который может обрабатывать некоторые пользовательские файлы без входа в систему, количество пользовательских операций обычно ограничивается IP. Некоторые студенты могут сказать, что достаточно обновить страницу, сжать каждый раз 20 картинок, обновить и снова сжать, если есть 500 картинок, вы обновляете 25 раз, это очень весело, правда!

Поскольку большинство веб-архитектур редко предоставляют серверы приложений напрямую внешнему миру, обычно настраивается слой.NginxВ качестве прокси-серверов и балансировщиков нагрузки некоторые из них могут даже иметь несколько уровней прокси-серверов. Учитывая, что большинство веб-архитектур используютNginxВ качестве обратного прокси-сервера пользовательский запрос не запрашивает напрямую сервер приложений, а перенаправляет пользовательский запрос на сервер через унифицированный уровень доступа, установленный Nginx, поэтому его можно установить, задав поле заголовка HTTP-запроса.X-Forwarded-Forдля подделки IP.

X-Forwarded-Forсредство, используемое для идентификации代理или负载均衡Поле заголовка HTTP-запроса самого исходного IP-адреса клиента при подключении к веб-серверу. Конечно, этот IP не является статическим, и каждый запрос должен менять IP случайным образом, обманывая сервер приложений. Если сервер приложений добавляет фальшивую идентификацию IP, возможно, он не сможет продолжать использовать случайные IP-адреса.

ограничение громкости

Ограничение объема понятно, и нет необходимости создавать такой большой образ, который тратит впустую пропускную способность, трафик и время загрузки. При загрузке изображения используйтеfs模块Определить, превышает ли размер файла5M, если да, не загружать, иначе продолжить загрузку. Конечно, чтобыTinyJpg/TinyPngОценка интерфейса также работает.

выходная информация

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

кодирование

Благодаря приведенному выше анализу мы начнем кодирование.

Произвольно генерировать заголовки HTTP-запросов

Так как можно пройтиX-Forwarded-ForЧтобы подделать IP, должна быть функция, которая случайным образом генерирует поля заголовка HTTP-запроса, а соответствующие поля заголовка запроса генерируются случайным образом каждый раз, когда запрашивается интерфейс. Открытьtinyjpg.comилиtinypng.comзагрузить изображение черезChrome DevToolsанализироватьNetworkОбнаружено, что его интерфейс запросаweb/shrink. Кроме того, каждый запрос не должен концентрироваться на одномhostname, распределяется случайным образом поtinyjpg.comилиtinypng.comбудет лучше. путем инкапсуляцииRandomHeaderФункция случайным образом генерирует информацию заголовка запроса для последующего использования.https模块кRandomHeader()Сгенерированная конфигурация запрашивается в качестве входного параметра.

trampleразрабатывается авторомWeb/NodeБиблиотека инструментов общих функций, включая общие функции инструментов, помогает писать менее общий код. Для получения подробной информации, пожалуйста, проверьтеДокументация, кстати Звезде за поощрение.

工具接口

const { RandomNum } = require("trample/node");

const TINYIMG_URL = [
    "tinyjpg.com",
    "tinypng.com"
];

function RandomHeader() {
    const ip = new Array(4).fill(0).map(() => parseInt(Math.random() * 255)).join(".");
    const index = RandomNum(0, 1);
    return {
        headers: {
            "Cache-Control": "no-cache",
            "Content-Type": "application/x-www-form-urlencoded",
            "Postman-Token": Date.now(),
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
            "X-Forwarded-For": ip
        },
        hostname: TINYIMG_URL[index],
        method: "POST",
        path: "/web/shrink",
        rejectUnauthorized: false
    };
}

Загружать и скачивать изображения

использоватьPromiseупаковка上传图片а также下载图片функция, которая удобна для последующего использованияAsync/AwaitСинхронизируйте асинхронный код. Отладка конкретных точек останова следующих функций обсуждаться не будет.Заинтересованные студенты могут самостоятельно отлаживать входные и выходные параметры функции!

const Https = require("https");
const Url = require("url");

function UploadImg(file) {
    const opts = RandomHeader();
    return new Promise((resolve, reject) => {
        const req = Https.request(opts, res => res.on("data", data => {
            const obj = JSON.parse(data.toString());
            obj.error ? reject(obj.message) : resolve(obj);
        }));
        req.write(file, "binary");
        req.on("error", e => reject(e));
        req.end();
    });
}

function DownloadImg(url) {
    const opts = new Url.URL(url);
    return new Promise((resolve, reject) => {
        const req = Https.request(opts, res => {
            let file = "";
            res.setEncoding("binary");
            res.on("data", chunk => file += chunk);
            res.on("end", () => resolve(file));
        });
        req.on("error", e => reject(e));
        req.end();
    });
}

Сжать изображение

пройти через上传图片Функция получает информацию о сжатом изображении, а затем передает下载图片Функция генерирует локальные файлы.

const Fs = require("fs");
const Path = require("path");
const Chalk = require("chalk");
const Figures = require("figures");
const { ByteSize, RoundNum } = require("trample/node");

async function CompressImg(path) {
    try {
        const file = Fs.readFileSync(path, "binary");
        const obj = await UploadImg(file);
        const data = await DownloadImg(obj.output.url);
        const oldSize = Chalk.redBright(ByteSize(obj.input.size));
        const newSize = Chalk.greenBright(ByteSize(obj.output.size));
        const ratio = Chalk.blueBright(RoundNum(1 - obj.output.ratio, 2, true));
        const dpath = Path.join("img", Path.basename(path));
        const msg = `${Figures.tick} Compressed [${Chalk.yellowBright(path)}] completed: Old Size ${oldSize}, New Size ${newSize}, Optimization Ratio ${ratio}`;
        Fs.writeFileSync(dpath, data, "binary");
        return Promise.resolve(msg);
    } catch (err) {
        const msg = `${Figures.cross} Compressed [${Chalk.yellowBright(path)}] failed: ${Chalk.redBright(err)}`;
        return Promise.resolve(msg);
    }
}

Сжать целевое изображение

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

const Ora = require("ora");

(async() => {
    const spinner = Ora("Image is compressing......").start();
    const res = await CompressImg("src/pig.png");
    spinner.stop();
    console.log(res);
})();

Видите ли, после сжатия глупые свиньи стали красивыми свинками, а свиньи с электрическими глазами — хорошие свиньи. Пожалуйста, проверьте исходный кодcompress-img.

电眼猪

Если вы сжимаете все изображения, соответствующие условиям в указанной папке, вы можете использоватьfs模块получить изображение и использоватьmap()Сопоставьте путь к одному изображению какCompressImg(path), затем пройтиPromise.all()Просто сделай это. Я не буду публиковать код здесь, просто примите это как мысленный вопрос и завершите его самостоятельно.

Вышеупомянутая функция сжатия изображений заключена вLoaderещеPluginШерстяная ткань? Далее будет пошаговый анализ.

Loader&Plugin

webpackЭто интерфейсный инструмент упаковки ресурсов, который выполняет статический анализ на основе зависимостей модулей, а затем генерирует соответствующие статические ресурсы из этих модулей в соответствии с заданными правилами.

много онлайнwebpackВ туториале автор больше не будет тратить много времени и болтать.Я считаю,что все студенты стандартWebpack配置工程师. Краткий обзор следующегоwebpackкомпозиция, строительный механизм и строительный процесс, я полагаю, что также могут быть расположены из этих точек знанияLoaderа такжеPluginсуществуетWebpack构建流程В какой он роли?

本文所说的webpack都是基于webpack v4

сочинение

  • Entry:Вход
  • Output: выход
  • Loader:конвертер
  • Plugin: Расширитель
  • Mode:модель
  • Module: модуль
  • Target:Цель

механизм сборки

  • Преобразование кода с помощью Babel и создание зависимостей в одном файле
  • Запустите рекурсивный анализ из входного файла и сгенерируйте граф зависимостей
  • Упакуйте каждый упомянутый модуль в немедленно выполняемую функцию
  • Запишите окончательный файл пакета вbundle.jsсередина

Процесс сборки

  • исходный
    • 初始参数: объединить аргументы командной строки и файла конфигурации.
  • компилировать
    • 执行编译: инициализируется в соответствии с параметрамиCompiler对象, загрузить всеPlugin,воплощать в жизньrun()
    • 确定入口: найти все входные файлы в соответствии с файлом конфигурации
    • 编译模块: найти все отношения зависимых модулей в соответствии с файлом ввода, вызвать всеLoaderдля преобразования
    • 生成图谱: получить преобразованное содержимое каждого модуля и его зависимостей.
  • выход
    • 输出资源: Собрать модули в блоки, а затем в пакеты в соответствии с зависимостями (module → chunk → bundle)
    • 生成文件: Записать содержимое вывода подтверждения в файловую систему в соответствии с файлом конфигурации.
Loader

LoaderИспользуется для преобразования исходного кода модуля, автор переводит его как转换器.LoaderПреобразование всех типов файлов вwebpackДействительный модуль, способный обрабатывать, а затем использоватьwebpackУпаковочные возможности их перерабатываются во второй раз.

LoaderИмеет следующие характеристики:

  • Принцип единой ответственности (只完成一种转换)
  • Конвертировать полученный контент
  • вернуть результат преобразования
  • Поддержка связанных вызовов

LoaderПреобразуйте все типы файлов в модули, на которые может напрямую ссылаться граф зависимостей приложения, поэтомуLoaderМожет использоваться для компиляции некоторых файлов, таких какpug → html,sass → css,less → css,es5 → es6,ts → jsЖдать.

Обработка файла может использовать несколькоLoader,LoaderПорядок выполнения и порядок конфигурации меняются местами, то есть конецLoaderСначала выполнить, начатьLoaderНаконец выполнить. первый казненныйLoaderПолучить содержимое исходного файла в качестве параметра, другиеLoaderполучить предыдущее исполнениеLoaderВозвращаемое значение используется как параметр, а последнее выполненноеLoaderБудет возвращен результат преобразования файла. Вкратце в одном предложении:Работник сборочной линии Futu Kang.

LoaderИдеи развития сводятся к следующему:

  • пройти черезmodule.exportsэкспортировать один函数
  • Первый параметр по умолчанию функцииsource(содержимое исходного файла)
  • Ресурсы процесса в теле функции (можно ввести функцию расширения стороннего модуля)
  • пройти черезreturnВозвращает окончательный результат преобразования (в виде строки)
编写Loader时要遵循单一职责原则,每个Loader只做一种转换工作
Plugin

PluginИспользуется для расширения для выполнения более широкого круга задач, автор переводит как扩展器.Pluginширокий ассортимент, вWebpack构建流程Вы можете найти время в качестве точки вставки от начала до конца, пока вы не можете думать об этом, вы не можете этого сделать. Так что я думаю, чтоPluginкоэффициент функцииLoaderболее могущественный.

PluginИмеет следующие характеристики:

  • мониторwebpackСобытия, транслируемые в жизненном цикле среды выполнения
  • проходить в нужное времяwebpackПредоставленный API для изменения результата вывода
  • webpackМеханизм потока событий Tapable обеспечивает упорядоченность плагинов.

существуетwebpackМногие события транслируются в течение жизненного цикла среды выполнения.PluginВы можете слушать эти события и передавать их в нужное времяwebpackПредоставленный API изменяет результат вывода. существуетwebpackПосле запуска выполнить во время чтения конфигурацииnew MyPlugin(opts)инициализация自定义PluginПолучить его экземпляр при инициализацииCompiler对象После этого черезcompiler.hooks.event.tap(PLUGIN_NAME, callback)мониторwebpackШироковещательные события, когда указанное событие будет перехвачено, оно пройдетCompilation对象Управляйте связанной бизнес-логикой. Вкратце в одном предложении:посмотреть на себя.

PluginИдеи развития сводятся к следующему:

  • пройти черезmodule.exportsэкспортировать один函数或类
  • существует函数原型或类привязатьapply()доступCompiler对象
  • существуетapply()указывает привязку кwebpackсобственный хук событий
  • в хуке событий черезwebpackПредоставленные ресурсы обработки API (могут быть введены функции расширения сторонних модулей)
  • пройти черезwebpackПредоставленный метод возвращает этот ресурс
传给每个Plugin的Compiler和Compilation都是同一个引用,若修改它们身上的属性会影响后面的Plugin,所以需谨慎操作
Разница между загрузчиком и плагином
  • Природа
    • LoaderСуть в функции, которая конвертирует полученный контент и возвращает результат конвертации
    • PluginПо сути, класс, который слушаетwebpackЗапускать события, транслируемые в жизненном цикле, и проходить в нужное времяwebpackПредоставленный API для изменения результата вывода
  • настроить
    • Loaderсуществуетmodule.ruleСредняя конфигурация, тип — массив, и каждому элементу соответствует правило разбора модуля.
    • Pluginсуществуетpluginконфигурация, тип — массив, каждый элемент соответствует экземпляру расширителя, а параметры передаются через конструктор

упаковка

анализировать

Из вышеизложенного видно, чтоLoaderа такжеPluginРазличий в позиционировании ролей и механизме исполнения много, как выбрать? У каждого есть свои достоинства, конечно, его еще нужно проанализировать и выбрать.

LoaderсуществуетwebpackОн играет роль преобразователя в модуле, который используется для преобразования исходного кода модуля.Простое понимание состоит в том, чтобы преобразовать файл в другую форму файла, и тема этой статьи压缩图片,jpgЕще после сжатияjpg,pngЕще после сжатияpng, по-прежнему нет изменений в типах файлов.LoaderПроцесс конвертации прилагается повсюдуWebpack构建流程, что означает, что время упаковки включает в себя затраты времени на сжатие изображения.webpackЧто касается оптимизации производительности, то это немного противоречит принципу. а такжеPluginслучается, слушаетwebpackЗапускать события, транслируемые в жизненном цикле, и проходить в нужное времяwebpackПредоставленный API изменяет вывод, поэтому его можно использовать повсюду.Webpack构建流程Операция вставки сжатых картинок после завершения (после вывода всех упакованных файлов). Другими словами, время упаковки больше не включает временные затраты на сжатие картинок.После завершения упаковки вы можете делать то, что можете, и что еще можете делать, сжимать картинки.

Поэтому, в зависимости от потребностей,Pluginкак первый выбор.

кодирование

Согласно вышеизложенномуPluginРазвивайте идеи, а затем начинайте программировать.

Автор поместил это сжатое изображениеPluginпо имениtinyimg-webpack-plugin,tinyimgиметь в видуTinyJpgа такжеTinyPngкомбинированный.

Создайте новый проект со следующей структурой каталогов.

tinyimg-webpack-plugin
├─ src
│  ├─ index.js
│  ├─ schema.json
├─ util
│  ├─ getting.js
│  ├─ setting.js
├─ .gitignore
├─ .npmignore
├─ license
├─ package.json
├─ readme.md

Основные файлы следующие.

  • src
    • index.js: функция входа
    • schema.json: проверка параметров
  • util
    • get.js: постоянная коллекция
    • settings.js: коллекция функций

Установите необходимые модули для проекта, и вышеcompress-imgЗависимости согласованы, дополнительная установкаschema-utilsдля подтвержденияPluginСоответствуют ли параметры требованиям.

npm i chalk figures ora schema-utils trample

Инкапсулирует наборы констант и функций

поставить вышеcompress-imgизTINYIMG_URLа такжеRandomHeader()Инкапсулирован в набор инструментов, где постоянный набор увеличиваетсяIMG_REGEXPа такжеPLUGIN_NAMEдве константы.

// getting.js
const IMG_REGEXP = /\.(jpe?g|png)$/;

const PLUGIN_NAME = "tinyimg-webpack-plugin";

const TINYIMG_URL = [
    "tinyjpg.com",
    "tinypng.com"
];

module.exports = {
    IMG_REGEXP,
    PLUGIN_NAME,
    TINYIMG_URL
};
// setting.js
const { RandomNum } = require("trample/node");

const { TINYIMG_URL } = require("./getting");

function RandomHeader() {
    const ip = new Array(4).fill(0).map(() => parseInt(Math.random() * 255)).join(".");
    const index = RandomNum(0, 1);
    return {
        headers: {
            "Cache-Control": "no-cache",
            "Content-Type": "application/x-www-form-urlencoded",
            "Postman-Token": Date.now(),
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
            "X-Forwarded-For": ip
        },
        hostname: TINYIMG_URL[index],
        method: "POST",
        path: "/web/shrink",
        rejectUnauthorized: false
    };
}

module.exports = {
    RandomHeader
};

пройти черезmodule.exportsЭкспорт функции или класса

// index.js
module.exports = class TinyimgWebpackPlugin {};

существует函数原型或类привязатьapply()доступCompiler对象

// index.js
module.exports = class TinyimgWebpackPlugin {
    apply(compiler) {
        // Do Something
    }
};

существуетapply()указывает привязку кwebpackсобственный хук событий

Из вышеприведенного анализа видно, что операция вставки сжатых картинок после вывода всех упакованных файлов, поэтому следует выбрать обработчик событий, соответствующий этому таймингу. отДокументация API хуков компилятора Webpackможно найти в,emitименно этоPluginОбязательные обработчики событий.emitсуществуетВыполнить перед генерацией ресурсов в выходной каталог, теперь можно получить данные и пути вывода всех файлов изображений.

Для удобства при определенных условиях启用功能а также打印日志, поэтому установите соответствующую конфигурацию.

  • enabled: включить ли функцию
  • logged: распечатывать ли журнал

существуетapply()Бизнес-логика, связанная с процессами, вPluginвходные параметры, то параметры должны быть проверены. определитьPluginизSchema,пройти черезschema-utilsпроверитьPluginввод.

// schema.json
{
    "type": "object",
    "properties": {
        "enabled": {
            "description": "start plugin",
            "type": "boolean"
        },
        "logged": {
            "description": "print log",
            "type": "boolean"
        }
    },
    "additionalProperties": false
}
// index.js
const SchemaUtils = require("schema-utils");

const { PLUGIN_NAME } = require("../util/getting");
const Schema = require("./schema");

module.exports = class TinyimgWebpackPlugin {
    constructor(opts) {
        this.opts = opts;
    }
    apply(compiler) {
        const { enabled } = this.opts;
        SchemaUtils(Schema, this.opts, { name: PLUGIN_NAME });
        enabled && compiler.hooks.emit.tap(PLUGIN_NAME, compilation => {
            // Do Something
        });
    }
};

Интегрироватьcompress-imgприбытьPlugin

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

// index.js
const Fs = require("fs");
const Https = require("https");
const Url = require("url");
const Chalk = require("chalk");
const Figures = require("figures");
const { ByteSize, RoundNum } = require("trample/node");

const { RandomHeader } = require("../util/setting");

module.exports = class TinyimgWebpackPlugin {
    constructor(opts) { ... }
    apply(compiler) { ... }
    async compressImg(assets, path) {
        try {
            const file = assets[path].source();
            const obj = await this.uploadImg(file);
            const data = await this.downloadImg(obj.output.url);
            const oldSize = Chalk.redBright(ByteSize(obj.input.size));
            const newSize = Chalk.greenBright(ByteSize(obj.output.size));
            const ratio = Chalk.blueBright(RoundNum(1 - obj.output.ratio, 2, true));
            const dpath = assets[path].existsAt;
            const msg = `${Figures.tick} Compressed [${Chalk.yellowBright(path)}] completed: Old Size ${oldSize}, New Size ${newSize}, Optimization Ratio ${ratio}`;
            Fs.writeFileSync(dpath, data, "binary");
            return Promise.resolve(msg);
        } catch (err) {
            const msg = `${Figures.cross} Compressed [${Chalk.yellowBright(path)}] failed: ${Chalk.redBright(err)}`;
            return Promise.resolve(msg);
        }
    }
    downloadImg(url) {
        const opts = new Url.URL(url);
        return new Promise((resolve, reject) => {
            const req = Https.request(opts, res => {
                let file = "";
                res.setEncoding("binary");
                res.on("data", chunk => file += chunk);
                res.on("end", () => resolve(file));
            });
            req.on("error", e => reject(e));
            req.end();
        });
    }
    uploadImg(file) {
        const opts = RandomHeader();
        return new Promise((resolve, reject) => {
            const req = Https.request(opts, res => res.on("data", data => {
                const obj = JSON.parse(data.toString());
                obj.error ? reject(obj.message) : resolve(obj);
            }));
            req.write(file, "binary");
            req.on("error", e => reject(e));
            req.end();
        });
    }
};

в хуке событий черезwebpackПредоставляемые ресурсы обработки API

пройти черезcompilation.assetsПолучить объекты всех упакованных файлов, отфильтроватьjpgа такжеpng,использоватьmap()Сопоставьте данные одного изображения какthis.compressImg(file), затем пройтиPromise.all()Просто сделай это.

Вся бизнес-логика объединяетPromiseа такжеAsync/AwaitДве общие фичи ES6, с ними крайне интересно играть в асинхронное программирование вместе, подробнее о них можно прочитать в статье автора4000 лайкова также140 000 просмотровстатья«15 000 слов, описывающих все возможности ES6».

// index.js
const Ora = require("ora");
const SchemaUtils = require("schema-utils");

const { IMG_REGEXP, PLUGIN_NAME } = require("../util/getting");
const Schema = require("./schema");

module.exports = class TinyimgWebpackPlugin {
    constructor(opts) { ... }
    apply(compiler) {
        const { enabled, logged } = this.opts;
        SchemaUtils(Schema, this.opts, { name: PLUGIN_NAME });
        enabled && compiler.hooks.emit.tap(PLUGIN_NAME, compilation => {
            const imgs = Object.keys(compilation.assets).filter(v => IMG_REGEXP.test(v));
            if (!imgs.length) return Promise.resolve();
            const promises = imgs.map(v => this.compressImg(compilation.assets, v));
            const spinner = Ora("Image is compressing......").start();
            return Promise.all(promises).then(res => {
                spinner.stop();
                logged && res.forEach(v => console.log(v));
            });
        });
    }
    async compressImg(assets, path) { ... }
    downloadImg(url) { ... }
    uploadImg(file) { ... }
};

пройти черезwebpackПредоставленный метод возвращает этот ресурс

Поскольку операция сжатия изображений выполняется в целомWebpack构建流程После завершения так возвращать нечего, поэтому и не обрабатывается.

контрольwebpackВерсия зависимости

из-заtinyimg-webpack-pluginна основеwebpack v4, так и должно бытьpackage.jsonдобавлено вpeerDependencies, используемый для сообщения установке, чтоPluginМодуль должен существоватьpeerDependenciesзависимости в.

{
    "peerDependencies": {
        "webpack": ">= 4.0.0",
        "webpack-cli": ">= 3.0.0"
    }
}

Суммировать

На самом деле довольно просто выполнить кодирование шаг за шагом в соответствии с идеями разработки, изложенными выше. Если вам нужно разработать что-то, связанное с вашим собственным проектомPlugin, надо еще ознакомитьсяДокументация API хуков компилятора Webpack, я считаю, что все учащиеся могут сделать идеальноеPluginпублично заявить.

tinyimg-webpack-pluginПожалуйста, нажмите на исходный кодздесьПроверить,StarКак насчет одного, хи-хи.

电眼猪

тестовое задание

весьPluginРазработка завершена, а затем нам нужно пройти процесс тестирования, чтобы увидеть, сможем ли мы поставить это压缩图片的扩展器пробежать. Я считаю, что все студенты соответствуют стандартуWebpack配置工程师, вы можете написать собственную тестовую демонстрацию, чтобы проверитьPlugin.

Создать в корневом каталогеtest文件夹и добавьте файлы в соответствии со следующей структурой каталогов.

tinyimg-webpack-plugin
├─ test
│  ├─ src
│  │  ├─ img
│  │  │  ├─ favicon.ico
│  │  │  ├─ gz.jpg
│  │  │  ├─ pig-1.jpg
│  │  │  ├─ pig-2.jpg
│  │  │  ├─ pig-3.jpg
│  │  ├─ index.html
│  │  ├─ index.js
│  │  ├─ index.scss
│  │  ├─ reset.css
│  └─ webpack.config.js

Установите и протестируйте демо-версиюwebpackсоответствующие модули конфигурации.

npm i -D @babel/core @babel/preset-env babel-loader clean-webpack-plugin css-loader file-loader html-webpack-plugin mini-css-extract-plugin node-sass sass sass-loader style-loader url-loader webpack webpack-cli webpackbar

После завершения установки приступайте к улучшениюwebpack.config.jsКод, количество кода немного велико, просто вставьте ссылку напрямую, пожалуйста, ткнитездесь.

Наконец вpackage.jsonсерединаscriptsвставить следующееnpm scripts, затем выполнитеnpm run testОтладьте и протестируйте демо.

{
    "scripts": {
        "test": "webpack --config test/webpack.config.js"
    }
}

выпускать

Опубликовать вNPM仓库Это очень просто, всего несколько строк команд. Если вы еще не зарегистрированы, перейдите наNPMЗарегистрируйте аккаунт. Если текущее изображение淘宝镜像, нужно выполнитьnpm config set registry https://registry.npmjs.org/Вернитесь к исходному зеркалу.

Следующая волна операций может завершить выпуск.

  • Войдите в каталог:cd my-plugin
  • Вход в учетную запись:npm login
  • Проверь состояние:npm whoami
  • Опубликовать модуль:npm publish
  • Выйти из аккаунта:npm logout

Если вы не хотите запоминать такое количество команд, вы можете использовать разработанную авторомpkg-masterПубликация в один клик. Если есть какие-то ошибки, публикация будет немедленно прервана, и будет отображаться сообщение об ошибке. Это очень простой в использовании инструмент управления модулями NPM, который объединяет создание и публикацию. Для получения подробной информации, пожалуйста, проверьтеДокументация, кстати Звезде за поощрение.

Установить

npm i -g pkg-master

использовать

Заказ Сокращенное название Функция описывать
pkg-master create pkg-master c Создать модуль модуль сборки基础文件
pkg-master publish pkg-master p опубликовать модуль обнаружить нпм运行环境а также账号状态, модуль автоматически освобождается при передаче

发布模块

доступ

Установить

npm i tinyimg-webpack-plugin

использовать

настроить Функция Формат описывать
enabled Включить ли функцию true/false Рекомендуется включать только в производственной среде
logged распечатывать ли журнал true/false распечатать информацию об обработке

существуетwebpack.config.jsилиwebpack配置Вставьте следующий код.

Использование в CommonJS

const TinyimgPlugin = require("tinyimg-webpack-plugin");

module.exports = {
    plugins: [
        new TinyimgPlugin({
            enabled: process.env.NODE_ENV === "production",
            logged: true
        })
    ]
};

Использование в ЕСМ

Должен бытьbabelИспользуется в среде Node по благословению

import TinyimgPlugin from "tinyimg-webpack-plugin";

export default {
    plugins: [
        new TinyimgPlugin({
            enabled: process.env.NODE_ENV === "production",
            logged: true
        })
    ]
};

Рекомендовать готовый каркас сборки React/Vue для автоматизации приложений с нулевой конфигурацией.

bruce-cliЯвляетсяReact/VueАвтоматизация приложений для создания строительных лесов, его преимущество в нулевой конфигурации «из коробки» очень подходит для студентов начального уровня, младших-средних и передовых студентов проектов быстрой разработки.Его также можно использовать при созданииbrucerc.jsфайл, чтобы переопределить его конфигурацию по умолчанию, вам нужно сосредоточиться только на написании бизнес-кода, не обращая внимания на написание кода сборки, что делает структуру проекта более лаконичной. Не забудьте проверить документацию при его использовании и поставить звезду, если вам это нравится.

Конечно, у автораtinyimg-webpack-pluginР Гbruce-cli, с нулевой конфигурацией из коробки.

  • Адрес Github: пожалуйста, отметьтездесь
  • Официальный документ веб-сайта: пожалуйста, нажмитездесь
  • Документация по самородкам: пожалуйста, отметьтездесь

Суммировать

В общем, разработайтеWebpack PluginЭто не сложно, просто хорошо проанализируйте потребности и поймитеwebpackЧтобы запускать события, транслируемые в жизненном цикле, напишите自定义Pluginпроходить в нужное времяwebpackПредоставленный API изменяет результат вывода.

Если ты чувствуешьtinyimg-webpack-pluginчтобы помочь вам, доступны по адресуIssueначальство提出你的宝贵建议, автор внимательно прочитает и объединит ваши предложения. подобноtinyimg-webpack-pluginпожалуйста, дайте одинStar,илиForkэтот проект для себяGithubи настроить функции в соответствии с вашими потребностями.

Эпилог

❤️Подписаться + Нравится + Избранное + Комментарий + Переслать ❤️, оригинальность это не просто, поощряйте автора к созданию более качественных статей

Обратите внимание на общедоступный номерIQ前端, внешний общедоступный аккаунт, ориентированный на навыки разработки CSS / JS, вас ждут другие галантереи переднего плана

  • Ответить после подписки资料Получите бесплатные учебные материалы
  • Ответить после подписки进群Втяните вас в группу технического обмена
  • Добро пожаловать, чтобы следоватьIQ前端,БолееНавыки разработки на CSS/JSНажимайте только на публичный аккаунт