Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
- run: npm testonly
173 changes: 102 additions & 71 deletions cli.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
#!/usr/bin/env node
import process from 'node:process';
import arrify from 'arrify';
import meow from 'meow';
import getStdin from 'get-stdin';
import imagemin from 'imagemin';
import ora from 'ora';
import plur from 'plur';
import stripIndent from 'strip-indent';
import pairs from 'lodash.pairs';
import {isUint8Array} from 'uint8array-extras';

const cli = meow(`
import process from "node:process";
import arrify from "arrify";
import meow from "meow";
import getStdin from "get-stdin";
import imagemin from "imagemin";
import ora from "ora";
import plur from "plur";
import stripIndent from "strip-indent";
import pairs from "lodash.pairs";
import { isUint8Array } from "uint8array-extras";

const cli = meow(
`
Usage
$ imagemin <path|glob> [options]
$ imagemin <path|glob> ... --out-dir=build [--plugin=<name> ...]
$ imagemin <file> > <output>
$ cat <file> | imagemin > <output>
Expand All @@ -21,6 +23,8 @@ const cli = meow(`
--out-dir, -o Output directory

Examples
$ imagemin images/*
$ imagemin images/* --plugin.pngquant.quality={0.1,0.2} --plugin.gifsicle.quality={0.1,0.2}
$ imagemin images/* --out-dir=build
$ imagemin foo.png > foo-optimized.png
$ cat foo.png | imagemin > foo-optimized.png
Expand All @@ -29,109 +33,136 @@ const cli = meow(`
# Non-Windows platforms may support the short CLI syntax for array arguments
$ imagemin foo.png --plugin.pngquant.quality={0.1,0.2} > foo-optimized.png
$ imagemin foo.png --plugin.webp.quality=95 --plugin.webp.preset=icon > foo-icon.webp
`, {
importMeta: import.meta,
flags: {
plugin: {
type: 'string',
shortFlag: 'p',
isMultiple: true,
default: [
'gifsicle',
'jpegtran',
'optipng',
'svgo',
],
},
outDir: {
type: 'string',
shortFlag: 'o',
`,
{
importMeta: import.meta,
flags: {
plugin: {
type: "string",
shortFlag: "p",
isMultiple: true,
default: ["gifsicle", "jpegtran", "optipng", "svgo"],
},
outDir: {
type: "string",
shortFlag: "o",
},
},
},
});
);

const requirePlugins = plugins => Promise.all(plugins.map(async ([plugin, options]) => {
try {
const {default: _plugin} = await import(`imagemin-${plugin}`);
return _plugin(options);
} catch {
console.error(stripIndent(`
const requirePlugins = (plugins) =>
Promise.all(
plugins.map(async ([plugin, options]) => {
try {
const { default: _plugin } = await import(`imagemin-${plugin}`);
return _plugin(options);
} catch {
console.error(
stripIndent(`
Unknown plugin: ${plugin}

Did you forget to install the plugin?
You can install it with:

$ npm install -g imagemin-${plugin}
`).trim());

process.exit(1);
}
}));

const normalizePluginOptions = plugin => {
`).trim(),
);
process.exit(1);
}
}),
);

const normalizePluginOptions = (plugin) => {
const pluginOptionsMap = {};

for (const v of arrify(plugin)) {
Object.assign(
pluginOptionsMap,
typeof v === 'object'
? v
: {[v]: {}},
);
Object.assign(pluginOptionsMap, typeof v === "object" ? v : { [v]: {} });
}

return pairs(pluginOptionsMap);
};

const run = async (input, {outDir, plugin} = {}) => {
/**
* Delete all hierarchical files in the original directory while preserving the folder structure
* @param {*} dir
*/
const emptyDirSync = (dir) => {
if (fs.existsSync(dir)) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const currentPath = path.join(dir, file);
if (fs.statSync(currentPath).isDirectory()) {
emptyDirSync(currentPath);
} else {
fs.unlinkSync(currentPath);
}
});
}
};

const run = async (input, { outDir, plugin } = {}) => {
const pluginOptions = normalizePluginOptions(plugin);
const plugins = await requirePlugins(pluginOptions);
const spinner = ora('Minifying images');
const spinner = ora("Minifying images");

if (isUint8Array(input)) {
process.stdout.write(await imagemin.buffer(input, {plugins}));
process.stdout.write(await imagemin.buffer(input, { plugins }));
return;
}

if (outDir) {
spinner.start();
}

let files;
let files,
failedCount = 0;
try {
files = await imagemin(input, {destination: outDir, plugins});
files = await imagemin(input, { destination: outDir, plugins });
if (!outDir) {
if (fs.statSync(input[0]).isDirectory()) {
emptyDirSync(input[0]);
}
files.forEach((file) => {
fs.writeFile(file.sourcePath, file.data, (err) => {
if (err) {
failedCount++;
console.error(`${file.sourcePath} -- Write failed!`, err);
}
});
});
}
} catch (error) {
spinner.stop();
throw error;
}

if (!outDir && files.length === 0) {
return;
}
// if (!outDir && files.length === 0) {
// return;
// }

if (!outDir && files.length > 1) {
console.error('Cannot write multiple files to stdout, specify `--out-dir`');
process.exit(1);
}
// if (!outDir && files.length > 1) {
// console.error('Cannot write multiple files to stdout, specify `--out-dir`');
// process.exit(1);
// }

if (!outDir) {
process.stdout.write(files[0].data);
return;
}
// if (!outDir) {
// process.stdout.write(files[0].data);
// return;
// }

spinner.stop();

console.log(`${files.length} ${plur('image', files.length)} minified`);
console.log(
`${files.length - failedCount} ${plur("image", files.length)} minified`,
);
};

if (cli.input.length === 0 && process.stdin.isTTY) {
console.error('Specify at least one file path');
console.error("Specify at least one file path");
process.exit(1);
}

await run(
cli.input.length > 0
? cli.input
: await getStdin.buffer(),
cli.input.length > 0 ? cli.input : await getStdin.buffer(),
cli.flags,
);
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"node": ">=18"
},
"scripts": {
"test": "xo && ava"
"test": "xo && ava",
"testonly": "ava"
},
"files": [
"cli.js"
Expand Down Expand Up @@ -63,4 +64,4 @@
"n/no-unsupported-features": "off"
}
}
}
}
39 changes: 21 additions & 18 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> Minify images

*Issues with the output should be reported on the `imagemin` [issue tracker](https://github.com/imagemin/imagemin/issues).*
_Issues with the output should be reported on the `imagemin` [issue tracker](https://github.com/imagemin/imagemin/issues)._

## Install

Expand All @@ -16,23 +16,26 @@ npm install --global imagemin-cli
$ imagemin --help

Usage
$ imagemin <path|glob> ... --out-dir=build [--plugin=<name> ...]
$ imagemin <file> > <output>
$ cat <file> | imagemin > <output>

Options
--plugin, -p Override the default plugins
--out-dir, -o Output directory

Examples
$ imagemin images/* --out-dir=build
$ imagemin foo.png > foo-optimized.png
$ cat foo.png | imagemin > foo-optimized.png
$ imagemin foo.png --plugin=pngquant > foo-optimized.png
$ imagemin foo.png --plugin.pngquant.quality=0.1 --plugin.pngquant.quality=0.2 > foo-optimized.png
# Non-Windows platforms may support the short CLI syntax for array arguments
$ imagemin foo.png --plugin.pngquant.quality={0.1,0.2} > foo-optimized.png
$ imagemin foo.png --plugin.webp.quality=95 --plugin.webp.preset=icon > foo-icon.webp
$ imagemin <path|glob> [options]
$ imagemin <path|glob> ... --out-dir=build [--plugin=<name> ...]
$ imagemin <file> > <output>
$ cat <file> | imagemin > <output>

Options
--plugin, -p Override the default plugins
--out-dir, -o Output directory

Examples
$ imagemin images/*
$ imagemin images/* --plugin.pngquant.quality={0.1,0.2} --plugin.gifsicle.quality={0.1,0.2}
$ imagemin images/* --out-dir=build
$ imagemin foo.png > foo-optimized.png
$ cat foo.png | imagemin > foo-optimized.png
$ imagemin foo.png --plugin=pngquant > foo-optimized.png
$ imagemin foo.png --plugin.pngquant.quality=0.1 --plugin.pngquant.quality=0.2 > foo-optimized.png
# Non-Windows platforms may support the short CLI syntax for array arguments
$ imagemin foo.png --plugin.pngquant.quality={0.1,0.2} > foo-optimized.png
$ imagemin foo.png --plugin.webp.quality=95 --plugin.webp.preset=icon > foo-icon.webp
```

## Related
Expand Down
Loading