Problem Statement
In production, the benefits of image optimization using Astro's Image/Picture component are lost when integrating with Tina CMS and Tina Cloud. However, I have found a workaround to resolve this issue. Whether this workaround is the best or a good fit for client websites remains uncertain, but here are the details. For further context, you can read the github discussion here.
Preface
Typically, you have a markdown file with an image path pointing to a locally based image, like so:
imgSrc: /src/assets/img/logo.png
...
To leverage the image optimization benefits of the Astro Image component, such as generating multiple versions of an image based on device density, you would use dynamic image imports as described in astro docs. Everything works perfectly in development mode when you run npm run "tinacms dev -c \"astro dev\"",
. Tina CLI commands But for clarity here an example of importing images dynamically.
---
import type { ImageMetadata } from "astro";
import { Image } from "astro:assets";
interface Props {
imgSrc: string;
}
const { imgSrc } = Astro.props;
const images = import.meta.glob<{ default: ImageMetadata }>("/src/assets/img/*.{jpeg,jpg,png,gif}");
if (!images[imgSrc]) {
throw new Error(`"${imgSrc}" does not exist in glob: "src/assets/img/*.{jpeg,jpg,png,gif}"`);
}
---
<Image
width="70"
height="70"
src={images[imgSrc]()}
alt="test image"
densities={[1.5, 2]}
loading="lazy"
/>
The Production Issue
In production, Tina CMS typically retrieves its media from its own CDN server (e.g., https://assets.tina.io/image). This setup conflicts with Astro's automatic image optimization and the associated glob pattern.
The function tries to search for the image in the local path. This works in development mode, but in production, the imgSrc
returned from the markdown file is no longer a local string. Instead, it returns a URL like https://assets.tina.io/image, causing the search function aka glob function to fail and resulting in a build error.
For more information, refer to the github discussion here.
Workaround for Using Image Optimization
To still leverage Astro's image optimization in production, you need to adapt the build script:
Modified Build Script
The build script must be updated to:
"scripts": {
"build": "tinacms build --local -c \"astro build\""
}
However, be aware that dynamically fetching data will no longer work as expected. For example, querying dynamic data using Tina's client in for example a Date component will not working properly.
Example script of my dynamically data fetches
<script>
import { formatMarkdownUrl, formatDateString } from "../utils/format";
document.addEventListener("DOMContentLoaded", async () => {
try {
const { client } = await import(
"../../tina/__generated__/client"
);
async function getLiveDatesResponse() {
try {
const response =
await client.queries.live_dateConnection({
sort: "date",
});
return response;
} catch (error) {
console.error(
error,
);
return null;
}
}
}
})
</script>
Conclusion
This workaround allows you to leverage Astro's image optimization benefits in production while using Tina CMS and Tina Cloud. However, it introduces limitations in dynamically fetching data, which may not be suitable for all use cases. Evaluate whether this approach fits your project's requirements and constraints.
For further reading and to join the discussion, check out the GitHub discussion.
Top comments (2)
A short update on my situation.
We all know it, you sit in front of a problem, ponder and try around and the solution is so simple, only you just don't see it -.-
It helped me to reread my own written article. In sentence
I indirectly presented myself with a solution.
A simple if condition to check whether the images should be used locally or from the Tina CDN is sufficient here. Here is my code:
With this solution I can now use optimized images as well as the dynamic query via the graphql server as in my example in the date component.
Whether it is a legitimate way I can not answer, it feels like a workaround that works for my purposes so far
hey Jan, please how do i adapt this in regards to displaying markdown content that contains images using the
<Content/>
component in Astro.