From 1b4baf659aa532098abe4170cc77cc6dfc1477fe Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 12 Aug 2021 17:47:05 +0200 Subject: [PATCH] Require Node.js 12.20 and move to ESM --- .github/funding.yml | 3 -- .github/workflows/main.yml | 6 ++-- index.js | 69 ++++++++++++++++++-------------------- license | 2 +- package.json | 32 +++++++++--------- readme.md | 23 ++----------- test.js | 26 +++++++------- 7 files changed, 68 insertions(+), 93 deletions(-) delete mode 100644 .github/funding.yml diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index 1a630e9..0000000 --- a/.github/funding.yml +++ /dev/null @@ -1,3 +0,0 @@ -github: sindresorhus -open_collective: sindresorhus -custom: https://sindresorhus.com/donate diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1870cf..441975c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,12 +10,10 @@ jobs: fail-fast: false matrix: node-version: - - 14 - - 12 - - 10 + - 16 steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/index.js b/index.js index e67929b..cda7733 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,15 @@ -const path = require('path'); -const log = require('fancy-log'); -const PluginError = require('plugin-error'); -const through = require('through2-concurrent'); -const prettyBytes = require('pretty-bytes'); -const chalk = require('chalk'); -const imagemin = require('imagemin'); -const plur = require('plur'); +import {createRequire} from 'node:module'; +import path from 'node:path'; +import process from 'node:process'; +import log from 'fancy-log'; +import PluginError from 'plugin-error'; +import through from 'through2-concurrent'; +import prettyBytes from 'pretty-bytes'; +import chalk from 'chalk'; +import imagemin from 'imagemin'; +import plur from 'plur'; + +const require = createRequire(import.meta.url); const PLUGIN_NAME = 'gulp-imagemin'; const defaultPlugins = ['gifsicle', 'mozjpeg', 'optipng', 'svgo']; @@ -13,25 +17,16 @@ const defaultPlugins = ['gifsicle', 'mozjpeg', 'optipng', 'svgo']; const loadPlugin = (plugin, ...args) => { try { return require(`imagemin-${plugin}`)(...args); - } catch (_) { - log(`${PLUGIN_NAME}: Couldn't load default plugin "${plugin}"`); + } catch { + log(`${PLUGIN_NAME}: Could not load default plugin \`${plugin}\``); } }; const exposePlugin = plugin => (...args) => loadPlugin(plugin, ...args); -const getDefaultPlugins = () => - defaultPlugins.reduce((plugins, plugin) => { - const instance = loadPlugin(plugin); +const getDefaultPlugins = () => defaultPlugins.flatMap(plugin => loadPlugin(plugin)); - if (!instance) { - return plugins; - } - - return plugins.concat(instance); - }, []); - -module.exports = (plugins, options) => { +export default function gulpImagemin(plugins, options) { if (typeof plugins === 'object' && !Array.isArray(plugins)) { options = plugins; plugins = undefined; @@ -41,17 +36,17 @@ module.exports = (plugins, options) => { // TODO: Remove this when Gulp gets a real logger with levels silent: process.argv.includes('--silent'), verbose: process.argv.includes('--verbose'), - ...options + ...options, }; - const validExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.svg']; + const validExtensions = new Set(['.jpg', '.jpeg', '.png', '.gif', '.svg']); let totalBytes = 0; let totalSavedBytes = 0; let totalFiles = 0; return through.obj({ - maxConcurrency: 8 + maxConcurrency: 8, }, (file, encoding, callback) => { if (file.isNull()) { callback(null, file); @@ -63,7 +58,7 @@ module.exports = (plugins, options) => { return; } - if (!validExtensions.includes(path.extname(file.path).toLowerCase())) { + if (!validExtensions.has(path.extname(file.path).toLowerCase())) { if (options.verbose) { log(`${PLUGIN_NAME}: Skipping unsupported image ${chalk.blue(file.relative)}`); } @@ -77,14 +72,14 @@ module.exports = (plugins, options) => { (async () => { try { const data = await imagemin.buffer(file.contents, { - plugins: localPlugins + plugins: localPlugins, }); const originalSize = file.contents.length; const optimizedSize = data.length; const saved = originalSize - optimizedSize; const percent = originalSize > 0 ? (saved / originalSize) * 100 : 0; - const savedMsg = `saved ${prettyBytes(saved)} - ${percent.toFixed(1).replace(/\.0$/, '')}%`; - const msg = saved > 0 ? savedMsg : 'already optimized'; + const savedMessage = `saved ${prettyBytes(saved)} - ${percent.toFixed(1).replace(/\.0$/, '')}%`; + const message = saved > 0 ? savedMessage : 'already optimized'; if (saved > 0) { totalBytes += originalSize; @@ -93,7 +88,7 @@ module.exports = (plugins, options) => { } if (options.verbose) { - log(`${PLUGIN_NAME}:`, chalk.green('✔ ') + file.relative + chalk.gray(` (${msg})`)); + log(`${PLUGIN_NAME}:`, chalk.green('✔ ') + file.relative + chalk.gray(` (${message})`)); } file.contents = data; @@ -105,20 +100,20 @@ module.exports = (plugins, options) => { }, callback => { if (!options.silent) { const percent = totalBytes > 0 ? (totalSavedBytes / totalBytes) * 100 : 0; - let msg = `Minified ${totalFiles} ${plur('image', totalFiles)}`; + let message = `Minified ${totalFiles} ${plur('image', totalFiles)}`; if (totalFiles > 0) { - msg += chalk.gray(` (saved ${prettyBytes(totalSavedBytes)} - ${percent.toFixed(1).replace(/\.0$/, '')}%)`); + message += chalk.gray(` (saved ${prettyBytes(totalSavedBytes)} - ${percent.toFixed(1).replace(/\.0$/, '')}%)`); } - log(`${PLUGIN_NAME}:`, msg); + log(`${PLUGIN_NAME}:`, message); } callback(); }); -}; +} -module.exports.gifsicle = exposePlugin('gifsicle'); -module.exports.mozjpeg = exposePlugin('mozjpeg'); -module.exports.optipng = exposePlugin('optipng'); -module.exports.svgo = exposePlugin('svgo'); +export const gifsicle = exposePlugin('gifsicle'); +export const mozjpeg = exposePlugin('mozjpeg'); +export const optipng = exposePlugin('optipng'); +export const svgo = exposePlugin('svgo'); diff --git a/license b/license index e7af2f7..fa7ceba 100644 --- a/license +++ b/license @@ -1,6 +1,6 @@ MIT License -Copyright (c) Sindre Sorhus (sindresorhus.com) +Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/package.json b/package.json index 4647c56..cef230c 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,12 @@ "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", - "url": "sindresorhus.com" + "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "scripts": { "test": "xo && ava" @@ -36,26 +38,26 @@ "svg" ], "dependencies": { - "chalk": "^3.0.0", - "fancy-log": "^1.3.2", - "imagemin": "^7.0.0", + "chalk": "^4.1.2", + "fancy-log": "^1.3.3", + "imagemin": "^8.0.1", "plugin-error": "^1.0.1", - "plur": "^3.0.1", - "pretty-bytes": "^5.3.0", + "plur": "^4.0.0", + "pretty-bytes": "^5.6.0", "through2-concurrent": "^2.0.0" }, "devDependencies": { - "ava": "^2.3.0", - "get-stream": "^5.1.0", - "imagemin-pngquant": "^8.0.0", - "vinyl": "^2.2.0", - "xo": "^0.25.3" + "ava": "^3.15.0", + "get-stream": "^6.0.1", + "imagemin-pngquant": "^9.0.2", + "vinyl": "^2.2.1", + "xo": "^0.44.0" }, "optionalDependencies": { "imagemin-gifsicle": "^7.0.0", - "imagemin-mozjpeg": "^8.0.0", - "imagemin-optipng": "^7.0.0", - "imagemin-svgo": "^7.0.0" + "imagemin-mozjpeg": "^9.0.0", + "imagemin-optipng": "^8.0.0", + "imagemin-svgo": "^9.0.0" }, "peerDependencies": { "gulp": ">=4" diff --git a/readme.md b/readme.md index e18ab0a..b519cc1 100644 --- a/readme.md +++ b/readme.md @@ -15,10 +15,10 @@ $ npm install --save-dev gulp-imagemin ### Basic ```js -const gulp = require('gulp'); -const imagemin = require('gulp-imagemin'); +import gulp from 'gulp'; +import imagemin from 'gulp-imagemin'; -exports.default = () => ( +export default () => ( gulp.src('src/images/*') .pipe(imagemin()) .pipe(gulp.dest('dist/images')) @@ -43,23 +43,6 @@ exports.default = () => ( // … ``` -Note that you may come across an older, implicit syntax. In versions < 3, the same was written like this: - -```js -// … -.pipe(imagemin({ - interlaced: true, - progressive: true, - optimizationLevel: 5, - svgoPlugins: [ - { - removeViewBox: true - } - ] -})) -// … -``` - ### Custom plugin options and custom `gulp-imagemin` options ```js diff --git a/test.js b/test.js index 353414a..2d6c2c3 100644 --- a/test.js +++ b/test.js @@ -1,21 +1,21 @@ -import {promisify} from 'util'; -import fs from 'fs'; -import path from 'path'; +import {promises as fs} from 'node:fs'; +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; import imageminPngquant from 'imagemin-pngquant'; import Vinyl from 'vinyl'; import getStream from 'get-stream'; import test from 'ava'; -import gulpImagemin from '.'; +import gulpImagemin, {mozjpeg, svgo} from './index.js'; -const readFile = promisify(fs.readFile); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); const createFixture = async (plugins, file = 'fixture.png') => { - const buffer = await readFile(path.join(__dirname, file)); + const buffer = await fs.readFile(path.join(__dirname, file)); const stream = gulpImagemin(plugins); stream.end(new Vinyl({ path: path.join(__dirname, file), - contents: buffer + contents: buffer, })); return {buffer, stream}; @@ -32,9 +32,9 @@ test('minify JPEG with custom settings', async t => { const mozjpegOptions = { quality: 30, progressive: false, - smooth: 45 + smooth: 45, }; - const {buffer, stream} = await createFixture([gulpImagemin.mozjpeg(mozjpegOptions)], 'fixture.jpg'); + const {buffer, stream} = await createFixture([mozjpeg(mozjpegOptions)], 'fixture.jpg'); const file = await getStream.array(stream); t.true(file[0].contents.length < buffer.length); @@ -50,13 +50,13 @@ test('use custom plugins', async t => { }); test('use custom svgo settings', async t => { - const svgoOpts = { + const svgoOptions = { js2svg: { indent: 2, - pretty: true - } + pretty: true, + }, }; - const {stream} = await createFixture([gulpImagemin.svgo(svgoOpts)], 'fixture-svg-logo.svg'); + const {stream} = await createFixture([svgo(svgoOptions)], 'fixture-svg-logo.svg'); const compareStream = (await createFixture(null, 'fixture-svg-logo.svg')).stream; const file = await getStream.array(stream); const compareFile = await getStream.array(compareStream);