UNPKG

@hilosiva/vite-plugin-image-optimizer

Version:

画像アセットを最適化する Vite 用プラグイン。

1 lines 11.8 kB
{"version":3,"sources":["../src/libs/ViteSharpOptimizer.ts","../src/index.ts"],"sourcesContent":["import sharp from \"sharp\";\nimport path from \"path\";\n\ninterface SharpImage {\n file: string;\n sharpImage: sharp.Sharp;\n}\n\ninterface Options {\n supportedExts: string[]; // サポートする拡張子の配列\n generate: {\n inputExts: string[]; // 作成するフォーマットの元となるフォーマットの拡張子の配列\n outputExts: string[]; // 作成するフォーマットの拡張子の配列\n preserveExt: boolean; // 新しいフォーマットのファイル名に元の拡張子を追加するかどうか\n };\n jpg?: sharp.JpegOptions; // JPG形式のオプション\n jpeg?: sharp.JpegOptions; // JPEG形式のオプション\n png?: sharp.PngOptions; // PNG形式のオプション\n gif?: sharp.GifOptions; // GIF形式のオプション\n webp?: sharp.WebpOptions; // WebP形式のオプション\n avif?: sharp.AvifOptions; // AVIF形式のオプション\n [key: string]: any; // その他のオプション項目\n}\n\nexport interface ViteSharpOptimizerOptions {\n supportedExts?: string[]; // サポートする拡張子の配列\n generate?: {\n inputExts?: string[]; // 作成するフォーマットの元となるフォーマットの拡張子の配列\n outputExts?: string[]; // 作成するフォーマットの拡張子の配列\n preserveExt?: boolean; // 新しいフォーマットのファイル名に元の拡張子を追加するかどうか\n };\n jpg?: sharp.JpegOptions; // JPG形式のオプション\n jpeg?: sharp.JpegOptions; // JPEG形式のオプション\n png?: sharp.PngOptions; // PNG形式のオプション\n gif?: sharp.GifOptions; // GIF形式のオプション\n webp?: sharp.WebpOptions; // WebP形式のオプション\n avif?: sharp.AvifOptions; // AVIF形式のオプション\n [key: string]: any; // その他のオプション項目\n}\n\nexport class ViteSharpOptimizer {\n private outputDir: string;\n private sharpImageLists: SharpImage[];\n private originalSize: number;\n private optimizeSize: number;\n private extFunctions: { [key: string]: string };\n private defaultOptions: Options;\n private options: Options;\n\n constructor(outputDir: string, _options: object = {}, bundle: any) {\n this.outputDir = outputDir;\n this.sharpImageLists = [];\n this.originalSize = 0;\n this.optimizeSize = 0;\n\n this.extFunctions = {\n \".jpg\": \"jpeg\",\n \".jpeg\": \"jpeg\",\n \".png\": \"png\",\n \".gif\": \"gif\",\n \".webp\": \"webp\",\n \".avif\": \"avif\",\n };\n\n this.defaultOptions = {\n supportedExts: [\".jpg\", \".jpeg\", \".png\", \".gif\", \".webp\", \".avif\"],\n generate: {\n inputExts: [\".jpg\", \".jpeg\", \".png\"],\n outputExts: [\".webp\", \".avif\"],\n preserveExt: false,\n },\n jpg: {},\n jpeg: {},\n png: {},\n gif: {},\n webp: {},\n avif: {},\n };\n\n this.options = this.deepMerge(this.defaultOptions, _options);\n\n this._init(bundle);\n }\n\n private deepMerge(target: any, source: any) {\n if (typeof target !== \"object\" || typeof source !== \"object\") {\n return source;\n }\n\n const keys = Object.keys(source);\n\n for (const key of keys) {\n if (!(key in target)) {\n target[key] = source[key];\n } else if (typeof target[key] === \"object\" && typeof source[key] === \"object\") {\n target[key] = this.deepMerge(target[key], source[key]);\n } else {\n target[key] = source[key];\n }\n }\n\n return target;\n }\n\n private async _init(bundle: any) {\n const imageFileList = Object.keys(bundle).filter((key) => {\n const extName = path.extname(key);\n return this.options.supportedExts.includes(extName);\n });\n\n this.sharpImageLists = imageFileList.map((file) => {\n const sharpImage = sharp(bundle[file].source);\n return { file, sharpImage };\n });\n\n if (this.sharpImageLists.length > 0) await this._run();\n }\n\n private async _run() {\n await Promise.all(\n this.sharpImageLists.map(async (item, index) => {\n await this._optimize(item, index);\n\n if (this.isGenerateFormat(item.file)) {\n for (let i = 0; i < this.options.generate.outputExts.length; i++) {\n await this._createImage(item, this.options.generate.outputExts[i]);\n }\n }\n })\n );\n\n console.log(`\\n✨ Total \\x1b[30m${this.formatBytes(this.optimizeSize)} / ${this.formatBytes(this.originalSize)} ${this.getRatio(this.originalSize, this.optimizeSize)}`);\n }\n\n private async _optimize(item: SharpImage, index: number) {\n const { sharpImage, file } = item;\n const extName = path.extname(file);\n const sfunc = this.extFunctions[extName];\n\n const metadate = await sharpImage.metadata();\n const info = await (sharpImage as any)[sfunc](this.options[extName.replace(\".\", \"\")])\n .toFile(`${this.outputDir}/${file}`)\n .catch((err: any) => console.log(err));\n\n if (index === 0) console.log(`\\n✨ \\x1b[36m[vite-plugin-image-optimizer] \\x1b[39m- optimized images successfully:`);\n this.setInfo(file, metadate, info);\n }\n\n private async _createImage(item: SharpImage, ext: string) {\n const { sharpImage, file } = item;\n const sfunc = this.extFunctions[ext];\n\n const metadate = await sharpImage.metadata();\n const info = await (sharpImage as any)[sfunc](this.options[ext.replace(\".\", \"\")])\n .toFile(`${this.outputDir}/${this.changeExtension(file, ext)}`)\n .catch((err: any) => console.log(err));\n\n this.setInfo(this.changeExtension(file, ext), metadate, info);\n }\n\n private getRatio(originalSize: number, compressedSize: number): string {\n if (originalSize <= 0 || compressedSize <= 0) return \"N/A\";\n\n const ratio = ((originalSize - compressedSize) / originalSize) * 100;\n const absoluteRatio = Math.abs(ratio);\n const sign = absoluteRatio > 100 ? \"+\" : \"-\";\n return `${sign + absoluteRatio.toFixed(2)}%`;\n }\n\n private getLastDirName(path: string): string {\n const parts = path.split(\"/\");\n return parts[parts.length - 1];\n }\n\n formatBytes(bytes: number): string {\n const units = [\"bytes\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n let index = 0;\n\n while (bytes >= 1024 && index < units.length - 1) {\n bytes /= 1024;\n index++;\n }\n\n return `${bytes.toFixed(2)} ${units[index]}`;\n }\n\n isGenerateFormat(file: string): boolean {\n const extName = path.extname(file);\n\n return this.options.generate.inputExts && this.options.generate.inputExts.includes(extName.toLowerCase());\n }\n\n changeExtension(file: string, ext: string): string {\n if (this.options.generate.preserveExt) {\n return file + ext;\n } else {\n return file.substring(0, file.lastIndexOf(\".\")) + ext;\n }\n }\n\n setInfo(file: string, metadate: any, info: any) {\n this.originalSize += metadate.size;\n this.optimizeSize += info.size;\n\n console.log(\n `\\x1b[30m${this.getLastDirName(this.outputDir)}/\\x1b[34m${file} \\x1b[32m${this.getRatio(metadate.size, info.size)} \\x1b[30m${this.formatBytes(metadate.size)} → ${this.formatBytes(info.size)}`\n );\n }\n}\n","import { ViteSharpOptimizer } from \"./libs/ViteSharpOptimizer\";\nimport type { ViteSharpOptimizerOptions } from \"./libs/ViteSharpOptimizer\";\n\nexport function viteImageOptimizer(opts: ViteSharpOptimizerOptions = {}): any {\n return {\n name: \"@hilosiva/viteImageOptimizer\",\n async writeBundle(_options: any, bundle: any) {\n new ViteSharpOptimizer(_options.dir, opts, bundle);\n },\n };\n}\n"],"mappings":"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","names":["sharp","path","ViteSharpOptimizer","outputDir","_options","bundle","target","source","keys","key","imageFileList","extName","file","sharpImage","item","index","i","sfunc","metadate","info","err","ext","originalSize","compressedSize","ratio","absoluteRatio","parts","bytes","units","viteImageOptimizer","opts","_options","bundle","ViteSharpOptimizer"]}