Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import { visit } from 'unist-util-visit';
import sharp from 'sharp';
import path from 'node:path';
import { existsSync } from 'node:fs';
/** In-memory cache: imagePath -> { width, height } */
const dimensionCache = new Map();
/**
* Resolve a local src (e.g. `/images/blog/foo.png`) to an absolute file path.
*/
function resolveImagePath(src) {
return path.join(process.cwd(), 'static', src);
}
/**
* Get image dimensions via sharp, with caching.
* Returns { width, height } or null on failure.
*/
async function getImageDimensions(filePath) {
if (dimensionCache.has(filePath)) {
return dimensionCache.get(filePath);
}
try {
const metadata = await sharp(filePath).metadata();
const dims = { width: metadata.width, height: metadata.height };
dimensionCache.set(filePath, dims);
return dims;
} catch (err) {
// Cache the failure too so we don't retry
dimensionCache.set(filePath, null);
return null;
}
}
export default function rehypeImageDimensions() {
return async (tree) => {
const imageNodes = [];
visit(tree, 'element', (node) => {
if (node.tagName !== 'img') return;
const src = node.properties?.src;
if (!src) return;
// Only process local images starting with /images/
if (!src.startsWith('/images/')) return;
// Skip if width and height are already set
if (node.properties.width && node.properties.height) return;
imageNodes.push(node);
});
// Process all images in parallel
await Promise.all(
imageNodes.map(async (node) => {
const src = node.properties.src;
const filePath = resolveImagePath(src);
if (!existsSync(filePath)) {
console.warn(
`[rehype-image-dimensions] File not found, skipping: ${filePath}`
);
return;
}
const dims = await getImageDimensions(filePath);
if (!dims || !dims.width || !dims.height) {
console.warn(
`[rehype-image-dimensions] Could not read dimensions, skipping: ${filePath}`
);
return;
}
node.properties.width = String(dims.width);
node.properties.height = String(dims.height);
})
);
};
}
|