-
-
Notifications
You must be signed in to change notification settings - Fork 54
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
Persist in-memory cache #51
Comments
For thoses wanting a quick solution for caching optimized images whenever build starts from scratch, here is a solution. Warning, it checks for already existing file outputs by looking if their output path file is existing, it may or may not be ideal depending on your const fs = require('fs');
const Image = require('@11ty/eleventy-img');
const path = require('path');
const shortHash = require('shorthash2');
/** ... */
const options = {
/** ... */
filenameFormat: (id, src, width, format) => {
const extension = path.extname(src);
const name = path.basename(src, extension);
const stats = fs.statSync(src);
const hash = shortHash(`${src}|${stats.size}`);
return `${name}-${hash}-${width}w.${format}`;
},
};
const stats = Image.statsSync(src, options);
/** Creating a flat array of all the output paths from the stats object. */
const outputPaths = Object.keys(stats).reduce((acc, key) => {
return [
...acc,
...stats[key].map((resource) => {
return resource.outputPath;
}),
];
}, []);
/** Checking if all output files exists. */
let hasImageBeenOptimized = true;
for (const outputPath of outputPaths) {
/** Edit the output file path resolving, depending of this file */
if (!fs.existsSync(path.resolve(__dirname, '..', '..', outputPath))) {
hasImageBeenOptimized = false;
}
}
if (!hasImageBeenOptimized) {
Image(src, options);
}
/** Do whatever you want with the `stats` object */
const imageAttributes = {
// [...]
};
const html = Image.generateHTML(stats, imageAttributes, {
whitespaceMode: 'inline',
}); If you are deploying on Netlify you can cache your npm install netlify-plugin-cache In your [[plugins]]
package = "netlify-plugin-cache"
[plugins.inputs]
paths = ["<YOUR OPTIMIZED FILES OUTPUT DIR PATH>"] |
I would love for something like this to exist in the official plugin. I thought I was doing something wrong when I saw that builds took three minutes (converting 22 images into three formats and ten sizes each [though, maybe that's overkill?]). |
Just adding my tuppence here, that I'd like this too as I'm using the Image.generateHTML code to pull images remotely. The caching side of it works, but 11ty still chucks those cached images through the resizing process which annoys my laptop and takes a lot longer than is ideal :) I'm really not clear on how to get Dimitri's work-around to work with the generateHTML method - if indeed I can |
@snibbo71 My piece of code does not take into account whether the resource is remote or local. I use it with the html generation function. After my shortcode, you can generate your html code with the const imageAttributes = {
// [...]
};
const html = Image.generateHTML(stats, imageAttributes, {
whitespaceMode: 'inline',
}); (I've just added it to my previous comment, to be sure that every future reader will understand) Both Then in my shortcode, we check if those output files are existing (that's why we rely on a hashed src+file size string in output file names), if not, we call the |
Heya, thanks for the quick reply. I must be doing something entirely wrong because nothing is cached in my setup - even local stuff. Remote images just blow your code up unfortunately :) (Actually, it's the fs.statSync and Image.statSync that dies with ENOENT - which isn't entirely surprising) I shall keep playing. I have too many images to deal with to have to redo them every time I change a template :) If I come up with anything I'll post back |
Having dug into this, FileSizeCache isn't persistent, which explains why it doesn't work across restarts. At the moment I can't dig much further to see whether there's any reason not to make that another AssetCache subclass. There may be good reasons not to persist this information. And that's largely down to the fact that I'm somewhat over my head as this is my first look at anything serious with node.js anyway :) |
I'm sorry, I haven't been into 11ty image for a moment, and I never used remote images fetching. Good luck in your research! 😄 |
Since it came up in the Eleventy Meetup today, here’s a quick config-based solution that won’t build images that haven’t changed (after the initial build): const eleventyImage = require("@11ty/eleventy-img");
module.exports = function(eleventyConfig) {
let modifiedFiles = [];
eleventyConfig.on("beforeWatch", files => {
modifiedFiles = files || [];
});
// This function will likely not match your project and will require you to customize to your build.
eleventyConfig.addJavaScriptFunction("eleventyImageHtml", async function(src, options, htmlAttributes) {
let stats;
if(modifiedFiles.length === 0 || modifiedFiles.includes(src)) {
// During watch/serve, only generate images that have been modified.
stats = await eleventyImage(src, options);
} else {
// Return the metadata only without generating the Image.
stats = eleventyImage.statsSync(src, options);
}
return eleventyImage.generateHTML(stats, htmlAttributes);
});
} Read more about Events: https://www.11ty.dev/docs/events/ This solution will work in Eleventy 0.11.1+ Sample usage in an class Test {
async render() {
return this.eleventyImageHtml("./nebula.jpg", {
widths: [300],
}, {
alt: "Nebula"
});
}
}
module.exports = Test; |
Thanks very much, @zachleat — but guess I’ll have to wait until it’s incorporated in the regular |
Oh, I’ve made a mistake in my code, sorry about that! I’ll fix it |
So I went down the rabbit hole here, perhaps unnecessarily. Just to rewind a bit—we’re all aware of the existing In-Memory Cache feature right? https://www.11ty.dev/docs/plugins/image/#in-memory-cache-new-in-image-0.7.0 (this larger issue #51 is specific to persisting the in-memory cache to the file system) The approach documented at #51 (comment) is unnecessary when Also note that you can use |
Hi! Sorry, complete amateur chiming in here as I've tried interpreting the latest comments—and implementing the code provided in the most recent instance—and, I think, it's not working as desired … at least for me. No matter what I try, I can't get the cache to persist when I come back to my project a 2nd, 3rd, etc. time. Each time I open the project and run (in my case) …or, is this to be expected as eleventy-img is not setup for this particular scenario? …double-or, am I a dope and completely missing something here? |
@marcamos It works for only remote images, not local images — the latter of which is what I asked @zachleat about during an Eleventy Meetup session, which I think is part of why he entered the conversation here recently. Unfortunately, doesn’t appear that caching local images to streamline the dev process is in the cards for the plugin, at least for the time being. Perhaps there are programmatic reasons why; I’m not qualified to guess. |
fwiw, I have local images caching, i.e. not rebuilt on initial run based on @dimitrinicolas' previous answer If a nunjucks shortcode is of any use to you, see https://gist.github.com/tobystokes/b4b8bb743ec4c57317f6ef043093ff95 |
@brycewray @marcamos #116 @zeroby0 has a PR open to add this, pending review! |
@zachleat Thanks :D ! Do you think there is someone I can request to review it? For some reason I have received no feedback or suggestions on it. I'm new to the repos, I don't know how things work here |
@zeroby0 I added a few comments—it’s looking super solid! |
Shipping this with Eleventy Image 1.0—thank you! |
In-memory cache is empty whenever Eleventy build starts from scratch. It's not an issue for sites with small number of images. But for sites with large number of large images, compressing them takes quite a lot of time.
In my case (https://kamituel.pl) I've over 300 high resolution source images that I'd ideally serve in 2-3 formats (avif, jpg, maybe webp) in multiple sizes.
I propose a new config option that would, if enabled, persist the in-memory cache to disk and reuse it the next time the build starts.
If maintainers consider this idea to be a good candidate to exist in eleventy-img itself, I'd be happy to formulate this proposal more concretely and later help / submit a PR.
The text was updated successfully, but these errors were encountered: