gatsby-source-sanity
Version:
Gatsby source plugin for building websites using Sanity.io as a backend.
211 lines • 8.43 kB
JavaScript
;
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
const parseUrl = require("url-parse");
exports.LOWEST_FLUID_BREAKPOINT_WIDTH = 100;
exports.DEFAULT_FIXED_WIDTH = 400;
exports.DEFAULT_FLUID_MAX_WIDTH = 800;
var ImageFormat;
(function (ImageFormat) {
ImageFormat["NO_CHANGE"] = "";
ImageFormat["WEBP"] = "webp";
ImageFormat["JPG"] = "jpg";
ImageFormat["PNG"] = "png";
})(ImageFormat || (ImageFormat = {}));
const idPattern = /^image-[A-Za-z0-9]+-\d+x\d+-[a-z]+$/;
const sizeMultipliersFixed = [1, 1.5, 2, 3];
const sizeMultipliersFluid = [0.25, 0.5, 1, 1.5, 2, 3];
function buildImageUrl(loc, stub) {
const { projectId, dataset } = loc;
const { assetId, extension, metadata } = stub;
const { width, height } = metadata.dimensions;
const base = 'https://cdn.sanity.io/images';
return `${base}/${projectId}/${dataset}/${assetId}-${width}x${height}.${extension}`;
}
function getBasicImageProps(node, loc) {
if (!node) {
return false;
}
const obj = node;
const ref = node;
const img = node;
let id = '';
if (typeof node === 'string') {
id = node;
}
else if (obj.asset) {
id = obj.asset._ref || obj.asset._id;
}
else {
id = ref._ref || img._id;
}
const hasId = !id || idPattern.test(id);
if (!hasId) {
return false;
}
const [, assetId, dimensions, extension] = id.split('-');
const [width, height] = dimensions.split('x').map(num => parseInt(num, 10));
const aspectRatio = width / height;
const metadata = img.metadata || { dimensions: { width, height, aspectRatio } };
const url = img.url || buildImageUrl(loc, { url: '', assetId, extension, metadata });
return {
url,
assetId,
extension,
metadata,
};
}
function convertToFormat(url, toFormat) {
const parsed = parseUrl(url, true);
const filename = parsed.pathname.replace(/.*\//, '');
const extension = filename.replace(/.*\./, '');
const isConvertedToTarget = parsed.query.fm === toFormat;
const isOriginal = extension === toFormat;
// If the original matches the target format, remove any explicit conversions
if (isConvertedToTarget && isOriginal) {
const _a = parsed.query, { fm } = _a, params = __rest(_a, ["fm"]);
parsed.set('query', params);
return parsed.toString();
}
if (isConvertedToTarget || isOriginal) {
return url;
}
const newQuery = Object.assign(Object.assign({}, parsed.query), { fm: toFormat });
parsed.set('query', newQuery);
return parsed.toString();
}
function isWebP(url) {
const isConverted = url.includes('fm=webp');
const isOriginal = /[a-f0-9]+-\d+x\d+\.webp/.test(url);
return isConverted || isOriginal;
}
function getFixedGatsbyImage(image, args, loc) {
const props = getBasicImageProps(image, loc);
if (!props) {
return null;
}
const width = args.width || exports.DEFAULT_FIXED_WIDTH;
const height = args.height;
const { url, metadata, extension } = props;
const { dimensions, lqip } = metadata;
const isOriginalSize = (w, h) => w === dimensions.width && h === dimensions.height;
let desiredAspectRatio = dimensions.aspectRatio;
// If we're cropping, calculate the specified aspect ratio
if (args.height) {
desiredAspectRatio = width / args.height;
}
let forceConvert = null;
if (args.toFormat) {
forceConvert = args.toFormat;
}
else if (isWebP(props.url)) {
forceConvert = 'jpg';
}
const hasOriginalRatio = desiredAspectRatio === dimensions.aspectRatio;
const outputHeight = Math.round(height ? height : width / desiredAspectRatio);
const imgUrl = isOriginalSize(width, outputHeight) ||
(hasOriginalRatio && width > dimensions.width && outputHeight > dimensions.height)
? url
: `${url}?w=${width}&h=${outputHeight}&fit=crop`;
const widths = sizeMultipliersFixed.map(scale => Math.round(width * scale));
const initial = { webp: [], base: [] };
const srcSets = widths
.filter(currentWidth => currentWidth <= dimensions.width)
.reduce((acc, currentWidth, i) => {
const resolution = `${sizeMultipliersFixed[i]}x`;
const currentHeight = Math.round(currentWidth / desiredAspectRatio);
const imgUrl = isOriginalSize(currentWidth, currentHeight)
? url
: `${url}?w=${currentWidth}&h=${currentHeight}&fit=crop`;
const webpUrl = convertToFormat(imgUrl, 'webp');
const baseUrl = convertToFormat(imgUrl, forceConvert || props.extension);
acc.webp.push(`${webpUrl} ${resolution}`);
acc.base.push(`${baseUrl} ${resolution}`);
return acc;
}, initial);
const src = convertToFormat(imgUrl, forceConvert || extension);
const srcWebp = convertToFormat(imgUrl, 'webp');
return {
base64: lqip || null,
aspectRatio: desiredAspectRatio,
width: Math.round(width),
height: outputHeight,
src,
srcWebp,
srcSet: srcSets.base.join(',\n') || `${src} 1x`,
srcSetWebp: srcSets.webp.join(',\n') || `${srcWebp} 1x`,
};
}
exports.getFixedGatsbyImage = getFixedGatsbyImage;
function getFluidGatsbyImage(image, args, loc) {
const props = getBasicImageProps(image, loc);
if (!props) {
return null;
}
const { url, metadata, extension } = props;
const { dimensions, lqip } = metadata;
const isOriginalSize = (w, h) => w === dimensions.width && h === dimensions.height;
const maxWidth = Math.min(args.maxWidth || exports.DEFAULT_FLUID_MAX_WIDTH, dimensions.width);
const specifiedMaxHeight = args.maxHeight
? Math.min(args.maxHeight, dimensions.height)
: undefined;
let desiredAspectRatio = dimensions.aspectRatio;
// If we're cropping, calculate the specified aspect ratio
if (specifiedMaxHeight) {
desiredAspectRatio = maxWidth / specifiedMaxHeight;
}
const maxHeight = specifiedMaxHeight || Math.round(maxWidth / dimensions.aspectRatio);
let forceConvert = null;
if (args.toFormat) {
forceConvert = args.toFormat;
}
else if (isWebP(props.url)) {
forceConvert = 'jpg';
}
const baseSrc = isOriginalSize(maxWidth, maxHeight) ||
(maxWidth >= dimensions.width && maxHeight >= dimensions.height)
? url
: `${url}?w=${maxWidth}&h=${maxHeight}&fit=crop`;
const src = convertToFormat(baseSrc, forceConvert || extension);
const srcWebp = convertToFormat(baseSrc, 'webp');
const sizes = args.sizes || `(max-width: ${maxWidth}px) 100vw, ${maxWidth}px`;
const widths = sizeMultipliersFluid
.map(scale => Math.round(maxWidth * scale))
.filter(width => width < dimensions.width && width > exports.LOWEST_FLUID_BREAKPOINT_WIDTH)
.concat(dimensions.width);
const initial = { webp: [], base: [] };
const srcSets = widths
.filter(currentWidth => currentWidth <= dimensions.width)
.reduce((acc, currentWidth) => {
const currentHeight = Math.round(currentWidth / desiredAspectRatio);
const imgUrl = isOriginalSize(currentWidth, currentHeight)
? url
: `${url}?w=${currentWidth}&h=${currentHeight}&fit=crop`;
const webpUrl = convertToFormat(imgUrl, 'webp');
const baseUrl = convertToFormat(imgUrl, forceConvert || props.extension);
acc.webp.push(`${webpUrl} ${currentWidth}w`);
acc.base.push(`${baseUrl} ${currentWidth}w`);
return acc;
}, initial);
return {
base64: lqip || null,
aspectRatio: desiredAspectRatio,
src,
srcWebp,
srcSet: srcSets.base.join(',\n'),
srcSetWebp: srcSets.webp.join(',\n'),
sizes,
};
}
exports.getFluidGatsbyImage = getFluidGatsbyImage;
//# sourceMappingURL=getGatsbyImageProps.js.map