├── .gitattributes
├── .gitignore
├── .npmignore
├── license
├── package.json
├── readme.md
├── src
├── index.js
└── util.js
└── 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
/.gitattributes:
--------------------------------------------------------------------------------
1 | * linguist-language=javascript
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist
3 | node_modules
4 | package-lock.json
5 | yarn.lock
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist
3 | node_modules
4 | package-lock.json
5 | yarn.lock
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020-present, Joway Young, https://github.com/JowayYoung
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tinyimg-webpack-plugin",
3 | "version": "0.1.0",
4 | "description": "A Webpack Plugin For Compressing Image",
5 | "keywords": [
6 | "tinyimg-webpack-plugin",
7 | "tiny",
8 | "tinyimg",
9 | "tinyjpg",
10 | "tinypng",
11 | "webpack",
12 | "plugin",
13 | "minimizer",
14 | "compress",
15 | "image",
16 | "img",
17 | "jpg",
18 | "png"
19 | ],
20 | "author": {
21 | "name": "JowayYoung",
22 | "phone": "18819249731",
23 | "email": "young.joway@aliyun.com"
24 | },
25 | "homepage": "https://github.com/JowayYoung",
26 | "repository": {
27 | "type": "git",
28 | "url": "https://github.com/JowayYoung/tinyimg-webpack-plugin"
29 | },
30 | "license": "MIT",
31 | "type": "module",
32 | "main": "src/index.js",
33 | "scripts": {
34 | "remove": "rimraf node_modules package-lock.json yarn.lock",
35 | "test": "webpack --config test/webpack.config.js"
36 | },
37 | "engines": {
38 | "node": ">=16.0.0",
39 | "npm": ">=7.10.0"
40 | },
41 | "dependencies": {
42 | "chalk": "5.0.0",
43 | "figures": "4.0.0",
44 | "schema-utils": "4.0.0",
45 | "trample": "0.4.0"
46 | },
47 | "devDependencies": {
48 | "@babel/core": "7.16.10",
49 | "@babel/preset-env": "7.16.11",
50 | "babel-loader": "8.2.3",
51 | "clean-webpack-plugin": "4.0.0",
52 | "css-loader": "6.5.1",
53 | "html-webpack-plugin": "5.5.0",
54 | "mini-css-extract-plugin": "2.5.2",
55 | "sass": "1.49.0",
56 | "sass-loader": "12.4.0",
57 | "webpack": "5.67.0",
58 | "webpack-cli": "4.9.1",
59 | "webpackbar": "5.0.2"
60 | },
61 | "peerDependencies": {
62 | "webpack": ">=5.0.0",
63 | "webpack-cli": ">=4.0.0"
64 | }
65 | }
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Tinyimg Webpack Plugin
2 |
3 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
4 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
5 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
6 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
7 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
8 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
9 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
10 | [](https://github.com/JowayYoung/tinyimg-webpack-plugin)
11 |
12 | > `tinyimg-webpack-plugin`是一个压缩图像的Webpack扩展器,提供**JPG**与**PNG**的压缩功能
13 |
14 | ### 安装
15 |
16 | - 使用**NPM**安装:`npm i tinyimg-webpack-plugin`
17 | - 使用**Yarn**安装:`yarn add tinyimg-webpack-plugin`
18 |
19 | > 安装准备
20 |
21 | - 提前安装`webpack`与`webpack-cli`:`npm i webpack webpack-cli`
22 | - 必须依赖`webpack v5`与`webpack-cli v4`
23 |
24 | > 安装失败
25 |
26 | - 切换**NPM镜像**为淘宝镜像:`npm config set registry https://registry.npm.taobao.org/`
27 | - 重新执行安装命令:`npm i tinyimg-webpack-plugin`
28 |
29 | > 兼容版本
30 |
31 | - ⚠️ 若需兼容`webpack v4`请安装`tinyimg-webpack-plugin@0.0.6`
32 |
33 | ### 使用
34 |
35 | ⚠️ 建议只在生产环境下使用
36 |
37 | 配置|功能|取值|默认|描述
38 | :-:|:-:|:-:|:-:|-
39 | `logged`|打印日志|`Boolean`|`false`|打印压缩图像相关信息
40 |
41 | ```js
42 | import TinyimgPlugin from "tinyimg-webpack-plugin";
43 |
44 | export default {
45 | // 其他Webpack配置
46 | plugins: [
47 | new TinyimgPlugin({ logged: true })
48 | ]
49 | };
50 | ```
51 |
52 | ### 版权
53 |
54 | MIT © [JowayYoung](https://github.com/JowayYoung)
55 |
56 | ### 后记
57 |
58 | **关注公众号`IQ前端`,一个专注于CSS/JS开发技巧的前端公众号,更多前端小干货等着你喔**
59 |
60 | 
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { request } from "https";
2 | import { URL } from "url";
3 | import Chalk from "chalk";
4 | import Figures from "figures";
5 | import { validate } from "schema-utils";
6 | import { ByteSize, RoundNum } from "trample/dist/node.js";
7 | import Webpack from "webpack";
8 |
9 | import { IMG_REGEXP, OPTS_SCHEMA, PLUGIN_NAME, RandomHeader } from "./util.js";
10 |
11 | const { blueBright, greenBright, redBright, yellowBright } = Chalk;
12 | const { cross, tick } = Figures;
13 | const { Compilation, sources } = Webpack;
14 |
15 | export default class TinyimgWebpackPlugin {
16 | constructor(opts = {}) {
17 | this.opts = opts;
18 | validate(OPTS_SCHEMA, opts, { name: PLUGIN_NAME });
19 | }
20 | apply(compiler) {
21 | const { logged } = this.opts;
22 | // DEP_WEBPACK_COMPILATION_ASSETS
23 | // https://juejin.cn/post/6953259412651769869
24 | // https://juejin.cn/post/7011025053013770270
25 | // https://juejin.cn/post/7013995927874568206
26 | compiler.hooks.thisCompilation.tap(PLUGIN_NAME, compilation => {
27 | const opts = {
28 | name: PLUGIN_NAME,
29 | stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
30 | };
31 | compilation.hooks.processAssets.tapPromise(opts, assets => {
32 | const imgs = Object.keys(assets).filter(v => IMG_REGEXP.test(v));
33 | if (!imgs.length) return Promise.resolve();
34 | const promises = imgs.map(v => this.compressImg(assets, v));
35 | return Promise.all(promises).then(res => logged && res.forEach((v, i) => console.log(i < res.length - 1 ? v : `${v}\n`)));
36 | });
37 | });
38 | }
39 | async compressImg(assets = null, path = "") {
40 | try {
41 | const file = assets[path].source();
42 | const obj = await this.uploadImg(file);
43 | const data = await this.downloadImg(obj.output.url);
44 | const oldSize = redBright(ByteSize(obj.input.size));
45 | const newSize = greenBright(ByteSize(obj.output.size));
46 | const ratio = blueBright(RoundNum(1 - obj.output.ratio, 2, true));
47 | const msg = `${tick} Compressed [${yellowBright(path)}] succeeded: Old Size ${oldSize}, New Size ${newSize}, Optimization Ratio ${ratio}`;
48 | assets[path] = new sources.RawSource(Buffer.alloc(data.length, data, "binary"));
49 | return Promise.resolve(msg);
50 | } catch (err) {
51 | const msg = `${cross} Compressed [${yellowBright(path)}] failed: ${redBright(err)}`;
52 | return Promise.resolve(msg);
53 | }
54 | }
55 | downloadImg(url) {
56 | const opts = new URL(url);
57 | return new Promise((resolve, reject) => {
58 | const req = request(opts, res => {
59 | let file = "";
60 | res.setEncoding("binary");
61 | res.on("data", chunk => file += chunk);
62 | res.on("end", () => resolve(file));
63 | });
64 | req.on("error", e => reject(e));
65 | req.end();
66 | });
67 | }
68 | uploadImg(file) {
69 | const opts = RandomHeader();
70 | return new Promise((resolve, reject) => {
71 | const req = request(opts, res => res.on("data", data => {
72 | const obj = JSON.parse(data.toString());
73 | obj.error ? reject(obj.message) : resolve(obj);
74 | }));
75 | req.write(file, "binary");
76 | req.on("error", e => reject(e));
77 | req.end();
78 | });
79 | }
80 | };
--------------------------------------------------------------------------------
/src/util.js:
--------------------------------------------------------------------------------
1 | import { RandomNum } from "trample/dist/node.js";
2 |
3 | const IMG_REGEXP = /\.(jpe?g|png)$/;
4 |
5 | const OPTS_SCHEMA = {
6 | additionalProperties: false,
7 | properties: {
8 | logged: {
9 | description: "Print Log",
10 | type: "boolean"
11 | }
12 | },
13 | type: "object"
14 | };
15 |
16 | const PLUGIN_NAME = "tinyimg-webpack-plugin";
17 |
18 | const TINYIMG_URL = [
19 | "tinyjpg.com",
20 | "tinypng.com"
21 | ];
22 |
23 | function RandomHeader() {
24 | const ip = new Array(4).fill(0).map(() => parseInt(Math.random() * 255)).join(".");
25 | const index = RandomNum(0, 1);
26 | return {
27 | headers: {
28 | "Cache-Control": "no-cache",
29 | "Content-Type": "application/x-www-form-urlencoded",
30 | "Postman-Token": Date.now(),
31 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36",
32 | "X-Forwarded-For": ip
33 | },
34 | hostname: TINYIMG_URL[index],
35 | method: "POST",
36 | path: "/web/shrink",
37 | rejectUnauthorized: false
38 | };
39 | }
40 |
41 | export {
42 | IMG_REGEXP,
43 | OPTS_SCHEMA,
44 | PLUGIN_NAME,
45 | TINYIMG_URL,
46 | RandomHeader
47 | };
--------------------------------------------------------------------------------
/test/src/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JowayYoung/tinyimg-webpack-plugin/6d9db897042cce66574e0b5a66786c76bd675c79/test/src/img/favicon.ico
--------------------------------------------------------------------------------
/test/src/img/gz.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JowayYoung/tinyimg-webpack-plugin/6d9db897042cce66574e0b5a66786c76bd675c79/test/src/img/gz.jpg
--------------------------------------------------------------------------------
/test/src/img/pig-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JowayYoung/tinyimg-webpack-plugin/6d9db897042cce66574e0b5a66786c76bd675c79/test/src/img/pig-1.jpg
--------------------------------------------------------------------------------
/test/src/img/pig-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JowayYoung/tinyimg-webpack-plugin/6d9db897042cce66574e0b5a66786c76bd675c79/test/src/img/pig-2.jpg
--------------------------------------------------------------------------------
/test/src/img/pig-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JowayYoung/tinyimg-webpack-plugin/6d9db897042cce66574e0b5a66786c76bd675c79/test/src/img/pig-3.jpg
--------------------------------------------------------------------------------
/test/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |