Gatsby Headaches: Working With Media (Part 1)<\/h1>\nJuan Diego Rodr\u00edguez<\/address>\n 2023-10-09T11:00:00+00:00
\n 2024-06-12T20:05:40+00:00
\n <\/header>\n
Working with media files in Gatsby might not be as straightforward as expected. I remember starting my first Gatsby project. After consulting Gatsby\u2019s documentation, I discovered I needed to use the gatsby-source-filesystem<\/code> plugin to make queries for local files. Easy enough!<\/p>\nThat\u2019s where things started getting complicated. Need to use images? Check the docs and install one — or more! — of the many, many plugins available for handling images. How about working with SVG files? There is another plugin for that. Video files? You get the idea.<\/p>\n
It\u2019s all great until any of those plugins or packages become outdated and go unmaintained. That\u2019s where the headaches start.<\/p>\n
If you are unfamiliar with Gatsby<\/a>, it\u2019s a React-based static site generator that uses GraphQL to pull structured data from various sources and uses webpack to bundle a project so it can then be deployed and served as static files. It\u2019s essentially a static site generator with reactivity that can pull data from a vast array of sources.<\/p>\nLike many static site frameworks in the Jamstack, Gatsby has traditionally enjoyed a great reputation as a performant framework<\/a>, although it has taken a hit in recent years<\/a>. Based on what I\u2019ve seen, however, it\u2019s not so much that the framework is fast or slow but how the framework is configured to handle many of the sorts of things that impact performance, including media files.<\/p>\nSo, let\u2019s solve the headaches you might encounter when working with media files in a Gatsby project. This article is the first of a brief two-part series where we will look specifically at the media you are most likely to use: images, video, and audio. After that, the second part of this series<\/a> will get into different types of files, including Markdown, PDFs, and even 3D models.<\/p>\nSolving Image Headaches In Gatsby<\/h2>\n
I think that the process of optimizing images can fall into four different buckets:<\/p>\n
\n- Optimize image files.<\/strong>
\nMinimizing an image\u2019s file size without losing quality directly leads to shorter fetching times. This can be done manually or during a build process. It\u2019s also possible to use a service, like Cloudinary, to handle the work on demand.<\/li>\n- Prioritize images that are part of the First Contentful Paint (FCP).<\/strong>
\nFCP is a metric that measures the time<\/a> between the point when a page starts loading to when the first bytes of content are rendered. The idea is that fetching assets that are part of that initial render earlier results in faster loading rather than waiting for other assets lower on the chain.<\/li>\n- Lazy loading other images.<\/strong>
\nWe can prevent the rest of the images from render-blocking other assets using the loading="lazy"<\/code> attribute on images.<\/li>\n- Load the right image file for the right context.<\/strong>
\nWith responsive images<\/a>, we can serve one version of an image file at one screen size and serve another image at a different screen size with the srcset<\/code> and sizes<\/code> attributes or with the <picture><\/code> element.<\/li>\n<\/ol>\nThese are great principles for any website, not only those built with Gatsby. But how we build them into a Gatsby-powered site can be confusing, which is why I\u2019m writing this article and perhaps why you\u2019re reading it.<\/p>\n
Lazy Loading Images In Gatsby<\/h3>\n
We can apply an image to a React component in a Gatsby site like this:<\/p>\n
import * as React from \"react\";\n\nimport forest from \".\/assets\/images\/forest.jpg\";\n\nconst ImageHTML = () => {\n return <img src={ forest } alt=\"Forest trail\" \/>;\n};\n<\/code><\/pre>\nIt\u2019s important to import<\/code> the image as a JavaScript module. This lets webpack know to bundle the image and generate a path to its location in the public folder.<\/p>\nThis works fine, but when are we ever working with only one image? What if we want to make an image gallery that contains 100 images? If we try to load that many <img><\/code> tags at once, they will certainly slow things down and could affect the FCP. That\u2019s where the third principle that uses the loading="lazy"<\/code> attribute can come into play.<\/p>\nimport * as React from \"react\";\n\nimport forest from \".\/assets\/images\/forest.jpg\";\n\nconst LazyImageHTML = () => {\n return <img src={ forest } loading=\"lazy\" alt=\"Forest trail\" \/>;\n};\n<\/code><\/pre>\nWe can do the opposite with loading="eager"<\/code>. It instructs the browser to load the image as soon as possible, regardless of whether it is onscreen or not.<\/p>\nimport * as React from \"react\";\n\nimport forest from \".\/assets\/images\/forest.jpg\";\n\nconst EagerImageHTML = () => {\n return <img src={ forest } loading=\"eager\" alt=\"Forest trail\" \/>;\n};\n<\/code><\/pre>\nImplementing Responsive Images In Gatsby<\/h3>\n
This is a basic example of the HTML for responsive images:<\/p>\n
\n<img\n srcset=\".\/assets\/images\/forest-400.jpg 400w, .\/assets\/images\/forest-800.jpg 800w\"\n sizes=\"(max-width: 500px) 400px, 800px\"\n alt=\"Forest trail\"\n\/>\n<\/code><\/pre>\n<\/div>\nIn Gatsby, we must import<\/code> the images first and pass them to the srcset<\/code> attribute as template literals so webpack can bundle them:<\/p>\nimport * as React from \"react\";\n\nimport forest800 from \".\/assets\/images\/forest-800.jpg\";\n\nimport forest400 from \".\/assets\/images\/forest-400.jpg\";\n\nconst ResponsiveImageHTML = () => {\n return (\n <img\n srcSet={`\n\n ${ forest400 } 400w,\n\n ${ forest800 } 800w\n\n `}\n sizes=\"(max-width: 500px) 400px, 800px\"\n alt=\"Forest trail\"\n \/>\n );\n};\n<\/code><\/pre>\nThat should take care of any responsive image headaches in the future.<\/p>\n
Loading Background Images In Gatsby<\/h3>\n
What about pulling in the URL for an image file to use on the CSS background-url<\/code> property? That looks something like this:<\/p>\nimport * as React from \"react\";\n\nimport \".\/style.css\";\n\nconst ImageBackground = () => {\n return <div className=\"banner\"><\/div>;\n};\n<\/code><\/pre>\n\/* style.css *\/\n\n.banner {\n aspect-ratio: 16\/9;\n background-size: cover;\n\n background-image: url(\".\/assets\/images\/forest-800.jpg\");\n\n \/* etc. *\/\n}\n<\/code><\/pre>\nThis is straightforward, but there is still room for optimization! For example, we can do the CSS version of responsive images, which loads the version we want at specific breakpoints.<\/p>\n
\/* style.css *\/\n\n@media (max-width: 500px) {\n .banner {\n background-image: url(\".\/assets\/images\/forest-400.jpg\");\n }\n}\n<\/code><\/pre>\nUsing The gatsby-source-filesystem<\/code> Plugin<\/h3>\nBefore going any further, I think it is worth installing the gatsby-source-filesystem<\/code> plugin. It\u2019s an essential part of any Gatsby project because it allows us to query data from various directories in the local filesystem<\/a>, making it simpler to fetch assets, like a folder of optimized images.<\/p>\nnpm i gatsby-source-filesystem\n<\/code><\/pre>\nWe can add it to our gatsby-config.js<\/code> file and specify the directory from which we will query our media assets:<\/p>\n\/\/ gatsby-config.js\n\nmodule.exports = {\n plugins: [\n {\n resolve: `gatsby-source-filesystem`,\n\n options: {\n name: `assets`,\n\n path: `${ __dirname }\/src\/assets`,\n },\n },\n ],\n};\n<\/code><\/pre>\nRemember to restart your development server to see changes from the gatsby-config.js<\/code> file.<\/p>\nNow that we have gatsby-source-filesystem<\/code> installed, we can continue solving a few other image-related headaches. For example, the next plugin we look at is capable of simplifying the cures we used for lazy loading and responsive images.<\/p>\nUsing The gatsby-plugin-image<\/code> Plugin<\/h3>\nThe gatsby-plugin-image<\/code> plugin<\/a> (not to be confused with the outdated gatsby-image<\/code> plugin<\/a>) uses techniques that automatically handle various aspects of image optimization<\/strong>, such as lazy loading, responsive sizing, and even generating optimized image formats for modern browsers.<\/p>\nOnce installed, we can replace standard <img><\/code> tags with either the <GatsbyImage><\/code> or <StaticImage><\/code> components, depending on the use case. These components take advantage of the plugin\u2019s features and use the <picture><\/code> HTML element to ensure the most appropriate image is served to each user based on their device and network conditions.<\/p>\nWe can start by installing gatsby-plugin-image<\/code> and the other plugins it depends on:<\/p>\n\nnpm install gatsby-plugin-image gatsby-plugin-sharp gatsby-transformer-sharp\n<\/code><\/pre>\n<\/div>\nLet\u2019s add them to the gatsby-config.js<\/code> file:<\/p>\n\/\/ gatsby-config.js\n\nmodule.exports = {\nplugins: [\n\n\/\/ other plugins\n`gatsby-plugin-image`,\n`gatsby-plugin-sharp`,\n`gatsby-transformer-sharp`],\n\n};\n<\/code><\/pre>\nThis provides us with some features we will put to use a bit later.<\/p>\n
Using The StaticImage<\/code> Component<\/h3>\nThe StaticImage<\/code> component serves images that don\u2019t require dynamic sourcing or complex transformations<\/strong>. It\u2019s particularly useful for scenarios where you have a fixed image source that doesn\u2019t change based on user interactions or content updates, like logos, icons, or other static images that remain consistent.<\/p>\nThe main attributes we will take into consideration are:<\/p>\n
\nsrc<\/code>:<\/strong> This attribute is required and should be set to the path of the image you want to display.<\/li>\nalt<\/code>:<\/strong> Provides alternative text for the image.<\/li>\nplaceholder<\/code>:<\/strong> This attribute can be set to either blurred<\/code> or dominantColor<\/code> to define the type of placeholder to display while the image is loading.<\/li>\nlayout<\/code>:<\/strong> This defines how the image should be displayed. It can be set to fixed<\/code> for, as you might imagine, images with a fixed size, fullWidth<\/code> for images that span the entire container, and constrained<\/code> for images scaled down to fit their container.<\/li>\nloading<\/code>:<\/strong> This determines when the image should start loading while also supporting the eager<\/code> and lazy<\/code> options.<\/li>\n<\/ul>\nUsing StaticImage<\/code> is similar to using a regular HTML <img><\/code> tag. However, StaticImage<\/code> requires passing the string directly to the src<\/code> attribute so it can be bundled by webpack.<\/p>\nimport * as React from \"react\";\n\nimport { StaticImage } from \"gatsby-plugin-image\";\n\nconst ImageStaticGatsby = () => {\n return (\n <StaticImage\n src=\".\/assets\/images\/forest.jpg\"\n placeholder=\"blurred\"\n layout=\"constrained\"\n alt=\"Forest trail\"\n loading=\"lazy\"\n \/>\n );\n };\n<\/code><\/pre>\nThe StaticImage<\/code> component is great, but you have to take its constraints into account:<\/p>\n\n- No Dynamically Loading URLs<\/strong>
\nOne of the most significant limitations is that the StaticImage<\/code> component doesn\u2019t support dynamically loading images based on URLs fetched from data sources or APIs.<\/li>\n- Compile-Time Image Handling<\/strong>
\nThe StaticImage<\/code> component\u2019s image handling occurs at compile time. This means that the images you specify are processed and optimized when the Gatsby site is built. Consequently, if you have images that need to change frequently based on user interactions or updates, the static nature of this component might not fit your needs.<\/li>\n- Limited Transformation Options<\/strong>
\nUnlike the more versatile GatsbyImage<\/code> component, the StaticImage<\/code> component provides fewer transformation options, e.g., there is no way to apply complex transformations like cropping, resizing, or adjusting image quality directly within the component. You may want to consider alternative solutions if you require advanced transformations.<\/li>\n<\/ul>\nUsing The GatsbyImage<\/code> Component<\/h3>\nThe GatsbyImage<\/code> component is a more versatile solution<\/strong> that addresses the limitations of the StaticImage<\/code> component. It\u2019s particularly useful for scenarios involving dynamic image loading, complex transformations, and advanced customization.<\/p>\nSome ideal use cases where GatsbyImage<\/code> is particularly useful include:<\/p>\n\n- Dynamic Image Loading<\/strong>
\nIf you need to load images dynamically based on data from APIs, content management systems, or other sources, the GatsbyImage<\/code> component is the go-to choice. It can fetch images and optimize their loading behavior.<\/li>\n- Complex transformations<\/strong>
\nThe GatsbyImage<\/code> component is well-suited for advanced transformations, using GraphQL queries to apply them.<\/li>\n- Responsive images<\/strong>
\nFor responsive design, the GatsbyImage<\/code> component excels by automatically generating multiple sizes and formats of an image, ensuring that users receive an appropriate image based on their device and network conditions.<\/li>\n<\/ul>\nUnlike the StaticImage<\/code> component, which uses a src<\/code> attribute, GatsbyImage<\/code> has an image<\/code> attribute that takes a gatsbyImageData<\/code> object. gatsbyImageData<\/code> contains the image information and can be queried from GraphQL using the following query.<\/p>\nquery {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n}\n<\/code><\/pre>\nIf you\u2019re following along, you can look around your Gatsby data layer at http:\/\/localhost:8000\/___graphql<\/code>.<\/p>\nFrom here, we can use the useStaticQuery<\/code> hook and the graphql<\/code> tag to fetch data from the data layer:<\/p>\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nimport { GatsbyImage, getImage } from \"gatsby-plugin-image\";\n\nconst ImageGatsby = () => {\n \/\/ Query data here:\n\n const data = useStaticQue(graphql``);\n\n return <div><\/div>;\n};\n<\/code><\/pre>\nNext, we can write the GraphQL query inside of the graphql<\/code> tag:<\/p>\n\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nconst ImageGatsby = () => {\n const data = useStaticQuery(graphql`\n query {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n }\n `);\n\n return <div><\/div>;\n};\n<\/code><\/pre>\n<\/div>\nNext, we import the GatsbyImage<\/code> component from gatsby-plugin-image<\/code> and assign the image\u2019s gatsbyImageData<\/code> property to the image<\/code> attribute:<\/p>\n\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nimport { GatsbyImage } from \"gatsby-plugin-image\";\n\nconst ImageGatsby = () => {\n const data = useStaticQuery(graphql`\n query {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n }\n `);\n\n return <GatsbyImage image={ data.file.childImageSharp.gatsbyImageData } alt={ data.file.name } \/>;\n};\n<\/code><\/pre>\n<\/div>\nNow, we can use the getImage<\/code> helper function to make the code easier to read. When given a File<\/code> object, the function returns the file.childImageSharp.gatsbyImageData<\/code> property, which can be passed directly to the GatsbyImage<\/code> component.<\/p>\n\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nimport { GatsbyImage, getImage } from \"gatsby-plugin-image\";\n\nconst ImageGatsby = () => {\n const data = useStaticQuery(graphql`\n query {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n }\n `);\n\n const image = getImage(data.file);\n\n return <GatsbyImage image={ image } alt={ data.file.name } \/>;\n};\n<\/code><\/pre>\n<\/div>\nUsing The gatsby-background-image<\/code> Plugin<\/h3>\nAnother plugin we could use to take advantage of Gatsby\u2019s image optimization capabilities is the gatsby-background-image<\/code> plugin<\/a>. However, I do not recommend using this plugin since it is outdated and prone to compatibility issues. Instead, Gatsby suggests<\/a> using gatsby-plugin-image<\/code> when working with the latest Gatsby version 3 and above.<\/p>\nIf this compatibility doesn\u2019t represent a significant problem for your project, you can refer to the plugin\u2019s documentation for specific instructions<\/a> and use it in place of the CSS background-url<\/code> usage I described earlier.<\/p>\nSolving Video And Audio Headaches In Gatsby<\/h2>\n
\n 2024-06-12T20:05:40+00:00
\n <\/header>\n
gatsby-source-filesystem<\/code> plugin to make queries for local files. Easy enough!<\/p>\nThat\u2019s where things started getting complicated. Need to use images? Check the docs and install one — or more! — of the many, many plugins available for handling images. How about working with SVG files? There is another plugin for that. Video files? You get the idea.<\/p>\n
It\u2019s all great until any of those plugins or packages become outdated and go unmaintained. That\u2019s where the headaches start.<\/p>\n
If you are unfamiliar with Gatsby<\/a>, it\u2019s a React-based static site generator that uses GraphQL to pull structured data from various sources and uses webpack to bundle a project so it can then be deployed and served as static files. It\u2019s essentially a static site generator with reactivity that can pull data from a vast array of sources.<\/p>\nLike many static site frameworks in the Jamstack, Gatsby has traditionally enjoyed a great reputation as a performant framework<\/a>, although it has taken a hit in recent years<\/a>. Based on what I\u2019ve seen, however, it\u2019s not so much that the framework is fast or slow but how the framework is configured to handle many of the sorts of things that impact performance, including media files.<\/p>\nSo, let\u2019s solve the headaches you might encounter when working with media files in a Gatsby project. This article is the first of a brief two-part series where we will look specifically at the media you are most likely to use: images, video, and audio. After that, the second part of this series<\/a> will get into different types of files, including Markdown, PDFs, and even 3D models.<\/p>\nSolving Image Headaches In Gatsby<\/h2>\n
I think that the process of optimizing images can fall into four different buckets:<\/p>\n
\n- Optimize image files.<\/strong>
\nMinimizing an image\u2019s file size without losing quality directly leads to shorter fetching times. This can be done manually or during a build process. It\u2019s also possible to use a service, like Cloudinary, to handle the work on demand.<\/li>\n- Prioritize images that are part of the First Contentful Paint (FCP).<\/strong>
\nFCP is a metric that measures the time<\/a> between the point when a page starts loading to when the first bytes of content are rendered. The idea is that fetching assets that are part of that initial render earlier results in faster loading rather than waiting for other assets lower on the chain.<\/li>\n- Lazy loading other images.<\/strong>
\nWe can prevent the rest of the images from render-blocking other assets using the loading="lazy"<\/code> attribute on images.<\/li>\n- Load the right image file for the right context.<\/strong>
\nWith responsive images<\/a>, we can serve one version of an image file at one screen size and serve another image at a different screen size with the srcset<\/code> and sizes<\/code> attributes or with the <picture><\/code> element.<\/li>\n<\/ol>\nThese are great principles for any website, not only those built with Gatsby. But how we build them into a Gatsby-powered site can be confusing, which is why I\u2019m writing this article and perhaps why you\u2019re reading it.<\/p>\n
Lazy Loading Images In Gatsby<\/h3>\n
We can apply an image to a React component in a Gatsby site like this:<\/p>\n
import * as React from \"react\";\n\nimport forest from \".\/assets\/images\/forest.jpg\";\n\nconst ImageHTML = () => {\n return <img src={ forest } alt=\"Forest trail\" \/>;\n};\n<\/code><\/pre>\nIt\u2019s important to import<\/code> the image as a JavaScript module. This lets webpack know to bundle the image and generate a path to its location in the public folder.<\/p>\nThis works fine, but when are we ever working with only one image? What if we want to make an image gallery that contains 100 images? If we try to load that many <img><\/code> tags at once, they will certainly slow things down and could affect the FCP. That\u2019s where the third principle that uses the loading="lazy"<\/code> attribute can come into play.<\/p>\nimport * as React from \"react\";\n\nimport forest from \".\/assets\/images\/forest.jpg\";\n\nconst LazyImageHTML = () => {\n return <img src={ forest } loading=\"lazy\" alt=\"Forest trail\" \/>;\n};\n<\/code><\/pre>\nWe can do the opposite with loading="eager"<\/code>. It instructs the browser to load the image as soon as possible, regardless of whether it is onscreen or not.<\/p>\nimport * as React from \"react\";\n\nimport forest from \".\/assets\/images\/forest.jpg\";\n\nconst EagerImageHTML = () => {\n return <img src={ forest } loading=\"eager\" alt=\"Forest trail\" \/>;\n};\n<\/code><\/pre>\nImplementing Responsive Images In Gatsby<\/h3>\n
This is a basic example of the HTML for responsive images:<\/p>\n
\n<img\n srcset=\".\/assets\/images\/forest-400.jpg 400w, .\/assets\/images\/forest-800.jpg 800w\"\n sizes=\"(max-width: 500px) 400px, 800px\"\n alt=\"Forest trail\"\n\/>\n<\/code><\/pre>\n<\/div>\nIn Gatsby, we must import<\/code> the images first and pass them to the srcset<\/code> attribute as template literals so webpack can bundle them:<\/p>\nimport * as React from \"react\";\n\nimport forest800 from \".\/assets\/images\/forest-800.jpg\";\n\nimport forest400 from \".\/assets\/images\/forest-400.jpg\";\n\nconst ResponsiveImageHTML = () => {\n return (\n <img\n srcSet={`\n\n ${ forest400 } 400w,\n\n ${ forest800 } 800w\n\n `}\n sizes=\"(max-width: 500px) 400px, 800px\"\n alt=\"Forest trail\"\n \/>\n );\n};\n<\/code><\/pre>\nThat should take care of any responsive image headaches in the future.<\/p>\n
Loading Background Images In Gatsby<\/h3>\n
What about pulling in the URL for an image file to use on the CSS background-url<\/code> property? That looks something like this:<\/p>\nimport * as React from \"react\";\n\nimport \".\/style.css\";\n\nconst ImageBackground = () => {\n return <div className=\"banner\"><\/div>;\n};\n<\/code><\/pre>\n\/* style.css *\/\n\n.banner {\n aspect-ratio: 16\/9;\n background-size: cover;\n\n background-image: url(\".\/assets\/images\/forest-800.jpg\");\n\n \/* etc. *\/\n}\n<\/code><\/pre>\nThis is straightforward, but there is still room for optimization! For example, we can do the CSS version of responsive images, which loads the version we want at specific breakpoints.<\/p>\n
\/* style.css *\/\n\n@media (max-width: 500px) {\n .banner {\n background-image: url(\".\/assets\/images\/forest-400.jpg\");\n }\n}\n<\/code><\/pre>\nUsing The gatsby-source-filesystem<\/code> Plugin<\/h3>\nBefore going any further, I think it is worth installing the gatsby-source-filesystem<\/code> plugin. It\u2019s an essential part of any Gatsby project because it allows us to query data from various directories in the local filesystem<\/a>, making it simpler to fetch assets, like a folder of optimized images.<\/p>\nnpm i gatsby-source-filesystem\n<\/code><\/pre>\nWe can add it to our gatsby-config.js<\/code> file and specify the directory from which we will query our media assets:<\/p>\n\/\/ gatsby-config.js\n\nmodule.exports = {\n plugins: [\n {\n resolve: `gatsby-source-filesystem`,\n\n options: {\n name: `assets`,\n\n path: `${ __dirname }\/src\/assets`,\n },\n },\n ],\n};\n<\/code><\/pre>\nRemember to restart your development server to see changes from the gatsby-config.js<\/code> file.<\/p>\nNow that we have gatsby-source-filesystem<\/code> installed, we can continue solving a few other image-related headaches. For example, the next plugin we look at is capable of simplifying the cures we used for lazy loading and responsive images.<\/p>\nUsing The gatsby-plugin-image<\/code> Plugin<\/h3>\nThe gatsby-plugin-image<\/code> plugin<\/a> (not to be confused with the outdated gatsby-image<\/code> plugin<\/a>) uses techniques that automatically handle various aspects of image optimization<\/strong>, such as lazy loading, responsive sizing, and even generating optimized image formats for modern browsers.<\/p>\nOnce installed, we can replace standard <img><\/code> tags with either the <GatsbyImage><\/code> or <StaticImage><\/code> components, depending on the use case. These components take advantage of the plugin\u2019s features and use the <picture><\/code> HTML element to ensure the most appropriate image is served to each user based on their device and network conditions.<\/p>\nWe can start by installing gatsby-plugin-image<\/code> and the other plugins it depends on:<\/p>\n\nnpm install gatsby-plugin-image gatsby-plugin-sharp gatsby-transformer-sharp\n<\/code><\/pre>\n<\/div>\nLet\u2019s add them to the gatsby-config.js<\/code> file:<\/p>\n\/\/ gatsby-config.js\n\nmodule.exports = {\nplugins: [\n\n\/\/ other plugins\n`gatsby-plugin-image`,\n`gatsby-plugin-sharp`,\n`gatsby-transformer-sharp`],\n\n};\n<\/code><\/pre>\nThis provides us with some features we will put to use a bit later.<\/p>\n
Using The StaticImage<\/code> Component<\/h3>\nThe StaticImage<\/code> component serves images that don\u2019t require dynamic sourcing or complex transformations<\/strong>. It\u2019s particularly useful for scenarios where you have a fixed image source that doesn\u2019t change based on user interactions or content updates, like logos, icons, or other static images that remain consistent.<\/p>\nThe main attributes we will take into consideration are:<\/p>\n
\nsrc<\/code>:<\/strong> This attribute is required and should be set to the path of the image you want to display.<\/li>\nalt<\/code>:<\/strong> Provides alternative text for the image.<\/li>\nplaceholder<\/code>:<\/strong> This attribute can be set to either blurred<\/code> or dominantColor<\/code> to define the type of placeholder to display while the image is loading.<\/li>\nlayout<\/code>:<\/strong> This defines how the image should be displayed. It can be set to fixed<\/code> for, as you might imagine, images with a fixed size, fullWidth<\/code> for images that span the entire container, and constrained<\/code> for images scaled down to fit their container.<\/li>\nloading<\/code>:<\/strong> This determines when the image should start loading while also supporting the eager<\/code> and lazy<\/code> options.<\/li>\n<\/ul>\nUsing StaticImage<\/code> is similar to using a regular HTML <img><\/code> tag. However, StaticImage<\/code> requires passing the string directly to the src<\/code> attribute so it can be bundled by webpack.<\/p>\nimport * as React from \"react\";\n\nimport { StaticImage } from \"gatsby-plugin-image\";\n\nconst ImageStaticGatsby = () => {\n return (\n <StaticImage\n src=\".\/assets\/images\/forest.jpg\"\n placeholder=\"blurred\"\n layout=\"constrained\"\n alt=\"Forest trail\"\n loading=\"lazy\"\n \/>\n );\n };\n<\/code><\/pre>\nThe StaticImage<\/code> component is great, but you have to take its constraints into account:<\/p>\n\n- No Dynamically Loading URLs<\/strong>
\nOne of the most significant limitations is that the StaticImage<\/code> component doesn\u2019t support dynamically loading images based on URLs fetched from data sources or APIs.<\/li>\n- Compile-Time Image Handling<\/strong>
\nThe StaticImage<\/code> component\u2019s image handling occurs at compile time. This means that the images you specify are processed and optimized when the Gatsby site is built. Consequently, if you have images that need to change frequently based on user interactions or updates, the static nature of this component might not fit your needs.<\/li>\n- Limited Transformation Options<\/strong>
\nUnlike the more versatile GatsbyImage<\/code> component, the StaticImage<\/code> component provides fewer transformation options, e.g., there is no way to apply complex transformations like cropping, resizing, or adjusting image quality directly within the component. You may want to consider alternative solutions if you require advanced transformations.<\/li>\n<\/ul>\nUsing The GatsbyImage<\/code> Component<\/h3>\nThe GatsbyImage<\/code> component is a more versatile solution<\/strong> that addresses the limitations of the StaticImage<\/code> component. It\u2019s particularly useful for scenarios involving dynamic image loading, complex transformations, and advanced customization.<\/p>\nSome ideal use cases where GatsbyImage<\/code> is particularly useful include:<\/p>\n\n- Dynamic Image Loading<\/strong>
\nIf you need to load images dynamically based on data from APIs, content management systems, or other sources, the GatsbyImage<\/code> component is the go-to choice. It can fetch images and optimize their loading behavior.<\/li>\n- Complex transformations<\/strong>
\nThe GatsbyImage<\/code> component is well-suited for advanced transformations, using GraphQL queries to apply them.<\/li>\n- Responsive images<\/strong>
\nFor responsive design, the GatsbyImage<\/code> component excels by automatically generating multiple sizes and formats of an image, ensuring that users receive an appropriate image based on their device and network conditions.<\/li>\n<\/ul>\nUnlike the StaticImage<\/code> component, which uses a src<\/code> attribute, GatsbyImage<\/code> has an image<\/code> attribute that takes a gatsbyImageData<\/code> object. gatsbyImageData<\/code> contains the image information and can be queried from GraphQL using the following query.<\/p>\nquery {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n}\n<\/code><\/pre>\nIf you\u2019re following along, you can look around your Gatsby data layer at http:\/\/localhost:8000\/___graphql<\/code>.<\/p>\nFrom here, we can use the useStaticQuery<\/code> hook and the graphql<\/code> tag to fetch data from the data layer:<\/p>\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nimport { GatsbyImage, getImage } from \"gatsby-plugin-image\";\n\nconst ImageGatsby = () => {\n \/\/ Query data here:\n\n const data = useStaticQue(graphql``);\n\n return <div><\/div>;\n};\n<\/code><\/pre>\nNext, we can write the GraphQL query inside of the graphql<\/code> tag:<\/p>\n\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nconst ImageGatsby = () => {\n const data = useStaticQuery(graphql`\n query {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n }\n `);\n\n return <div><\/div>;\n};\n<\/code><\/pre>\n<\/div>\nNext, we import the GatsbyImage<\/code> component from gatsby-plugin-image<\/code> and assign the image\u2019s gatsbyImageData<\/code> property to the image<\/code> attribute:<\/p>\n\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nimport { GatsbyImage } from \"gatsby-plugin-image\";\n\nconst ImageGatsby = () => {\n const data = useStaticQuery(graphql`\n query {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n }\n `);\n\n return <GatsbyImage image={ data.file.childImageSharp.gatsbyImageData } alt={ data.file.name } \/>;\n};\n<\/code><\/pre>\n<\/div>\nNow, we can use the getImage<\/code> helper function to make the code easier to read. When given a File<\/code> object, the function returns the file.childImageSharp.gatsbyImageData<\/code> property, which can be passed directly to the GatsbyImage<\/code> component.<\/p>\n\nimport * as React from \"react\";\n\nimport { useStaticQuery, graphql } from \"gatsby\";\n\nimport { GatsbyImage, getImage } from \"gatsby-plugin-image\";\n\nconst ImageGatsby = () => {\n const data = useStaticQuery(graphql`\n query {\n file(name: { eq: \"forest\" }) {\n childImageSharp {\n gatsbyImageData(width: 800, placeholder: BLURRED, layout: CONSTRAINED)\n }\n\n name\n }\n }\n `);\n\n const image = getImage(data.file);\n\n return <GatsbyImage image={ image } alt={ data.file.name } \/>;\n};\n<\/code><\/pre>\n<\/div>\nUsing The gatsby-background-image<\/code> Plugin<\/h3>\nAnother plugin we could use to take advantage of Gatsby\u2019s image optimization capabilities is the gatsby-background-image<\/code> plugin<\/a>. However, I do not recommend using this plugin since it is outdated and prone to compatibility issues. Instead, Gatsby suggests<\/a> using gatsby-plugin-image<\/code> when working with the latest Gatsby version 3 and above.<\/p>\nIf this compatibility doesn\u2019t represent a significant problem for your project, you can refer to the plugin\u2019s documentation for specific instructions<\/a> and use it in place of the CSS background-url<\/code> usage I described earlier.<\/p>\nSolving Video And Audio Headaches In Gatsby<\/h2>\n