UNPKG

rsbuild-plugin-sharp-image-optimizer

Version:

A Rsbuild plugin for image optimization using Sharp

132 lines (131 loc) 6.92 kB
import * as __WEBPACK_EXTERNAL_MODULE_sharp__ from "sharp"; import * as __WEBPACK_EXTERNAL_MODULE_path__ from "path"; class SharpImageOptimizerPlugin { async optimize(compiler, compilation, assets) { let { RawSource } = compiler.webpack.sources, processedAssets = new Map(); for (let [name, asset] of Object.entries(assets)){ if (!!this.options.test.test(name)) try { let outputBuffer; let inputBuffer = asset.source(), ext = __WEBPACK_EXTERNAL_MODULE_path__.default.extname(name).toLowerCase(), originalFormat = ext.slice(1), sharpInstance = (0, __WEBPACK_EXTERNAL_MODULE_sharp__.default)(inputBuffer), newName = name; if (this.options.format && this.options.format !== originalFormat && !('jpg' === this.options.format && 'jpeg' === originalFormat) && !('jpeg' === this.options.format && 'jpg' === originalFormat)) { var _compilation_getAsset; switch(newName = name.replace(ext, `.${this.options.format}`), this.options.format){ case 'webp': outputBuffer = await sharpInstance.webp({ quality: this.options.quality, effort: this.options.effort }).toBuffer(); break; case 'avif': outputBuffer = await sharpInstance.avif({ quality: this.options.quality, effort: this.options.effort }).toBuffer(); break; case 'png': outputBuffer = await sharpInstance.png({ quality: this.options.quality, effort: this.options.effort }).toBuffer(); break; case 'jpeg': case 'jpg': outputBuffer = await sharpInstance.jpeg({ quality: this.options.quality }).toBuffer(); break; default: throw Error(`Unsupported format: ${this.options.format}`); } compilation.emitAsset(newName, new RawSource(outputBuffer), { ...null === (_compilation_getAsset = compilation.getAsset(name)) || void 0 === _compilation_getAsset ? void 0 : _compilation_getAsset.info, sourceFilename: name }), processedAssets.set(name, newName); } else { switch(originalFormat){ case 'png': outputBuffer = await sharpInstance.png({ quality: this.options.quality, effort: this.options.effort }).toBuffer(); break; case 'jpg': case 'jpeg': outputBuffer = await sharpInstance.jpeg({ quality: this.options.quality }).toBuffer(); break; case 'webp': outputBuffer = await sharpInstance.webp({ quality: this.options.quality, effort: this.options.effort }).toBuffer(); break; default: throw Error(`Unsupported format: ${originalFormat}`); } compilation.updateAsset(name, new RawSource(outputBuffer), asset.info); } } catch (error) { compilation.errors.push(new compiler.webpack.WebpackError(`Failed to process image ${name}: ${error instanceof Error ? error.message : String(error)}`)); } } if (processedAssets.size > 0) { for (let [name, asset] of Object.entries(assets))if (name.endsWith('.js')) { let source = asset.source().toString(), modified = !1; for (let [oldName, newName] of processedAssets.entries()){ let oldPath = oldName.replace(/\\/g, '/'), newPath = newName.replace(/\\/g, '/'); source.includes(oldPath) && (source = source.replace(RegExp(oldPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), newPath), modified = !0); } modified && compilation.updateAsset(name, new RawSource(source), asset.info); } for (let [oldName] of processedAssets)compilation.deleteAsset(oldName); } } apply(compiler) { compiler.hooks.compilation.tap('SharpImageOptimizerPlugin', (compilation)=>{ compilation.hooks.processAssets.tapPromise({ name: 'SharpImageOptimizerPlugin', stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE }, async (assets)=>this.optimize(compiler, compilation, assets)); }); } constructor(options = {}){ var obj, key, value; obj = this, value = void 0, (key = "options") in obj ? Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }) : obj[key] = value, this.options = { test: /\.(png|jpe?g)$/i, quality: 85, effort: 6, ...options }; } } let sharpImageOptimizer = (options = {})=>{ let { test = /\.(jpe?g|png|webp|avif)$/i, quality = 80, effort = 4, ...pluginOptions } = options; return { name: 'rsbuild-plugin-sharp-image-optimizer', setup (api) { api.modifyBundlerChain((chain, { isProd })=>{ if (isProd) { var _config_output_distPath, _config_output; let imagePath = (null === (_config_output = api.getNormalizedConfig().output) || void 0 === _config_output ? void 0 : null === (_config_output_distPath = _config_output.distPath) || void 0 === _config_output_distPath ? void 0 : _config_output_distPath.image) ?? 'static/image'; chain.plugin('sharp-image-optimizer-plugin').use(SharpImageOptimizerPlugin, [ { test, quality, effort, ...pluginOptions, imagePath } ]); } }); } }; }; export { sharpImageOptimizer };