From bcb0b345c0eed2e027eadc43c0d2fed6531a17ab Mon Sep 17 00:00:00 2001 From: Anton Golub Date: Fri, 6 Aug 2021 15:46:59 +0300 Subject: [PATCH] Require Node.js 12.20 and move to ESM (#29) Co-authored-by: Sindre Sorhus --- .github/workflows/main.yml | 22 ++++++++++++ .travis.yml | 5 --- cli.js | 69 +++++++++++++++++++++----------------- package.json | 33 +++++++++--------- readme.md | 6 +++- test.js | 36 +++++++++++--------- 6 files changed, 105 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..3b8aa86 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,22 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + name: Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: + - 16 + - 14 + - 12 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9d7745e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - '14' - - '12' - - '10' diff --git a/cli.js b/cli.js index bc871e0..da1748d 100755 --- a/cli.js +++ b/cli.js @@ -1,13 +1,14 @@ #!/usr/bin/env node -'use strict'; -const arrify = require('arrify'); -const meow = require('meow'); -const getStdin = require('get-stdin'); -const imagemin = require('imagemin'); -const ora = require('ora'); -const plur = require('plur'); -const stripIndent = require('strip-indent'); -const pairs = require('lodash.pairs'); +import {Buffer} from 'node:buffer'; +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'; const cli = meow(` Usage @@ -27,6 +28,7 @@ const cli = meow(` $ 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', @@ -36,20 +38,21 @@ const cli = meow(` 'gifsicle', 'jpegtran', 'optipng', - 'svgo' - ] + 'svgo', + ], }, outDir: { type: 'string', - alias: 'o' - } - } + alias: 'o', + }, + }, }); -const requirePlugins = plugins => plugins.map(([plugin, options]) => { +const requirePlugins = plugins => Promise.all(plugins.map(async ([plugin, options]) => { try { - return require(`imagemin-${plugin}`)(options); - } catch (_) { + const {default: _plugin} = await import(`imagemin-${plugin}`); // eslint-disable-line node/no-unsupported-features/es-syntax + return _plugin(options); + } catch { console.error(stripIndent(` Unknown plugin: ${plugin} @@ -61,19 +64,26 @@ const requirePlugins = plugins => plugins.map(([plugin, options]) => { process.exit(1); } -}); +})); const normalizePluginOptions = plugin => { - return pairs(arrify(plugin).reduce((m, v) => { - return typeof v === 'object' ? - {...m, ...v} : - {[v]: {}, ...m}; - }, {})); + const pluginOptionsMap = {}; + + for (const v of arrify(plugin)) { + Object.assign( + pluginOptionsMap, + typeof v === 'object' + ? v + : {[v]: {}}, + ); + } + + return pairs(pluginOptionsMap); }; const run = async (input, {outDir, plugin} = {}) => { const pluginOptions = normalizePluginOptions(plugin); - const plugins = requirePlugins(pluginOptions); + const plugins = await requirePlugins(pluginOptions); const spinner = ora('Minifying images'); if (Buffer.isBuffer(input)) { @@ -118,10 +128,9 @@ if (cli.input.length === 0 && process.stdin.isTTY) { } (async () => { - if (cli.input.length > 0) { - await run(cli.input, cli.flags); - } else { - await run(await getStdin.buffer(), cli.flags); - } + await run( + cli.input.length > 0 + ? cli.input + : await getStdin.buffer(), + cli.flags); })(); - diff --git a/package.json b/package.json index fb2317e..95324bc 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,12 @@ "license": "MIT", "repository": "imagemin/imagemin-cli", "funding": "https://github.com/imagemin/imagemin-cli?sponsor=1", + "type": "module", "bin": { "imagemin": "cli.js" }, "engines": { - "node": ">=10" + "node": ">=12.20" }, "scripts": { "test": "xo && ava" @@ -31,30 +32,32 @@ "svg" ], "dependencies": { - "arrify": "^2.0.1", - "get-stdin": "^8.0.0", - "imagemin": "^7.0.0", + "arrify": "^3.0.0", + "get-stdin": "^9.0.0", + "imagemin": "^8.0.0", "lodash.pairs": "^3.0.1", - "meow": "^7.0.1", - "ora": "^4.0.3", + "meow": "^10.1.1", + "ora": "^5.4.1", "plur": "^4.0.0", - "strip-indent": "^3.0.0" + "strip-indent": "^4.0.0" }, "devDependencies": { - "ava": "^3.8.0", - "execa": "^4.0.0", - "imagemin-pngquant": "^8.0.0", - "xo": "^0.30.0" + "ava": "^3.15.0", + "execa": "^5.1.1", + "imagemin-pngquant": "^9.0.2", + "typescript": "^4.3.5", + "xo": "^0.43.0" }, "optionalDependencies": { "imagemin-gifsicle": "^7.0.0", - "imagemin-jpegtran": "^6.0.0", - "imagemin-optipng": "^7.0.0", - "imagemin-svgo": "^7.0.0" + "imagemin-jpegtran": "^7.0.0", + "imagemin-optipng": "^8.0.0", + "imagemin-svgo": "^9.0.0" }, "xo": { "rules": { - "node/process-exit-as-throw": 2 + "node/process-exit-as-throw": 2, + "node/no-unsupported-features": "off" } } } diff --git a/readme.md b/readme.md index 707d649..3ee92fb 100644 --- a/readme.md +++ b/readme.md @@ -29,10 +29,14 @@ $ imagemin --help $ 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,0.2} > foo-optimized.png + $ imagemin foo.png --plugin.pngquant.quality=0.5 --plugin.pngquant.quality=1 > foo-optimized.png $ imagemin foo.png --plugin.webp.quality=95 --plugin.webp.preset=icon > foo-icon.webp ``` +**non-Windows** users can also use the short CLI syntax for array arguments: +`--plugin.pngquant.quality={0.5,1}` equals +`--plugin.pngquant.quality=0.5 --plugin.pngquant.quality=1` + ## Related - [imagemin](https://github.com/imagemin/imagemin) - API for this module diff --git a/test.js b/test.js index 7076cdf..ab5bf67 100644 --- a/test.js +++ b/test.js @@ -1,7 +1,13 @@ -const {promisify} = require('util'); -const fs = require('fs'); -const execa = require('execa'); -const test = require('ava'); +import {promisify} from 'node:util'; +import fs from 'node:fs'; +import {dirname} from 'node:path'; +import {fileURLToPath} from 'node:url'; +import process from 'node:process'; + +import execa from 'execa'; +import test from 'ava'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(__dirname); @@ -9,7 +15,7 @@ const readFile = promisify(fs.readFile); test('show version', async t => { const {stdout} = await execa('./cli.js', ['--version']); - t.is(stdout, require('./package.json').version); + t.is(stdout, JSON.parse(await readFile('./package.json')).version); }); test('optimize a GIF', async t => { @@ -17,7 +23,7 @@ test('optimize a GIF', async t => { const {stdout} = await execa('./cli.js', { input, - encoding: 'buffer' + encoding: 'buffer', }); t.true(stdout.length < input.length); @@ -28,7 +34,7 @@ test('optimize a JPG', async t => { const {stdout} = await execa('./cli.js', { input, - encoding: 'buffer' + encoding: 'buffer', }); t.true(stdout.length < input.length); @@ -39,7 +45,7 @@ test('optimize a PNG', async t => { const {stdout} = await execa('./cli.js', { input, - encoding: 'buffer' + encoding: 'buffer', }); t.true(stdout.length < input.length); @@ -50,7 +56,7 @@ test('optimize a SVG', async t => { const {stdout} = await execa('./cli.js', { input, - encoding: 'buffer' + encoding: 'buffer', }); t.true(stdout.length < input.length); @@ -65,12 +71,12 @@ test('support plugins', async t => { const {stdout: data} = await execa('./cli.js', ['--plugin=pngquant'], { input, - encoding: 'buffer' + encoding: 'buffer', }); const {stdout: compareData} = await execa('./cli.js', { input, - encoding: 'buffer' + encoding: 'buffer', }); t.true(data.length < compareData.length); @@ -85,7 +91,7 @@ test('throw on missing plugins', async t => { const input = await readFile('fixtures/test.png'); const error = await t.throwsAsync(execa('./cli.js', ['--plugin=unicorn'], { input, - encoding: 'buffer' + encoding: 'buffer', })); t.regex(error.stderr.toString(), /Unknown plugin: unicorn/); @@ -94,14 +100,14 @@ test('throw on missing plugins', async t => { test('support plugin options', async t => { const input = await readFile('fixtures/test.png'); - const {stdout: data} = await execa('./cli.js', ['--plugin.pngquant.dithering=1'], { + const {stdout: data} = await execa('./cli.js', ['--plugin.pngquant.dithering=1', '--plugin.pngquant.quality=0.1', '--plugin.pngquant.quality=0.4'], { input, - encoding: 'buffer' + encoding: 'buffer', }); const {stdout: compareData} = await execa('./cli.js', { input, - encoding: 'buffer' + encoding: 'buffer', }); t.true(data.length < compareData.length);