|
| 1 | +import fs from 'node:fs/promises'; |
| 2 | +import { optimize } from 'svgo'; |
| 3 | +import { glob } from 'glob'; |
| 4 | +import path from 'node:path'; |
| 5 | + |
| 6 | +// Find non-minified SVG imports in codebase with regex search: (\S+(?<!\.mini)\.svg) |
| 7 | + |
| 8 | +const config = { |
| 9 | + multipass: true, |
| 10 | + plugins: [ |
| 11 | + { |
| 12 | + name: 'preset-default', |
| 13 | + params: { |
| 14 | + overrides: { |
| 15 | + inlineStyles: { |
| 16 | + onlyMatchedOnce: false |
| 17 | + } |
| 18 | + } |
| 19 | + } |
| 20 | + }, |
| 21 | + 'removeStyleElement' |
| 22 | + ] |
| 23 | +}; |
| 24 | + |
| 25 | +const srcImages = await glob( |
| 26 | + ['src/images/**/*.svg', 'static/images/**/*.svg'], |
| 27 | + { ignore: '**/*.mini.svg' } |
| 28 | +); |
| 29 | + |
| 30 | +let bytesSaved = 0; |
| 31 | + |
| 32 | +const promises = srcImages.map(async (file) => { |
| 33 | + const data = await fs.readFile(file, 'utf-8'); |
| 34 | + const result = optimize(data, config); |
| 35 | + |
| 36 | + if (result.error) { |
| 37 | + console.error(result.error); |
| 38 | + process.exit(1); |
| 39 | + } |
| 40 | + |
| 41 | + const sizeDelta = result.data.length - data.length; |
| 42 | + bytesSaved += sizeDelta; |
| 43 | + |
| 44 | + console.log(file); |
| 45 | + console.log( |
| 46 | + sizeDelta <= 0 ? ' 🟢' : ' 🟡', |
| 47 | + `${((sizeDelta / data.length) * 100).toFixed(2)}%` |
| 48 | + ); |
| 49 | + console.log(' ', (sizeDelta / 1024).toFixed(2), 'kB'); |
| 50 | + |
| 51 | + const { dir, name } = path.parse(file); |
| 52 | + const destinationFile = path.join(dir, `${name}.mini.svg`); |
| 53 | + |
| 54 | + await fs.writeFile(destinationFile, result.data, 'utf-8'); |
| 55 | +}); |
| 56 | + |
| 57 | +await Promise.all(promises); |
| 58 | + |
| 59 | +console.log( |
| 60 | + 'Done!', |
| 61 | + (bytesSaved / 1024).toFixed(2), |
| 62 | + 'kB size difference total' |
| 63 | +); |
0 commit comments