Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependency modernization (continued) #129

Merged
merged 39 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7257457
fix(docs): remove outdated Sqoosh reference from README
j9t Oct 5, 2024
896e8b0
fix: bump version to 4.0.1 in package files
j9t Oct 5, 2024
5b2ebf4
fix: update test AVIF file in imagemin-guard
j9t Oct 6, 2024
8645a27
chore: update test images with optimized versions
j9t Oct 6, 2024
7182de1
feat: update test image
j9t Oct 6, 2024
e80a873
feat: switch to sharp for image compression
j9t Oct 6, 2024
a39da99
refactor: reorder imports for consistency
j9t Oct 6, 2024
424055e
feat: optimize output.png for better performance
j9t Oct 6, 2024
3f0fc4c
feat: remove plugin options and enforce lossless output
j9t Oct 6, 2024
ccf6eab
fix(utils): handle temp file cleanup in all scenarios
j9t Oct 6, 2024
d1fecf0
test: add dry run test for imagemin-guard
j9t Oct 6, 2024
080df4f
fix: remove unnecessary comment in imagemin-guard test
j9t Oct 6, 2024
480a512
chore: update test file comment for better clarity
j9t Oct 6, 2024
d07301a
feat: update README for Imagemin Guard
j9t Oct 6, 2024
000d03b
feat: update README clarifications and removal of outdated info
j9t Oct 6, 2024
9cc0d1a
fix: improve file handling and error management
j9t Oct 7, 2024
e112a62
feat: remove unused code and improve README
j9t Oct 7, 2024
a01abc1
feat: make size function asynchronous
j9t Oct 7, 2024
c92e69a
feat: refine README for better clarity
j9t Oct 7, 2024
6074af4
chore: add test image to media directory
j9t Oct 7, 2024
0c78615
fix: support uppercase file extensions in [Imagemin Guard]
j9t Oct 7, 2024
cc1087a
fix(utils): improve compression logic and status details
j9t Oct 7, 2024
8ac46ba
feat(docs): clarify output section header in README
j9t Oct 7, 2024
09d2a5a
chore: fix README wording for clarity
j9t Oct 8, 2024
5d67c05
feat: update README with new feature ideas
j9t Oct 8, 2024
27bf474
feat(media): add test for corrupted GIF
j9t Oct 9, 2024
0054553
refactor: rename test file for clarity
j9t Oct 9, 2024
07a225d
feat: improve image compression handling
j9t Oct 9, 2024
9749bbd
feat: improve file compression logging messages
j9t Oct 9, 2024
9aed0c5
feat: add logMessage function for consistent logging
j9t Oct 9, 2024
22ca1db
feat: enhance logMessage to support dynamic colors
j9t Oct 9, 2024
55bbba3
feat: improve error handling and code readability
j9t Oct 9, 2024
089a904
feat: enhance error logging and file handling in compression
j9t Oct 9, 2024
d97d7a2
docs: format parameters section in README
j9t Oct 9, 2024
cdbb17f
feat: switch from execFileSync to execFile
j9t Oct 9, 2024
95f104e
feat(docs): update README.md for clarity
j9t Oct 9, 2024
df19687
feat: add file size check and conditional copy
j9t Oct 9, 2024
1723c9a
refactor: improve maintainability in file compression logic
j9t Oct 9, 2024
7ef3e1d
fix: clarify error message for zero compressed file size
j9t Oct 9, 2024
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
24 changes: 11 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Imagemin Guard

(This project has been based on [sum.cumo’s imagemin-merlin](https://github.com/sumcumo/imagemin-merlin). [Changes are documented](https://github.com/sumcumo/imagemin-merlin/compare/master...j9t:master), and include this README. Imagemin Guard supports two additional file formats—WebP and AVIF—, comes with improved code and documentation, and is being maintained—including automatically updated dependencies.)
(This project was based on [sum.cumo’s imagemin-merlin](https://github.com/sumcumo/imagemin-merlin). [Changes are documented](https://github.com/sumcumo/imagemin-merlin/compare/master...j9t:master), and include this README. Imagemin Guard supports two additional file formats—WebP and AVIF—, comes with improved code and documentation, and is being maintained. For this reason it’s not based on any imagemin packages anymore.)

Imagemin Guard takes care of lossless compression of your images, to help you avoid bloat in your repositories. It’s an extension of [imagemin](https://www.npmjs.com/package/imagemin) and a fork of [imagemin-merlin (Merlin)](https://github.com/sumcumo/imagemin-merlin) that makes it convenient and safe to automatically compress JPG, PNG, GIF, WebP, and AVIF images.
Imagemin Guard takes care of near-lossless compression of your images, to help you avoid bloat in your repositories. It makes it convenient and as safe as possible to automatically compress JPG, PNG, GIF, WebP, and AVIF images.

It’s convenient because setup is simple. Install, run, add hook, done.

It’s safe because compression happens _losslessly_. Therefore, no worries about forgetting to compress images, but no worries about sacrificing too much quality, either. (You can take care of additional optimizations by yourself or through other tooling.)
It’s as safe as possible because compression happens losslessly (near-lossless for PNG and GIF images). Therefore, practically no worries about forgetting to compress images, but no worries about sacrificing too much quality, either. (You can take care of additional optimizations by yourself or through other tooling.)

## Installation and Use

Expand Down Expand Up @@ -45,15 +45,15 @@ git commit -m "feat: add Husky pre-commit hook for Imagemin Guard"

### Parameters

`--dry` allows to run Imagemin Guard in “dry mode.” All changed files can then be inspected under `/tmp/imagemin-guard`.
`--dry` allows to run Imagemin Guard in “dry mode.” All changes are being shown in the terminal.

`--ignore` allows to specify paths to be ignored (as in `--ignore=example,test`). Multiple paths have to be separated by comma. (Files and paths specified in .gitignore files are generally ignored.)

`--staged` (recommended with automated use) triggers a mode that watches JPG, PNG, GIF, WebP, and AVIF files in `git diff` and only compresses those files—that approach makes Imagemin Guard more efficient in operation.

## How Does the Output Look Like?

Roughly like this (the screenshot shows an early version of Merlin):
Roughly like this (the screenshot is still based on an early version of Merlin):

![Screenshot of Imagemin Guard’s predecessor, Merlin, in operation.](https://raw.githubusercontent.com/j9t/imagemin-guard/master/media/output.png)

Expand All @@ -63,19 +63,19 @@ Roughly like this (the screenshot shows an early version of Merlin):

## How Does Imagemin Guard Work?

Imagemin Guard is a Node script that puts a wrapper around [imagemin-cli](https://www.npmjs.com/package/imagemin-cli) and the packages [imagemin-mozjpeg](https://www.npmjs.com/package/imagemin-mozjpeg), [imagemin-optipng](https://www.npmjs.com/package/imagemin-optipng), [imagemin-gifsicle](https://www.npmjs.com/package/imagemin-gifsicle), [imagemin-webp](https://www.npmjs.com/package/imagemin-webp), and [imagemin-avif](https://www.npmjs.com/package/imagemin-avif).
Imagemin Guard is a Node script currently using [sharp](https://www.npmjs.com/package/sharp) and [gifsicle](https://www.npmjs.com/package/gifsicle) under the hood.

Automated compression works by monitoring whether a given change list includes any JPGs, PNGs, GIFs, WebPs, or AVIFs. It’s initiated by a Git hook. Only those images are compressed where there is an improvement. The compressed images can then be committed to the underlying repository.
Automated compression works by monitoring whether a given [change list](https://webglossary.info/terms/change-list/) includes any JPGs, PNGs, GIFs, WebPs, or AVIFs. It’s initiated by a Git hook. Only those images are compressed where there is an improvement. The compressed images can then be committed to the underlying repository.

Through this approach, though still glossed over here, Imagemin Guard makes up for what’s missing or complicated in imagemin and related packages, namely easy, riskless, automated, resource-friendly in-repo optimization.
Through this approach, though still glossed over here, Imagemin Guard makes up for what’s missing or complicated in other packages, namely easy, near-riskless, automated, resource-friendly in-repo optimization.
j9t marked this conversation as resolved.
Show resolved Hide resolved

## Why Use Imagemin Guard?

(This is a paraphrased remainder of earlier documentation, left in case it makes anything more clear ☺️)

You _can_ use Imagemin Guard if you need a simple, automatable, robust solution to compress images and to keep the compressed results in your repository (instead of only in the production environment).

That last piece is important, as Imagemin Guard compresses losslessly, so there’s no risk that images suffer from quality issues after processing. With this kind of defensive base compression, there’s no reason, and only advantages, to feed back compressed graphics into the respective source repository.
That last piece is important, as Imagemin Guard compresses near-losslessly, so there’s little risk that images suffer from quality issues after processing. With this kind of defensive base compression, there’s no reason, and only advantages, to feed back compressed graphics into the respective source repository.

## What Does Imagemin Guard _Not_ Do?

Expand All @@ -85,11 +85,9 @@ The point is: Micro-optimization still needs to be taken care of through other m

## What’s Next?

Following [Merlin](https://github.com/sumcumo/imagemin-merlin), which Imagemin Guard is based on, new features may include the option to configure the underlying imagemin plugins (somewhat prepared but not completed yet), or supporting projects in which the project’s .git folder is not at the same level as its package.json (at the moment, automatic mode doesn’t work in these cases).
There are a few ideas, like supporting projects in which the project’s .git folder is not at the same level as its package.json (currently, automatic mode doesn’t work in these cases).

Also, as some imagemin packages are not maintained at the moment, it may be useful or necessary to change to a different compression solution, like [Sqoosh](https://github.com/GoogleChromeLabs/squoosh). The situation is being monitored. Ideally, any change here will only happen under the hood.

Thoughts or suggestions? Please [file an issue](https://github.com/j9t/imagemin-guard/issues/new) or send a pull request (some code still needs care). Thank you!
Feedback is appreciated: Please [file an issue](https://github.com/j9t/imagemin-guard/issues/new) or send a pull request. Thank you!

## License

Expand Down
23 changes: 20 additions & 3 deletions bin/imagemin-guard.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const testFolder = path.join(__dirname, '../media/test')
const testFolderGit = path.join(__dirname, '../media/test-git')
const imageminGuardScript = path.join(__dirname, '../bin/imagemin-guard.js')
// Crutch to avoid files like .DS_Store to sneak in
// @@ Consolidate with package, to keep image definitions DRY
// @@ Consolidate with package, to keep image definitions DRY (once there’s better Jest ESM support?)
const allowedFileTypes = ['avif', 'gif', 'jpg', 'jpeg', 'png', 'webp']

// Function to copy files
Expand Down Expand Up @@ -55,7 +55,7 @@ function areImagesAlreadyCompressed(dir) {

describe('Imagemin Guard', () => {
beforeAll(() => {
// Backup original images
// Back up original images
copyFiles(testFolder, testFolderGit)
})

Expand All @@ -74,7 +74,6 @@ describe('Imagemin Guard', () => {
// Verify images are compressed
const { allCompressed, uncompressedFiles } = areImagesCompressed(testFolderGit)
if (uncompressedFiles.length > 0) {
// @@ Ensure all compressed files are listed
console.log('The following files were not compressed:', uncompressedFiles.join(', '))
}
expect(allCompressed).toBe(true)
Expand Down Expand Up @@ -106,4 +105,22 @@ describe('Imagemin Guard', () => {
}
expect(allCompressed).toBe(true)
})

test('Do not modify files in dry run', () => {
const originalStats = fs.readdirSync(testFolderGit).map(file => {
const filePath = path.join(testFolderGit, file)
return { file, stats: fs.statSync(filePath) }
})
execSync(`node ${imageminGuardScript} --dry`)
const newStats = fs.readdirSync(testFolderGit).map(file => {
const filePath = path.join(testFolderGit, file)
return { file, stats: fs.statSync(filePath) }
})
originalStats.forEach((original, index) => {
const newFile = newStats[index]
expect(newFile.file).toStrictEqual(original.file)
expect(newFile.stats.size).toStrictEqual(original.stats.size)
expect(newFile.stats.mtime).toStrictEqual(original.stats.mtime)
})
})
})
Binary file modified media/output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified media/test/test.avif
Binary file not shown.
Binary file modified media/test/test.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified media/test/test.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified media/test/test.webp
Binary file not shown.
Loading
Loading