diff --git a/README.md b/README.md
index 715087d..6979216 100644
--- a/README.md
+++ b/README.md
@@ -108,6 +108,13 @@ Default: `true`
> Ignore the optimized output if it is larger than the original file.
+### cache
+
+Type: `boolean`
+Default: `true`
+
+> Skip optimizing the input if it did not change since the last run.
+
### makeAvif / makeWebp
Type: `object`
diff --git a/package-lock.json b/package-lock.json
index 20aa19a..329c727 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,15 +11,15 @@
"packages/*"
],
"devDependencies": {
- "@typescript-eslint/eslint-plugin": "^6.9.1",
- "@typescript-eslint/parser": "^6.9.1",
+ "@typescript-eslint/eslint-plugin": "^6.11.0",
+ "@typescript-eslint/parser": "^6.11.0",
"@vheemstra/imagemin-avifenc": "^2.1.0",
"@vheemstra/imagemin-oxipng": "^1.0.0",
"@vitest/coverage-c8": "^0.32.2",
"@vitest/coverage-istanbul": "^0.34.6",
"cross-env": "^7.0.3",
"cross-var": "^1.1.0",
- "eslint": "^8.52.0",
+ "eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-vitest-globals": "^1.4.0",
@@ -32,7 +32,7 @@
"imagemin-svgo": "^10.0.1",
"imagemin-webp": "^8.0.0",
"npm-run-all": "^4.1.5",
- "prettier": "^3.0.3",
+ "prettier": "^3.1.0",
"serve": "^14.2.1",
"typescript": "^5.2.2",
"vite": "^4.5.0",
@@ -894,9 +894,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
- "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz",
+ "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
@@ -944,14 +944,26 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.52.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz",
- "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==",
+ "version": "8.53.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz",
+ "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@file-cache/core": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@file-cache/core/-/core-1.1.4.tgz",
+ "integrity": "sha512-UWUzHu67Mz95Z5Gs10mu/tvPVY5vIPdOiqM6+TVbaEdxNZ/9D5ojOwyHor/J09QzQhuXp1tIlKbu6/s1od2NvQ==",
+ "dependencies": {
+ "pkg-dir": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=16.12.0",
+ "npm": ">=6.14.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.13",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
@@ -1214,9 +1226,9 @@
"dev": true
},
"node_modules/@types/json-schema": {
- "version": "7.0.14",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz",
- "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==",
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
"dev": true
},
"node_modules/@types/keyv": {
@@ -1276,22 +1288,22 @@
"dev": true
},
"node_modules/@types/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==",
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz",
+ "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==",
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz",
- "integrity": "sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz",
+ "integrity": "sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "6.9.1",
- "@typescript-eslint/type-utils": "6.9.1",
- "@typescript-eslint/utils": "6.9.1",
- "@typescript-eslint/visitor-keys": "6.9.1",
+ "@typescript-eslint/scope-manager": "6.11.0",
+ "@typescript-eslint/type-utils": "6.11.0",
+ "@typescript-eslint/utils": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
"ignore": "^5.2.4",
@@ -1317,15 +1329,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz",
- "integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.11.0.tgz",
+ "integrity": "sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "6.9.1",
- "@typescript-eslint/types": "6.9.1",
- "@typescript-eslint/typescript-estree": "6.9.1",
- "@typescript-eslint/visitor-keys": "6.9.1",
+ "@typescript-eslint/scope-manager": "6.11.0",
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/typescript-estree": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0",
"debug": "^4.3.4"
},
"engines": {
@@ -1345,13 +1357,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz",
- "integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz",
+ "integrity": "sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.9.1",
- "@typescript-eslint/visitor-keys": "6.9.1"
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
@@ -1362,13 +1374,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz",
- "integrity": "sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz",
+ "integrity": "sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/typescript-estree": "6.9.1",
- "@typescript-eslint/utils": "6.9.1",
+ "@typescript-eslint/typescript-estree": "6.11.0",
+ "@typescript-eslint/utils": "6.11.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.0.1"
},
@@ -1389,9 +1401,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz",
- "integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.11.0.tgz",
+ "integrity": "sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
@@ -1402,13 +1414,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz",
- "integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz",
+ "integrity": "sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.9.1",
- "@typescript-eslint/visitor-keys": "6.9.1",
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/visitor-keys": "6.11.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -1429,17 +1441,17 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz",
- "integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.11.0.tgz",
+ "integrity": "sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "6.9.1",
- "@typescript-eslint/types": "6.9.1",
- "@typescript-eslint/typescript-estree": "6.9.1",
+ "@typescript-eslint/scope-manager": "6.11.0",
+ "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/typescript-estree": "6.11.0",
"semver": "^7.5.4"
},
"engines": {
@@ -1454,12 +1466,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz",
- "integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==",
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz",
+ "integrity": "sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.9.1",
+ "@typescript-eslint/types": "6.11.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
@@ -4963,15 +4975,15 @@
}
},
"node_modules/eslint": {
- "version": "8.52.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz",
- "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==",
+ "version": "8.53.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz",
+ "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.2",
- "@eslint/js": "8.52.0",
+ "@eslint/eslintrc": "^2.1.3",
+ "@eslint/js": "8.53.0",
"@humanwhocodes/config-array": "^0.11.13",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -8638,6 +8650,96 @@
"node": ">= 6"
}
},
+ "node_modules/pkg-dir": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-6.0.1.tgz",
+ "integrity": "sha512-C9R+PTCKGA32HG0n5I4JMYkdLL58ZpayVuncQHQrGeKa8o26A4o2x0u6BKekHG+Au0jv5ZW7Xfq1Cj6lm9Ag4w==",
+ "dependencies": {
+ "find-up": "^6.1.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/find-up": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
+ "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
+ "dependencies": {
+ "locate-path": "^7.1.0",
+ "path-exists": "^5.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/locate-path": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
+ "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
+ "dependencies": {
+ "p-locate": "^6.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/p-limit": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+ "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+ "dependencies": {
+ "yocto-queue": "^1.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/p-locate": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
+ "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
+ "dependencies": {
+ "p-limit": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/path-exists": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
+ "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/yocto-queue": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+ "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/pkg-types": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
@@ -8849,9 +8951,9 @@
}
},
"node_modules/prettier": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz",
- "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
+ "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
@@ -11782,6 +11884,7 @@
"version": "1.0.12",
"license": "MIT",
"dependencies": {
+ "@file-cache/core": "^1.1.4",
"chalk": "^5.2.0",
"fast-glob": "^3.2.12",
"fs-extra": "^11.1.1",
diff --git a/package.json b/package.json
index 22c89f6..255f2c3 100644
--- a/package.json
+++ b/package.json
@@ -56,15 +56,15 @@
"postversion": "git push --follow-tags"
},
"devDependencies": {
- "@typescript-eslint/eslint-plugin": "^6.9.1",
- "@typescript-eslint/parser": "^6.9.1",
+ "@typescript-eslint/eslint-plugin": "^6.11.0",
+ "@typescript-eslint/parser": "^6.11.0",
"@vheemstra/imagemin-avifenc": "^2.1.0",
"@vheemstra/imagemin-oxipng": "^1.0.0",
"@vitest/coverage-c8": "^0.32.2",
"@vitest/coverage-istanbul": "^0.34.6",
"cross-env": "^7.0.3",
"cross-var": "^1.1.0",
- "eslint": "^8.52.0",
+ "eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-vitest-globals": "^1.4.0",
@@ -77,7 +77,7 @@
"imagemin-svgo": "^10.0.1",
"imagemin-webp": "^8.0.0",
"npm-run-all": "^4.1.5",
- "prettier": "^3.0.3",
+ "prettier": "^3.1.0",
"serve": "^14.2.1",
"typescript": "^5.2.2",
"vite": "^4.5.0",
diff --git a/packages/core/package.json b/packages/core/package.json
index a1b41f0..7776006 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -61,6 +61,7 @@
"node": ">=16.0.0"
},
"dependencies": {
+ "@file-cache/core": "^1.1.4",
"chalk": "^5.2.0",
"fast-glob": "^3.2.12",
"fs-extra": "^11.1.1",
diff --git a/packages/core/src/index.test.ts b/packages/core/src/index.test.ts
index cdc8b84..23b3689 100644
--- a/packages/core/src/index.test.ts
+++ b/packages/core/src/index.test.ts
@@ -1368,6 +1368,7 @@ describe('logErrors', () => {
* dist/images/opaque-1.png.avif
*/
+// TODO: add tests using cache
// TODO: expand after-build checks
describe.skipIf(skipBuilds)('viteImagemin', () => {
@@ -1452,6 +1453,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
// skipIfLargerThan: 'optimized',
// skipIfLargerThan: 'smallest',
},
+ cache: false,
}
const testConfig = getBuildConfig(viteImagemin(options), {
@@ -1518,6 +1520,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
skipIfLargerThan: 'smallest' as const,
},
logger: mockLogger,
+ cache: false,
}
const testConfig = getBuildConfig(viteImagemin(options), {
@@ -1574,6 +1577,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
],
},
logger: mockLogger,
+ cache: false,
}
const testConfig = getBuildConfig(viteImagemin(options), {
@@ -1619,6 +1623,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
plugins: {
gif: [mockPlugin],
},
+ cache: false,
}
const testConfig = getBuildConfig(viteImagemin(options), {
@@ -1649,6 +1654,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
plugins: {
gif: [mockPlugin],
},
+ cache: false,
}
const testConfig = getBuildConfig(viteImagemin(options), {
@@ -1684,6 +1690,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
}),
],
},
+ cache: false,
}
const testConfig = getBuildConfig(viteImagemin(options), {
@@ -1714,6 +1721,7 @@ describe.skipIf(skipBuilds)('viteImagemin', () => {
plugins: {
none: [mockPlugin],
},
+ cache: false,
}
const testConfig = getBuildConfig(viteImagemin(options), {
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index dd2b147..9278761 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -1,5 +1,10 @@
import path from 'node:path'
-import { lstatSync, readdirSync, unlinkSync /*, rmSync */ } from 'node:fs'
+import {
+ existsSync,
+ lstatSync,
+ readdirSync,
+ unlinkSync /*, rmSync */,
+} from 'node:fs'
import { readFile, writeFile } from 'node:fs/promises'
import { Buffer } from 'node:buffer'
import { performance } from 'node:perf_hooks'
@@ -7,6 +12,8 @@ import chalk from 'chalk'
import { normalizePath, createFilter } from 'vite'
import imagemin from 'imagemin'
import isAPNG from 'is-apng'
+import { createCache } from '@file-cache/core'
+
import {
isFunction,
isBoolean,
@@ -34,6 +41,7 @@ import type {
ProcessResult,
ProcessFileReturn,
} from './typings'
+import { CacheInterface } from '@file-cache/core/mjs/CacheInterface'
export const parsePlugins = (rawPlugins: PluginsConfig) => {
let plugins: false | ResolvedPluginsConfig = false
@@ -84,8 +92,8 @@ export const parseOptions = (
false === _options.makeAvif.skipIfLargerThan
? _options.makeAvif.skipIfLargerThan
: isString(_options.makeAvif.skipIfLargerThan)
- ? _options.makeAvif.skipIfLargerThan
- : 'optimized',
+ ? _options.makeAvif.skipIfLargerThan
+ : 'optimized',
}
}
}
@@ -104,8 +112,8 @@ export const parseOptions = (
false === _options.makeWebp.skipIfLargerThan
? _options.makeWebp.skipIfLargerThan
: isString(_options.makeWebp.skipIfLargerThan)
- ? _options.makeWebp.skipIfLargerThan
- : 'optimized',
+ ? _options.makeWebp.skipIfLargerThan
+ : 'optimized',
}
}
}
@@ -131,6 +139,7 @@ export const parseOptions = (
skipIfLarger: isBoolean(_options?.skipIfLarger)
? _options.skipIfLarger
: true,
+ cache: isBoolean(_options?.cache) ? _options.cache : true,
plugins,
makeAvif,
makeWebp,
@@ -179,6 +188,7 @@ export async function processFile({
precisions,
bytesDivider,
sizeUnit,
+ cache,
}: ProcessFileParams): ProcessFileReturn {
// const start = performance.now()
@@ -200,6 +210,24 @@ export async function processFile({
}) as Promise
}
+ if (cache) {
+ const result = await cache.getAndUpdateCache(baseDir + filePathFrom)
+ if (!result.changed) {
+ const outputsStillExist = fileToStack.every(item => {
+ return existsSync(baseDir + item.toPath)
+ })
+
+ if (outputsStillExist) {
+ return Promise.reject({
+ oldPath: filePathFrom,
+ newPath: '',
+ error: '',
+ errorType: 'cache',
+ }) as Promise
+ }
+ }
+ }
+
let oldBuffer: Buffer
let oldSize = 0
@@ -526,8 +554,8 @@ export function logResults(
file.ratio < 0
? chalk.green(basenameTo)
: file.ratio > 0
- ? chalk.yellow(basenameTo)
- : basenameTo,
+ ? chalk.yellow(basenameTo)
+ : basenameTo,
' '.repeat(
maxPathLength - bulletLength - file.newPath.length + spaceLength,
),
@@ -542,8 +570,8 @@ export function logResults(
file.ratio < 0
? chalk.green(file.ratioString)
: file.ratio > 0
- ? chalk.red(file.ratioString)
- : file.ratioString,
+ ? chalk.red(file.ratioString)
+ : file.ratioString,
chalk.dim(' │ '),
// Duration
@@ -612,6 +640,9 @@ export function logErrors(
file.error,
)
break
+ case 'cache':
+ logArray.push(chalk.black.bgBlue(' CACHED '), ' ', file.error)
+ break
case 'warning':
logArray.push(
chalk.bgYellow(' WARNING '),
@@ -653,6 +684,9 @@ export function logErrors(
file.error,
)
break
+ case 'cache':
+ logArray.push(chalk.black.bgBlue(' CACHED '), ' ', file.error)
+ break
case 'warning':
logArray.push(
chalk.bgYellow(' WARNING '),
@@ -716,6 +750,8 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
let hadFilesToProcess = false
// const mtimeCache = new Map()
+ let cache: CacheInterface
+
return {
name: 'vite-plugin-imagemin',
enforce: 'post',
@@ -746,6 +782,17 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
const baseDir = `${root}/`
const rootRE = new RegExp(`^${escapeRegExp(baseDir)}`)
+ // Create cache for this run
+ cache = (await createCache({
+ noCache: options.cache === false,
+ mode: 'content',
+ keys: [
+ () => {
+ return JSON.stringify(options)
+ },
+ ],
+ })) as CacheInterface
+
// Get all input files to (potentially) process
const files = getAllFiles(processDir, logger)
.filter(filter)
@@ -852,6 +899,7 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
precisions,
bytesDivider,
sizeUnit,
+ cache,
}),
),
) as Promise
@@ -965,6 +1013,9 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
logResults(processedFiles[k], logger, maxLengths)
})
+ // Write cache state to file for persistence
+ await cache.reconcile()
+
Object.keys(erroredFiles)
.sort((a, b) => a.localeCompare(b)) // TODO: sort by (sub)folder and depth?
.forEach(k => {
@@ -989,16 +1040,18 @@ export default function viteImagemin(_options: ConfigOptions): PluginOption {
totalDuration.length,
) + 2
const totalRatio = (totalSize.to / totalSize.from - 1) * 100
- const totalRatioString =
- totalRatio < 0
+
+ const totalRatioString = isNaN(totalRatio)
+ ? '0 %'
+ : totalRatio < 0
? chalk.green(
`-${Math.abs(totalRatio).toFixed(precisions.ratio)} %`,
)
: totalRatio > 0
- ? chalk.red(
- `+${Math.abs(totalRatio).toFixed(precisions.ratio)} %`,
- )
- : `${Math.abs(totalRatio).toFixed(precisions.ratio)} %`
+ ? chalk.red(
+ `+${Math.abs(totalRatio).toFixed(precisions.ratio)} %`,
+ )
+ : `${Math.abs(totalRatio).toFixed(precisions.ratio)} %`
logger.info('')
diff --git a/packages/core/src/typings.d.ts b/packages/core/src/typings.d.ts
index cb11cdc..7abe90d 100644
--- a/packages/core/src/typings.d.ts
+++ b/packages/core/src/typings.d.ts
@@ -1,5 +1,6 @@
import type { Logger as ViteLogger, FilterPattern } from 'vite'
import type { Plugin as ImageminPlugin } from 'imagemin'
+import { CacheInterface } from '@file-cache/core/mjs/CacheInterface'
// type Required = {
// [P in keyof T]-?: T[P]
@@ -79,6 +80,12 @@ export interface ConfigOptions {
*/
verbose?: boolean
+ /**
+ * Only optimize contents if it was updated.
+ * @default true
+ */
+ cache?: boolean
+
/**
* Only use optimized contents if smaller than original.
* @default true
@@ -128,6 +135,7 @@ export interface ResolvedConfigOptions {
onlyAssets: boolean
verbose: boolean
skipIfLarger: boolean
+ cache: boolean
plugins: ResolvedPluginsConfig
makeAvif: false | ResolvedMakeConfigOptions
makeWebp: false | ResolvedMakeConfigOptions
@@ -162,6 +170,7 @@ export type ProcessFileParams = {
}
bytesDivider: number
sizeUnit: string
+ cache: CacheInterface
}
export type ProcessedFile = {
diff --git a/packages/playground/vite.config.ts b/packages/playground/vite.config.ts
index 97f4fa6..3eddf1d 100644
--- a/packages/playground/vite.config.ts
+++ b/packages/playground/vite.config.ts
@@ -51,6 +51,7 @@ export default defineConfig({
// skipIfLargerThan: 'optimized', // default
// skipIfLargerThan: 'smallest',
},
+ // cache: false,
}),
],
})