UNPKG

7.14 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _path = _interopRequireDefault(require("path"));
9
10var _os = _interopRequireDefault(require("os"));
11
12var _pLimit = _interopRequireDefault(require("p-limit"));
13
14var _schemaUtils = require("schema-utils");
15
16var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
17
18var _minify = _interopRequireDefault(require("./minify"));
19
20var _interpolateName = _interopRequireDefault(require("./utils/interpolate-name"));
21
22var _pluginOptions = _interopRequireDefault(require("./plugin-options.json"));
23
24function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25
26class 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); // Skip double minimize assets from child compilation
67
68 if (info.minimized) {
69 return false;
70 }
71
72 if (!compiler.webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
73 undefined, this.options)(name)) {
74 return false;
75 } // Exclude already optimized assets from `image-minimizer-webpack-loader`
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 // Collect assets from modules
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
263ImageMinimizerPlugin.loader = require.resolve('./loader');
264ImageMinimizerPlugin.normalizeConfig = require('./utils/normalize-config').default;
265var _default = ImageMinimizerPlugin;
266exports.default = _default;
\No newline at end of file