@carrotsearch/gatsby-transformer-html
Version:
A Gatsby transformer plugin for authoring content in HTML. Supports ToC generation, responsive images, section anchors and HighlightJS code highlighting.
79 lines (69 loc) • 2.51 kB
JavaScript
const { fluid } = require("gatsby-plugin-sharp");
const { notInPre } = require("../cheerio-utils");
const path = require("path");
/**
* Process images through "gatsby-plugin-sharp". This will copy and optimize
* the image in multiple resolutions for different devices.
*/
exports.ImageProcessor = function ({
getNodesByType,
pathPrefix,
imageQuality,
reporter,
cache
}) {
this.transform = async $ => {
const $img = $("img").filter(notInPre($));
if ($img.length === 0) {
return $;
}
// Collect nodes for all files we process.
const fileNodesByPath = getNodesByType("File").reduce((map, n) => {
map.set(n.relativePath, n);
return map;
}, new Map());
// Collect images whose relative paths point at existing files.
const imageNodesToProcess = [];
$img.each((i, img) => {
const src = path.posix.normalize(img.attribs.src);
if (fileNodesByPath.has(src)) {
imageNodesToProcess.push(fileNodesByPath.get(src));
} else {
reporter.warn(`Image file not found for img src ${src}.`);
}
});
// Process the images through the sharp plugin.
const processed = await Promise.all(
imageNodesToProcess.map(n =>
fluid({
file: n,
args: { maxWidth: 40 * 18, pathPrefix, quality: imageQuality },
reporter,
cache
})
)
);
const processedByRelativePath = processed.reduce((map, fluid, i) => {
map.set(imageNodesToProcess[i].relativePath, fluid);
return map;
}, new Map());
// Replace the images in the HTML.
$img
.filter((i, img) => processedByRelativePath.has(path.posix.normalize(img.attribs.src)))
.replaceWith((i, img) => {
const fluid = processedByRelativePath.get(path.posix.normalize(img.attribs.src));
const className = [img.attribs.class].filter(e => !!e).join(" ");
const ratio = `${(1 / fluid.aspectRatio) * 100}%`;
const previewImg = `<span style="padding-bottom: ${ratio}; background-image: url('${fluid.base64}')"
class="preview ${className}"> </span>`;
const mainImg = `<img class="${className}"
alt="${img.attribs.alt || ""}"
title="${img.attribs.title || ""}"
src="${fluid.src}"
srcSet="${fluid.srcSet}"
sizes="${fluid.sizes}" />`;
return `<div class="img" style="position: relative">${previewImg}${mainImg}</div>`;
});
return $;
};
};