Skip to content
Cloudflare Docs

Image maintenance

Though valuable for user understanding, images are difficult to maintain. We have a few strategies that we use to help make this easier.

Guidelines

We support a few different types of images in our docs, including:

Of these, we prefer Mermaid diagrams because they are searchable and easily changeable. The "cost" of updating a Mermaid diagram is much lower than re-taking a screenshot or working with a designer to update a diagram.

Maintenance

The best way to improve image maintenance is to avoid using them.

The other way to streamline maintenance is to remove images that are no longer referenced in your documentation. This pattern becomes particularly helpful if you need to audit images for UI changes or leaked information, because then you are not wasting time looking at unused images too.

We do that through a combination of GitHub actions.

Flag unused images

We have a specific GitHub action to flag unused images.

What the GitHub action does is:

  1. Finds all .png or .svg files in our content.
  2. Checks to see if those files are referenced in any of our MDX files.
  3. Ceates a GitHub issue if there are unreferenced files.

Evaluate image paths

In combination with flagging unused images, we also have logic in our build process to validate image paths.

astro.config.ts
export default defineConfig({
site: "https://developers.cloudflare.com",
markdown: {
smartypants: false,
remarkPlugins: [remarkValidateImages],
rehypePlugins: [
rehypeMermaid,
rehypeExternalLinks,
rehypeHeadingSlugs,
rehypeAutolinkHeadings,
// @ts-expect-error plugins types are outdated but functional
rehypeTitleFigure,
rehypeShiftHeadings,
],
},

This line ensures that our custom Remark plugin validates all images paths. If the path does not exist, we throw an error and prevent the site from building.

validate-images.ts
import { existsSync } from "node:fs";
import { join } from "node:path";
import { visit } from "unist-util-visit";
import type { Node } from "unist";
import type { VFile } from "vfile";
interface ImageNode extends Node {
type: "image";
url: string;
position?: {
start: { line: number; column: number };
end: { line: number; column: number };
};
}
export default function validateImages() {
const rootDir = process.cwd();
const assetsDir = join(rootDir, "src", "assets");
const publicDir = join(rootDir, "public");
return (tree: Node, file: VFile) => {
visit(tree, "image", (node: ImageNode) => {
const { url } = node;
let fullPath: string;
if (url.startsWith("~/assets/")) {
fullPath = join(assetsDir, url.slice(9));
} else if (url.startsWith("/")) {
fullPath = join(publicDir, url);
} else {
// Remote image or unrecognised URL
return;
}
if (!existsSync(fullPath)) {
const position = node.position
? ` at line ${node.position.start.line}, column ${node.position.start.column}`
: "";
const error = new Error(
`Image not found: "${url}"${position} in ${file.path}\n` +
`Expected to find at: ${fullPath}`,
) as Error & { file?: string };
error.file = file.path;
throw error;
}
});
};
}

When paired with flagging unused images, this path validation ensures that a tech writer can safely delete unused files in a pull request. So long as the site builds correctly, you have only deleted image files that are not referenced anywhere.