diff --git a/index.js b/index.js index 159a1ec..51dc77f 100755 --- a/index.js +++ b/index.js @@ -3,27 +3,39 @@ 'use strict'; const fs = require('fs'); -const path = require('path'); const meow = require('meow'); const ora = require('ora'); const globby = require('globby'); +const makeDir = require('make-dir'); +const hasExt = require('has-ext'); const upath = require('upath'); +const pAll = require('p-all'); const {minify} = require('html-minifier'); const CleanCSS = require('clean-css'); const Terser = require('terser'); +const imagemin = require('imagemin'); +const imageminMozjpeg = require('imagemin-mozjpeg'); +const imageminPngquant = require('imagemin-pngquant'); +const imageminSvgo = require('imagemin-svgo'); const cli = meow(` Usage $ minifly - Options + Options + --output, -o Output directory [default: minifly] --ignore, -i Ignore specific files or directories Examples $ minifly - $ minifly --ignore 'index.js,dist/*.css' + $ minifly --ignore 'index.js,dist/*.css' -o dist `, { flags: { + output: { + type: 'string', + alias: 'o', + default: 'minifly' + }, ignore: { type: 'string', alias: 'i' @@ -36,9 +48,9 @@ const cli = meow(` await globby(['*', '{,!(node_modules)/**/}', '!*.min.*', `!{${cli.flags.ignore}}`]).then(async files => { const minifyHtml = async () => { - const html = await files.filter(name => path.extname(name).substr(1) === 'html'); + const html = await files.filter(name => hasExt(name, 'html')); - html.map(async file => { + await html.map(async file => { const contents = await fs.readFileSync(file, 'utf8'); if (contents === '') { @@ -58,7 +70,10 @@ const cli = meow(` minifyURLs: true }); - fs.writeFile(upath.changeExt(file, '.min.html'), output, err => { + const path = await `${cli.flags.output}/` + file.substring(0, file.lastIndexOf('/')); + await makeDir(path); + + fs.writeFile(`${cli.flags.output}/${upath.changeExt(file, '.min.html')}`, output, err => { if (err) { spinner.fail('Error!\n' + err); } @@ -67,9 +82,9 @@ const cli = meow(` }; const minifyCss = async () => { - const css = await files.filter(name => path.extname(name).substr(1) === 'css'); + const css = await files.filter(name => hasExt(name, 'css')); - css.map(async file => { + await css.map(async file => { const contents = await fs.readFileSync(file, 'utf8'); if (contents === '') { @@ -78,7 +93,10 @@ const cli = meow(` const output = await new CleanCSS().minify(contents); - fs.writeFile(upath.changeExt(file, '.min.css'), output.styles, err => { + const path = await `${cli.flags.output}/` + file.substring(0, file.lastIndexOf('/')); + await makeDir(path); + + fs.writeFile(`${cli.flags.output}/${upath.changeExt(file, '.min.css')}`, output.styles, err => { if (err) { spinner.fail('Error!\n' + err); } @@ -87,9 +105,9 @@ const cli = meow(` }; const minifyJs = async () => { - const js = await files.filter(name => path.extname(name).substr(1) === 'js'); + const js = await files.filter(name => hasExt(name, 'js')); - js.map(async file => { + await js.map(async file => { const contents = await fs.readFileSync(file, 'utf8'); if (contents === '') { @@ -111,7 +129,10 @@ const cli = meow(` } }); - fs.writeFile(upath.changeExt(file, '.min.js'), output.code, err => { + const path = await `${cli.flags.output}/` + file.substring(0, file.lastIndexOf('/')); + await makeDir(path); + + fs.writeFile(`${cli.flags.output}/${upath.changeExt(file, '.min.js')}`, output.code, err => { if (err) { spinner.fail('Error!\n' + err); } @@ -119,7 +140,26 @@ const cli = meow(` }); }; - Promise.all([minifyHtml(), minifyCss(), minifyJs()]).then(() => { + const minifyImages = async () => { + const images = await files.filter(name => hasExt(name, ['jpg', 'png', 'svg'])); + + await imagemin(images, `${cli.flags.output}/images`, { + plugins: [ + imageminMozjpeg(), + imageminPngquant(), + imageminSvgo() + ] + }); + }; + + const actions = [ + () => minifyHtml(), + () => minifyCss(), + () => minifyJs(), + () => minifyImages() + ]; + + await pAll(actions, {concurrency: 4}).then(() => { spinner.succeed('Done!'); }); }).catch(error => { diff --git a/package.json b/package.json index 6bc5a74..f7e65a6 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,9 @@ "version": "1.0.0", "description": "🗜️ Minify different types of files easily", "main": "index.js", + "files": [ + "index.js" + ], "bin": { "minifly": "index.js" }, @@ -17,26 +20,38 @@ "css", "js", "javascript", + "images", + "jpg", + "png", + "svg", "terser", "clean-css", "html-minifier", + "imagemin", "fast", "globby", "concurrently" ], "author": "Antoni Kepinski (https://kepinski.me)", - "repository": "https://github.com/xxczaki/minifly", - "bugs": { - "url": "https://github.com/xxczaki/minifly/issues" - }, - "homepage": "https://github.com/xxczaki/minifly", + "repository": "https://github.com/xxczaki/minifly", + "bugs": { + "url": "https://github.com/xxczaki/minifly/issues" + }, + "homepage": "https://github.com/xxczaki/minifly", "license": "MIT", "dependencies": { "clean-css": "^4.2.1", "globby": "^9.2.0", + "has-ext": "^1.0.1", "html-minifier": "^4.0.0", + "imagemin": "^6.1.0", + "imagemin-mozjpeg": "^8.0.0", + "imagemin-pngquant": "^7.0.0", + "imagemin-svgo": "^7.0.0", + "make-dir": "^3.0.0", "meow": "^5.0.0", "ora": "^3.4.0", + "p-all": "^2.1.0", "terser": "^3.17.0", "upath": "^1.1.2" }, diff --git a/readme.md b/readme.md index c3e9c4b..025a99e 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,6 @@ - Fast and easy to use - Uses async/await - Minifies files concurrently -- Single source file (containing ~120 lines of code) - Supports [multiple file types](#supported-files) # Install @@ -45,6 +44,9 @@ Examples | HTML (*.html) | [html-minifier](https://github.com/kangax/html-minifier) | | CSS (*.css) | [clean-css](https://github.com/jakubpawlowicz/clean-css) | | JavaScript (*.js) | [terser](https://github.com/terser-js/terser) | +| JPG (*.jpg) | [imagemin-mozjpeg](https://github.com/imagemin/imagemin-mozjpeg) | +| PNG (*.png) | [imagemin-pngquant](https://github.com/imagemin/imagemin-pngquant) | +| SVG (*.svg) | [imagemin-svgo](https://github.com/imagemin/imagemin-svgo) | More file types will be supported soon :unicorn: