Darek Kay's picture
Darek Kay
Solving web mysteries

Delaying asset requests in Eleventy

While building my photography portfolio, I've put much effort into optimizing the picture loading behavior. One technique is to provide a visual fallback as long as the images are still loading. First, a static background color included in the markup is displayed. As soon as a tiny script has been loaded, the color placeholder is replaced with a blurred picture representation. Finally, the actual image is shown.

Three website screenshots. The first contains elements with a brown background. The second contains blurred images. The third contains fully rendered images.

I've noticed it was difficult to test my implementation. On a fast network, the fallback is only visible for a split of a second. The slow network simulation in the browser developer tools doesn't help much:

  • The JS script is small enough, so I still can't see the fixed color background.
  • The HTML page itself is delayed as well, which slows down the testing.

My first solution was to write a small Express server, routing my assets and artificially delaying responses. Only later I've learned that Eleventy 2.0 supports request middleware out of the box, so I've migrated my solution. Notice that Eleventy middleware is not yet documented — a GitHub issue was my main source of information.

The middleware API is similar to Express. In the following example, each asset request is delayed by one to five seconds:

const delayMiddleware = async (req, res, next) => {
  if (req.url.endsWith("/") || req.url.endsWith(".html")) {
    // no delay necessary for HTML pages
    return next();
  }

  const timeoutInSeconds = Math.floor(Math.random() * 5) + 1;
  return setTimeout(() => {
    return next();
  }, timeoutInSeconds * 1000);
};

To use custom middleware, we have to include it in the Eleventy configuration file:

module.exports = function (eleventyConfig) {
  eleventyConfig.setServerOptions({
    middleware: [delayMiddleware],
  });
}

I've extracted the delay middleware into a reusable utility that I can use in all my Eleventy projects. In the following example, I'm delaying only JPG files by one to three seconds:

const delayMiddleware = require("@darekkay/11ty/lib/utils/middleware/delay");

eleventyConfig.setServerOptions({
  middleware: [delayMiddleware({
    maxDelayInSeconds: 3,
    applyFilter: (req) => req.endsWith("jpg")
  })],
});

Related posts

Delaying asset requests in Eleventy