Using Contentful and Gatsby Together
with Khaled Garbaya
Contentful provides a flexible, powerful content management back-end, which pairs really well with Gatsby. In this episode, Khaled Garbaya will teach us how to use Contentful to power Gatsby sites.
Topics
Resources & Links
Transcript
What's up, everyone? And welcome to another episode of Learn With Jason. Today on the show, we have, I asked about pronunciation, I'm gonna get this wrong, but I'm gonna say it, Khaled Garbaya.
Wow, impressive. Thanks for having me.
Yeah, thanks so much for coming on. I'm super pumped to do this show. I think it's gonna be a really fun one. And I think, really useful. We hear a lot of people talk about Contentful as a CMS to power Gatsby. So, today we're gonna do that. We're gonna build a Gatsby site, and we're gonna use Contentful to manage the data. So, before we start, do you wanna talk a little bit about who you are, how you got here, what you're interested in? Do you like walks on the beach? Like, what's your deal?
Okay, so my name is Khaled Garbaya, I'm a software engineer. I work, actually, at Contentful. My day to day job is writing and maintaining SDKs and tools, and also writing APIs for the developers to work through with Contentful. How I got here. I love this livestream, and I actually think Jason is, like, hey, it would be cool if we can make an episode about this. And, here we are. I love walking on the beach, coming from a Mediterranean country. So, I'm originally from Tunisia, and yeah, we have some great beaches there. Other than that, yeah. I'm actually, been in Berlin for six years. I also run the JAMstack Berlin Meetup, so if you wanna, if you have a nice dog, and you are in Berlin, just come in. And, yeah, let's talk. Yeah, it's in North Africa, yeah. Exactly, that tiny country.
So, you probably know this, but the Achilles Heel of pretty much every American is geography. And so, I had no idea where Tunisia was. I've heard the name. And, this is super cool.
Yeah.
So, yeah. Where should people go if they go to Tunisia? Should they go to Tunis?
If you go, if you're a beach kind, you can go up to the North. You see like this fist in the water? Up from there?
This one, here?
Yeah. And then, if you go a little bit to the left, there's a beach there, Bizerte. That's the one that's, it's actually nice.
Oh, wow.
Yeah, like the whole coastline is really nice.
That's beautiful.
So, yeah, make sure to visit it. And then, if you're into desert and stuff, you can go all the way to, like, South. Really down, you can see, we have, like, we are part of the, yeah.
Oh, cool. So, there's, like, there's all sorts of stuff going on. Tataouine? Oh, my God.
So, I can tell you a story about Tataouine. So, you know the Star Wars, Tataouine. That's actually, it's named after this city, because you know that, that the First Episode was filmed in Tunisia?
Was it really?
Star Wars.
Oh, wow, this is, yeah. You can see the influence, huh?
Yeah, you can actually Google like Star Wars Tunisia, and then, you can see the actual scene. It's still there, and people are going there.
Oh, that's, that's fascinating. Okay.
So, now you know the history of Tataouine.
I love it. That makes me so happy. All right, cool. So, I think that we can maybe say that concludes our geography lesson for the day. Let's jump over and let's talk about Contentful.
[Crew Member] Holy buckets, did that just work?
Sound effects are starting. All right, so, what about Contentful? Let's talk through. Let's talk through how this is gonna work for us.
Okay. So, you can think of Contentful as the content infrastructure for your stack, because as you know, now JAMstack is actually like the low-level stack become a little bit higher now. It's like you have content, you have payment, you have other stuff, and these can be provided via API. So, Contentful puts in the content bucket, and it actually gives your editor a nice web app so they can edit content. And distribute the content through a CDN, and you can access it with, like the API, as you can see in that nice banner. And with that, also, we give you full flexibility. If you're a developer, you can actually extend the platform. You can build your own fields, if you wanna, if you have a specific use case for that, and so on. Yeah, so, that's basically Contentful. It actually integrates well with all the cool stuff that you have right now. Netlify, and so on.
Cool, so I'm just signing up, here. And, let's see.
Yeah.
Oh, that one's already been taken, so let's use my other one. Does that work?
Maybe an old name?
We'll make it Learn With Jason. How about that?
Yep.
Okay. What?
So, we can do, I develop content-rich products.
Okay.
Or, we can skip that. So this, we're basically, it will take you through,
Oh, yeah.
explains what Gatsby is, what Contentful is, sorry. And then, in five minutes, you'll manage to deploy your app, actually, to Netlify from Contentful.
Yeah, I really like, this is a cool graphic. I like this.
Yeah.
Okay, cool. So, I'm gonna skip, though, because I want you to teach us what's going on.
Yeah.
So, let's see. I have, yeah, what do we wanna do?
You are now in the Space Home.
Okay.
You can think of a space as like the container of your content. So, it's like your project.
Okay.
And, the first thing we need to do is to define like the blueprint of our content. So, we need to think, what do you wanna build? And, what are the components that will make up this site?
Okay.
I would avoid thinking in terms of pages.
Okay.
And, think in terms of content components. So, what makes, I don't know, a landing page? What makes a blog post, and everything. And then, we start from there.
So, okay, so if we're thinking in terms of content types, we wouldn't say, like, this is a blog page, and this is the home page. You would instead think, like, this is a post, and then, I have an author.
Yeah.
And then, I have a comment.
Yeah.
Like that?
Yeah, and these will make up the page.
Okay.
Because, you need to make your app kind of data-driven more than a use case-driven, which is actually that Gatsby also does.
Okay.
And, that works very well, for that.
Very cool, okay. So, if I want to start that, am I going to, like, the Content Model? Am I creating a new space? What should I do?
So, we are in the space now, so the space was created.
Okay.
We can do a Content Model. We can go to Content Model, and now we can see we don't have any. So, we can add Content Model.
Okay. All right. And, what do you think we should do? I'll let you drive this, because you're gonna know what takes the most time.
I think the simplest case would be like maybe you have a post. But, it can have Learn With Jason, since we named this Learn With Jason, maybe we can say, like Lessons, or something.
Sure, let's do that.
Yeah.
So, we've created a lesson. Now, we need fields.
Fields, yeah.
Let's do.
A text field that we can give it first a Title.
Okay, more than one value.
And, it will be like a short text. That's fine, we can hit create.
Okay. And then?
The body of the lesson can be rich text.
Okay, and now, this is, is this automatically gonna give me some kind of a WYSIWYG editor?
Yeah, so it will give you like a, yeah, WYSIWYG editor. You can also reference other entries inside of the editor.
Okay.
And, we also provide a few libraries like React Render, so you can actually capture all elements and render them however you want.
All right, pop quiz, what does WYSIWYG mean?
In other words. Yeah, this also works very well with design systems, so if you wanna intersect all the element, and replace them with your own components, styled components, and then inject the content. This is like that.
Oh, okay, so basically, when I'm in this description, like if I'm reading out of Contentful, I can inject my own components? Or, do I do that here?
It's when you read that.
Okay.
So, you get like a JSON representation, and all the functionality we already provide in-library, so, yeah.
Cool. All right, and the chat came in with the what you see is what you get. Awesome, awesome.
Yeah.
So, oh, no, I got an unstable internet note. That's always, that's good. Let's hope that doesn't--
Might be my internet, also.
Well, that's, it's complaining about mine. So, fingers crossed here that this doesn't go weird.
Yeah.
Okay, so we've got a Title and Description, and I guess probably we wanna?
So, also we can have an author, so this can be a reference.
A reference?
That we will create later. So, we can call it Author. For example.
Okay. These settings cannot be changed later.
Yeah, it's just one reference.
Okay.
In case you have a lesson with many authors, you can have many references.
Or, like if you had like tags, or something, and you wanted to connect multiples.
Yeah.
You could get it that way.
Exactly.
Okay. Very good.
Like a categories on stuff. We can add another reference for SEO, so you can actually, so we can attach some SEO metadata through another entry to your lesson.
Okay.
And, that will work with your SEO component through the stack, there. That's always great.
Okay. And then, I guess the last thing would maybe be to like actually link to the thing.
Video, or something.
Yeah.
Yeah.
That would just be like a?
Your video. Yeah, could be a video. And instead of hitting Create, you can do Create and Configure.
Okay.
And then, go to Appearance. To the top right. And, you can click URL. So, this also will help you to like preview the URL, and if it's right or not. And, this Help Text also, you can, yeah. You can provide some information to your editors when they edit that.
Or, in my case, a note to self. Let's put that one up here.
Yeah.
I love, this is a nice little drag and drop interface. So, this makes sense to me. That seems like a good move. And so, now I save?
Save, and we need to create the Author and the SEO content type. You go back to Content Model.
Ah, Content Model.
And then, add the content type.
Okay, so we'll do an author.
Author.
And for the field, we can probably just put a name, right?
Yeah, name. And, I mean, you can add stuff later that will show up. You can always update your content types.
What's the keyboard support like for the drag and drop? Let's find out.
Yeah, it's actually accessible. So, if you go to the other, that's right, yeah.
Let's do this, we'll just add like a Twitter. I'm gonna make this a URL.
Yep.
And, okay. So now, I come in here. What do I, how do I?
Is it like up and down?
Whoa! That is cool.
Whoa! Cool, cool, cool. Some, yeah.
I need the air horn. Man, I don't know if Marcy or Emberly are watching right now, but that's like, they're probably just like, yes.
Yeah.
No, that's awesome. That's very cool. I'm super happy to see that, actually. Okay, so, we'll save that one.
And then, we need the SEO button.
Okay. SEO.
SEO. And then, I can have a, yeah. Keywords.
Title. Or no, we probably want not rich text.
Not the rich text, yeah.
Text, and this can be a longer text, I think.
Yeah.
For description. And, I'm gonna skip keywords, because they're not super useful, I don't think.
Yeah, and then we hit Save. And, if we go really quickly to the first Content Model, we can actually make some Validations so we only accept Author type in the Author Reference, and so on. So if you hit Settings, and Validation, Accept only Author. Yeah. And you can type, yeah.
Must include an author.
Yeah, make that required.
We'll make that required, too, okay.
And then, you save.
Then save SEO.
We can do the same for SEO, too.
Okay. So, that has to be SEO. And, we can make that optional, because it's not a good idea, but technically, you should be able to do whatever you want.
Yeah.
Okay, so we've got our reference.
Cool.
Okay.
So, let's create some sample data. So, you can click Add Entry, and there, you can click Lesson.
Okay.
Give it a nice title.
Let's go look at...
The YouTube playlist.
Let's get one. So, on Monday, I had Swizec on.
With a bird, yeah. I watched this today, actually.
Yeah, this one was a lot of fun.
It was really funny.
All right, so pause that before it starts talking to me. And then, we'll, oh, where was I? Here?
Yeah.
We will say Data Visualization in React With Gatsby. I think that's what I called it. Drop in this link. Oh, cool, it's gonna do a preview?
Yep.
Oh, that's slick. I like that a lot. I did not realize that was gonna happen. Okay, that's even cooler. And then, let me just copy paste the description. So, let's just grab all of this. And, we'll come back in here.
And, it also accepts like a rich text, and then,
Yeah.
automatically generates the links and stuff.
Yeah, and so if I wanted to hit buttons, I could. I'm not gonna do that. Oh, let's try this. Let's just add one so that we've got it. Oh, no. It's got, these are not, there we go. Those were like line breaks, not actual element breaks.
Yeah.
Oh, okay. So, this is cool. I'm into it, I like this. Make that into, okay, now I'm making this harder than it needs to be. What have I done? Okay, how about that? I'm leaving that alone. That's plenty. Oh, God. Shut up, Jack. I'm feeling pretty judged right now. Okay, oh, no, I have to do a thing. I need to add a new author and link. Oh, cool, and it's gonna let me do this just like,
Yeah, you can change it from there.
right from the thing.
Yeah, it can create something from it pretty quickly. And then, your Twitter.
Okay. Publish. Okay, and I've already noticed a problem with this content model that I'm gonna need to fix. We don't need to do it now, but it just occurs to me that, what do you mean, you can't access the URL? Don't give me that business. But, I would want to include the guest, right? Like, I would wanna have a link to the guest, not necessarily to me.
Ah, yeah, that's actually...
So, actually, let's do this. We will pretend that the author is actually, there. So, we're gonna use that instead. So, this will be the guest, not the author. And then, for the SEO, we could do something like, let's see. Just grab this one again. And then, here, we'll take just the first bit. Drop it in, and then I'll get rid of the link. And I think that's good. Okay. So now...
Then you need to publish the main lesson, now.
Ah, publish, okay.
So, if you go back to content, we can see three content created. And, you can, if you go up to the content type, and then click Lesson, you can see only the lesson.
Yeah. Oh, okay. And then, I can like add other filters.
Can add other filters, and so on. You can also like type, and you will have a kind of auto-complete there. Yeah, like author, and, yeah. Yep.
Hm, what did not work?
Yeah, I think we need to do, I forget the syntax about that.
Click to select. Oh, you have to like actually, ah.
Yeah, you have to, ID.
I understand.
Yeah.
Okay, okay, I can work with that. And then, if I do click in here, I can, like, oh, I can't. Why when I, why can't I? That's weird.
Yeah.
Seems like you should be able to search for that. Product feedback.
I'll make sure to show this to the Front End team. So, don't worry.
Let's see. Okay, yeah, cool. So, we now have a lesson. We have, if I clear this back to Any, we've got SEO data for that, and we have an author.
Yes.
And now, if I go through and, what happens if I just edit this? If I go, I wanna try this, because I wanna see what happens.
Yeah.
I'm gonna edit this. And I'm gonna change it to Guest. Now, is it?
That's the name?
Uh-huh.
You can see the name actually changed. If you hit Save, obviously.
Oh, hit Save.
After you hit Save, yeah. But, the ID, since it's linked to other content, it will stay, if you go sysid, it's author.
Okay, so if I was gonna do something with this, I would have to delete this field and re-add it?
Yeah.
Okay.
And then, if you tried to delete it, it will tell you, hey, you actually have some content linked to that.
Okay. And, that's fine, you know, if this was gonna be a real thing, we would need to go back and fix that. But, since it's a demo, we'll just, we'll roll.
Yeah.
All right. So, do you wanna add? I feel like we probably don't wanna spend the whole time doing data entries, so maybe we just go build the site?
Yeah, maybe we can, so for a content model sense, I think Gatsby is using the name instead of ID. We can change it back to author so we won't have confusion.
Sure, yeah, that's probably smart. Content model.
We can put the content model, and then.
Guest.
Yeah, or, yeah, yeah. I mean, we can also use guest, so.
That's fine, we'll do this.
That's fine. All right, let's do some coding, then.
Let's do it. I have set up, I've got an empty folder here. So, in it, are we just, you wanna start from, like, all the way scratch?
Yeah, let's start from scratch.
All right, so what I'm going to do is, no. Gatsby new, put it in this folder, and we will use the Gatsby-starter-hello-world, which is just gonna give us a, like, kind of a basic Hello World page, and that's really all.
And, elevator music.
Good timing on the elevator music today. Okay, and then, over here somewhere, here, we have our site. So, this is the index file. We've got a Gatsby config with nothing in it. And, our only dependencies right now are Gatsby, React, and ReactDOM. So here, we can start doing things. So, what do I need?
Yeah. So, we need a dependency. We can add the Gatsby Contentful source. Or, source Contentful, yeah.
Anything else?
I think that, for now, that's it.
Okay. Let's, yeah, let's give it a shot. And then, while we're waiting for that, I'm going to pull up gatsby-source-contentful. And, we will post a link to that in the chat. Also, by having this up, I will have a reference on how to install it. Okay, so, we're gonna need a space ID and an access token.
Yeah.
So, let's start by setting this up. In here,
Yeah.
we're gonna add our plug-ins. And then, let's see, we wanna resolve to gatsby-source-contentful. In our options, we needed what, now?
SpaceID and accessToken.
And accessToken.
Yeah, and it's not that bad if you show the token, because this is read-only.
Okay.
But, yeah, best practice is always to use environment variables.
Okay. And so, I'm gonna set up a .env file, but since you said it's okay, I'm going to not worry about hiding this token.
Yep.
And, if you all wanna make websites to show off the Learn With Jason content, I honestly don't mind. I'm totally on board with that.
Yeah.
And so, up here, Gatsby ships with dotenv, so I'm just gonna require dotenv, and .config, and that's gonna pick up our .env file.
Yep.
So, I'm gonna save that. And then, we need to find, how do I find my Space ID?
Okay, so if you go to Settings.
Settings.
And then, API keys.
API keys.
We already create an example key for you. But, you can add other API keys.
Well, let's just add one.
Yeah. You can give it a name.
Let's go with Gatsby Read Token. So, here's the Space ID.
Yep.
So, I'm gonna drop that in here.
And, that's the Delivery API, yeah.
Which one do I want?
There's also the Preview token. The Preview token is used mostly for if you have content that's not published yet, and you wanna see it, and test it in your website. You can actually use that token. And, it's also read-only. So, both of the tokens are read-only.
Both are read-only. Oh, okay, but so this is actually kind of interesting, because what you're saying is, like if I'm, so if I use this one, I'm only gonna get published content.
Yes.
So, this would be like the production read-only token.
Exactly.
And then, if I was working locally, or if I was using
Yeah.
like Gatsby Preview, I would want the Preview API token, because that would show me my draft content
Yeah.
so that I could build, I could see what something looked like before I published it?
Exactly, yeah.
Cool. Okay, yeah, I like that. So, we're doing development, so I'll grab this Preview API token. And then, I'm gonna go back in here, save that. And then, save here. And, that's it, right? I just restart?
Yeah. If we do Yarn develop.
Okay, let's see how it goes.
And you pull some content. Yeah, I can see there.
Uh-oh.
Uh-oh.
Oh, interesting. It's, you know what? I think we have a bug in Gatsby, because I think what it's doing is it's parsing dependencies. And because we're not installing the plug-in yet, it's finding undefined GraphQL stuff. So, once we, oh. But, we did install the plug-in. Oh, no. What? Did you mean ContentfulSeo?
ContentfulSizes.
It's like the image stuff, right?
Was that?
That's interesting.
That is, that is like the image stuff, but I don't know. Yeah, you can see the Contentful stuff, though.
Well, maybe we just ignore that for now, then.
Nobody saw that, right?
Yeah, just everybody, just, you know, shh. Okay, so let me get rid of this. This is some stuff I did from a demo yesterday. So, we'll close that up. And now, we have our Contentful lessons. And then, let's just start by getting the title. Okay, so we're already in business. We've got our data coming in.
Yep.
What? Let's see, what else do we wanna do? So, do you wanna talk us through kind of how the individual things work? Because, I just queried a text field, but we've also got like the references, we've got the rich text.
Yep.
So, you can, we can play with that?
Yeah. So, the source plug-in uses, under the hood, the SDK, and the SDK actually will resolve all these references for you. Because, if you look at the raw JSON, most of it is actually links, and with IDs, and it links to another entity, or array of JSON.
Like a normal addressed API?
But, the SDK will resolve all of that, or it would be also resolved in Gatsby. So, if you go to Author.
Author.
And then, pick Name. And then, Try. You can see we resolved all the stuff for you.
Very cool. Okay, and so the URL, it looks like, it's gonna bring back that URL.
Yeah.
So, that preview stuff is only for the Dashboard. There's not like any resolutions that happen in the public data?
Yeah.
Cool.
And also, if you go to, let's take a look at the rich text.
Rich text.
It's different structure, still. I think Buddy. Was it Buddy or Description?
Description, I believe.
Yeah, Description, and then, JSON. So, that's what we will be using.
Oh, okay.
But, to render that, we will need our React renderer.
Got it.
To display this data. We would show it later.
Okay, okay. And, before we move on, it looks like I missed a question a second ago from ecomath. He asks, are you charged per content, or request threshold? So, I guess, how's pricing on Contentful?
How's pricing? If you go, I don't know, if you go to Contentful, Pricing.
Pricing.
Yeah.
Let's see. So, a Micro Space, 24 content types.
But, we have also the, like, the free, like the free model, which actually allows you to have two spaces, and up to,
Is it?
I think it is up to--
Ah, developers, deploy your first app in five minutes. The first space is free. So, you get one free Micro space.
Yeah.
10 free users, and a sample app.
And also, you get up to I think 25 or more content types.
It says it's one free Micro space.
I don't think...
So, it looks like 24 content types.
Yeah.
Okay.
That's a Micro space. But, you get it for free. And also, 5,000 records.
Yeah, 5,000 records.
I think there is some limit on the API calls, but I think it's like over a million or so. And, one terabyte or something of bandwidth.
Okay, so that seems pretty okay.
Yeah, so seems like pretty. I think it's very generous, and you should go over that, probably, you have a bigger project, I guess.
Mm-hmm.
But, I'm no expert in pricing, so I might be wrong in some of the basics.
Aw, ecomath, I appreciate that. He's making sure no one can charge me money. I'm glad you're looking out for me, because I certainly wasn't. That's Chris'. Okay, you know what, I take it back, ecomath. It's not Chris'.
Damn it.
Every time, every time, the chat loves trying to make me spend money. And, whenever Ben Lannon and Chris Biscardi get in a room together, they always have something that they make me buy.
Yeah, and also like for enterprise and stuff, we also provide some trial spaces, so they can have actually big spaces with all the features enabled so they can play around and see if it's good for them or not.
Cool. All right, awesome. So, we can, yeah. Oh, God, Chris Biscardi is here, now it's time for me to spend money. Okay, so, let's actually get something up on the screen. So, we've got our Contentful lesson coming in. We pulled in the title, the author. Let's look at the SEO. And so, with the SEO, it should just be the title and description. There it is. Oh, what's up, theprimeagen? With a party of 74, holy crap. All right, hey everybody. Welcome to the show where I get talked into spending all my money with Chris Biscardi and Benjamin Lannon. So, yeah, we are currently building out a Contentful and Gatsby site. We've got Khaled Garbaya on. We are configuring our Contentful space. So, we've set up in our content model, let's do save that. We are working on our content model. We've got a lesson, and that lesson allows us to put in the video link and a title description, and author reference, and an SEO reference. And then, our author model is for the people on the show, so the name in Twitter. And, the SEO is for the title and description SEO tags. So, we wanna get that figured out. We've put together one entry. So, we have the lesson itself is Data Visualization in React, which is what we did on this stream earlier this week. It's this episode, here, that you can go and watch. And, then we added some SEO tags and some author tags. And, we then set up Gatsby-source-Contentful in our Gatsby site. And, I was told that it's okay to show the Contentful tokens, because they're read-only. And, ecomath checked up for me, we can't get charged money for using those. So, we're all safe. And now, we're at the point where we're actually writing a GraphQL query to access this. So, this is a GraphQL query in Gatsby, using Gatsby's GraphQL Explorer. We are pulling Contentful data down. And so, at this point, what's our next step?
So, we can actually take part of this query. Let's first display the list of lessons.
The list of lessons.
And then, we will have a detailed page that would show the author and inject some SEO stuff, and so on.
Okay.
Yeah.
So, this one, we probably want to be a list of lessons. So, we will say, let's make that a, say it's the recent episodes. And then, we need to... Okay. So, I assume I need to do a GraphQL query here.
Yeah.
So, I'm gonna pull in GraphQL from Gatsby. And then, I'm gonna set up our query. And, should I just grab that query that we already wrote?
Yeah. Not all of it, though. Maybe the title.
We want the title?
Yeah, let's take the title, and have a list for the title. And then, when we click on it, it will show like a detailed page, as well. Show the author and more stuff. But, if you also wanna include the author in there, maybe you can do like by author.
Yeah. And then, to avoid having to write a Slug, I think I'm just gonna pull in the ID. Those are gonna be awful URLs, but we could use them.
Yeah.
I'm going to take--
Yeah, we missed the Slug.
Yeah. Actually, no, let's go edit our content model and do it.
We can add it really quickly, though. Yeah.
So, I'm gonna go into my lesson, I'm gonna add a field. It's gonna be, do I wanna use a text field, or is there a special type?
Yeah, it's a text, and then you call it Slug, and click Create and Config. There's actually a Slug. If you go, there it is.
Oh, nice.
Slug, yeah.
And is that gonna generate from--?
And this way, when you actually type anything in the title, the Slug will be generated automatically for you.
Oh, cool. Okay, so let me see that.
So, like next time you create a lesson, like a new lesson, if you type, I don't know the name of the lesson, then the Slug will, gets generated. Now we admit here, this is because this is an old one, but if a new one, actually it will generate the Slug for you.
Okay, so I have done that. And then, you said the ID will get the Slug, but I need to stop and start the, oops. Whoa, there. Need to stop and start this server, because we changed the model.
Yeah.
Okay. All right, and we're ignoring those errors, because I think that's a regression in Gatsby, because I saw that happen with another plug-in earlier. And once I refresh this page, there we go, we've got our Slug. So, we were able to add that in Contentful, get it into Gatsby real fast. And now, we can build out a list. So, let's take this query, go in here, just paste that in straight up. And now, whatever happens in this query is going to be delivered to this component as data.
In the data, yeah.
And then, we'll be able to do, so this becomes data, and we can go allContentfulLesson, let's alias this.
Yeah.
And so now, we'll be able to go data.lessons.nodes, and do something with it. So, let's go data.
You know, I always use Edge, Edge's Note, and today I learned about this Note. This is my show.
This is kind of a, this is like a sneaky little shortcut. We didn't tell anybody that we did it. Yeah. Oh, so here's a question. On vishawnsony, I'm so sorry for what I just did to your name. So, if you change the model, does it only apply to the new content?
It actually also applies to the old content.
Okay.
And, it depends on the case, but in complex cases, we have also the migration tool that will help you to actually migrate all your content in a programmatic way. So, I hope we'll have some time left, and I can show a few stuff there. We already talked about updating our content type at some point. So maybe we would add, we'll update the lesson to have author and guest. We can actually do that through the migration tool. But, we can do it once we have the website up and running.
Okay, yeah, let's do it. All right, so then I'm gonna have my h2, that will be a lesson dot, what was it, title?
Title, yeah.
And then, we can say with lesson.author.name. I guess we're just doing a list, aren't we?
And drop that link object in the link tag.
Yes, that is a good call. Let's get a link. So, since it's a local link, we're gonna use the Gatsby link. Link to, and we'll just link to Slug.
Good catch with the backslash. I always miss that.
I know, yeah. I bite myself, definitely trip myself up a lot with that. Oh, my God, what's happening? Come over here, there we go. All right, so now what we should get, if I go back to localhost:8000, is an error. And the reason that I got an error is what? Maybe I need to stop and restart.
Slug is reason.
Holy, holy buckets. Chris, Chris is going bonkers over here. Thank you so much. It's like five gift subs. Holy crap, thank you. Why, what are you?
I'm on it.
Oh, I know, I know what's happening. This is my fault. I did this, but it's actually this.
Lesson.slug.
Okay, but this is not good. What is happening here? GatsbyContentfulFixed on...
I think it's looking, somehow, for this Sharp plug-in stuff.
Yeah, that's, that's, does GatsbySourceContentful require the Sharp stuff?
I'm not sure, but probably. Maybe you can install the Sharp plug-in?
That's ContentfulAssets, Gatsby-source-filesystem. Oh, I bet I need, if it's using Gatsby-source-filesystem, we probably need to install it. So, let's do that.
Maybe also we can add the Sharp.
Gatsby-transformer-sharp and Gatsby-plugin-sharp?
Yeah.
Let's see here. Try that again, and we'll run a Yarn develop, and see if maybe it's just pulling those things. We might have to actually configure these. No, it doesn't like that. So, let's go back in here, and I'm going to Gatsby-transformer-sharp and Gatsby-plugin-sharp. And then, what, do I just need to filesystem and no?
Of course, filesystem, maybe, yeah.
With nothing? What happens then? I've never installed Gatsby-source-filesystem with nothing.
Me, too.
Please pick a path. Okay, so we need to, we need to set something up. So, I will use one of my favorite tricks, which is to create an empty folder. We'll call it Boop.
Boop?
We'll resolve it here. And then, we'll set up the options to be path: boop. Okay, let's try that one more time. Let's see if we still get those errors. Don't do it, don't do it. Oh, you punk. Why are you like this? Let's see.
Maybe we can see the results now, no?
Still can't see the results. So, what are we missing? Let's try...
Maybe deleting the cache and public pullers, and try again.
Yeah, I can, yeah, let me try that. Let's see, Gatsby clean. What was that, did you just not like that? Why is it locking up? Oh, no, oh, no. Did it delete those folders for us, though?
It should, yeah.
Okay, and let's run Yarn develop. Uh-oh, do the thing. Do the, no, do the thing. All right, so I'm wondering if this is actually an issue with like an outdated? I think this might be something with like a newer version of Gatsby. So, I'm gonna do something that I don't like to do, which is pin the version. And, let's just pin it to like 50, and see what happens. Because I think this is pretty new. Gatsby publishes a lot of patches, so going back 23 patches should hopefully get us before the regression. I hope. Oh, no. Oh, boy, we got bad business.
I'm looking. Some, where is it? I have some projects with working versions, so maybe I can...
Okay. Add a media type with a dummy pic? Oh, that's actually a really good, that's a good idea, is it? Because we haven't, is it because we haven't created any media? How would I?
But, that shouldn't be required. This is weird, though.
It shouldn't be.
What's the version of the source-content you have? Is it 2.1.19, or something?
Let's find out. I'm using 2.1.25.
Maybe try 19?
- Okay. Let's check the lock file. 2.1.19, that's the only one we're using. So, let's try this one more time. What's your Gatsby version in that working project?
It's 2.13.61.
Okay. Do you have other things installed, like Sharp, and filesystem, and stuff?
Yes, I have Sharp, I have filesystem. I have also transformerSkip, but I'm not sure if that's usual.
That one definitely shouldn't matter. Let me do the Yarn. Do you have media assets in your demo? Because I'm wondering if this is an issue where
Yeah.
the content types aren't being inferred, and that's causing the error.
Mm-hmm.
So, I think maybe we just need to add an asset.
I definitely have assets in here.
Okay, let's add an asset, because my instinct here is that whatever we're doing is, it's breaking because we don't have an asset. So, if I just like add an image in here, is that gonna be enough, do you think?
Yeah, we can try that. And then, Asset.
Create a new asset.
You can click Create new asset.
Let's do, over here I've got...
Maybe screenshot from the video, or something, would also work.
Yeah, I've got, here, this is you.
You need Contentful first. Click Create.
Oh, no. Here I was so hopeful that that would just work. Let's see, all right, here we go. Asset, Create new asset. And, we'll call this Image. File selector, let's see. This was a good episode, so let me get...
This should work, yeah.
Okay.
And, you can click Publish.
I better actually name that before I Publish. Okay, and so that...
And maybe we need to publish the main, yeah, the main entry.
Publish, okay. All right, let's try it again.
It's trying now. Okay, then probably we have a bug in the source plug-in, I think.
Yeah. I actually think this, this I'm pretty sure, is Gatsby's fault. But that's a good thing, because that means that we can also unpin these versions. So, let's re-add Gatsby and Gatsby-source-Contentful, at the unpinned versions. The you very much, keyboardranger. I don't remember how to give points, because I'm bad at these things. But, I remember how to do this one. Okay.
Someone needs to be happy now.
All right, so, cool. Then, now that we've got these, I can run Yarn develop, and hopefully what happens is everything just runs the way that we expect it to. At which point, I should be able to actually load this thing.
Yep.
Let's do it. Let's do it, it's happening. All right.
Woo-hoo.
That's interesting that I did. Oh, I used like a template literal in here. Let's close this up, let's go over to the index, and there we go. Here we go, okay. So, that's doing a thing. We haven't built this page yet, though, so we probably need to go do that.
Yeah, so we can go to the Gatsby node.
I guess we need to create a Gatsby node.
Yep.
And then, we're going to create pages.
Yeah. I always copy paste the thing from the documentation. Yeah.
This is, this one, I just know it by heart, because I have to do it pretty much every stream. So, we're gonna get a result, and that's going to be the result of awaiting a GraphQL call.
Yep.
That GraphQL call is gonna be allContentful?
AllContentfulLesson.
Lesson. Nodes.
Nodes.
Slug.
We can get the, I think the Slug is enough. Yep.
Yeah, I mean, we just need to create the pages, right?
Const, you have an extra S in Const.
Oops, sure do. All right, then I grab out the reporter. And, if we have errors, we will reporter.panic. Panic. And then, we'll say error loading lessons. And, I learned the other day that you actually have to stringify this to get it to work. So then, I'm going to do reporter, a result.errors.
Result.errors.
Okay.
Cool. Otherwise we'd create the pages.
Exactly. So, we can do results.data.allContentfulLessons.nodes, dot. No, forEach.
forEach.
And, inside of this, we can run actions.createPage. We wanna set up the path to be
The Slug, yeah.
Lesson.slug.
And, the context, we send the Slug along, because we'll use it inside the template. Also the template.
So we, the template, we haven't created this yet, but we're gonna put it in the source. Templates, and we'll say lesson-template.
Yep.
And, add a context. That context will be the Slug, and that Slug will be lesson.slug.
Dot slug, awesome.
Okay. So, now that that exists, we are gonna have to create this template. So, let's go template, woops, teamplates. Templates, lesson-template.js. Import React from react. And then, we're gonna set up a lesson template.
Yep.
And, I think we're just gonna be able to return, like... I just wanna make sure this works before we get too deep into the data part. So, there's our lessonTemplate.
I think, is something wrong with React?
Oh, sure was.
Okay.
Okay. So, we've got our lesson template. And now, if we build this, what should happen is it should take us through to an actual page, and that page will just show our TODO content. So, let's take a look, something's broken. It doesn't like, created a page and didn't pass the path to the component. What?
Okay, that's something new.
I typoed something.
Path, it's there.
Component.
Ah, yes.
That's my fault. I was thinking in templates, and I screwed it up. So, let's do that. Okay, so that did what we want. So, if I go back out here.
Awesome.
We've still got our list, but if I click through, now we have data-visualization-in-react as our Slug, and it says TODO: show lesson data.
Awesome.
And, if we, let's see, we're kinda done in there, now. So, what do we wanna do next? We wanna import GraphQL from
Gatsby.
Gatsby. And then, we need to use...
We have the query.
And so, in this case, we have to use an exported query like this, like a page query, because we need to use that Slug in context. And because we passed it here, anything that gets passed in the context of a create page call is available as a variable here. We know that's a string, and we want it to be required. So, it should fail if the Slug doesn't get passed. That's what this little guy means.
Yeah.
And then, we can do. Oh, let's write this in here, because that's gonna make more sense to my brain.
We can do a content, and ContentfulLesson.
ContentfulLesson. And then, we're gonna search by Slug. And so, we want the Slug to equal,
Equal to.
What was it?
Yeah.
Data-visualization-in-react. And then, down here, we can actually get some stuff. Let's make sure I got that right. Okay, that's the right Slug. And so then, what's the info we need, right? We need the video?
Video.
Description.
Description-JSON.
Uh-huh. And what was the other thing?
And author.
That's right.
Maybe name and the link to Twitter, so we can make like a nice anchor.
Yeah, we need our SEO stuff, too.
And, yeah, SEO.
Okay, so what I don't think I wanna take the time to do, here, is, wait, is this right? Description.
Yeah.
Why is it double?
It's actually wrapped, because that can, like the long text actually also can be a markdown.
Oh, I understand. Okay, so here's our SEO.
But since we are not using markdown, we can use it as raw text.
Okay. Here's our author. There's the rich text, which we'll have to figure out how to show. And then, we've got the title and the video.
Yep.
Okay, that looks right. So, let's go in here. Gonna paste this.
Awesome.
I'm gonna get rid of this one. And, we've got one extra down here, as well. And then, we're gonna use this Slug here. Okay, so we have all of this data. That's gonna come in here as data. And then, we're going to show something with it. So, let's set up a div. We'll do an h1 with the, let's see. I'm gonna alias this again, because that makes my life easier. So, it'll be data lesson. Let's actually just destructure that, lesson. So now, I can do lesson.title. And let's make sure that works. I'm gonna have to stop and restart to get it to pick up that query.
Mm-hmm.
Let's see. And, if I come back out here? Okay, we're getting that. So then, we can come in here, and let's say, like, the Guest is gonna be lesson.author.name. And we can set up a link to their Twitter, which would be lesson.author.twitter. And we'll say, like, Twitter.
Yep.
Okay, that's what we want. I mean, that's kinda what we want.
Awesome.
Oops.
Okay, so now it's time to render some rich text.
Yeah, so how do we do that?
Awesome. So, we provide a React renderer for that, so we don't need to do the parsing and so on, because we provide it. Like, you have a tree, and you need to go through it. So, what we need to do is install a few dependencies.
Okay.
So, it's @contentful/rich-text-react. And then, -renderer.
I'm sorry, say what?
Renderer.
Oh, renderer. Yeah, okay.
Yep. And, another one, @contentful/rich-text-types. And, yeah, with dashes, exactly.
Okay. Oh, I jumped the gun. Those were the two?
Yeah, these are the two.
Parseit, I can't tell if you're into or upset by the font. And also, I am not using Dank Mono, I am using Operator Mono. There's a link to all the stuff that I use, if you're into it. Okay, so that is working, so I'm gonna run develop again.
So, let's go to the lesson, it's a named import. So, import documentToReactComponents. It's a lower case D.
Like that?
Yep. From the Contentful, yeah, that one.
Okay.
Okay. And now, we can go to the GSX. And maybe have a div or something to contain that. And then, call that function, and give it the lesson.description.JSON. So, this functions within a React component.
Lesson.description.JSON, if I can spell.
Yeah, with a P, exactly. So now, we should see some content. Yeah.
Ooh, that looks nice.
So, these are default ones. If you want, you can see here, actually, we added in an image which is not displayed in there. So, the document React components actually accepts the second parameters, which is an object.
Okay.
And now, we need to import blocks from the rich text types, first.
Import blocks?
Yeah, blocks all upper case, as a named import. It's kind of a constant, so all upper case, blocks.
Oh, I understand. Okay, blocks. Wow.
Yeah.
My spelling is 100% today. So, I've got blocks.
Yeah, so there, and then, let's add the key so we can open kind of an array. Like, the square brackets. And then type BLOCKS dot, all upper case. Yeah, you can see that, EMBEDDED_ASSET.
Okay, is this right?
And then, after that...
Like, object and then array?
Yes, that will be treated as, it's a string, so it will be treated as a key.
I understand, okay.
So, that will be a function. You can do an arrow function that accepts node and children.
Okay.
Yeah, and that will return a React component. Here, we can return an image. You can either use like SPImage, or even a normal image. And then,
Wait.
the source would be--
will Contentful, does Contentful like return and automatically set up Gatsby image thing, or do I need to run a query for that?
In this case here, not, because, yeah, the plug-in was not updated. It's quite complex to actually inject stuff inside the rich text, because it's not queriable.
Okay.
It's not actually directly on nodes. But yeah, hopefully, you truly have a better support code.
For now, we don't wanna try to do that, then?
Yeah.
Okay.
So, that will be node.data.target, it's gonna be long, .fields.file. And then, square brackets, and then en-US, like a locale.
Like so?
Yeah. String, and the US is upper case. Yeah, and then, .url.
Okay.
Yeah.
And then, for the alt?
And then alt, you can do .fields.title. So, it'll be like node.title.target, yeah. Fields, and then from there, it's title. I think it's called title.
Like that?
Yep.
Okay.
All right. So, this should work and display the image.
Let's see, it didn't like it.
We saved, didn't we?
We saved, so I did this. BLOCKS.EMBEDDED_ASSET.
EMBEDDED_ASSET. Do we have the image in the rich text? Did we?
I have no idea, let's find out. Let's see in here. Asset.
Yeah.
Fields, title, file, but we didn't...
Ah, title English U.S., that's fine.
It's not making a difference.
Maybe you can inspect the HM and see if, actually, there's something.
That one came back empty, so I wonder if that's what it was. What if we just do something like this?
Yeah.
And then we'll comment this one.
Ah, sorry, the syntax is wrong. So, inside the object, the option object, so you can wrap all of that in another key, which is called render node.
Here?
Yeah. RenderNode, exactly.
Like this?
And object, and then you move all that block inside.
Oops. No, there?
Yep.
How about that?
Yep.
Hey.
Hey, we have an image.
All right. So, let's do a quick style cleanup here. MaxWidth we'll say is 300.
Well, we can actually do another cool thing using the image APIs in there. So, if you append to the image URL, like w=, make it a maxWidth. So, it will be like question mark, and, yep. And then, question mark, W is 300.
Nice.
And, you can see that's actually a 300-pixel image. So, what Contentful will do is transform the image and cache it for you, so that the next hit, it will give you the cached image.
Cool, that's nice.
And, you can also specify the quality, and also crop the image, and do all of that.
How do I? Is the quality just like a Q?
Let me check the Contentful image API.
Let's find out.
Because, yeah, it's here.
Is that changing anything?
We need some elevator music.
I think that changed it. Oh, yeah, that definitely works. So, if you set the Q to whatever value between zero and 100. So, I set it to 90, that looks okay.
Yep.
Yeah, I'm into it. Okay, so I feel like we've got some good stuff going here. So, we were able to kind of get our lesson out, we pulled out our guest, we've got rich text. We figured out how to replace our images with custom markups. So, if we wanted to get wild, we could go through and build out the source set object, and everything that we needed for Gatsby.
Yeah.
I think that's probably kind of outside the scope of what we really wanna dive into here. But, what if I want to replace like my heading? Can I just add another one of these?
You can actually add another one, give it BLOCKS, and then, you can heading one, for example. Or, heading two. Yeah, heading two, and then, heading two will be, yeah, exactly the same function.
Exactly what it is.
So, it'll be like node, and...
This is kind of, it's making sense to me. So I've got, like, here's our asset. Where was it?
Yep.
Links, text, heading two. So, nodeType, heading-2.
Yeah.
And then inside, we've got content and value. And so, if I wanna mess with this, what I can do is go to, we'd do node, and then I would return, let's just change the color on it. So I'll do h2 style, color is red. And then, I would do like node.content.value? Is that right?
I think the renderer will do some more transformation. So, it will be like node, and then children, and the value will be inside of the children object.
Oh, it would be inside children?
Yep. Because, an h2 may contain other elements.
Ah, I understand. Okay, yeah, that totally worked.
So yeah, you can replace that also with your, if you have a design system, and all well-defined components, you can replace all of them, or wrap them in a new thing. You can even wrap an h2 in an h1, if you wanna troll some people.
If you wanna get real weird. So, that's, yeah, that's super cool. So, I, yeah, clean that up a little bit. Well, awesome. So, this all seems to be doing what we want. Do you want to? So, let's do this. You wanted to get into the migrations. We've got about 20 minutes left. Do you think 20 minutes is enough time to do a migration?
20 minutes? Let's try and see.
Okay.
So, let's install the Contentful CLI, and you can install it as a global dependency.
What's the package name?
Contentful-cli.
Contentful-cli.
Yep.
Okay. I like that the chat has really gone off on a tangent discussing the favorite thing, their favorite ligatures.
Yeah.
Uh-oh, what's this? Is this one of those optional ones?
Yeah, I think it's some warning.
Optional dependency, yeah, I don't, okay.
It's optional, yeah.
Okay, so I have the Contentful CLI.
So do Contentful space login. And, you will have a browser window, you might want to show it outside of this. Before you click authorize, maybe you need to move this outside of the stream. Because, this is a management token.
Ah, okay.
And, using this management token, you can actually read and write.
Gotcha. And so now, I'm taking this offscreen, paste my token, and okay. The token has been added.
Awesome. Okay, cool. So, maybe we can create a file where, let's call it, so we wanna add, like we said we wanna add a guest content type to that file.
Yeah. Yeah, jonniebigodes, because I trust you 100%. I absolutely believe you that you wouldn't use my token to troll me. You people and your empty promises and lies. So, yeah, let's dive in.
We've created the guest file for that.
Okay. Wait, how do we do that?
And, let's call it add-author.JS, or something.
Like this?
Yeah.
Okay.
And then, we can open that.
Okay.
So, first thing, we do a model export. And, it will be a function that accepts a migration object. Yeah. Okay, so the migration object, this will be passed to, by the CLI to your code. So here, you can actually create content types, or edit content types. For our case, we will need to edit the content type. So, we need to do const, and then call it, which one you wanna add it?
Well, we wanted to change author to guest.
Yeah, I mean, also, or even add the guest to the author.
I'm up for either, I think. In this case, we're here to learn, not to get it exactly right.
At least, as a guest, not like, an additive thing usually works for demo sake.
Let's do it.
Adding would work more than changing for the time.
Okay, so I'm creating a guest.
Yeah, so guest, and that will be migration.createContentType. First argument will be an ID, which is a string. So, we can call it guest, lowercase guest. And then, the next is an object. Here would be name, so we can give it also guest, yeah. And then, description, if you wanna do that. Cool. So actually, we can right now test this migration script. We can actually progressively create different migration script for every step. So, that's always recommended.
Yeah.
Yeah, so we can save this.
Do I not need to? So, I don't need to make this a constant?
Yeah, we don't need that, because we want...
Okay.
Maybe, yeah, sorry, we need actually to do that, because we need to add a few fields with it, right?
But we're gonna do that later?
Yeah, or we can do it later.
Do we have to return it? Or, like, yeah, I guess I'm not quite sure why. Like, what do we do with this?
So, here we will create a content type, but it will be empty. So, it's basically kind of useless. So, I think it's a good idea to also add the fields in here.
Okay.
Yeah. So, we do guest.createfield. So, we'll have also name.
Name.
Yeah, and then object. This would have also a name. So, it can be, yeah, name, and then, type.
We'll just, text?
And here will be, actually, uppercase S symbol.
Like that?
So, this is the short text type. And, we can make it also required, so we can do also required: true.
Okay.
We can duplicate that to add also the URL. And it'll be URL, and of type Symbol. Required can be false, maybe.
Okay.
Do we need something else?
Why do I have some multiples? Why did that? I don't know how I hit that button twice. Okay, so we have a name and a symbol. Then, do I need to like return the guest or something? Or, is it, this is just kinda how?
No, that should be fine.
Okay.
Okay, so now we go to the terminal and do the Contentful space. You can type actually space.
Oh, I was like, no, I did a space.
And then, migration.
Migration.
And then, we do, let me find the correct syntax to call it. It's just somewhere. It's weird, I work with these tools everyday, but I still need to remember all the syntax.
I know the feeling.
Yeah, yeah. So, we have space, not that one, migration. Okay, so it's dash, dash, space, dash, ID.
And then, I need my space ID, I assume.
Yeah, you give it the space ID.
Which was here.
Yep.
Do it, is it equals?
Yeah, that will work with all of the syntax, even with the space. And then, you give it the name of the file, which is create, add-author, yeah. Then you hit Enter. Yeah, so here it gives you summary what will happen.
Cool. That's nice. Migration is planned.
Yep.
Guest, who's on the show? We've got name and URL. And, I'm gonna hit yes, YOLO.
Yes.
Okay. So now?
If you go to Contentful now, you can see a new content model.
Oh, dang, look at that.
Yep.
All right, that's super slick, man. That's really cool.
[Sound Effect] Holy buckets.
Yeah.
Awesome. Oh, and we have a holy buckets race.
Yeah.
That was impressive. Okay, so that's slick. And honestly, I feel like we have, I feel like we're at a pretty healthy stopping point, here. Right? Is there anything you wanna cover before we wrap?
Yeah, I think that's, I mean, of course, with a migration, you can do more stuff.
Sure.
You can link this, you can transform entries. We can talk about this like for days.
Yeah, and unfortunately, we are...
Yeah, I mean, the thing behind migration is always what I say, that we don't get the content modeling right from the first time. And, the migration tool will help you always, like evolve your content in programmatic ways. So, it can actually send this code to GitHub, and other people can run different migrations, as well.
Yeah, good call.
It's very helpful.
Ecomath, this is a Sanity shirt. But yeah, so, awesome. With that being said, Khaled, where should people find you? I've got your Twitter here, throw that in the chat. Where else should people go?
So, you can find me on Twitter. I also run a weekly digest, weekly newsletter digest. It's called learnjamstack.com. Yeah. You can see the nice logo there, my creativeness is--
Very good, I like it, I'm into it.
Yeah, so if you subscribe, I send the weekly digest. They're really nice resources. And I also have a list there about, wow, new subscriber, yay.
Getting in there.
Yeah, make sure you're not a robot.
I am not a robot. Okay, I'm in, I am officially a subscriber.
Awesome, cool. Yeah, so I send some digests. I also do courses in Egghead.io, so if you're interested in the JAMstack in general, Contentful is one. I have also course about Contentful and Gatsby. Yep, that's the first. And, I have other lessons related to JavaScript, and so on.
How do I get to your whole? What I really want is your whole list of things. Where is this?
I think if you do...
There you are.
Yeah.
All right, instructors. There he is, okay. Go get those Egghead lessons. That's some good stuff. Oh, I should've shared my, Joel gave me an affiliate link for Egghead, that's always nice.
That's a missed opportunity, you know?
Get those affiliate bucks, man. That's it, that was my coffee for the day. So, all right. So, people are gonna go follow you on Egghead, they're gonna go get that Learn JAMstack letter. Get you followed on Twitter. Anywhere else they should be looking for you? Oh, no, is that you freezing or me freezing? It's me freezing, look at my internet go unstable.
Yeah, someone's internet is not stable.
You're letting me down, you're letting me down, whatever provider I have, CenturyLink. Killing me. All right, cool. So, Khaled, thank you so much for coming on. Everybody who's watching, please go over and follow, and/or subscribe to my Twitch channel. Upcoming, we've got really good stuff. Next Monday, Sara Vieira, the Internet Meme Lord, and Queen of Building Dumb Shit, is gonna come on, and we're gonna build some dumb shit. It's gonna be really fun. We've also got David from Strapi coming on, and we're gonna do some really fun stuff using CMS. And then, the one and only Ken Wheeler is gonna come on. I think we were talking about doing, like, I think we're gonna build a step sequencer, like a beat machine. We've got some animation and 3D stuff coming on with Paul Henschel. Sara Drasner, we're gonna do more 3D and animation stuff. It's, like, the list goes deep. It's gonna be so good. So, definitely, you know, subscribe, follow, all those good things. And, until next time, I guess we will see you soon. And, stick around in the chat, because we'll do a raid. Thanks again, Khaled.
Yeah, thank you, bye.