Well, the webpack plugin with a tinypng compressed image is also soeasy

Time:2020-9-28

preface

Once published a performance optimization articleFront end performance optimization guideThe author summarizes some performance optimization experience used in the project development process. To tell you the truth, performance optimization may be useful in the interview process. In fact, few students will pay attention to the details of performance optimization in the process of project development.

If you pay close attention to the topic of performance optimization, you may find thatNo matter how best to optimize the code is not as good as doing a compression of an image。 Therefore, image compression has become the most common operation in performance optimization. Whether it is manual compression or automatic compression, it must be in the process of project development.

Automatic image compression is usually done inwebpackAccess to third parties when building projectsLoader&PluginTo deal with it. openGithub, search elementwebpack imageThe most common keyword is starimage-webpack-loaderandimagemin-webpack-pluginthese two items.Loader&Plugin。 Many students may choose them, convenient, easy to use, no brain access.

But, these twoLoader&PluginThere are some special problems that are based onimageminDeveloped.imageminSome of the dependencies are hosted on foreign servers innpm i xxxThey are installed by defaultGitHub ReleasesIf it is not standard Internet access, you can not install it, even if the standard Internet access is not necessarily installed. So the author published an article about NPM image processingTalk about the dangerous pits in NPM imageTo solve these problems of installation failure due to network environment. In addition to this installation problem,imageminThere is another big problem, that is, the loss of compression texture is more serious, the larger the image volume, the more obvious, there are always a few compressed images are distorted, and the overall compression rate is not very high. In this way, when delivering the project, you may be caught by the careful Miss QA. How can you compare it with the design drawing!

tool

Image compression tool

At this time, some students may have moved to manual compression of pictures. Better use of image compression tools is nothing more than the following several, if there is a better tool to use in the comments to add Oh! At the same time, the author also sorted out their differences for reference.

Well, the webpack plugin with a tinypng compressed image is also soeasy

tool Open Source charge API Free experience
QuickPicture ✖️ ✔️ ✖️ There are more types of compressibility, better compression texture, limited volume and quantity
ShrinkMe ✖️ ✖️ ✖️ There are many types of compressibility, general compression texture, no quantity limitation and volume limitation
Squoosh ✔️ ✖️ ✔️ There are less types of compressibility, general compression texture, no quantity limitation and volume limitation
TinyJpg ✖️ ✔️ ✔️ There are less types of compressibility, good compression texture, limited quantity and volume
TinyPng ✖️ ✔️ ✔️ There are less types of compressibility, good compression texture, limited quantity and volume
Zhitu ✖️ ✖️ ✖️ Compressible type is general, compression texture is general, there are quantitative restrictions, there are volume restrictions

As can be seen from the above table comparison, free experience will existVolume limitationThis is understandable, even if the charge is the same. After all, everyone uploads a single picture of more than 10 meters. Which server can afford it. Then againQuantity limitOnly 20 pieces can be uploaded at a time. It seems that there is a rule. If the compression quality is good, the quantity will be limited. Otherwise, there will be no limit on the number. Of course, there will be no limit after charging. Then againCompressible typeThe image type is generallyjpgpnggifsvgandwebpgifCompression is usually distorted,svgUsually used on vector icons, rarely used in scene images,webpSince compatibility issues are rarely used, they can be compressedjpgandpngThat’s enough. of courseCompression textureIn summary, most students will chooseTinyJpgandTinyPngIn fact, they are brothers from the same manufacturer.

In the official account of the WeChat discussion group launched a simple vote, and ultimatelyTinyJpgandTinyPngWin.

Well, the webpack plugin with a tinypng compressed image is also soeasy

Tinyjpg / tinypng problems
  • Upload and download depend onManual
  • It can only be compressedjpgandpng
  • It can only be compressed at a time20Zhang
  • The maximum volume of each piece cannot exceed5M
  • Visual processing information is not particularly complete
Compression principle of tinyjpg / tinypng

TinyJpg/TinyPngUsing intelligent lossy compression technology to reduce the size of the image, selectively reduce the similar colors in the image, only a few bytes can be saved. The visual impact is almost invisible, but there is a big difference in file size. And useIntelligent lossy compression technologygo by the name ofquantification

TinyJpg/TinyPngIn compressionPNG fileThe effect is more significant. Scan the similar colors in the image and merge them. Reduce the number of colors24 bit PNG fileConvert to smaller ones8-bit PNG fileTo discard all unnecessary metadata.

grossPNG fileAll of them50%~70%Even if the vision is good, it is difficult to distinguish. The use of optimized images can reduce bandwidth traffic and load time. The images used by the whole website areTinyJpg/TinyPngCompression once, the effect is no more code optimization can catch up with.

Well, the webpack plugin with a tinypng compressed image is also soeasy

Tinyjpg / tinypng development API

After consulting relevant information, we found thatTinyJpg/TinyPngFor the time being, it has not yet open source its compression algorithm, but provides an API suitable for developers. Students who are interested in itDevelopment API documentationtake a look.

stayNodeaspect,TinyJpg/TinyPngIt’s officialtinifyAs the core JS Library of compressed images, it is very simple to use. SeefileYeah. However, if you want to develop API, you still can’t escape the charge. Do you want to pay for the month or free? If you want to be free, you can continue to look down. Local tyrants are free!

Well, the webpack plugin with a tinypng compressed image is also soeasy

realization

I also often use itTinyJpg/TinyPngThe procedure ape, charge, that’s impossible. Looking for a breakthrough and solving problems is the most basic quality of a procedural ape.We need to identify what problems we need to solve

analysis

From the above, it is only necessary toTinyJpg/TinyPngThe original function is transformed into the following functions.

  • Automatic upload and download
  • Compressiblejpgandpng
  • There is no quantitative limit
  • There is a volume limit and the maximum volume cannot exceed5M
  • Whether the compression is successful or not, the details are output

Automatic processing

For the front-end developers, this kind of brainless upload and download operation must be automated, easy and labor-saving. But this operation has to be combinedwebpackTo deal with, in the end is to developLoaderstillPluginWe will analyze it later. But careful students to see the title to know what way to deal with.

Compression type

gifCompression is usually distorted,svgUsually used on vector icons, rarely used in scene images,webpSince compatibility issues are rarely used, they can be compressedjpgandpngThat’s enough. When filtering images, usePath moduleDetermine whether the file type isjpgandpngIf yes, continue processing, otherwise do not process.

Quantity limit

Of course, the quantity limit can’t exist. If there are more than 20 pictures in the project, it’s not batch processing by score. This can’t exist. For this kind of website which can process some user files without login status, the number of user operations is usually limited by IP. Some students may say, refresh the page is not on the line, each time compress 20 pictures, and then refresh and compress again, in case there are 500 pictures, you will refresh 25 times, this is very fun, right!

Since most web architectures rarely provide services directly from the application server, they usually set up a layerNginxAs agents and load balancing, some may even have multi-layer agents. Given that most web architectures useNginxAs a reverse proxy, user requests are not directly requested by the application server, but are forwarded to the server through the unified access layer set by nginx. Therefore, the HTTP request header field can be setX-Forwarded-ForTo forge IP.

X-Forwarded-ForUsed to identify passing throughagentorload balancing The HTTP request header field of the most original IP address of the client connecting to the web server. Of course, this IP is not immutable. Each request needs to change the IP randomly to cheat the application server. If the application server adds forged IP identification, it may not be able to continue to use random IP.

Volume limitation

The size limit is understandable. There is no need to make a picture of that size. It wastes bandwidth, traffic and loading time. When uploading images, useFS moduleDetermine whether the file volume exceeds5MIf yes, do not upload, otherwise continue to upload. Of course, give it toTinyJpg/TinyPngInterface judgment is OK.

Output information

Compression success or not to let others know, the output of the original size, compression size, compression ratio and error prompt, let others know the processing information.

code

Through the above analysis, then start coding.

Randomly generate HTTP request header

Since it can be passedX-Forwarded-ForTo forge IP, there must be a function that randomly generates HTTP request header fields. Each time an interface is requested, the relevant request header fields are generated randomly. opentinyjpg.comortinypng.comUpload a picture and passChrome DevToolsanalysisNetworkThe request interface is found to beweb/shrink。 Also, don’t focus on a single requesthostnameGo ahead and distribute them randomlytinyjpg.comortinypng.comIt will be better. By encapsulationRandomHeaderThe function generates the request header information randomly and uses it laterHTTPS modulewithRandomHeader()The generated configuration is requested as an input parameter.

trampleIt is one developed by the authorWeb/NodeGeneral function tool library, including conventional tool functions, to help you write less general code. Please check for detailsfileBy the way, give a star encouragement.

Well, the webpack plugin with a tinypng compressed image is also soeasy

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
    };
}

Upload and download pictures

usePromiseencapsulationUpload picturesandDownload picturesFunction, convenient for subsequent useAsync/AwaitSynchronize asynchronous code. The following function of the specific breakpoint debugging will not say, interested students to debug the function of the input and output parameters ha!

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();
    });
}

Compress picture

adoptUpload picturesFunction to obtain the compressed image information, and then according to the image information throughDownload picturesFunction generates a local file.

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);
    }
}

Compress target image

After completing the function corresponding to the above steps, you can compress the image freely. Here we use an image as a demonstration.

const Ora = require("ora");

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

You see, after compression, stupid pigs become handsome pigs. Pigs that can blink are good pigs. Please check the source codecompress-img

Well, the webpack plugin with a tinypng compressed image is also soeasy

If you want to compress all the images in the specified folder, you can clickFS moduleGet and use imagesmap()Map a single image path toCompressImg(path), and then passPromise.all()Operation is enough. Do not post the code here, as a thinking question, complete by yourself.

Encapsulate the function of the above compressed picture intoLoaderstillPluginWhat about it? Next, we will analyze it step by step.

Loader&Plugin

webpackIs a front-end resource packaging tool, it carries on the static analysis according to the module dependency, and then generates the corresponding static resources according to the specified rules.

There’s a lot onlinewebpackThe course, the author will no longer spend a lot of lengthy, I believe that all students are a standardWebpack configuration engineer。 Here is a brief reviewwebpackIt is believed that the composition, construction mechanism and process of construction can also be located from these knowledge pointsLoaderandPluginstayWebpack construction processWhat kind of role does China play.

The webpack mentioned in this paper is based on webpack v4

form

  • Entry: entrance
  • Output: output
  • Loader: converter
  • Plugin: extender
  • Mode: mode
  • Module: module
  • Target: target

Construction mechanism

  • Convert the code through Babel and generate a single file dependency
  • Recursively analyze and generate dependency graph from the entry file
  • Package each reference module into an immediate function
  • Write the final bundle file tobundle.jsin

Build process

  • initial

    • Initial parameters: merge command line and configuration file parameters
  • compile

    • Perform compilation: initial according to parametersCompiler object, load allPlugin, executerun()
    • Determine the entrance: find all the entry files according to the configuration file
    • Compiling module: find out all dependent module relationships according to the entry file and call allLoaderMake the conversion
    • Generative map: get the transformed content of each module and its dependency
  • output

    • Output resourcesModules are assembled into blocks and then into packages according to dependency relationship(module → chunk → bundle)
    • Generating files: write the confirmation output to the file system according to the configuration file
Loader

LoaderFor conversion module source code, the author translated it intoconverterLoaderAll types of files can be converted towebpackCan handle the valid module, and then use thewebpackThe ability to package them again.

LoaderIt has the following characteristics:

  • Single responsibility principle(Only one conversion is completed)
  • Convert received content
  • Return conversion result
  • Support chain call

LoaderConvert all types of files into modules that can be referenced directly by the application’s dependency graph, soLoaderCan be used to compile some files, such aspug → htmlsass → cssless → csses5 → es6ts → jsEtc.

Processing a file can use more than oneLoaderLoaderThe execution order and configuration order of are opposite, namely the endLoaderFirst, firstLoaderFinally, the implementation. First implementedLoaderReceive the contents of the source file as parameters, and othersLoaderReceive previous executedLoaderThe return value of is used as a parameterLoaderThe conversion result of the file is returned. In a word:Ftukang assembly line factory worker

LoaderThe development ideas are summarized as follows:

  • adoptmodule.exportsExport afunction
  • The first default parameter of the function issource(source file content)
  • Processing resources in function body (third party module extension function can be introduced)
  • adoptreturnReturns the final conversion result (in string)
When writing loaders, the principle of single responsibility should be followed, and each loader should only do one transformation
Plugin

PluginTo expand the scope of the implementation of the task, the author translated it intoExtenderPluginIt’s a wide range, in theWebpack construction processFrom the beginning to the end, you can find the opportunity as the insertion point, as long as you can’t think of it without you. So the author thinks thatPluginFunction ratio ofLoaderMore powerful.

PluginIt has the following characteristics:

  • monitorwebpackRun events broadcast in the lifecycle
  • Pass at the right timewebpackThe provided API changes the output
  • webpackThe tapable event flow mechanism of plugins ensures the order of plugins

staywebpackMany events are broadcast during the operation life cycle,PluginThese events can be monitored and passed at the appropriate timewebpackThe API provided changes the output. staywebpackAfter startup, it is executed during the read configuration processnew MyPlugin(opts)initializationCustom pluginGet its instance and initialize theCompiler objectAfter that, it was passedcompiler.hooks.event.tap(PLUGIN_NAME, callback)monitorwebpackBroadcast event, when the specified event is caught, theCompilation objectOperation related business logic. In a word:Do it yourself

PluginThe development ideas are summarized as follows:

  • adoptmodule.exportsExport aFunction or class
  • stayFunction prototype or classUpper boundapply()visitCompiler object
  • stayapply()Specifies a binding to thewebpackOwn event hook
  • Through the event hookwebpackAPI processing resources provided (third party module extension function can be introduced)
  • adoptwebpackThe method provided returns the resource
The compiler and compilation passed to each plugin are the same reference. Modifying their properties will affect the subsequent plugins, so be careful
Loader / plugin differences
  • essence

    • LoaderIn essence, it is a function that converts the received content and returns the conversion result
    • PluginEssentially a class, listeningwebpackEvents broadcast in the operational life cycle pass at the appropriate timewebpackThe provided API changes the output
  • to configure

    • Loaderstaymodule.ruleEach item corresponds to a module parsing rule
    • PluginstaypluginThe type is an array. Each item corresponds to an extender instance, and the parameters are passed in through the constructor

encapsulation

analysis

It can be seen from the aboveLoaderandPluginThere are many differences in role orientation and execution mechanism. How to choose? Each has its own advantages. Of course, it still needs to be analyzed and selected.

LoaderstaywebpackPlay the role of converter, used to convert module source code, simple understanding is to convert the file into another form of file, and the theme of this article isCompress picturejpgAfter compression orjpgpngAfter compression orpngIn terms of file type, there is still no change.LoaderThe conversion process is attached to the whole processWebpack construction processIt means that the packing time includes the time cost of compressing pictureswebpackPerformance optimization is a bit against the principle. andPluginIt happens to be listeningwebpackEvents broadcast in the operational life cycle pass at the appropriate timewebpackThe API provided changes the output result, so it can be used in theWebpack construction processThe operation of inserting compressed pictures after the completion of the output of all packed files. In other words, the packaging time no longer includes the time cost of compressed images. After packaging, you can do what you want to do, what else you can do, compress pictures.

So according to the demand,PluginAs the first choice.

code

Based on the abovePluginDevelopment ideas, then start coding.

The author of this compressed imagePluginNamedtinyimg-webpack-plugintinyimgsignifyTinyJpgandTinyPngSyncytium.

Create a new project with the following directory structure.

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

The main documents are as follows.

  • src

    • index.js : entry function
    • schema.json : parameter verification
  • util

    • getting.js : collection of constants
    • setting.js : function collection

Modules required for the installation project, and the abovecompress-imgDependency consistency, additional installationschema-utilsFor verificationPluginWhether the parameters meet the requirements.

npm i chalk figures ora schema-utils trample

Encapsulates the set of constants and functions

Add the abovecompress-imgOfTINYIMG_URLandRandomHeader()Encapsulate to the tool collection, where the constant set is increasedIMG_REGEXPandPLUGIN_NAMETwo constants.

// 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
};

adoptmodule.exportsExport a function or class

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

stayFunction prototype or classUpper boundapply()visitCompiler object

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

stayapply()Specifies a binding to thewebpackOwn event hook

From the above analysis, it can be seen that the operation of inserting compressed pictures after the output of all packaged files is completed, so the event hook corresponding to the time should be selected. fromWebpack compiler hooks API documentationIt can be found in,emitThis is itPluginRequired event hook.emitstayExecute before generating resources to output directoryAt this moment, the data and output path of all image files can be obtained.

For convenience under specific conditionsEnable functionandPrint log, so set the relevant configuration.

  • enabled: enable feature
  • logged: print log

stayapply()Processing related business logic in thePluginThe parameter must be checked. Define aPluginOfSchema, throughschema-utilsTo verifyPluginThe input parameters of.

// 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
        });
    }
};

integrationcompress-imgreachPlugin

In the process of integration, there will be some small changes. Students can compare and see what details have changed.

// 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();
        });
    }
};

Through the event hookwebpackAPI processing resources provided

adoptcompilation.assetsGet the objects of all package files and filter outjpgandpng, usingmap()Map single image data tothis.compressImg(file), and then passPromise.all()Operation is enough.

It combines the whole business logicPromiseandAsync/AwaitTwo common features of ES6, it’s very interesting to combine them to play asynchronous programming. For more details, please refer to this article4000 likesand140000 readingArticle“15000 words to summarize all features of 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) { ... }
};

adoptwebpackThe method provided returns the resource

Because the compressed image operation is in the wholeWebpack construction processAfter completion, there is nothing to return, so it is not processed.

controlwebpackDependent version

becausetinyimg-webpack-pluginbe based onwebpack v4, so you need topackage.jsonAddpeerDependenciesTo inform the installation of thePluginThe module for must existpeerDependenciesThe dependence in.

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

summary

According to the above summary of development ideas to complete the coding step by step, in fact, it is quite simple. If you need to develop something related to your own projectPluginStill need to be familiar withWebpack compiler hooks API documentationI believe all of you can poke a perfect onePluginCome out.

tinyimg-webpack-pluginPlease stamp the source codeheresee,StarHow about one, hee hee.

Well, the webpack plugin with a tinypng compressed image is also soeasy

test

wholePluginAfter the development is completed, we need to go through the test process to see if we can put this into practiceExpander for compressed picturesRun through. I believe you are a standardWebpack configuration engineerYou can write your own test demo to verify yourPlugin

Create in rootTest folderAnd add files according to the following directory structure.

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

Install thewebpackRelated configuration module.

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

After installation, start to improvewebpack.config.jsCode, code a little bit more, direct paste link good, please stamphere

At the end of the daypackage.jsonMediumscriptsInsert the followingnpm scripts, and then executenpm run testDebug test demo.

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

release

Publish toNPM warehouseIt’s very simple, just a few lines of command. If you haven’t registered, go aheadNPMSign up for an account on. If the current image isTaobao image, need to be executednpm config set registry https://registry.npmjs.org/Switch back to the source.

The next wave of operations will complete the release.

  • Enter the directory:cd my-plugin
  • Login account:npm login
  • Calibration status:npm whoami
  • Release module:npm publish
  • Exit account:npm logout

If you don’t want to remember so many commands, you can use the author’s developmentpkg-masterOne click release, if there are some errors, it will immediately interrupt the release and prompt the error message. It is a very easy to use NPM module management tool for integrated creation and release. Please check for detailsfileBy the way, give a star encouragement.

install

npm i -g pkg-master

use

command abbreviation function describe
pkg-master create pkg-master c Create module Generating module’sBasic documents
pkg-master publish pkg-master p Release module Detection of NPMOperating environmentandAccount statusThe module will be published automatically if it passes

Well, the webpack plugin with a tinypng compressed image is also soeasy

Access

install

npm i tinyimg-webpack-plugin

use

to configure function format describe
enabled Is the feature enabled true/false It is recommended to open only in production environment
logged Print log true/false Print processing information

staywebpack.config.jsorWebpack configurationInsert the following code.

Using in commonjs

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

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

Using in ESM

Must be inbabelUsed in node environment under blessing

import TinyimgPlugin from "tinyimg-webpack-plugin";

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

Recommend a zero configuration out of the box react / Vue application to build scaffold automatically

bruce-cliIt’s aReact/VueThe application of automation construction scaffold, its zero configuration out of the box advantages, very suitable for entry-level, junior high school, rapid development project front-end students to use, but also through the creationbrucerc.jsFile to cover the default configuration, only focus on the writing of business code, not the construction code, so that the project structure is more concise. Remember to check the document when you use it, and give a star if you like.

Of course, the author hastinyimg-webpack-pluginIntegration intobruce-cliZero configuration is out of the box.

  • GitHub address: Please stamphere
  • Official website document: Please stamphere
  • Gold digging documents: Please stamphere

summary

In general, develop aWebpack PluginIt’s not difficult. Just analyze the needs and understandwebpackRun events broadcast in the life cycle, writeCustom pluginPass at the right timewebpackThe API provided changes the output.

If you feel thattinyimg-webpack-pluginIt’s helpful for you, but you canIssueupperGive your valuable adviceI will carefully read and integrate your suggestions. liketinyimg-webpack-pluginPlease give me oneStar, orForkThis project to their ownGithubOn, according to their own needs to customize the function.

Recommended Today

Explain idea git branch backoff specified historical version

scene When I submitted this modification to the local and remote branches, I found that there were still some changes missing in this submission, or this modification was totally wrong, but I also pushed it to the remote repository. How to go back? problem How can the content that has been submitted to the repository […]