Check out a free preview of the full Intermediate Gatsby, v2 course:
The "Handle Remote Images" Lesson is part of the full, Intermediate Gatsby, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Jason demonstrates how to handle image optimization from custom data that has images from external URLs by using node-fetch and gatsby-source-filesystem. Gatsby can pull in and optimize external images at build time by creating what's called a "remote file node".

Get Unlimited Access Now

Transcript from the "Handle Remote Images" Lesson

[00:00:00]
>> So I'm not gonna go into the low level of Gatsby's image optimization. You can go watch the section from the intro to Gatsby course, if you wanna get a download on that. But what we're gonna do here is I want to inject more stuff into our data object.

[00:00:18] Again, using a resolver. So, the way that I'm gonna do this is actually by taking advantage of what's called a remote file node, which is built into the Gatsby source file system. So if I come out here I'm gonna install a couple things. So this is the first time we're installing a package in our workspace.

[00:00:38] This is different than a normal node installation. And it's a little bit hard to remember if you don't always work in monorepos. So, I'm probably going to screw this up at some point today, but I remembered this time, so it's yarn workspace site ad. That is how you install a dependency when you were using yarn workspaces.

[00:00:58] And I want to add a couple here. I want to add node-fetch because we're gonna make a fetch request to an API, and I'm going to add gatsby-source-filesystem. So let's get those installed. And the reason this is important is that if I run npm install, it's going to put that into this package, which is not useful.

[00:01:23] When we run yarn add it ends up in this package, which is where it needs to be in order to build and run the site properly. So that's a little gotcha when you're working with workspaces. You just have to remember, or else your build will fail and you'll be super confused.

[00:01:38] And then you'll remember it and go fix it and it'll all be fine, but it's a good thing to try to remember. So now that we've done this, we've got the file system, we've got our node-fetch. And I'm gonna go into gatsby-node here and let's import the files we need.

[00:01:56] So right up at the top, I'm going to get fetch, and that's going to be requiring node-fetch. And then I'm also going to get createremotefileNode. And that comes out of, oops. That comes out of gatsby-source-filesystem. So these are the two functions that we needed to install things for.

[00:02:19] And then back down to the resolvers we go. So in here, in the resolvers, I am going to bring in a whole bunch of new things that we're gonna have to use as part of creating remote file node. Because the way create remote file node works is we actually pass all the helpers down into create remote file node.

[00:02:40] So I'm just going to import a whole bunch of stuff. So let's get the actions. Let's get the cache, let's get createnodeId. Let's get, let's see, we've already got createResolvers. So then let's get, we need the store and we need the reporter. And each of these like, so the cache is the Gatsby cache.

[00:03:02] The store is, I don't even know what the store is. It's something that Gatsby needs and then the reporter is, if we want to put anything in the terminal. So these kind of warnings and other, sorry, not those ones, but the notices that we can post out from Gatsby, those are done through the reporter.

[00:03:24] So in here then I want to add another field. So this field is going to be called cover And I want this one to be a type of file and then for the resolve, because we're gonna make a request using the fetch API, I'm gonna make this one async and it's gonna get that source again.

[00:03:48] And inside, I want to make a request to the, let's see, we're gonna make a request to the openlibrary.org. So openlibrary.org is super cool, openlibrary.org. This is a cool project where you can kind of look at and read a bunch of books like anything that's open public domain I think is the term for it.

[00:04:17] And just it's all very, very cool. But what's really cool about it is down here at the bottom, they've got developer stuff. And we have a web API. And so we can look at books, right? This is super cool. So we are able to get books based on the ISBNs.

[00:04:34] And that means, we can look up the cover of this book using the open library, which is great. So I'm going to await, a fetch call. And this is a big long URL. So I'm gonna grab the ISBN API down here. So this is what I want, it is a link to get the ISBN or the book data based on an ISBN.

[00:04:59] And we're gonna again drop in source.isbn. So, this will give us back a response with the request from the open library API. And then I wanna check if it's okay. So, if it's broken, if we get an error. So if it's not response okay, then I'm going to.

[00:05:20] I don't really care if this breaks. So instead I'm going to say, we'll just warn and we'll say, error loading details about, let's get source.name. And then we can say like got response.status, which is like the http status. So, if it's missing you would get a 404, if it's broken we'd get a 500, something like that.

[00:05:51] And then we can say what the status text was. So, this would be the like, if the status is 404, the text would be not found. That's the standard HTTP text for that. So, we'll just give ourselves a helpful error so that we can actually figure out what's going on if something's missing.

[00:06:09] And then we'll just return null. So there will be no cover for a book where there's an error, and that's okay. We don't mind if there's no cover. Then I can get the covers out of response.json, which I need to await. So if we look at what actually comes in here, looking at this, then we know that this is hard to read.

[00:06:37] Let's open it in the network tab. This is a tip when you get an API response, you can come into the tab here and look at the network and it will preview the response. So it's way easier to read. So what I'm looking for is covers. Now, this is not particularly useful [LAUGH].

[00:06:56] I don't know how to actually use that. So I had to dig into this a little bit and try to figure it out. And what I did was I looked at the book page, and if you view this image. This is the cover Id and everything else is boilerplate.

[00:07:17] So if we get that cover Id, then we can use this format to create our cover. So now that I've got my covers ,I can go if covers.length, meaning if there's at least one cover provided because there won't always be. I see a question.
>> So the reporter has a method to let graphql know that there's an error with the resolver?

[00:07:45] The reporter is a way to like Gatsby know that there was something happening in the build process. So you can do a reporter.info and just say, I got here or you can do a reporter.panic and actually fail the Gatsby build. It's effectively a way for you to communicate within the structure of Gatsby.

[00:08:06] It's a extra powerful consul.lug, is the short answer. So here, now that we know that we've got at least one cover, what we can do is get a, we're gonna return a create remote file node. So, this is similar to create node call, in that it will take an object, but you're not passing it a node, it's gonna create the node.

[00:08:41] Instead, we're passing it a bunch of stuff that it needs to create the node. So the first thing is, what's the URL? Well, we wanna use this cover, and if you remember, the cover was, and covers is an array. So we actually have to pull out the first.

[00:09:01] Covers 0, I just pulled out the first one I'm sure there's probably a better way to do that. I'm happy with this one. And this then, is our URL to a remote cover. But we don't wanna wait on the openlibrary.org, we don't want to put a strain on their CDN.

[00:09:18] We wanna make a local copy and we want to optimize it so that we get the fastest possible images. So to do that, we're gonna pass in all these things that we pulled in from Gatsby. So the store, the cache, createNode, the createNodeId and reporter, all get tossed into this create remote file node code.

[00:09:40] And if there's no cover, we're just gonna return null. So, no matter what, we will resolve this function, but it might be empty, right and so it's okay. If this is not returned, we'll just get a null response. So let's save that. And let's run it. But we're not quite done yet and I'll show you why.

[00:10:05] So what we're doing when we create a remote file node, is we are taking a file and we're putting it into the Gatsby system. But by default, file nodes aren't image like optimized images. File nodes are just files, you can put anything as a file node, a JSON file.

[00:10:24] JavaScript file, and image, CSV, whatever, you can put it all in there. And so what we'll get is, if I reload, I get my cover, and then I get a bunch of information about the cover, but none of these are like public URLs. And none of these are, what did I just miss?

[00:10:45] Dang it, I missed one step, which is that, I also needed to pull out the createNode API from actions, whoops. Okay, so let's rebuild one more time. And so looking in here, these are details about files, these are not details about images. So, we'll be able to query quite a bit here, we'll be able to get a lot of information but there's not actually anything that we can use as part of our Gatsby site, just yet.

[00:11:15] This is more like meta information that would allow the site to to function but you can see it's like, it's put in the cache, the cache doesn't get deployed. So we can't actually use this just yet. And it's also not optimized. This is just a straight up copy of whatever was on the internet, which means if this is a 15 megabyte image.

[00:11:32] It's a 15 megabyte image there's no optimization done here. So what we need to do to make this work is, we need to add a couple more things. We're gonna use those Gatsby image plugins. So yarn workspace site add, and we're gonna bring in gatsby-plugin-image, gatsby-plugin-sharpe, and gatsby-trensformer-sharp.

[00:11:58] And the transformer is actually the biggest part because what this does, is it looks for file nodes to be created. Checks if they are images and then transforms those nodes into image sharp nodes, which become children of the file nodes. So that's what's happening under the hood. And now that we've actually looked at those Gatsby API's and how nodes get created.

[00:12:19] It's not everything that's happening but you can kind of tell like, so this is, it's running the createNode API, it's setting that parent value and setting children values. So that each of these gets run the way that we want it to. And kind of built into this this graphql structure that we want.

[00:12:35] So, as we get these installed, I'm gonna head over to my gatsby.config. And let's set up our plugins. Array here we're gonna include gatsby-plugin-image, gatsby-plugin-sharp, and gatsby-transformer-sharp. And close out that array so that it doesn't explode, everybody's happy, all right, so let's try this one more time. And so what this does is, this is bringing in all the internal stuff that Gatsby needs to optimize our images.

[00:13:20] So as this builds, now when we download the images, which will be cached, so we don't have to download them twice, which is nice. The plugins will kick in and they will optimize those images now, which is, the major value proposition of Gatsby. All right, so let's take a look again.

[00:13:43] And let's see what we got here. So inside we've got, instead of an absolute path, now I can look at child image sharp. And I'm going to use the Gatsby image data. And I could set all of these but I'm not gonna worry about it for now because we're just kind of looking at it how it works.

[00:13:59] So I can query this and now I actually get back an optimized Gatsby image. Based on our cover data, so if I go look at this image Hey, we now have a local optimized copy of this cover. And if I look at one that's got a bigger cover cuz I think that one's got a pretty, pretty tiny one.

[00:14:26] Whoa, what did I do? Let's look at the I think the Blake crouch one is big, so this is a fairly big image. And if I come and look at this out here, so there's the big version of it. And then if I go in and look at the smaller version like here is a tiny one, let me grab this, And drop that, Gatsby created a smaller version of that image.

[00:14:52] So now we have an optimized set of cover images for different resolutions, different uses inside the site, and that means that we're able to actually build some stuff with this, right? So we've now like, I wanna just kind of reiterate how freaking cool it is that we were able to do all of this in such short order with relatively low effort.

[00:15:16] We were able to take advantage of Gatsby's API's. And I know like I say low effort. I know we did a lot of code here. Like this is not a trivial thing that you're just gonna drop in and do. But compared to the alternative of standing up your own data layer and figuring out how to get all these relationships going.

[00:15:34] And doing the dance of making all these requests and downloading files and all the things that you need to do to get this running. This is so much more approachable. So I find this really exciting. So we were able to generate a derived field, but not only were we able to generate derived fields.

[00:15:53] We're also able to do it where we're like hitting third party API's as part of generating these derived fields. And getting whole images down that we can then copy and optimize and make available. This is a really, really powerful workflow. So now that we've got all of this data, we've got our books, we've got our authors, I want to build a site for a book club and let me commit our code.

[00:16:16] And then we can go ahead and start doing that. Let's see how much should we add? We added quite a bit this time, so let's add everything, we'll say git commit and let's see. Add remote file nodes and optimized images. Okay, let's push that up.