Skip to content

Commit

Permalink
Require Node.js 12.20 and move to ESM
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Aug 12, 2021
1 parent ed39463 commit 1b4baf6
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 93 deletions.
3 changes: 0 additions & 3 deletions .github/funding.yml

This file was deleted.

6 changes: 2 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 32 additions & 37 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,32 @@
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'];

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;
Expand All @@ -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);
Expand All @@ -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)}`);
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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');
2 changes: 1 addition & 1 deletion license
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (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:

Expand Down
32 changes: 17 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down
23 changes: 3 additions & 20 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'))
Expand All @@ -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
Expand Down
26 changes: 13 additions & 13 deletions test.js
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 1b4baf6

Please sign in to comment.