Build Jamstack Apps with Gatsby
with Obinna Ekwuno
In this episode, Obinna Ekwuno teaches us how to build and deploy Gatsby apps on Netlify for blazing fast, fun-to-develop websites!
Resources & Links
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone. Welcome to another episode of Learn with Jason. Today on the show we have Obinna. Thank you so much for joining us. How you doing?
OBINNA: I'm good. I'm good. How is everyone doing?
JASON: I'm just super pumped to have you here. I feel like we've been talking for a while, and this is our first chance to really sit down and build something together. So this is going to be a blast. So for those of us who are not familiar with you, do you want to give us a bit of a background?
OBINNA: Oh, yeah. So my name is Obinna Ekwuno. I live in Lagos, Nigeria. I work as a software engineer. A fun fact about me would be I like to write poetry. I do poetry on the weekends and play Call of Duty. That's what I do.
JASON: Nice. That's very cool. So yeah, today we are going to dig into some Gatsby stuff. We're going to look at building a Gatsby site. I think maybe a fun thing to talk about for a minute is, like, why would you choose Gatsby as a framework for a site if you were going to build one?
OBINNA: Yeah, so mostly I love to use Gatsby to build stuff because it gives me some of the -- it cuts steps for me to create a fully functional application by offering some starters and stuff. You can even have a whole Gatsby site build already that you could just go in and customize what you want. So it saves the time for all the other -- all the beginner stuff and helps you do it right. Getting it right the first time is really hard. I also love the accessibility, like built-in stuff, like routing. Yeah, those are like the things I love about Gatsby and why I would use Gatsby to build up stuff.
JASON: Yeah, yeah. Well, cool. So I think on that note, maybe we should just hop right in and start building something. So let me switch over to our programming screen. So this is Obinna's Twitter profile. Make sure you go give a follow. What's up, Nicky? Thanks for the boops. So yeah -- yeah, human, I love that. So make sure you go follow Obinna. Let's look at the Gatsby site here a little bit. So if we're going to build a site, one thing that I've noticed is that Gatsby has kind of fragmented the ways that you get started. Like, there are starters. There are themes. There are recipes. What's the difference, and why would I choose one over the other?
OBINNA: Yeah, so a Gatsby starter is kind of like I said, a full site that you can easily customize and then you can use it to create the stuff you want. So you can have like a starter that, let's say it's a blog or an e-commerce site already built up, and you can continue from there. A theme is like a plug-in, but then it has what we call a Gatsby config file. It has its own configurations that you can kind of -- so you have -- so themes offers you the ability to have multiple sites ready, and you can link them into the site you're trying to build, which is a really cool feature because you can take from different places and make something awesome. Recipes is like a way -- so usually if you're trying to build a Gatsby site, you have the whole -- you have like the whole, oh, I'm trying to install this, trying to do this or that. So recipes kind of offers you a way to just install all the things you need to install with a single command. So yeah.
JASON: Very cool. Okay. So I think then -- so what should we build today? Like, we could build a blog. We could build, you know, photo sharing, a whole bunch of things. What do you think would be the most fun?
OBINNA: Hmm, let's try to do a portfolio. That would be cool, to just get photos in.
JASON: Excellent. So if we want to do that, let's go into this folder. Where should I start?
OBINNA: So maybe we should use -- let's get something -- Hmm. What do you think? Should we get something plain? So Gatsby has a bunch of -- yeah?
JASON: I kind of like that idea. I'm a big fan of let's start with an empty folder and see what happens as we add. So Hello World sounds good to me.
JASON: You want me to do that? So we'll do npx Gatsby so we get the CLI. You want to remind me of the command?
OBINNA: Gatsby new. The name of like the project. So what could we call it? Maybe boop.
JASON: Nicky says we need to have corgi. So let's call it corgfolio.
OBINNA: Oh, neat. That's cool. (Laughter)
JASON: All right. Then I need to choose a starter, right?
JASON: How do I do that again?
OBINNA: So usually what I do is just Google like Gatsby hello world starter, and you can get the link.
JASON: This one here?
JASON: Okay, so here's the link in the chat. Then I just paste this in right here?
OBINNA: Yeah, yeah.
OBINNA: So why I like to use the hello world, it's plain, it doesn't have plug-ins. So when you start adding stuff in, you don't have those arrows of maybe something is showing up in other places.
JASON: Another good suggestion from the chat was to call it poetfolio so you can share your -- ah, that's also a good one. (Laughter)
OBINNA: That's nice. That would be nice.
JASON: Hello, everyone. What's up, y'all? Good to see you here. So let's talk a little bit about kind of what -- so what's our plan here? While we're waiting for this to install. So we're going to build a portfolio. A portfolio, if I was doing it, I would want like the name of the project, a short little description, and like a screenshot or a picture to go with it.
JASON: So we could do this -- like one of the nice things about Gatsby is you can pull your data from anywhere. So what's your favorite way to pull data into a site?
OBINNA: I really love, like, contentful. So I would love to put that out there, like use contentful to source to Gatsby.
JASON: Yeah, let's do it.
OBINNA: Just a sneak peek into what we're going to do. We're going to use a new way to source data. So that's something to look forward to.
JASON: Yeah, let's do it. While we're waiting for the Gatsby site to install -- actually, it looks like it just finished. Oh, no. I got an error. No, it looks like it finished and I got a weird error at the end. Let's take a look at the site and see if anything is broken. We called this corgfolio. Look at this, I have so many things about corgis, I can't auto complete that. So let's open this up in a code editor. Let's see here. We've got a node module. So it looks like it installed everything. Here's our Gatsby config. There's nothing to it. We've got a package json that's got Gatsby react and react-dom. Excellent. Looks like this worked. I don't know what that error was. We'll just ignore it and hope it goes away. All right. So we're going to need a contentful site. Let me get started with contentful. Am I on that page? I'm on that page. What am I supposed to be seeing here? Let's see if I can do this. I'm a little bit worried that I have -- oh, whoops. Just a second while I get this all figured out.
OBINNA: So another thing is there's a Gatsby contentful starter, because that's already set up and stuff. But, hmmm.
JASON: I mean, it's kind of nice to learn how it gets set up.
OBINNA: How you set up, yeah.
JASON: Because that starter is great once you already understand. What I found with starters is if you start with the starter, if you're not just trying to get something out there that you never think about again, then the risk that you run is that you like don't really know what's going on under the hood. So when you have questions, it's really hard to even know where to start looking.
JASON: So what I like about standing it up this way is it'll give us -- oh, come on. I'm in the wrong window over here. All right. So now that we're in, good. Going to make me answer questions. Great, got it. Oh, come on. Really? Weird, okay.
OBINNA: What's happening?
JASON: It like auto completed.
OBINNA: Hi, Chris.
JASON: What's up, Chris? Thank you for the sub. Okay, which way do you think we want to go here? I feel like we probably want to explore content modeling because we already know what we're doing for deploying the site, right?
JASON: I'm just going to go with that. Preparing our space. Okay. So do you want to talk a little bit about -- like, what do you like about contentful? What makes it your choice?
OBINNA: Yeah, really mostly because it's the first I used. So I can have like two free -- what's it called -- like workspaces. It's just my choice. It's kind of like this cartoon I watched where someone tells him to pick his weapon of choice and he picks a straw. Why? This is what I want to use.
JASON: Yeah, for sure. Well, cool. So let's see. It looks like we're able to get started. It's got us in the space home. Did it give us a bunch of sample content? It did. So it gave us sample content. Should I just delete all this?
OBINNA: Yeah, so we can show how to actually set this up.
JASON: Yeah, let's do it. So I'm going to select all of this, and I want to -- nope. Do I have an option? Unpublish.
OBINNA: Oh, this is just unpublish.
JASON: I wonder if I have to unpublish before I can delete? Okay, yeah. You can't delete published content. I get it. Permanently delete, yeah. YOLO.
OBINNA: Yes, please.
JASON: So this will put us in an empty setup. Now we'll do content. It looks like we don't need any of this either, so I believe -- can I not just delete these?
OBINNA: This is weird.
JASON: Delete. Okay. I'm not going to do that. We're just going to ignore these. So let's just add a content type. So what should we call our first content type here? Actually, do we need multiples? Yeah, we do need like an auto then, say -- what would I call this?
JASON: Portfolio piece? Okay. Let's just call it like portfolio item. That's super clear. We won't mess that up. An entry we want to display in our portfolio.
OBINNA: Naming things is always hard.
JASON: It definitely is. Okay. So we have our portfolio item. So then we have to use the default editor, use the custom editor? Hmmm. I don't know. Let's see. Let's maybe just start with adding a field. So what should our first field be?
OBINNA: Probably the title.
JASON: Okay. So you think text for that?
OBINNA: Yeah, text would be good.
JASON: Okay. Then maybe we'll just give this project name. Short text, that sounds right. Good. Several names? No, we're not doing that. Should we configure? Is there anything else we're going to need on this, do you think?
OBINNA: Um, no.
JASON: Okay, let's just create it. Then we're going to need media because we want to do an image of the project. So let's do like a project screenshot. I might shorten that to screenshot. I feel like for the sake of keeping it simple, maybe we stick with one file.
OBINNA: Yeah, for sure.
JASON: Thank you for the sub. Good to see you. Let's create that. Then what else did we say? We wanted a description?
OBINNA: Yeah, we would want a description for like the content. So maybe --
JASON: Should we do a rich text?
OBINNA: Rich text, yeah.
JASON: All right. Let's give it a shot.
OBINNA: Mostly -- I get this question a lot, like why rich text and not just text? So I figured it was because most people would want to add photos and stuff or screenshots to descriptions or add like a gif or something.
JASON: Oh, this is cool. I wanted to see what the configurations were for rich text. You can just disable stuff. We don't want an H1 because the page is going to have an H1, right? So we can turn that off and prevent our content editors from accidently doing things that would be bad for SEO. That's really cool. I didn't know that was possible. Embedded entries and assets. This seems like something we probably don't want. We'll leave those out, keep it as simple as possible. Validation, oh, we can make it required. We can limit it.
OBINNA: We can maybe make it require like an auto.
JASON: Oh, that's cool. I don't know if we can do that from this field, but we can definitely add it. I like this. This is really cool. All right. Then you said we need an author, right? Actually, this is a good question. If this is our blog, our portfolio, do we need an author? Or can we just say, all of these are my projects?
OBINNA: If I was building for myself, I wouldn't need an author. For example, if I wanted to have stuff from my friends, all that, then probably want to do who posted what.
JASON: Okay. Well, let's -- maybe we should make a call here. Do we want to do this as a portfolio for one person or like a shared portfolio? What do you think?
OBINNA: You said? I lost you for a minute.
JASON: No worries. Do you want to do this as an individual portfolio or as a shared portfolio?
OBINNA: Maybe an individual portfolio. Someone wants us to do it as a single one.
JASON: Okay, cool. Let's do it that way. So we'll save this content model. Now we have got a portfolio item. So then, I believe, if we go over to our content, we should be able to add a portfolio item. Nice, okay. Oh, I actually made something that's perfect for this. We'll call the first one corgi memes. Then I'm going to create a new asset and link. We'll call this the Drake meme. I think we accidently enabled localization here. Then we'll say a variation on the Drake meme with corgi heads instead of Drake's.
OBINNA: Do we have a photo of that?
JASON: Yeah, I do. (Laughter) This is what I spent my time doing yesterday. I'm technically on vacation right now.
JASON: I took time off from yesterday through next Monday. So I made this because that's how I spend my free time, apparently.
OBINNA: Whoa. (Laughter)
JASON: So let's see here. I'm going to publish that. Then is it done? So then I'm going hit this button here.
OBINNA: Let me see, yeah.
JASON: So now we have a project name. We added that asset. So that's there. Then, let's see.
OBINNA: I'm curious, do we want to add -- I don't think we need to add a slug.
JASON: Won't it do that -- oh, it won't do that for us.
OBINNA: No, it won't do that. I'm curious because the way we're going to query for this in the Gatsby starter might not require -- like, the slug will be set from, say, the project name.
JASON: Yeah, so are we going to have Gatsby do that, or should we have contentful give us a slug?
OBINNA: I think Gatsby will do that.
JASON: Okay. Let's publish one. Then let's do probably one more content piece. And let's call this one Blast Off, because I did another silly thing. Let me find it.
OBINNA: This is nice.
JASON: Yeah, this is the other thing I did with my time yesterday. Let's go here. I made this.
JASON: Which, I don't know why I made this but kind of making me smile. So let's drop this one in. No, not the German file. I don't want that. I think I need to turn off the localization, maybe, so we don't get ourselves in trouble. Hey, no, go back. What did I do? Here, drop the file. Try that again. There it goes. So there is our file. I just -- oh, nice. Good call, yeah. Who just said to do that? Jordan, thank you for that. So I just unchecked that box. Now it doesn't have a translation anymore. So corgis in space. So we can publish that. Then we'll just keep that same -- all right. So now we've got two portfolio items. Do you want to add more, or do you think two is enough to get us started?
OBINNA: I mean, two is good.
JASON: Okay, cool.
OBINNA: But if you have some other nice photo, I'm down to add some more.
JASON: These are the only two I made yesterday. We could find more if we need them, but I think for now, this is probably good. It'll let us get on the way, right.
JASON: So, now I've got content in contentful. We've got the Gatsby starter over here. How do we get them talking to each other?
OBINNA: So, you would need like the Gatsby contentful plug-in.
OBINNA: I guess one thing we would need to install. Gatsby source contentful.
JASON: This one here?
JASON: Okay, so let me install that. We'll just do it all from this command line now. And that'll show up in here once we get it. So we're going to need environment variable through the build process. So we need a contentful access token, good. And we need a space ID. So is this one the space ID? I'm assuming.
OBINNA: Your space ID should be in settings.
JASON: Should be here.
OBINNA: I think you need to generate. Or should it be there?
JASON: So here's the space ID.
OBINNA: Yeah, that's it.
JASON: So I can copy that. I'll go into Gatsby config and grab the things we're going to need here. So we'll say space ID is going to be that. Then I need to get an API key as well.
OBINNA: API key, yeah.
JASON: And that's an access token. What kind of access -- or wait, we don't need the delivery API.
JASON: Actually, do we even need an access token? Because the content from contentful is public by default, right?
OBINNA: Yeah, so you would need an access token.
JASON: Okay. We don't need the preview API. Okay, so delivery -- so is delivery like published and preview is if we want draft content?
OBINNA: Yeah, so you would need like a preview if you need to enable some preview.
JASON: Got it, all right. So I'm going to add an API key. This will be our corgfolio Gatsby site. So this is the content delivery API. I'll have to roll these tokens after the stream. But these are read only, right? I'm not going to keep scrolling down just in case.
OBINNA: These are read only.
JASON: Okay. So what do you recommend if I want to put this into the environment? Like, what's the standard path here?
OBINNA: So the way I would enable any -- so when you're dealing with API keys and the space ID stuff, I would use an environment variable because that would be because obviously you don't want to go push your secrets to like GitHub or something, even though there's a bot that tells you. But that would be the best way to go about it.
JASON: Okay. So you want me to create a .env. So we'll go contentful -- what's it called out here? Access token. Then I'm going to paste in that API key. Good. So now -- actually, one thing that I like to do is when I have like related bits of configuration, even though this doesn't need to be secret, I like keeping it in the same place because then if I need to go change this later, I'm not like, oh, wait, where did I set the space ID? Where did I set the token?
JASON: Okay. So then, we've got this. Do I need to do anything to get those environment variables here?
OBINNA: Yeah, so you would need to do like a -- so Gatsby shifts with a .env. So you would just require .config.
JASON: So now we have access to our environment variables. 245 should mean we can just drop this right in, and we can swap this one out for process.env.contentful space ID.
OBINNA: Yeah, so -- yep.
JASON: Okay. So does that mean we should have content now if I run the site?
OBINNA: Well, not really. So what you've done is you've connected this is the space ID and this is where Gatsby is going to source things from, but you still need to get that info into Gatsby.
OBINNA: Maybe we can try to -- what's it called? We can try to. Because what we have is just a text saying hello world.
JASON: Yeah, so if I wanted to see the data, like we've got enough now that I could look at the data, right?
OBINNA: Yeah, for sure. You can look at the data.
JASON: Okay, cool. Do you want to tell me how I would do that?
OBINNA: So if we run a Gatsby develop --
JASON: Let's see, I'm going to look in here. It is here. So npm run develop. Doesn't like that. What didn't it like?
JASON: It doesn't like -- oh, I think -- did I mix my yarn and npm? I sure did. Okay. So I'm going to remove the yarn lock. I'm also going to remove node modules. I'm going to npm install again.
OBINNA: Yeah, this happens a lot to me. Oh, okay.
JASON: So .env is part of Gatsby. It's a dependency. So we could explicitly set it, but we don't have to in this case. But yeah, the yarn versus npm thing is super tricky. I do that at least once a project. I screw up and yarn install something or npm install something and end up with two lock files. Gatsby has .env as a dependency. Do you know the answer to this one?
OBINNA: Um, no.
JASON: Okay. I can answer this one. So by default, Gatsby will look for a .env.development and .env.production so you have access to those in your built files. I actually don't love the .development, .production because it's out of the norm for .env, which means you have to run a special config instead of path. But it is kind of nice if you have multiple environments where it basically picks up based on your node environment. You can set the mode to production or development, and it'll pick up those environment variables. But yeah, in this case, it's just easier to use it directly. Okay. So now it should actually work. Let's run develop. What don't you like? Store state provider? Uh-oh.
OBINNA: I think -- I don't know why, but this happened to me this morning. I thought it was on my end. So I feel maybe it would be the hello world starter. I don't know why.
JASON: Okay. Let's see if anything got updated since this got released. Looks like there's a patch. So let's npm upgrade, and hopefully this patch fixed the issue. Oh, you had to install .env. Okay. Really shouldn't make us do that.
OBINNA: Okay. We added the Gatsby config.
JASON: Yeah, so we've got our Gatsby config. If it fails again, I'm going to drop this starter out, and that'll help us know if it's contentful or not. Let's do npm outdated to make sure our dependencies are up to date. I don't care about prettier. Let's do npm run develop. Yeah, there must have been a bug in the last release. So just upgrade to latest and we're fine. Okay. So now we've got two URLs. This is the one we're interested in, right?
OBINNA: Yeah, this is where we can see how data is set up in the recurring form and how we can structure our queries.
JASON: So this is very cool. This explorer, how much do you love this explorer?
OBINNA: I mean, it's so nice because I can just click stuff, and it just displays. It has this cool stuff where you have this code explorer and it actually shows you an example of how you query the components. It's awesome.
JASON: So nice. So I'm going to click on portfolio item because that's the thing we care about. Then Gatsby gives us edges and nodes. I don't need any of the metadata, so I'm going to go straight to nodes. We can see here we've got our project name. That's what we created. Our screenshot. That's got a bunch of subfiles. So let's start with maybe, probably fluid. I'm just going to get the source for now. Then I think we also wanted the --
JASON: I was thinking a description. We can use that as alt text. Then down here, what was the last thing we needed? Here is our project description as well. Oh, this is interesting. So this comes with a whole bunch of extra. Wow. What is all that? Let's start with this and see what comes out. So we can see our project name is blast off. Our screenshot. There's an image, and it looks like it comes from contentful cdn. Oh, wow. Look at that. I never knew this happened. I just hovered over.
JASON: It just showed a preview. That's amazing. I did not know that worked. Okay. So this description is not what we want. (Laughter)
OBINNA: Yeah. (Laughter)
JASON: Let's see if we can find something. Content, marks? Maybe. Nope. Maybe there's something we need we're not getting here. Downloading assets, we don't care about that.
OBINNA: The description?
JASON: Well, I just want the rich text. Do I have to do something special for rich text?
OBINNA: Um, yeah.
JASON: What's up, Will?
OBINNA: So, let me see. I know that getting rich text to display on Contentful is a lot more than how it would be with something like Sanity.
JASON: I was here and clicked the wrong link. Rich text. Here. There's a whole section in the docs on this. So let's look at what it says. Rich text feature is supported in the source plug-in. You can use the following query to get the output. I don't think so.
JASON: Because it would say description-rich text, right?
OBINNA: Yeah, and it's not there.
JASON: Do I need to use -- oh, weird. Look at this. It did like a whole thing. That's not right. One of you is going to be -- so we almost got some stuff here. Yeah, we're going to have to like parse all of that. The way rich text is rendered -- oh, okay. So we just need a thing. We just have to actually pull in this. I get it. I understand. Okay. Got it.
OBINNA: Yeah, rich text in contentful is kind of weird. So you need to get blocks from rich text.
JASON: So we'll basically feed this so that module.
JASON: Okay, I get it. Cool. That makes sense. I just realized, I totally forgot to do a shout out to the sponsors. If you want to see live captions for the show, we got them running live at lwj.dev/live. You can see the captions down here. Those are provided by White Coat Captioning. Rachel is doing that for us today. Thank you very much. And the live captions are provided or made possible by Netlify, Fauna, Sanity, and Auth0, who all kick in to sponsor the show to make it more accessible to more people. So as always, thank you so much for making that possible for us. Now that I've remembered to do the thing I'm supposed to do, let's see if we can get this stuff on screen. What do you think?
OBINNA: All right, cool.
JASON: All right. So once we've seen this, what's my next step?
OBINNA: So we would want to like feed this into Gatsby.
JASON: So should I just copy/paste it?
OBINNA: So yeah, you want to copy/paste the query, but then -- yeah.
JASON: And where do you want me to put this?
OBINNA: So usually if we were going to query for stuff, we would use the Gatsby node, like the js to get -- so we'd want to get the slug and then try to feed that into a template component that would map out. But, hmmm. I'm trying to show -- what do you think, should I just show the way of like querying from using the new API?
JASON: Yeah, why not. Let's do it.
OBINNA: All right, cool. So let me see. I'm just going to pull up documentation.
JASON: I'm going to answer a couple questions while you're pulling up those docs.
OBINNA: All right, cool.
JASON: Chris, blitz Jacks has only lasted 11 months. That's why. So jam stack is an architecture. Gatsby is a meta framework for react that creates JAMStack sites. So you do as much work as you can during a build step and generate assets. Then ship those to a CDN or other document-based hosting. Like you could do it through FTP if you wanted. The general goal of that is that by shipping JAMStack sites, you're eliminating a lot of points of failure because there's no longer a server that has to render templates. There's no longer a database. So if you get lots and lots of traffic all at once, you're not going to overload your node server. You're not going to overload your database. You're just going to have these static files, and CDNs are specifically designed to handle huge amounts of traffic. Gatsby is going to make that a little bit easier by having, you know -- actually, Obinna, do you want to take this, talk about what Gatsby is doing to make sites more JAMStack compatible?
OBINNA: Yeah, so the way Gatsby's role in like the JAMStack is to help you source data from different places. So it's like the view of everything and helps you to get data from CMSs, helps you create services and renders this to the browser as static files that later get regenerated into, what's it called, into like a react application on the front end. So, yeah. I just sent you the link to the doc so you can share.
JASON: Okay. Did you send that in -- let's see.
JASON: Creating pages from the cloud system, is that right?
OBINNA: Yeah. Oh, wow. My power just went out. Let's act like nothing happened.
JASON: Oh, no.
OBINNA: Yeah, it's going to come back on in like five minutes. Let's just pretend nothing happened.
JASON: Okay. So this is the doc you wanted me to be looking at, right?
OBINNA: Yeah. So now that we have our query -- so usually you would notice that we'd have to go back to the -- we'd go to Gatsby node and put that query in and try to create a template and have all of that information there from the template. That's like the normal flow of programmatically creating pages. And what I say programmatically, I mean CMSs and stuff. Yay, and let there be light.
OBINNA: So, yeah. So that's for like programmatically creating pages. Recently, at Gatsby we're trying to make creating pages more intuitive. Because people are used to having pages, that's how static sites work. So this new API is still in private beta. If you want access to it, you can just send me an email or something. I can send that to you to test it out. So instead of doing all of that, querying from Gatsby node, now we're going to try and query from the page's directory. But we would have to kind of put some brackets around the -- so if you look at the doc -- can you scroll down?
JASON: Like here?
OBINNA: No, no. That's for clients. So now we also support like if you're trying to do client route and all of that cool stuff. Now we're just going to look at creating collection pages.
JASON: Interesting, okay. All right.
OBINNA: Yeah, so now instead of having to create a template and all of that, when you do the -- so usually what we use a slug to do, we can just do that component.
JASON: Okay. So then that means that I would need to -- let's see. Let's look at this query here. Let's see if I get this. I am going to get a portfolio item. So I would need its type name, is that right? So I would do --
OBINNA: Yeah, so --
OBINNA: Is if you wanted the -- what's it called? The name. So if you look at the example in the documentation, we can see that -- so if you scroll up a bit, yeah, we can see the name, if you look at the query -- no, scroll up. No, I'm supposed to say scroll down. I'm trying to see what's under. My bad. So you can see that the query here, we use the name as what the URL should be. So what's in the component is the product name, which would auto generate. So every file you create, it would show, say, look at host 8,000/the name or whatever. If you want the ID to be the way to identify that single page, so that's how we can generate that.
JASON: Interesting, okay. So if I want to do this, I need to -- let's see. Let's actually do a quick search for a single portfolio item so we can see. We'll get the ID and the project name. So we would want Contentful portfolio item.
OBINNA: Yeah. No, we would --
JASON: That doesn't seem right.
JASON: Here. So then the file name that I want -- do I put this in pages?
OBINNA: Yeah, in pages. We're trying to make page creation intuitive.
JASON: So I would do this, dot project name, dot js.
OBINNA: So the problem is this is still in private beta. So this is a feature we're still just trying to get people to look at it. So the name of the file would have to match the way the query is. So let's see the query.
JASON: Okay. That's actually what I was trying to figure out. Here it's doing an all product. Then it uses product.name.
OBINNA: Yeah, .name.
JASON: So what I'm wondering is -- I'm assuming it's using the type.
OBINNA: Yeah, yeah.
JASON: So if I do a -- let's just go back here. I'll do an all Contentful portfolio item, nodes, ID. Okay, stop. Then I get the project name, right. So I would want Contentful portfolio item, dot project name, if I'm understanding correctly.
OBINNA: Well, yeah. Yeah.
OBINNA: That's what it would look like, yeah.
JASON: So that means that in the file itself --
OBINNA: Oh, ignore that.
JASON: Not doing this?
OBINNA: No, don't do that.
JASON: Okay. So I'm going to get props. No.
JASON: Collection pages.
OBINNA: So what's above is if you're doing any client only routes, something like authentication. Then we would use the brackets. Now I really just want to focus on the page creation. So that's --
JASON: Whoops. There's a lot of Google stuff on that. But that link will work for you. So, okay. So when I make this then, I am going to get import react from react. Then if I export -- call this portfolio item -- I'm going to get props. So if I just dump this, I should assume I'm going to get some sort of data automatically added?
OBINNA: No, so you actually have to put in the -- what's it called, the query in the components.
JASON: So I import graphql from Gatsby. Then export const query from graphql. I'm going to put -- I guess we can just start here with this.
OBINNA: Can you check what this query returns?
OBINNA: Okay, yeah.
JASON: Oops, oh, yeah. That wouldn't return, would it? Am I not running? I'm not. Okay. It doesn't like -- oh, I need to add a flag.
OBINNA: Oh, yeah. My bad. So when using this, because it's an experiment, we need to add that flag.
JASON: Okay. Thank you for the sub, sworlo. All right. It does not like my -- oh, that's just me writing bad code.
OBINNA: Yeah. (Laughter)
JASON: (Laughter) That's okay. I can live with that. I'll handle my own bad code. Null 2. Make it look a little nicer. Then let's see if that fixes it. It says yes. So let's go look at this thing. I'm really excited. That's a cool API. So let me give it a 404 so we can see what got created. Holy buckets. No way.
OBINNA: Yes way.
JASON: It didn't give me any props or anything. Let me see if that's -- okay. So for whatever reason, it's loading but not returning -- like, it's not actually outputting my -- oh, I bet this needs to be a default.
OBINNA: Yeah. Oh, I think I saw a tweet about putting in like naming your functions.
JASON: Yeah, so this is something I've started doing for debugging. Instead of like export default and then making this arrow function, like this, which is what I think kind of the standard is, if you flip that around and give it a function, then you get to name your component and have a default export. So it's kind of nice. I really like that as a flow. Now that I've made this a default export, we can see, look at that. So it pulled in -- let's see, we get a path. We get a location. So these are all Gatsby things. Page resources. What else did we get? Data.
JASON: Dang, that's cool. I don't know why it has the --
OBINNA: Multiple. So it's getting all -- I don't know why it does that.
JASON: Wait, does this give me a choice? Interesting. What does that mean?
OBINNA: So that's why I wanted to know what this query returned.
JASON: Yeah, it is definitely odd that it did that. I'm curious. Like, this is pretty wild, though. This is really cool that it's able to do that. So it comes in with page context, which means that I could actually do -- like, let's do this. I'm going to write this out here because I'm going to get it wrong on the first try. We want a single thing. So I'm going to close this one down. Let me grab this ID. Then we're going to get a Contentful portfolio item. We want it to have an ID of ID. You're just not going to help with that, are you? Then I want ID, put that in there. Then I can say I want the project name. I want the screenshot. Then we're just going to get the source.
JASON: Then I want the description. ID invalid.
OBINNA: Should we check -- shouldn't that be if the ID is a string?
JASON: Oh, yeah. That's not right. That's not what we want. So this is actually because it's -- don't do that. We want it to equal.
OBINNA: Yeah, equal to like a string.
JASON: So then this will make these ID. Okay. So then if I run it, there we go.
OBINNA: Yep, yep.
JASON: That's pretty dope. I'm excited about that. Do I need -- I'm still not 100% clear on how we get the --
JASON: Oh, here's a description. I was getting the wrong description. Okay. Man, this is powerful stuff. I'm excited about this.
JASON: So let's take this, and we'll just drop this in straight up. Okay.
OBINNA: The cool thing is we no longer have to use Gatsby node for creating like all of this. So now we can just get all this information in one single page thingy. Then work with that from there.
JASON: Yeah, yeah. Well, thank you, Michael, for the sub. Wow. Sub and an insult. What do you call it? Is it a sub twitch? Yeah, no, thank you very much. So Brandon, yes, this is the variable section. So this is really cool because it means that we can try out different pages by just swapping this instead of having to hard code the value up here. And the reason that's important in Gatsby is that if we look at this page here, you see how we get this page context? The page context includes an ID. That means that we can pull the ID as a variable. So when we write this here, this ID is going to come in from the page context, which means that we don't have to do anything fancy. We just know that whatever page got generated, we're going to get the ID for it so we pull the right data for it. This is -- this is really nice because writing this in Gatsby node is a huge pain.
OBINNA: I know, right? When Blaine showed me this, I was like, what? Nice! Give me more.
JASON: We are trying to pull in our portfolio from Contentful and get it up on the page. We're using some brand new Gatsby APIs that make this stuff a whole lot simpler, which is really nice. Now that we've got this data, I actually think we can start getting something on the screen. So let's write this out, and I'm going to get just the data because that's the only part that I need. Actually, let me reload this first. Let's keep those props. Save. There we go. Now that I've saved, we get a portfolio item, project name, our screenshot, we get our description. Okay, so we can actually build out a thing here now. So I'm going to get down to the data and then here we can say item is data.contentfulportfolioitem. Then if I just drop this item in here, it'll get a little simpler to read. So we have our project name, our screenshot, description. Good. So then I want to show the item.projectname. Did that not work? There. So now we get our project name. If I go to blast off, it says Blast Off now. So then let's try to get this screenshot. You want to walk me through Gatsby image? Or actually, can we use Gatsby image with this?
OBINNA: Yeah, we should be able to use Gatsby image with this.
JASON: All right. How would we go about doing that?
OBINNA: So my approach to this, first of all, you want to import image from Gatsby.
OBINNA: Wait, it comes straight out of Gatsby now? Or do I need to install Gatsby image.
OBINNA: Oh, I forgot we were using clean slates. So there's nothing.
JASON: So let's do npm install Gatsby image. Then I'm going to import image from Gatsby image. So regular image when you use the regular system, there's a graphql.
OBINNA: So it should be like the same thing. The only difference is that -- so this API is built on top of the create page API. You can still do the same things, it's just the way it looks for the information is different.
JASON: Okay. Is that fragment somewhere that I can find?
OBINNA: It should be in the -- so let me just link this to the chat.
JASON: Ah, here we go. Looks like it's right here. For fluid image on a Contentful asset with web p. That seems like what we would want. Let's grab that. So I can just swap this out wholesale, I think. Then let's do npm run develop. It's going to complain because I haven't used image. Hopefully it won't die.
OBINNA: Yeah, sometimes when I'm coding on my own and it starts to tell me something, I'll be like, yeah, yeah, yeah, sure, sure, sure. I hear you.
JASON: Okay, cool. These are all the options. I used fluid with web p. Web p, for those not familiar, is a newer image format that's supported in most modern browsers that is a lot smaller than standard image formats. It also supports things -- like you can do an animated gif as web p, which is really nice. It supports transparency, like pngs, but at a much smaller size. So we'll use this first and fall back to a jpeg or whatever afterward, which I very much enjoy. So now that's running, okay. Save this. So I just switched out to that Contentful fragment. We get a base 64 version, the aspect ratio, its source, source set, here's the web p stuff, and sizes. Awesome. So then I can go in here. I can just put in image.
OBINNA: Image, yeah.
JASON: And that would be what? Item.screenshot.fluid.
OBINNA: Yeah. And the alt, we can use the item.screen.description.
OBINNA: So a cool fact and something that I love about Gatsby is if --
JASON: Look at that.
OBINNA: Whoa! Blast-off, nice.
JASON: And if we go back again to the 404 and go to the corgi memes, then --
OBINNA: Lay low.
JASON: Right? But this is such powerful stuff that we are about an hour into the show, and we've been able to not just model our content in Contentful, but get a new site stood up and now we're getting data from Contentful. So whenever we make changes to Contentful, it's going to show up here. And we didn't have to write that Gatsby node file, which has always been like, I think, one of the biggest hurdles for people who are getting started with Gatsby. So I think that is really powerful stuff. I'm really -- that's great.
OBINNA: Yeah. I was going to say, one thing I love about the Gatsby -- the way Gatsby handles things, if you don't add an alt tag, it will tell you you don't have an alt tag to your image. It would tell you -- like, so if you run that, it would say --
JASON: Does it yell at me out here?
OBINNA: No, it's going to yell at you in the CLI.
JASON: Okay. Let me start and stop.
OBINNA: Did that show you?
JASON: I think it's still thinking.
OBINNA: It should tell you alt tag not found or image doesn't have an alt tag.
JASON: I haven't saved this yet, so I'm just waiting for it.
OBINNA: Oh, still thinking.
JASON: Is it stuck? No, seems okay. Okay, yeah, it seems okay. May have been something else.
OBINNA: It should show that. I mean, sometimes when I spin up Gatsby sites, it would warn me. My personal sites, I had to fix up my accessibility, which is really something I'm not proud of. I mean, I always tell people to put alt tags, then I had that problem.
JASON: I mean, it'll happen, right? Any time I build something, I'll go and run the accessibility checks, and I also make sure that I can keyboard nav. That's a big one for me, making sure that if I tap through the site, I can get to everything. Gatsby image might make it empty by default. I'm not 100% sure. That's a good question.
OBINNA: Oh, maybe -- hmm.
JASON: Yeah. I don't want to rabbit hole on that because I want to make sure we finish with the Contentful rich fields. I also want to get a list of these on the home page. So let's move on, and I would like to figure out -- so how do I show this json here? I want to get that into an actual like formatted description. So how would I go about that?
OBINNA: So you would need like a -- let me just pull this. I know that handling descriptions from Contentful is weird, so you can have -- you would need like a rich text type plug-in. Let me get this. Up need to get this -- so yeah, you need to document to react components and block.
JASON: Okay. Does it have like a default?
OBINNA: So you need to install this npm.
JASON: Okay. So let's install. Sorry, was there another thing I needed?
OBINNA: Yeah, you need to get blocks from rich text types. But I think -- yeah.
JASON: Well, this would only be if we want to customize, right? By default, it would just do --
JASON: Let's see what happens if we just use the one. Then if we decide we want to customize, we can do that. So I'm going to start with import document to react components. I just run that against whatever the rich text.json is. Good. All right. Let's try that. So I'm just going to pull this in directly. Then I think what I'll do is let's get the description. Document to -- I'm going to copy/paste that, actually. We're going to put in item.description.json, I believe. Check that.
OBINNA: Yes, yeah.
JASON: And I think I can just leave that, right? If we leave the options by default, what I'm hoping is it'll --
OBINNA: It will just automatically use -- yeah.
JASON: So let's see what it gives us. I'm going to put the description here. Let's just give that a shot and see what happens.
OBINNA: Let's see, is it done installing?
JASON: Oh, I've got to run develop.
OBINNA: So, let me see.
JASON: Okay, here. Look at that. So let's see what our actual mark-up looks like here. I'm going to make this a little more narrow so we can look at this without -- there we go.
OBINNA: Yeah, so if you have Gatsby admin installed, that kind of listens to your Gatsby develop. So whenever something is added, you can just automatically restart that for you.
JASON: Oh, cool.
OBINNA: I've only ever used it in -- like, so if I'm using a theme. I think it should work in all cases.
JASON: Okay, cool. Very cool. So this is great. It's a little weird they used italics and not emphasis, but actually, that's a perfect reason for us to do this customization. Let's use actual emphasis here. So we'll go back to here, and we need this Contentful rich text types.
JASON: All right. So I'm going to -- you say if I do -- oops. So I'm going to install this. We'll go side by side on the terminal there. Then I need to get import marks -- blocks and marks? I don't need blocks. Just marks.
OBINNA: Marks, yeah.
JASON: So I want marks.italic probably. Let's maybe go look at this component.
OBINNA: Let's just be sure.
JASON: Very helpful. Thank you.
OBINNA: Is there's a tweet by Sara. I think she did it in like 2016. This plug-in never happened. This doesn't exist.
JASON: Let's look at the marks here. So we want italic. We can handle that. That's going to come from Contentful rich text types. So then our options, which we can probably just do in line, will be your render mark. Then we can do marks.italic. That gives us a handler function, which is just a component, it looks like. So I can take the text, and then I can make it emphasis and put the text in there.
OBINNA: Let's see.
JASON: What am I doing wrong?
OBINNA: I think it's the -- yeah.
JASON: Okay. Let's give this a shot and see what happens. So now when we go in here, it is emphasis instead of italics. So that is pretty handy, right? That gives us a pretty decent amount of control without a huge amount of work. We also got to dig right into the source code of a package there. So let's share this.
OBINNA: We should probably send in a PR to add docs for this.
JASON: If someone is looking for a great first issue, this is a way to get involved in open source. Add in the read me just a list of what the types are. It looks like they're very thoroughly, like pretty easy to track here. You've got blocks. So you have this list. Then you've got marks, which is this list. So you'd be able to create a list of those so we'd be able to find them easily in the docs.
OBINNA: So someone could build something awesome, but nobody knows what it does.
JASON: Yeah, honestly, I think a lot of packages that are really, really useful end up not getting used because people don't know what to do with them. Writing good docs, having good read mes, some examples, that makes all the difference in the world for getting someone to try a new project.
OBINNA: Yeah, I agree.
JASON: Cool. So this is great. Now I'm going to drop out the data dump here. It's gorgeous. That is some good looking stuff going on in here. So the next thing we want is probably to get a list of these on the home page. We've got about 15 minutes to get that done. So if I was going to do that, what do I want to do?
OBINNA: So you obviously want to get -- so maybe change the -- hmm. So usually I would think, how would I do this if I was using -- querying from Gatsby node. I would have to query for all the -- so the title and the index or js then map that into a component. So I think maybe that would be a good place to start.
JASON: Oh, you know what we might be able to do, actually? Come to think of it, we could maybe reuse -- we'd have to figure out how to swap the title so it's not H1 every time. But we could reuse almost this entire component to save us from having to rewrite all of this. Yeah, let's do that. So let's take this one, go into source, go components, portfolio item.js. We can import react from react. We'll export function portfolio item. That's going to get an item. Here we can get rid of that piece.
JASON: Then we could say something like --
OBINNA: Export default?
JASON: I mean, we can do it either way. We can export default or import it as a named.
OBINNA: All right. Cool, cool, cool.
JASON: I've been doing name just because it's a little easier when you start moving between es module or common js. Naming tends to work a little more consistently in between. So what I'm going to do is I'm going to put in this page equals true. Then I'm going to do a heading component equals is page, and we'll return -- how would we do this? H1, children. Let's do it like this. We'll do children. So this is basically a full-blown component here. So we'll do H1 children or we'll do H2 children. So this is a little hacky, but basically what I'm setting up here is so we can quickly flag whether or not this should be an H1. Then down here we can just make it a heading component. If I spell it correctly, what we should see now is that these will return the right level of heading depending on where they are. Then if we go into this page here, we can now return portfolio item with an item of item and is page. Then the rest of this is what we just pulled out. So we just need to make sure that we actually import -- oh, we need to import all this stuff here.
JASON: Okay. Then we can drop that part out. We need to import our portfolio item from components. I've got to double back. Components, portfolio item. I'm going to rename this one to be page.
OBINNA: I'm just looking at the -- yeah. So I was just looking at the docs for, what's it called, the file system page creation. There's something for routing and linking.
JASON: Oh, okay.
OBINNA: Blaine is in the chat. Blaine says try the new collection routes in API.
JASON: Okay. Let's take a look at that. Routing and linking. If you wanted to link to the product, you'd have a component like this.
OBINNA: Hmmm. Oh.
JASON: So we'd do all products. We want the name, and we want the path. We would say whatever the URL is.
JASON: Oh, that's sweet.
OBINNA: Yeah, I didn't even see this. Thanks, Blaine.
JASON: All right. Let's try it. So let's go into index here. We're going to import -- wow. I don't know what language that was. Graphql from Gatsby. And I need the link component. So then we would want to export const query, equals graphql. And we're going to --
OBINNA: Oh, I'm looking at the chat. He says there's a mistake in the docs. There shouldn't be --
JASON: The colon. Use the period. Okay. So we just match the actual name. So it'll be -- I'm going to copy that directly. We'll go back to the index file. So what we're trying to do is we're doing a query, and we're going to get all Contentful portfolio items. We're going to get nodes. Then we're going to get the name and Gatsby path, file path, and it was /portfolio. Okay. So let's give this -- what does it say? Cannot query name. Oh, that's because it doesn't have a project name. Link is defined but never used. Okay, that's fine. I don't care. There we go. Okay, that's better. Now if I go -- let's take our props, and let's just look at what we've got. Stringify those props, make it look a little nicer, and let's go look at our homepage. Why aren't you outputting anything? Okay, fine. What am I doing wrong here? We're returning pre tag. Oh, I destructured props. Yes, I did. Thank you.
OBINNA: Thank, Blaine.
JASON: I would have stared at that for way too long. So now we have our page resources. To query the node path, the file path argument must omit the file extension.
OBINNA: Oh, so make the /props -- yeah.
JASON: Did that not actually pick up? There it is. Just had to save a couple times to get it to actually kick. So this gives us our data, all Contentful portfolio items, our nodes. I still don't know why these are duplicated, but whatever. (Laughter) So yeah, I'm honestly like super confused by that. In our Contentful content --
OBINNA: I have never had it duplicate for me. It just creates one of it.
JASON: There are two entries in our entire thing. So I stop, I'm going to just run a quick Gatsby clean. Then let's npm run develop again and see if that cleans it up. Let's go here. No, still has them doubled here. I don't know why. Let's not worry about it because we're almost out of time. So instead, let's get these things listed on the page. So what I'm going to do is we know on the portfolio item that we're getting all of this data. So let me get the description and everything. Let's go back and add that. So now we're going to get all of these details, and that means that we can do a -- we can destructure down to data. And in our data, which we'll continue to dump, we should then be able to -- let's just put this over here. I think what we should be able to do is we can go with data.allcontentfulportfolioitem.nodes. I'm going to clean that up. Let's clean this up. So we'll say items equals. Then we can say items.map with an item, and we should be able to do a portfolio item, which we've just auto imported. Then I'm going to bring this link back in. Let's set the item to item. Is page is going to be false. And what happens -- this is probably bad form, but I'm just going to say item.GatsbyPath. We're just going to link the whole thing. So we'd want to go clean this up later. We are going to need a key on this, which can be the -- let's include the ID. So the key would be item.ID. There you go. Look at him go. All right. So we get the doubles, but that's fine because now if I go in here and click to Blast Off, we actually see Blast Off. Look at that. That is really cool. So then we can clean this up a little bit. Actually, why don't we just do this. We'll do a filter. No. How would we do this? We can -- actually, I think this will do it.
OBINNA: Oh, to remove the doubles?
JASON: Maybe I don't care. So I could write a filter. I think -- so the filter we would want to get the index of the item and compare it to the first index of searching for that item, but I don't care. We'll just have our doubles. But what we can do is we can set up our H1, and then we can also go to this page here, and we can import link from Gatsby and we will link to the home page back to all portfolio items. And finish this. Okay. So it doesn't like something. Back to all portfolio items. Am I missing something? What are you complaining about? Okay. So let's go over here. Corgi memes, back. That is -- I mean, that's pretty -- that is slick. I will say that was much nicer to work with than getting into the Gatsby node file. When the docs catch up and kinds of make this the de facto way to do things, it's going to clean things up a lot. Once it clicked and my head got around it, this is really intuitive. Then the ability to build your pages with these types of queries. Like, this is really nice because it's effectively a relative link. I can just say I want to link to that page, and it just does that, which is really, really nice. Well, cool. So yeah, Obinna, I think we've got ourselves a functioning portfolio site. This is super exciting. We're also out of time. One last shout out to our sponsors. Remember, we have live captioning during the show and on every show from White Coat Captioning. Huge thanks to the team for being here and making this show more accessible to more people. And thanks to our sponsors, Netlify, Fauna, Sanity, and Auth0 for chipping in to make this the most accessible show that it can be. Obinna, anywhere that people should go if they want to follow up with you or learn more about Gatsby? I'll start with your Twitter.
OBINNA: Yeah, so follow me on Twitter. My inbox is open. Happy to answer any questions. I also recently put out my personal site, Obinnaspeaks.dev. I've been playing with this. This is actually based off a starter, but I've been playing with it and adding more features. If you go to the blog, I will be putting out mostly tweaking stuff. So I have one blog post there right now. I'll add more stuff. Please reach out to me. I'm always happy to answer any questions.
OBINNA: Just ask me.
JASON: Very cool. We'll put more links for Gatsby and what we did today into the show notes. Make sure you go check out the schedule because we've got some amazing stuff coming up. We've got Prince Wilson coming on to teach us Rust. We have Kelly Vaughn coming on to teach us Shopify. Emma is coming on to argue with me about tacos. Ben is going to come on and teach us about react and typescript, which is a super fun one. Eve is going to come teach us about some interesting stuff with graphql. Shelby is going to teach us about observability. If you don't know what observability is, like I don't, you're going to have a lot of fun on this episode because I legit have no idea how the things she's doing work. I'm really excited to learn about it. Monica Powell is going to teach us about webmention and next.js. Natalia is going to teach us about Vue and Apollo Client 3. The list gone on and on. We've got a couple in the can that I haven't even announced yet. So please, please, please go check out that schedule. Very, very fun stuff coming up on the show. With that being said, thank you all for hanging out with us today. Obinna, thank you so much for hanging out with us today.
OBINNA: Thanks for having me.
JASON: We'll see you next time.
OBINNA: Bye, everyone.