From 46f356ae2d8cc0741af73bf93a8764a809bf1861 Mon Sep 17 00:00:00 2001 From: Sarah Mogin Date: Tue, 23 Jan 2018 14:24:43 -0500 Subject: [PATCH] [gatsby-source-contentful] Make base64 query to field-level to speed up asset queries (#3617) * [gatsby-source-contentful] Add withBase64 option to speed up image queries * Revert "[gatsby-source-contentful] Add withBase64 option to speed up image queries" This reverts commit bb080f7bc3e78a006841a7715202439632ad2692. * remove base64 from resolveResponsiveResolution * create base64 resolver * update sizes, reset resize to original state * update tests * update resize and tests --- .../__snapshots__/extend-node-type.js.snap | 12 +- .../src/extend-node-type.js | 435 +++++++++--------- 2 files changed, 226 insertions(+), 221 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/extend-node-type.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/extend-node-type.js.snap index 4732775d2ccca..7cd690f2081a7 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/extend-node-type.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/extend-node-type.js.snap @@ -7,7 +7,7 @@ exports[`contentful extend node type createUrl ignores options it doesn't unders exports[`contentful extend node type resolveResize generates resized images 1`] = ` Object { "aspectRatio": 0.75, - "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAbABQDAREAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAABgIHAwQJ/8QALhAAAQMDAgIHCQAAAAAAAAAAAQIDBAAFEQYSEzEHFCEiQVFhFRYkMkJDcXKj/8QAGQEAAgMBAAAAAAAAAAAAAAAAAQIAAwQF/8QAJREAAQQCAQEJAAAAAAAAAAAAAQACAxEEQSEiEhMxQlFhcYGh/9oADAMBAAIRAxEAPwDp4Zz3vV1Tf8OIXF2YHzb8Zzz5UNpL6qWixdparPY3lO5clSUIdVtHeSQo49OQoXwl7RoFJaZWo8tWNcqHh7Mz/U0u0nnRF2+O3DRmiJtilRJLDtyY4jzm4oLQDgXtx9WRjyrSGNhcWZAINfuvpcl078mCOXBc0guFk3VAkOqtqz6oXZQK7amhQ+lJy0rcUJy9PrlIRtOCgOqBOeXMVZ3TywzaHCwuyo2ZTccnqLSR8A+qPR2o9v0nYLbGQhhqM68oIbSAEYX4Afuazue6TlxspYo2RRNjjAAF+CtiI+JUVl4fcQFdnqKsW8cqKrfGXN62plJk8Is8Qjt2E52/jNH2QoXamIrIxhlsY5d0dlBMsgAAwBgeQqKL/9k=", + "baseUrl": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg", "height": 533, "src": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=400", "width": 400, @@ -17,7 +17,7 @@ Object { exports[`contentful extend node type resolveResize generates resized images using all options 1`] = ` Object { "aspectRatio": 1.1278195488721805, - "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAbABQDAREAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAABgIHAwQJ/8QALhAAAQMDAgIHCQAAAAAAAAAAAQIDBAAFEQYSEzEHFCEiQVFhFRYkMkJDcXKj/8QAGQEAAgMBAAAAAAAAAAAAAAAAAQIAAwQF/8QAJREAAQQCAQEJAAAAAAAAAAAAAQACAxEEQSEiEhMxQlFhcYGh/9oADAMBAAIRAxEAPwDp4Zz3vV1Tf8OIXF2YHzb8Zzz5UNpL6qWixdparPY3lO5clSUIdVtHeSQo49OQoXwl7RoFJaZWo8tWNcqHh7Mz/U0u0nnRF2+O3DRmiJtilRJLDtyY4jzm4oLQDgXtx9WRjyrSGNhcWZAINfuvpcl078mCOXBc0guFk3VAkOqtqz6oXZQK7amhQ+lJy0rcUJy9PrlIRtOCgOqBOeXMVZ3TywzaHCwuyo2ZTccnqLSR8A+qPR2o9v0nYLbGQhhqM68oIbSAEYX4Afuazue6TlxspYo2RRNjjAAF+CtiI+JUVl4fcQFdnqKsW8cqKrfGXN62plJk8Is8Qjt2E52/jNH2QoXamIrIxhlsY5d0dlBMsgAAwBgeQqKL/9k=", + "baseUrl": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg", "height": 399, "src": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=450&h=399&q=50&fit=fill", "width": 450, @@ -27,7 +27,7 @@ Object { exports[`contentful extend node type resolveResponsiveResolution generates responsive resolution data for images 1`] = ` Object { "aspectRatio": 0.75, - "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAbABQDAREAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAABgIHAwQJ/8QALhAAAQMDAgIHCQAAAAAAAAAAAQIDBAAFEQYSEzEHFCEiQVFhFRYkMkJDcXKj/8QAGQEAAgMBAAAAAAAAAAAAAAAAAQIAAwQF/8QAJREAAQQCAQEJAAAAAAAAAAAAAQACAxEEQSEiEhMxQlFhcYGh/9oADAMBAAIRAxEAPwDp4Zz3vV1Tf8OIXF2YHzb8Zzz5UNpL6qWixdparPY3lO5clSUIdVtHeSQo49OQoXwl7RoFJaZWo8tWNcqHh7Mz/U0u0nnRF2+O3DRmiJtilRJLDtyY4jzm4oLQDgXtx9WRjyrSGNhcWZAINfuvpcl078mCOXBc0guFk3VAkOqtqz6oXZQK7amhQ+lJy0rcUJy9PrlIRtOCgOqBOeXMVZ3TywzaHCwuyo2ZTccnqLSR8A+qPR2o9v0nYLbGQhhqM68oIbSAEYX4Afuazue6TlxspYo2RRNjjAAF+CtiI+JUVl4fcQFdnqKsW8cqKrfGXN62plJk8Is8Qjt2E52/jNH2QoXamIrIxhlsY5d0dlBMsgAAwBgeQqKL/9k=", + "baseUrl": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg", "height": 533, "src": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=400", "srcSet": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=400&h=533 1x, @@ -41,7 +41,7 @@ Object { exports[`contentful extend node type resolveResponsiveResolution generates responsive resolution data for images using all options 1`] = ` Object { "aspectRatio": 1.1278195488721805, - "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAbABQDAREAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAABgIHAwQJ/8QALhAAAQMDAgIHCQAAAAAAAAAAAQIDBAAFEQYSEzEHFCEiQVFhFRYkMkJDcXKj/8QAGQEAAgMBAAAAAAAAAAAAAAAAAQIAAwQF/8QAJREAAQQCAQEJAAAAAAAAAAAAAQACAxEEQSEiEhMxQlFhcYGh/9oADAMBAAIRAxEAPwDp4Zz3vV1Tf8OIXF2YHzb8Zzz5UNpL6qWixdparPY3lO5clSUIdVtHeSQo49OQoXwl7RoFJaZWo8tWNcqHh7Mz/U0u0nnRF2+O3DRmiJtilRJLDtyY4jzm4oLQDgXtx9WRjyrSGNhcWZAINfuvpcl078mCOXBc0guFk3VAkOqtqz6oXZQK7amhQ+lJy0rcUJy9PrlIRtOCgOqBOeXMVZ3TywzaHCwuyo2ZTccnqLSR8A+qPR2o9v0nYLbGQhhqM68oIbSAEYX4Afuazue6TlxspYo2RRNjjAAF+CtiI+JUVl4fcQFdnqKsW8cqKrfGXN62plJk8Is8Qjt2E52/jNH2QoXamIrIxhlsY5d0dlBMsgAAwBgeQqKL/9k=", + "baseUrl": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg", "height": 399, "src": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=450&h=399&q=50&fit=fill", "srcSet": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=450&h=399&q=50&fit=fill 1x, @@ -55,7 +55,7 @@ Object { exports[`contentful extend node type resolveResponsiveSizes generates responsive size data for images 1`] = ` Object { "aspectRatio": 0.75, - "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAbABQDAREAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAABgIHAwQJ/8QALhAAAQMDAgIHCQAAAAAAAAAAAQIDBAAFEQYSEzEHFCEiQVFhFRYkMkJDcXKj/8QAGQEAAgMBAAAAAAAAAAAAAAAAAQIAAwQF/8QAJREAAQQCAQEJAAAAAAAAAAAAAQACAxEEQSEiEhMxQlFhcYGh/9oADAMBAAIRAxEAPwDp4Zz3vV1Tf8OIXF2YHzb8Zzz5UNpL6qWixdparPY3lO5clSUIdVtHeSQo49OQoXwl7RoFJaZWo8tWNcqHh7Mz/U0u0nnRF2+O3DRmiJtilRJLDtyY4jzm4oLQDgXtx9WRjyrSGNhcWZAINfuvpcl078mCOXBc0guFk3VAkOqtqz6oXZQK7amhQ+lJy0rcUJy9PrlIRtOCgOqBOeXMVZ3TywzaHCwuyo2ZTccnqLSR8A+qPR2o9v0nYLbGQhhqM68oIbSAEYX4Afuazue6TlxspYo2RRNjjAAF+CtiI+JUVl4fcQFdnqKsW8cqKrfGXN62plJk8Is8Qjt2E52/jNH2QoXamIrIxhlsY5d0dlBMsgAAwBgeQqKL/9k=", + "baseUrl": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg", "sizes": "(max-width: 400px) 100vw, 400px", "src": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=400", "srcSet": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=100&h=133 100w, @@ -71,7 +71,7 @@ Object { exports[`contentful extend node type resolveResponsiveSizes generates responsive sizes data for images using all options 1`] = ` Object { "aspectRatio": 0.75, - "base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAlgCWAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAAbABQDAREAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAABgIHAwQJ/8QALhAAAQMDAgIHCQAAAAAAAAAAAQIDBAAFEQYSEzEHFCEiQVFhFRYkMkJDcXKj/8QAGQEAAgMBAAAAAAAAAAAAAAAAAQIAAwQF/8QAJREAAQQCAQEJAAAAAAAAAAAAAQACAxEEQSEiEhMxQlFhcYGh/9oADAMBAAIRAxEAPwDp4Zz3vV1Tf8OIXF2YHzb8Zzz5UNpL6qWixdparPY3lO5clSUIdVtHeSQo49OQoXwl7RoFJaZWo8tWNcqHh7Mz/U0u0nnRF2+O3DRmiJtilRJLDtyY4jzm4oLQDgXtx9WRjyrSGNhcWZAINfuvpcl078mCOXBc0guFk3VAkOqtqz6oXZQK7amhQ+lJy0rcUJy9PrlIRtOCgOqBOeXMVZ3TywzaHCwuyo2ZTccnqLSR8A+qPR2o9v0nYLbGQhhqM68oIbSAEYX4Afuazue6TlxspYo2RRNjjAAF+CtiI+JUVl4fcQFdnqKsW8cqKrfGXN62plJk8Is8Qjt2E52/jNH2QoXamIrIxhlsY5d0dlBMsgAAwBgeQqKL/9k=", + "baseUrl": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg", "sizes": "(max-width: 450px) 100vw, 450px", "src": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=450&h=399&q=50", "srcSet": "//images.contentful.com/ubriaw6jfhm1/10TkaLheGeQG6qQGqWYqUI/5421d3108cbb699561acabd594fa2cb0/ryugj83mqwa1asojwtwb.jpg?w=113&h=100&q=50 113w, diff --git a/packages/gatsby-source-contentful/src/extend-node-type.js b/packages/gatsby-source-contentful/src/extend-node-type.js index 40fc085fa4aa8..3b336ffb797e0 100644 --- a/packages/gatsby-source-contentful/src/extend-node-type.js +++ b/packages/gatsby-source-contentful/src/extend-node-type.js @@ -72,8 +72,10 @@ const isImage = image => _.get(image, `file.contentType`) ) -const getBase64Image = (imgUrl, args = {}) => { - const requestUrl = `https:${imgUrl}?w=20` +const getBase64Image = (imageProps) => { + if (!imageProps) return null + + const requestUrl = `https:${imageProps.baseUrl}?w=20` // TODO add caching. return new Promise(resolve => { base64Img.requestBase64(requestUrl, (a, b, body) => { @@ -82,26 +84,24 @@ const getBase64Image = (imgUrl, args = {}) => { }) } -const getBase64ImageAndBasicMeasurements = (image, args) => - new Promise(resolve => { - getBase64Image(image.file.url, args).then(base64Str => { - let aspectRatio - if (args.width && args.height) { - aspectRatio = args.width / args.height - } else { - aspectRatio = - image.file.details.image.width / image.file.details.image.height - } +const getBasicImageProps = (image, args) => { + let aspectRatio + if (args.width && args.height) { + aspectRatio = args.width / args.height + } else { + aspectRatio = + image.file.details.image.width / image.file.details.image.height + } + + return { + baseUrl: image.file.url, + contentType: image.file.contentType, + aspectRatio, + width: image.file.details.image.width, + height: image.file.details.image.height, + } +} - resolve({ - contentType: image.file.contentType, - base64Str, - aspectRatio, - width: image.file.details.image.width, - height: image.file.details.image.height, - }) - }) - }) const createUrl = (imgUrl, options = {}) => { // Convert to Contentful names and filter out undefined/null values. const args = _.pickBy( @@ -123,205 +123,188 @@ exports.createUrl = createUrl const resolveResponsiveResolution = (image, options) => { if (!isImage(image)) return null - return new Promise(resolve => { - getBase64ImageAndBasicMeasurements(image, options).then( - ({ contentType, base64Str, width, height, aspectRatio }) => { - let desiredAspectRatio = aspectRatio - - // If we're cropping, calculate the specified aspect ratio. - if (options.height) { - desiredAspectRatio = options.width / options.height - } - - // If the user selected a height (so cropping) and fit option - // is not set, we'll set our defaults - if (options.height) { - if (!options.resizingBehavior) { - options.resizingBehavior = `fill` - } - } - - // Create sizes (in width) for the image. If the width of the - // image is 800px, the sizes would then be: 800, 1200, 1600, - // 2400. - // - // This is enough sizes to provide close to the optimal image size for every - // device size / screen resolution - let sizes = [] - sizes.push(options.width) - sizes.push(options.width * 1.5) - sizes.push(options.width * 2) - sizes.push(options.width * 3) - sizes = sizes.map(Math.round) - - // Filter out sizes larger than the image's width. - const filteredSizes = sizes.filter(size => size < width) - - // Sort sizes for prettiness. - const sortedSizes = _.sortBy(filteredSizes) - - // Create the srcSet. - const srcSet = sortedSizes - .map((size, i) => { - let resolution - switch (i) { - case 0: - resolution = `1x` - break - case 1: - resolution = `1.5x` - break - case 2: - resolution = `2x` - break - case 3: - resolution = `3x` - break - default: - } - const h = Math.round(size / desiredAspectRatio) - return `${createUrl(image.file.url, { - ...options, - width: size, - height: h, - })} ${resolution}` - }) - .join(`,\n`) - - let pickedHeight - if (options.height) { - pickedHeight = options.height - } else { - pickedHeight = options.width / desiredAspectRatio - } - - return resolve({ - base64: base64Str, - aspectRatio: aspectRatio, - width: Math.round(options.width), - height: Math.round(pickedHeight), - src: createUrl(image.file.url, { - ...options, - width: options.width, - }), - srcSet, - }) + const { baseUrl, width, aspectRatio } = getBasicImageProps(image, options) + + let desiredAspectRatio = aspectRatio + + // If we're cropping, calculate the specified aspect ratio. + if (options.height) { + desiredAspectRatio = options.width / options.height + } + + // If the user selected a height (so cropping) and fit option + // is not set, we'll set our defaults + if (options.height) { + if (!options.resizingBehavior) { + options.resizingBehavior = `fill` + } + } + + // Create sizes (in width) for the image. If the width of the + // image is 800px, the sizes would then be: 800, 1200, 1600, + // 2400. + // + // This is enough sizes to provide close to the optimal image size for every + // device size / screen resolution + let sizes = [] + sizes.push(options.width) + sizes.push(options.width * 1.5) + sizes.push(options.width * 2) + sizes.push(options.width * 3) + sizes = sizes.map(Math.round) + + // Filter out sizes larger than the image's width. + const filteredSizes = sizes.filter(size => size < width) + + // Sort sizes for prettiness. + const sortedSizes = _.sortBy(filteredSizes) + + // Create the srcSet. + const srcSet = sortedSizes + .map((size, i) => { + let resolution + switch (i) { + case 0: + resolution = `1x` + break + case 1: + resolution = `1.5x` + break + case 2: + resolution = `2x` + break + case 3: + resolution = `3x` + break + default: } - ) - }) + const h = Math.round(size / desiredAspectRatio) + return `${createUrl(baseUrl, { + ...options, + width: size, + height: h, + })} ${resolution}` + }) + .join(`,\n`) + + let pickedHeight + if (options.height) { + pickedHeight = options.height + } else { + pickedHeight = options.width / desiredAspectRatio + } + + return { + aspectRatio: aspectRatio, + baseUrl, + width: Math.round(options.width), + height: Math.round(pickedHeight), + src: createUrl(baseUrl, { + ...options, + width: options.width, + }), + srcSet, + } } exports.resolveResponsiveResolution = resolveResponsiveResolution const resolveResponsiveSizes = (image, options) => { if (!isImage(image)) return null - return new Promise(resolve => { - getBase64ImageAndBasicMeasurements(image, options).then( - ({ contentType, base64Str, width, height, aspectRatio }) => { - let desiredAspectRatio = aspectRatio - - // If we're cropping, calculate the specified aspect ratio. - if (options.maxHeight) { - desiredAspectRatio = options.maxWidth / options.maxHeight - } - - // If the users didn't set a default sizes, we'll make one. - if (!options.sizes) { - options.sizes = `(max-width: ${options.maxWidth}px) 100vw, ${ - options.maxWidth - }px` - } - - // Create sizes (in width) for the image. If the max width of the container - // for the rendered markdown file is 800px, the sizes would then be: 200, - // 400, 800, 1200, 1600, 2400. - // - // This is enough sizes to provide close to the optimal image size for every - // device size / screen resolution - let sizes = [] - sizes.push(options.maxWidth / 4) - sizes.push(options.maxWidth / 2) - sizes.push(options.maxWidth) - sizes.push(options.maxWidth * 1.5) - sizes.push(options.maxWidth * 2) - sizes.push(options.maxWidth * 3) - sizes = sizes.map(Math.round) - - // Filter out sizes larger than the image's maxWidth. - const filteredSizes = sizes.filter(size => size < width) - - // Add the original image to ensure the largest image possible - // is available for small images. - filteredSizes.push(width) - - // Sort sizes for prettiness. - const sortedSizes = _.sortBy(filteredSizes) - - // Create the srcSet. - const srcSet = sortedSizes - .map(width => { - const h = Math.round(width / desiredAspectRatio) - return `${createUrl(image.file.url, { - ...options, - width, - height: h, - })} ${Math.round(width)}w` - }) - .join(`,\n`) - - return resolve({ - base64: base64Str, - aspectRatio: aspectRatio, - src: createUrl(image.file.url, { - ...options, - width: options.maxWidth, - height: options.maxHeight, - }), - srcSet, - sizes: options.sizes, - }) - } - ) - }) + const { baseUrl, width, aspectRatio } = getBasicImageProps(image, options) + + let desiredAspectRatio = aspectRatio + + // If we're cropping, calculate the specified aspect ratio. + if (options.maxHeight) { + desiredAspectRatio = options.maxWidth / options.maxHeight + } + + // If the users didn't set a default sizes, we'll make one. + if (!options.sizes) { + options.sizes = `(max-width: ${options.maxWidth}px) 100vw, ${ + options.maxWidth + }px` + } + + // Create sizes (in width) for the image. If the max width of the container + // for the rendered markdown file is 800px, the sizes would then be: 200, + // 400, 800, 1200, 1600, 2400. + // + // This is enough sizes to provide close to the optimal image size for every + // device size / screen resolution + let sizes = [] + sizes.push(options.maxWidth / 4) + sizes.push(options.maxWidth / 2) + sizes.push(options.maxWidth) + sizes.push(options.maxWidth * 1.5) + sizes.push(options.maxWidth * 2) + sizes.push(options.maxWidth * 3) + sizes = sizes.map(Math.round) + + // Filter out sizes larger than the image's maxWidth. + const filteredSizes = sizes.filter(size => size < width) + + // Add the original image to ensure the largest image possible + // is available for small images. + filteredSizes.push(width) + + // Sort sizes for prettiness. + const sortedSizes = _.sortBy(filteredSizes) + + // Create the srcSet. + const srcSet = sortedSizes + .map(width => { + const h = Math.round(width / desiredAspectRatio) + return `${createUrl(image.file.url, { + ...options, + width, + height: h, + })} ${Math.round(width)}w` + }) + .join(`,\n`) + + return { + aspectRatio: aspectRatio, + baseUrl, + src: createUrl(baseUrl, { + ...options, + width: options.maxWidth, + height: options.maxHeight, + }), + srcSet, + sizes: options.sizes, + } } exports.resolveResponsiveSizes = resolveResponsiveSizes const resolveResize = (image, options) => { if (!isImage(image)) return null - return new Promise(resolve => { - getBase64ImageAndBasicMeasurements(image, options).then( - ({ contentType, base64Str, width, height, aspectRatio }) => { - // If the user selected a height (so cropping) and fit option - // is not set, we'll set our defaults - if (options.height) { - if (!options.resizingBehavior) { - options.resizingBehavior = `fill` - } - } - - if (options.base64) { - resolve(base64Str) - return - } - - const pickedWidth = options.width - let pickedHeight - if (options.height) { - pickedHeight = options.height - } else { - pickedHeight = pickedWidth / aspectRatio - } - resolve({ - src: createUrl(image.file.url, options), - width: Math.round(pickedWidth), - height: Math.round(pickedHeight), - aspectRatio, - base64: base64Str, - }) - } - ) - }) + const { baseUrl, aspectRatio } = getBasicImageProps(image, options) + + // If the user selected a height (so cropping) and fit option + // is not set, we'll set our defaults + if (options.height) { + if (!options.resizingBehavior) { + options.resizingBehavior = `fill` + } + } + + const pickedWidth = options.width + let pickedHeight + if (options.height) { + pickedHeight = options.height + } else { + pickedHeight = pickedWidth / aspectRatio + } + return { + src: createUrl(image.file.url, options), + width: Math.round(pickedWidth), + height: Math.round(pickedHeight), + aspectRatio, + baseUrl, + } } exports.resolveResize = resolveResize @@ -336,7 +319,12 @@ exports.extendNodeType = ({ type }) => { type: new GraphQLObjectType({ name: `ContentfulResolutions`, fields: { - base64: { type: GraphQLString }, + base64: { + type: GraphQLString, + resolve(imageProps) { + return getBase64Image(imageProps) + }, + }, aspectRatio: { type: GraphQLFloat }, width: { type: GraphQLFloat }, height: { type: GraphQLFloat }, @@ -376,7 +364,12 @@ exports.extendNodeType = ({ type }) => { type: new GraphQLObjectType({ name: `ContentfulSizes`, fields: { - base64: { type: GraphQLString }, + base64: { + type: GraphQLString, + resolve(imageProps) { + return getBase64Image(imageProps) + }, + }, aspectRatio: { type: GraphQLFloat }, src: { type: GraphQLString }, srcSet: { type: GraphQLString }, @@ -419,7 +412,12 @@ exports.extendNodeType = ({ type }) => { type: new GraphQLObjectType({ name: `ContentfulResponsiveResolution`, fields: { - base64: { type: GraphQLString }, + base64: { + type: GraphQLString, + resolve(imageProps) { + return getBase64Image(imageProps) + }, + }, aspectRatio: { type: GraphQLFloat }, width: { type: GraphQLFloat }, height: { type: GraphQLFloat }, @@ -460,7 +458,12 @@ exports.extendNodeType = ({ type }) => { type: new GraphQLObjectType({ name: `ContentfulResponsiveSizes`, fields: { - base64: { type: GraphQLString }, + base64: { + type: GraphQLString, + resolve(imageProps) { + return getBase64Image(imageProps) + }, + }, aspectRatio: { type: GraphQLFloat }, src: { type: GraphQLString }, srcSet: { type: GraphQLString }, @@ -502,6 +505,12 @@ exports.extendNodeType = ({ type }) => { type: new GraphQLObjectType({ name: `ContentfulResize`, fields: { + base64: { + type: GraphQLString, + resolve(imageProps) { + return getBase64Image(imageProps) + }, + }, src: { type: GraphQLString }, width: { type: GraphQLInt }, height: { type: GraphQLInt }, @@ -527,10 +536,6 @@ exports.extendNodeType = ({ type }) => { resizingBehavior: { type: ImageResizingBehavior, }, - base64: { - type: GraphQLBoolean, - defaultValue: false, - }, toFormat: { type: ImageFormatType, defaultValue: ``,