UNPKG

gatsby-source-sanity

Version:

Gatsby source plugin for building websites using Sanity.io as a backend.

211 lines 8.43 kB
"use strict"; 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