1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.default = void 0;
|
7 |
|
8 | var _path = _interopRequireDefault(require("path"));
|
9 |
|
10 | var _os = _interopRequireDefault(require("os"));
|
11 |
|
12 | var _pLimit = _interopRequireDefault(require("p-limit"));
|
13 |
|
14 | var _schemaUtils = require("schema-utils");
|
15 |
|
16 | var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
|
17 |
|
18 | var _minify = _interopRequireDefault(require("./minify"));
|
19 |
|
20 | var _interpolateName = _interopRequireDefault(require("./utils/interpolate-name"));
|
21 |
|
22 | var _pluginOptions = _interopRequireDefault(require("./plugin-options.json"));
|
23 |
|
24 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
25 |
|
26 | class ImageMinimizerPlugin {
|
27 | constructor(options = {}) {
|
28 | (0, _schemaUtils.validate)(_pluginOptions.default, options, {
|
29 | name: 'Image Minimizer Plugin',
|
30 | baseDataPath: 'options'
|
31 | });
|
32 | const {
|
33 | filter = () => true,
|
34 | test = /\.(jpe?g|png|gif|tif|webp|svg|avif)$/i,
|
35 | include,
|
36 | exclude,
|
37 | severityError,
|
38 | minimizerOptions = {
|
39 | plugins: []
|
40 | },
|
41 | loader = true,
|
42 | maxConcurrency,
|
43 | filename = '[path][name][ext]',
|
44 | deleteOriginalAssets = false
|
45 | } = options;
|
46 | this.options = {
|
47 | severityError,
|
48 | filter,
|
49 | exclude,
|
50 | minimizerOptions,
|
51 | include,
|
52 | loader,
|
53 | maxConcurrency,
|
54 | test,
|
55 | filename,
|
56 | deleteOriginalAssets
|
57 | };
|
58 | }
|
59 |
|
60 | async optimize(compiler, compilation, assets, moduleAssets) {
|
61 | const cache = compilation.getCache('ImageMinimizerWebpackPlugin');
|
62 | const assetsForMinify = await Promise.all(Object.keys(assets).filter(name => {
|
63 | const {
|
64 | info,
|
65 | source
|
66 | } = compilation.getAsset(name);
|
67 |
|
68 | if (info.minimized) {
|
69 | return false;
|
70 | }
|
71 |
|
72 | if (!compiler.webpack.ModuleFilenameHelpers.matchObject.bind(
|
73 | undefined, this.options)(name)) {
|
74 | return false;
|
75 | }
|
76 |
|
77 |
|
78 | if (this.options.loader && moduleAssets.has(name)) {
|
79 | return false;
|
80 | }
|
81 |
|
82 | const input = source.source();
|
83 |
|
84 | if (this.options.filter && !this.options.filter(input, name)) {
|
85 | return false;
|
86 | }
|
87 |
|
88 | return true;
|
89 | }).map(async name => {
|
90 | const {
|
91 | info,
|
92 | source
|
93 | } = compilation.getAsset(name);
|
94 | const cacheName = (0, _serializeJavascript.default)({
|
95 | name,
|
96 | minimizerOptions: this.options.minimizerOptions
|
97 | });
|
98 | const eTag = cache.getLazyHashedEtag(source);
|
99 | const cacheItem = cache.getItemCache(cacheName, eTag);
|
100 | const output = await cacheItem.getPromise();
|
101 | return {
|
102 | name,
|
103 | info,
|
104 | inputSource: source,
|
105 | output,
|
106 | cacheItem
|
107 | };
|
108 | }));
|
109 | const cpus = _os.default.cpus() || {
|
110 | length: 1
|
111 | };
|
112 | const limit = (0, _pLimit.default)(this.options.maxConcurrency || Math.max(1, cpus.length - 1));
|
113 | const {
|
114 | RawSource
|
115 | } = compiler.webpack.sources;
|
116 | const scheduledTasks = [];
|
117 |
|
118 | for (const asset of assetsForMinify) {
|
119 | scheduledTasks.push(limit(async () => {
|
120 | const {
|
121 | name,
|
122 | inputSource,
|
123 | cacheItem,
|
124 | info
|
125 | } = asset;
|
126 | let {
|
127 | output
|
128 | } = asset;
|
129 | let input;
|
130 | const sourceFromInputSource = inputSource.source();
|
131 |
|
132 | if (!output) {
|
133 | input = sourceFromInputSource;
|
134 |
|
135 | if (!Buffer.isBuffer(input)) {
|
136 | input = Buffer.from(input);
|
137 | }
|
138 |
|
139 | const {
|
140 | severityError,
|
141 | isProductionMode,
|
142 | minimizerOptions
|
143 | } = this.options;
|
144 | const minifyOptions = {
|
145 | filename: name,
|
146 | input,
|
147 | severityError,
|
148 | isProductionMode,
|
149 | minimizerOptions
|
150 | };
|
151 | output = await (0, _minify.default)(minifyOptions);
|
152 |
|
153 | if (output.errors.length > 0) {
|
154 | output.errors.forEach(error => {
|
155 | compilation.errors.push(error);
|
156 | });
|
157 | return;
|
158 | }
|
159 |
|
160 | output.source = new RawSource(output.output);
|
161 | await cacheItem.storePromise({
|
162 | source: output.source,
|
163 | warnings: output.warnings
|
164 | });
|
165 | }
|
166 |
|
167 | const {
|
168 | source,
|
169 | warnings
|
170 | } = output;
|
171 |
|
172 | if (warnings && warnings.length > 0) {
|
173 | warnings.forEach(warning => {
|
174 | compilation.warnings.push(warning);
|
175 | });
|
176 | }
|
177 |
|
178 | const newName = (0, _interpolateName.default)(name, this.options.filename);
|
179 | const isNewAsset = name !== newName;
|
180 |
|
181 | if (isNewAsset) {
|
182 | const newInfo = {
|
183 | related: {
|
184 | minimized: newName,
|
185 | ...info.related
|
186 | },
|
187 | minimized: true
|
188 | };
|
189 | compilation.emitAsset(newName, source, newInfo);
|
190 |
|
191 | if (this.options.deleteOriginalAssets) {
|
192 | compilation.deleteAsset(name);
|
193 | }
|
194 | } else {
|
195 | const updatedAssetsInfo = {
|
196 | minimized: true
|
197 | };
|
198 | compilation.updateAsset(name, source, updatedAssetsInfo);
|
199 | }
|
200 | }));
|
201 | }
|
202 |
|
203 | await Promise.all(scheduledTasks);
|
204 | }
|
205 |
|
206 | apply(compiler) {
|
207 | this.options.isProductionMode = compiler.options.mode === 'production' || !compiler.options.mode;
|
208 | const pluginName = this.constructor.name;
|
209 | const moduleAssets = new Set();
|
210 |
|
211 | if (this.options.loader) {
|
212 |
|
213 | compiler.hooks.compilation.tap({
|
214 | name: pluginName
|
215 | }, compilation => {
|
216 | compilation.hooks.moduleAsset.tap({
|
217 | name: pluginName
|
218 | }, (module, file) => {
|
219 | moduleAssets.add(file);
|
220 | });
|
221 | });
|
222 | compiler.hooks.afterPlugins.tap({
|
223 | name: pluginName
|
224 | }, () => {
|
225 | const {
|
226 | filename,
|
227 | deleteOriginalAssets,
|
228 | filter,
|
229 | test,
|
230 | include,
|
231 | exclude,
|
232 | severityError,
|
233 | minimizerOptions
|
234 | } = this.options;
|
235 | const loader = {
|
236 | test,
|
237 | include,
|
238 | exclude,
|
239 | enforce: 'pre',
|
240 | loader: _path.default.join(__dirname, 'loader.js'),
|
241 | options: {
|
242 | filename,
|
243 | deleteOriginalAssets,
|
244 | severityError,
|
245 | filter,
|
246 | minimizerOptions
|
247 | }
|
248 | };
|
249 | compiler.options.module.rules.push(loader);
|
250 | });
|
251 | }
|
252 |
|
253 | compiler.hooks.compilation.tap(pluginName, compilation => {
|
254 | compilation.hooks.processAssets.tapPromise({
|
255 | name: pluginName,
|
256 | stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE
|
257 | }, assets => this.optimize(compiler, compilation, assets, moduleAssets));
|
258 | });
|
259 | }
|
260 |
|
261 | }
|
262 |
|
263 | ImageMinimizerPlugin.loader = require.resolve('./loader');
|
264 | ImageMinimizerPlugin.normalizeConfig = require('./utils/normalize-config').default;
|
265 | var _default = ImageMinimizerPlugin;
|
266 | exports.default = _default; |
\ | No newline at end of file |