Visual Editing w/Next.js, Contentful, and Stackbit
Finding a workflow that’s good for devs *and* content writers is hard. In this episode, Tiff Janzen will teach us how to use Stackbit to make all your teams happy.
Links & Resources
Click to expand the full transcript
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. And welcome to another episode of Learn With Jason. Today on the show, we've got Tiff Janzen. How you doing?
TIFF: I'm good. How are you doing today?
JASON: I'm great. I'm so excited to have you on the show. This is going to be a lot of fun. We're using a lot of tech that I'm kind of familiar with but don't get too many opportunities to work with. So I'm really excited to dig a little deeper. Before we talk about that, let's talk about you. For folks who haven't heard of you before, do you want to give us a bit of background on yourself?
TIFF: Sure, sounds great. So a little bit about myself, I started as a software developer about -- well, about six years ago now, worked at both startups, big companies. After that, I transitioned into a dev rel role, where I am now at Stackbit. And I also create video content about how to break into tech, some small kind of coding videos, and just connect with the community. That's what I love to do. So I'm happy to be here today.
JASON: Yeah, I think this is going to be a lot of fun. So I guess let's maybe let a little bit of the premise in, then we can talk about the specifics. So we're talking today about how to build visual editing into a website. So visual editing is not something that is all that new. We've had visual editing for a long time in different platforms, but I think it's a little stigmatized. Because I think that a lot of times when devs think about visual editing, they start thinking about what you see is what you get. For those of us who have tried to use those as part of a development flow, they tend to come with a lot of pitfalls and caveats, and it's kind of like learning a whole new programming language because of how complex they can become. So is that -- like, would you call what we're doing today WYSIWYG editing?
TIFF: I'm glad you brought that up. Any type of tool that falls into -- not necessarily falls into, but touches the low-code kind of area, developers go, "not for me." I get it. A lot of times it's one of those I thinks where your mind goes to similar to what you just said. There's going to be so much restrictions. I'm not going to be able to use what tech I want. And we see this oftentimes, too, when you're working on a team, or this is where I've experienced it a lot. You're working on a team, and you need a tool that you can work with for both non-technical but also technical people. Meaning, you're a content-driven, very heavy content-driven website. What website really isn't nowadays? And you need to find this tool. So what happens is you end up kind of meeting in the middle and settling. The marketers want to use a specific tool or content editor, or you have engineers over here saying not this tool. So you find a tool to meet in the middle with. To go back to your question, when we dive into Stackbit, it's the complete opposite in that sense. Stackbit, first of all, doesn't touch your production stack, which I think is amazing. It also -- you can work with whatever tech you want. You can bring in whether you want to work with -- like today we're going to work with Next.js and Contentful for the headless CMS, but you can say work with, you know, if you want to bring in React or Svelte. There's tons of different examples we have on our site as well. It really is there to -- I like to say everyone can work in their own environment. So for me, what drew me to Stackbit initially is because of this exact problem of, you know, having tools that kind of just met in the middle and didn't really make anyone happy. In turn, what typically happens is, as an engineer, the marketing or content editors end up coming to you to make these changes, right. You're heads down in a feature, you're focused in on it, and as you know, when you're in the middle of coding something, the worst thing that can happen is getting pulled out of the zone, right. A lot of times what happens to make these small changes, and although they're small changes for the content that need to be updated, it takes up a lot of time. Then you have to get back in the zone. So yeah, I'm really excited. That's what drew me to Stackbit and this tool.
JASON: That's very cool. And so the way that I've always sort of thought about this is I have a lot of, like -- I've tried to set up clients or co-workers with easy, and I'm always going to have to air quote easy, ways to manage websites. The earliest version I can think of is I tried to make my own content management system early in the day, before I realized that you shouldn't do that. (Laughter) So I built a little CMS and gave it to some of my clients. Then I found that, one, it was never flexible enough. They always wanted to do something I hadn't built yet. And two, it just required a ton of maintenance. I spent a lot of time trying to figure out, oh, why did it break when they copy/pasted this into it? Or why did it break when they put this kind of image and not that kind of image? It was always little headaches that kept me from doing things I wanted to do and putting me in firefighting mode. From there, I went to WordPress. It was at least way more flexible, and I still think that WordPress is kind of -- if you want to start standing up ways to let people that aren't developers manage content, WordPress is still one of the top contenders in the space because they did an excellent job of it. Then over years, you know, I got out of the PHP game. I started working on stuff like I went to Gatsby and later at Netlify. That led me to a lot of headless CMSs. So stuff like Contentful and Sanity and others. And whenever you get into this space, I'm like, okay, maybe for an easy side, I should put somebody toward Webflow. Maybe I should put them toward Wix or somebody in the chat is saying flashbacks of Dreamweaver. And maybe that would be the right way to do it, but what I found is that was a trade-off that was so expensive to come back from. Once you put it into web flow, it's not an easy thing to pull it out of web flow if you decide you need a more complicated use case or whatever. And I'm sure the Webflow team would tell me why I'm wrong in that statement because I haven't looked at it in years. But the experience that I've had, at least, is when you go all in on a visual editor, you tend to be all in on that visual editor. One of the things that I found when I was at IBM is I was trying to find a way to let our docs team, our content management team, people who were fully capable of writing Markdown or doing HTML if they needed to, but really they just didn't want to. It slowed them down, took them out of their flow. So they wanted a way to do content editing. I found -- what you said about there being a compromise where you meet in the middle and nobody is happy, I found it to be a little different, where whoever was at the top of the reporting chain got to dictate how everybody else suffered. So in a company that's led by engineers, they'll say, welt, just use Markdown. Then all the folks who don't want to write Markdown are like, I don't like Markdown. I want to be able to copy/paste from Microsoft Word. The engineers are like, well, too bad, that's how it works. Get into GitHub, open a pull request. They're like, I don't know what a pull request is. Whatever, figure it out. Or you get a company where the head of the company or the head of the team is a marketing exec, a copyright or something like that. They say, engineers, I don't care you don't want to work in this Byzantine editor. So now you have to do these weird workarounds to try to shoehorn code in a way that the marketing team won't accidently delete or edit when they're trying to mess things around. So what I'm cautiously optimistic about as I hear you describe Stackbit is it sounds like this is a little bit of a way for everybody to have their cake and eat it too. What I'm understanding from the engineering standpoint is you mention two things that I want to dig into. One is you said it never touches your production stack. I really want to hear more about that. And two, you mentioned that you can use it with Next or Svelte or React. So that's probably the easiest one to answer. I'll ask that first. How flexible is Stackbit? Can I plug it into plain old HTML and CSS? Does it need to be a framework?
TIFF: So essentially with Stackbit, you can -- it's flexible enough to work with any site framework that can be run using a Node-based development server. So I mentioned we're going to be using Next. I mentioned Svelte. A ton of other ones too that I'm blanking on right now.
JASON: Is something like Vite -- like would Vite work? It would give me a plain HTML site being served by Vite. I guess I'm curious where is the delineation. Does it need to be something that runs through, like a Babble or Vite parser for bundling, or is it as long as a Node server is running, Stackbit can go?
TIFF: As long as a Node server is running, Stackbit can go.
JASON: Oh, cool. Okay.
TIFF: For a lot of examples, I use Next.js and Contentful. We definitely are trying to work with other examples too. In the docs, there are those examples. But I think the reason that even for today that we're using Next.js and Contentful is it's just kind of our go to. Also, there's no additional customization needed or anything. It's just kind of out of the box ready to go.
JASON: Yeah, it is always kind of nice when you can just plug something in and not have to think about it anymore. Okay. So then the second part of that question was -- I asked two things. The first one was about the flexibility and what you could use on the stack. The second one was not touching the production stack. So can you say more about what that means? Because in my own mind, what I'm imagining is that in order to use an editor of any kind, it has to be part of the production stack. So how is Stackbit different? How is it managing that?
TIFF: So what it is, is when you install -- and we'll go through this. When you install the Stackbit CLI, it's essentially a site preview you see when you're working with it. So it's just essentially your site running in the development server. During this time, it's the only time that Stackbit is necessary to interact with your code. So anything else that we require in the code can be stripped out for production. We'll go through this step by step and kind of cover it as we go. It's a good way to visually see what is happening and why it's not needed. But say we've installed the CLI. We've got the visual editor up and running. For the development part, it's in a good place. So what we do is we push our changes to GitHub, to your repo. From there, in Stackbit, you'll take that repo, and you can go into Stackbit, into your portfolio, and put the URL there. What that will do is it will spin up a cloud version of that project essentially. So then your marketers can go in with this URL, modify it, change it, all the content and whatnot, which is directly reflected back, in this case, in Contentful.
JASON: Okay. Very cool. Very, very cool. Great. So I feel like all my other questions I'm going to say, like, how does this work, and you're going to say I need to show you code. So maybe it makes sense to switch over and look at code. So let me push that button, and we'll head over there. Where the heck did my -- there it is.
TIFF: Actually, Jason, one thing you mentioned I wanted to touch on is -- sorry. Two side notes. We have a very similar history. You mentioned you started in PHP, I believe. I did as well. And you worked at IBM. I did as well.
JASON: Wait, okay. We got to go for the trifecta. Were you also a musician?
TIFF: No. Absolutely not.
JASON: Almost. Two for three.
TIFF: Well, video content. We could count that as something.
JASON: Exactly. We're basically the same person is what we've just discovered.
TIFF: Exactly. And I wanted to say, you kind of touched on a little bit, cost. You know, storing your content in a headless CMS, it can get expensive pretty quickly. I was talking to actually our solutions engineer, Joe, recently, who's been playing around with this demo. We're going to be sharing more about it on Stackbit shortly, but playing around with this idea of separating your content sources and how that can really impact many different things but also from a financial standpoint. So using your headless CMS to store content that is --
JASON: Looks like we're having some connection issues. I'm looking at the stream. It's looking like it's coming from -- crap. Okay. Let's see how this goes. Everybody just breathe. Okay. Are you back?
TIFF: I feel like I'm getting back.
JASON: I feel like you're getting back. We're getting audio, but it's a little choppy.
TIFF: We're slowly improving, I think.
JASON: Yes. Okay. All right. So you were in the middle of making a point when we lost you. You were talking about the storing content in different places.
TIFF: Can you hear my audio now, Jason?
TIFF: Okay. Perfect. I'll continue, but if you stop hearing me, just let me know. So yeah, storing content in different places. For this example that we were walking through, he was storing -- he was separating the presentation layer from the data layer of content. So a lot of times what ends up happening is when you're using a headless CMS, your presentation layer is tightly coupled to your data layer, meaning that the content you're storing, you're also defining maybe some of the styling properties there and whatnot. What this does, though, if you want to reuse that content, which we often do, you have to -- it's already tied to that specific styling and whatnot. So to reuse it, you're going to have to either store it in a different space, depending on if it's for a different website or duplicate it essentially, which can get very expensive very quickly. So what we were playing around with and really talking about is this idea of storing a presentation layer. In this example we do, it's with JSON files.
JASON: Oh, interesting.
TIFF: So your presentation layer is where you define the components that are going to be -- sorry, the content references and the components using this content. What this does is it allows you to scale. It's much more cost effective. But then with this architecture of having your content stored like this, the miss link really is it still goes back to how are your editors or marketers going to be able to work with this now that it's stored in two places. So it solves a big problem, but it also creates a new one. Then, of course, we bring in Stackbit, that missing link here. So it's able to solve that problem of allowing your content editors to just work directly within the visual editor with multiple content sources. So I just wanted to touch on that. When it comes to pricing, I think it really solves that.
JASON: Yeah, and that also can solve -- like, one of the things I found is I really like the way that different content solutions handle different things. Like, I'm a really big fan of -- I'm not going to name names, to not get into a thing, but there's one that is maybe great for long-form written content, and there's one that's maybe great for custom data types where you want structured data. Other times, like you said, all you really need is a JSON blob because you're just trying to list out your categories and you don't need a custom headless CMS to put an array of 15 categories together, right. Like, that can be JSON. So being able to pull those different things together and edit them all through one interface because Stackbit can do that is -- that's pretty compelling. So, okay, great. I think now I just want to start playing with it. So I'm going to move us into the pair programming view.
JASON: And why don't we get a window up, if I can find my windows. We're going to bring this one over here. And first and foremost, let me do a quick shout out to our live captioning. So we've got Rachel here with us from White Coat Captioning today. Thank you so much, Rachel, for being here. There is a closed caption button right on your video player in Twitch so you can see those there. That is made possible through the generous support of our sponsors. We have Netlify, Nx, New Relic, and Pluralsight all kicking in to make this show more accessible to more people, which I very much appreciate. We are talking today to Tiff. You said you're not on Twitter. So where should I send people if they want to keep up with you?
TIFF: For sure. I would say all other social platforms, I am TiffInTech. So Instagram, TikTok, and YouTube. I do have Twitter.
JASON: Just not using it.
TIFF: I feel like it's such a dev thing to be using it. I'm just really lacking.
JASON: I've never once thought about Twitter as being like a requirement. Honestly, it's one of those things I wish I didn't do. (Laughter) oh, I've got to pause that so it doesn't make noise.
TIFF: It's a scary place.
JASON: Okay. All right. Okay. Are we good? Yes. All right. You are still lagging a little bit. I apologize if I'm talking over the top of you. How are we doing?
TIFF: Can you hear me now?
JASON: I can hear you now. Okay. So I have the Stackbit website up. I've dropped a link to that. And that is the extent of what I know here. So what should I do first to get this project running?
TIFF: Amazing. Are you -- well, let's start by cloning this project. So do you want me to send -- I know I sent it to you in an email, but do you want me to send it to you in the chat, or what's best?
JASON: Let me see. I don't know if I have the repo. I have the Contentful space.
TIFF: Okay. Give me a sec here and I will send it to you.
JASON: We have a chat window here in the video thing.
TIFF: Perfect. Give me a sec. Everything is moving slower now. So just give me a minute here.
JASON: Cursed by the streaming gods today.
TIFF: Oh, I know. Okay. Let me see. I know I have it in my email, but it's loading here. While it's loading, I'll tell you a little bit about the project we're working on today. So it was built by Sean, who is our developer experience engineer, and we wanted to build a project that was kind of something you can put your shoes into as far as something we all kind of navigate through. So it's a doc site. I know one of the big things oftentimes that, as developers, we dislike doing is keeping up-to-date documentation. Or maybe it's just me. So he built this doc site. The purpose is to really go through what it would be like when you're onboarding at a new company, whether you're a technical writer or maybe a developer as well, and you need to start making updates into this documentation. Now, obviously, if you're a developer, you can run it locally and make changes that way. But even then, it kind of goes back to what you were honing in on earlier. It's like whether you're a technical writer or content editor or even developer, some of these things shouldn't require you to completely spin up your development server, to then go into your headless CMS, to find these changes, then flip back and forth to see them, and then push. Time should be spent elsewhere. If even you have the ability to do so. So give me a sec here. Let's see if it loaded. Perfect. All righty. Okay.
JASON: All right.
TIFF: And I can just drop it in the chat?
JASON: You can. That's totally fine. All right. So I'm grabbing this link here.
TIFF: Then wherever you want to put it.
JASON: Oh, GitHub. So secure. Okay. So I have got this here. In fact, I can -- look at this cool thing. They have the GitHub CLI set up to do this for me. So I'm going to move into -- actually, no. Here's what I'll do. I'm going to clone this. Then I'm going to fork it. Failed to fork? What? Oh, I'm not in the thing. That would make sense. So we're moving into the doc site example. And I'm going to fork this one.
JASON: Oh, it forked into my personal. Whatever. That's fine. So this then gives us -- let's take a look. I have a Next site, it looks like. So we're looking at Next. We've got Next with React, then some Contentful stuff. Okay.
TIFF: Exactly. So far --
JASON: Go ahead.
TIFF: Sorry, Jason. So far there's no use of Stackbit. I'll let you know when we start integration with Stackbit. But this is literally just cloning a Next.js project that has Contentful in it already as well. But nothing related to Stackbit here. You can think of it as when we're going through the example of you're onboarding to a new company, a new project, and they send you the repository. You clone it, and we want to get it running locally. So let's -- I'm just looking at your screen here. So then we can just run npm install. Then the next step, we'll add some environment tokens that I sent you. Once again, this isn't Stackbit related. We're adding in environment tokens for Contentful.
JASON: Got it. Okay.
TIFF: And maybe just rename that.
JASON: Env.local is what I want, right?
TIFF: Just .env.
JASON: Okay. We'll do the .env. I'm going to pull this off screen because it's got some sensitive details in it. You so kindly sent those to me beforehand so that I don't have to do it myself. Okay. So I've got that set. This .env is now created, and it's got these values in it. So now am I able to start the server?
TIFF: Did you npm install? Maybe I missed it.
JASON: I did run an npm install, yeah.
TIFF: Okay, perfect. So just run npm run dev. Just start the server up.
TIFF: Perfect. We can open it up.
JASON: All right. So that is running in local host 3000. So I will head over to our browser here and fire up 3000. And here's our Acme Corp.
TIFF: Yeah, so right now we've done nothing new that we're not all familiar with or most of us aren't all familiar with in the sense of cloning a project, installing its dependencies and running it locally. So this can be any project that you want to work with as we kind of spoke about before. I always name everything Acme Corp. I know it's from a movie or somewhere. I can't remember exactly. If anyone knows, leave it in the chat. But yeah, so this is just a doc site, an example doc site. The content is coming from Contentful. So I'll get you to log into Contentful with the email address that I sent the invite to. So think of this as, you know, going back to our example. You're joining a company.
JASON: We've got you frozen. Let me get logged into Contentful while we hope you come back. Oh, I'm going to have to sign up with -- let's see. This one. Okay. So here's our Acme Corp. Let's see. Tiff has dropped. So I'm going to poke around in here for a minute while hopefully she rejoins. Yes, chat, this is Arc Browser. It is Mac only. I like it very much. I have a couple invites, if folks want them. Send me a whisper, DM on Twitter or something. Okay. So we've got content. We've got our 54 entries in here, which I'm very glad this was set up beforehand because one of the things that we always fall victim to on this show is starting with something that's completely empty, and then we spend half the show doing dummy content. Tiff, you're back.
TIFF: I'm back. Can you hear me?
JASON: I can hear you, yes.
TIFF: Perfect. Okay. So I just kind of caught the last bit of that. But yes, so came prepared with the content already in place. So yeah, this is where the content is coming from. I want to highlight here some different workflows. If you go back to the local host 3000, and we'll get into Stackbit right after this, but this is really important. It does a good job describing the difference in workflows with and without Stackbit, if that makes sense.
TIFF: So if you scroll down a little bit to the docs section, you can see there's a card grid there. In our code base, it's just a simple component that's rendering the content that is coming from Contentful. If you search card grid, it will be there. So, pretty simple.
TIFF: But what I want to kind of touch on here is say you come into this doc site, and you're either a -- even if you're a developer, technical writer, whomever you are, and you want to change the order of these cards. So in order to do that actually, it's not right now through the code that you'd have to do it. You'd have to go into Contentful. What you'd have to do is really search for this. So once again, I'm leading you through this because I know where all this is. But just imagine you're onboarding to a new company, and you're trying to work through this. So right now if you go to where it says "any," next to content type, if you change that to -- or if we filter by slug even. Sorry, it's just a little tiny for me.
JASON: I see an option for card grid. That looks promising.
TIFF: Go to page.
TIFF: Yeah, page and then you could try card grid too. But let's do it this way for now. Then go filter by slug. Let's just try and get to the homepage.
JASON: And slug for homepage, is that just home?
TIFF: Oh, sorry, just slash. Just backslash.
JASON: Okay. So I see the welcome. This looks like the homepage.
TIFF: Click on that one.
TIFF: Then if you scroll down a bit.
JASON: Card grid.
TIFF: You can see your card grid, which is embedded in the homepage. Click on card grid. Then this is where these three card sections are coming from. So something as simple as you want to change -- arrange the order of the content. We have to, you know, flip back and forth from our local host, which we have to have the code running locally, spin that up. Then we have to go into a different platform. You know, headless CMS. Then kind of sift through to find this. This, once again s a very small example. As I'm sure you've seen when you're working with headless CMS, the number of content stored in them can get hectic quickly. So if we wanted to change these card orders, you could simply drag them around. It's fine if you want to or not. But I just wanted to hone in on that before we go through using it with Stackbit. You might have to publish it as well. Yeah, publish changes.
JASON: So I think in dev, it's pulling the drafts. I was curious if that was going to be the case. And so this takes a second, but it did work, which is pretty -- I mean, that is already pretty nice that this is set up to do that.
TIFF: Yeah, exactly. It's supposed to do that, but because it was taking a sec, I didn't know if something silly was going on. So that's great. We'll give it a sec here. So you can see this is just kind of one small example that I wanted to highlight before we really dive into it. I think it does a great job on a very small scale of just showing how tedious this can be. And once again, I know I'm repeating myself, this is someone that has to be decently technical to do. Or at least be trained to do this, as far as cloning the repo and things that can go wrong.
TIFF: So that's really where Stackbit comes in.
JASON: Oh, it looks like we're losing you again. Maybe try just turning your video off for now, and we'll see if we can get a better audio signal.
JASON: That immediately sounded promising.
TIFF: Hey, Jason. Can you hear me?
JASON: Yeah, yeah. We'll roll on that. Thanks, everybody, for sticking with us. Oh, and the chat says that Acme is from Looney Tunes. All that good stuff.
TIFF: Amazing. That's cool. Okay. That's from my childhood. So thank you for letting me know.
JASON: All right. So I'm ready now.
TIFF: Perfect. So open up a second terminal. You can keep your dev server running. Then you're in the project. Yes, you are. So type in npm install-g @stackbit/cli. There's a few different commands that this gives us. For today, we're going to be going through the main one, Stackbit dev, but there's a lot of different customizations that depending on your project and whatnot you can dive into. Perfect. Okay.
JASON: We're using 0.2.84 today. And I'm ready.
TIFF: Perfect, yep. The latest version. All right. So now all I want you to do -- this is literally -- I just want to hone in on this and remind everybody who's watching. Up to this point, nothing was Stackbit related. It's very standard, what you do to start up a project, right. So now we've installed the CLI. Then I just want you to simply run Stackbit dev while your development server is still running.
TIFF: Then from there, this creates a URL.
JASON: It says forwarding request to local host 3000. We've gotten a source, Stackbit is running. Should I click on this?
JASON: Okay. So a few things I'm seeing out of the gate, here's our site. It's got some info about Stackbit. Then a bunch of controls that you're going to have to explain to me.
TIFF: And before I even do that, I want to explain a little bit about -- because for me, I was like, okay, what is really going on here? Let's take a step back and kind of dive into it a little bit. So we have our dev server running on 3000 still, which we need to do when we run Stackbit dev, which we did. What is happening is you can see in the URL -- not now on the browser, but given to us in the terminal. It was local host 8090. So what we are doing is we are essentially proxying traffic to your dev server. So to your local host 3000. This is configurable as well, but for this, we'll stick with 3000. What we are doing is we're adding a script to the proxied site, which handles content editing capabilities embedded in the site. So it might -- we can try looking now. If you go inspect on the site.
JASON: Inspect. Like this?
TIFF: Yeah, and then go to -- yep. Then go to your network tab. And you can see here the script running. So it's looking for content changes every second essentially. So any changes that are made in Contentful, this is how we know. So just to give a bit of insight as to what is going on behind the scenes, I guess you could say. Then going back, we have up here this kind of suggestion, which I really love, of Stackbit config file is missing, which we will add in a second here. But first, to kind of talk a little bit about what is going on, the side panel to the left, there's some functions or features, I should say, that come right out of the box. If you click on some of them there, you can see there is content, for example. If you click on it, it will be empty because we still have to add our config file, which will enable Stackbit to talk to Contentful. Then there will be content from Contentful there. Then if you go down one to component presets, same thing. But right out of the box, we can see we're already starting to get the shell of what is happening. And this is literally -- this also is a newer feature we have, where you can add in different buttons and links, say to docs or other things like that. And you can see in the top left-hand corner, we're still working locally. Just a nice way to show that. So let's go ahead and add in the Stackbit config file. That's the last step for Stackbit that's required. So literally for Stackbit, all we have done thus far is install --
JASON: Install the CLI, really.
TIFF: Oh, we're going to install two more dev dependencies first, actually. You can stop either one of the -- yeah, you can stop that. Then we're going to install two dev dependencies. Once again, because Stackbit isn't touching our production site. It's going to be @Stackbit/types.
JASON: Whoops. I meant to hit space. I hit enter.
TIFF: That's okay. Then we're going to do the same thing but @Stackbit/cms-contentful. And then these are two packages that -- for types, it's because we're working with TypeScript. So it gives us more features there. Then with Contentful, because we're working with Contentful.
JASON: And if I wanted to look at a list of all of your compatible CMSs s there one -- can we, like, just go look? Because someone asked is this like Sanity. It's not because Sanity is a standalone, headless CMS. And this is like -- you're using Stackbit as a layer on top of a different headless CMS, which is pretty dang cool. So yeah, here it's Contentful, Markdown, don't know that one. That's Sanity there. Nuxt, React, Angular, Svelte. Pretty dang cool these can all be plugged together like that. Sorry, that was my little detour because of the chat.
TIFF: No, and I'm going to add to that detour. For those who are interested in it, with what can be used with Stackbit, one thing we did a while back was -- so it can be used with any structured content source. So we talk a lot about headless CMSs with Stackbit, but this could be -- you could use a database. You could use any API with structured content essentially. One thing that our solutions engineer, Joe, did -- he always makes the coolest projects -- is he used Figma's API with Stackbit. So that was pretty --
TIFF: Yeah, and that's really interesting too. Then the designers, you know, you can set up a lot of guardrails or specifications, and it just becomes this whole other environment, which is amazing. But I won't derail too far off of that. Just to kind of hone in on the content sources.
JASON: Yeah, that stuff is really cool.
TIFF: So let's create this new -- yeah, it is. Back in VS Code, let's create a config file, just in your parent. Perfect. Yep. And we'll call this file Stackbit.config.ts. Perfect. Then from here, we're going to import the two dependencies that we just installed. So import, curly brackets, Contentful content source. All capital Cs. And it's actually not camel case. The first C as well is capital. Then from @Stackbit CMS Contentful. Yep. Then we're going to import one more thing. Import, curly brackets. This is camel case. @Stackbit/types.
JASON: Let's see if it's going to give me my auto complete here.
TIFF: Come on. It's lower case D define. There we go.
JASON: Define Stackbit config. All right.
TIFF: Yes, exactly. So those are the two dependencies we need to import. So now we're going to export this config file. So we can go export default define Stackbit config. Then inside of there, let's put -- oh, yeah. You're already ahead of me. Sorry. It's lagging a second here. Then we're going to give Stackbit some information. So let's do Stackbit version. It's camel case. Then we're going to do single quotes. And I always pronounce this wrong, the tilde, the little wave. Then go SSG name, camel case. And we're using Next.js.
TIFF: Then we're going to do content sources, camel case. Third one down. We're going to put this in an array. And we're going to do new Contentful content source. Then from there, curly brackets. And we're going to give -- now what we're going to do is essentially tell Stackbit a bit of information about the Contentful space and organization that we're using. So first one we're going to do is space ID. So third one down.
JASON: And that's going to be --
TIFF: That's going to be our Contentful -- out of our .env file.
JASON: Yeah, so I can copy/paste these across. Then what was the other one we needed?
TIFF: Then do the same for environment.
TIFF: Contentful_ environment. Then go preview token. And do same thing. Yes, perfect. Then maybe do -- because we're using TypeScript, do exclamation mark after these. I see it's giving you a little bit of a headache. So just telling it that it will exist. You don't have to worry about being undefined. Oh, no, sorry. After the ID.
JASON: Oh, I got it. I got it. You know, I've never done that in TypeScript before.
TIFF: You know, I haven't either until I joined Stackbit. What does it say here?
JASON: Space ID environment preview token is not assignable. I think it's missing an access token is why it's mad. That's my guess.
TIFF: Try, yeah. Okay, perfect. Oh, actually, instead of Contentful access token, I changed the name in the tokens I sent you. So do Contentful management token. It's different than the one you just copied, actually. I was being bad and changed the name.
JASON: Okay. So now it's happy because it's got all the required fields.
TIFF: Oh, do exclamation mark on line ten as well, at the end of the environment.
TIFF: Give that a save.
JASON: Oh, wait. Is it export const config?
TIFF: Or just export default even. Yeah.
JASON: All right.
TIFF: It's happy. Perfect. So to kind of talk a little bit about this config file a bit more, as I mentioned, this is telling Stackbit a little bit of information about the content source we are using. So in this case, giving it some environment tokens and whatnot. Having this config file now is what will enable two-way sync. We'll go through that. I think I'm a visual learner. So when I speak about things, I'm like, we'll go through it and see it. It's just the easiest way to learn from me, I guess. So yeah, it enables two-way sync. And let's start Stackbit dev again. I just want to highlight here, Jason, if we had Stackbit dev running already and say we stopped our local development server instead of Stackbit dev, one thing that's really cool is it doesn't -- we don't typically refresh the page. So if you go to local host 8090 now --
JASON: Did it start?
TIFF: Perfect. This is what we want. It should be good to go. And this isn't like a warning, per se. It's more so just help -- I find it really helpful. You can X out of it, but it's just really helpful next steps. So as you can see now, we have our content that is coming in from Contentful. We could even do something where it's like -- let's go to -- yeah, let's go to change something like the title in the card grid. You can change any kind of content here. You can put hello world or anything like that. Then just click out of it, wait for it to load there. If you exit out and we go down, where is that home section grid?
JASON: I don't think that's being used.
TIFF: Let's go back there and go to heading. Yeah, getting started is used.
JASON: Yeah, okay. We'll add a little exclamation point on that one. Here's the thingy telling me it's happening. And look.
JASON: So, okay. Right out of the gate, this is really impressive because what just changed is that for me as a developer, instead of now having to have both the site open for dev and Contentful open for dev, I now have it all in one place. So as I'm making my changes here, I can change code and see the code change, and I can change content and see it update right over here. And that is really, really cool. I feel like we're just barely scratching the surface here.
TIFF: I agree.
JASON: Oh, good question from the chat. The question is if another user changes content, does it live update here too?
TIFF: Okay, yes. Sorry. Let's take a step back. Yes, it does. Great question. But right now, as you're setting this up, this URL is unique to your machine. So right now, because we're in setup phase, it's unique to your machine. But as I kind of alluded to at the beginning, which I'll speak more about at the end, once we're done with this process. Once we push our changes to GitHub and then we take that repo and input it into your dashboard in Stackbit, put in that repository, essentially to make it shareable inside of Stackbit, we can create a new -- it will create a new cloud project to point to the GitHub URL. It's super user friendly to do, whether you're a developer or marketer. Your marketers could do it, for example. As a developer, you could be like, here's a link to this repository. I installed Stackbit CLI and two dependencies and added a config file. So then you push it, they can take this URL, and put it into Stackbit. Then what will happen is Stackbit will essentially create a container. The container basically handles everything we were doing but in a hosted environment. Once again, it's not a public URL, but it's a URL that other collaborators can be invited to, if that makes sense.
JASON: Yeah, and for someone who's a content creator, they wouldn't necessarily need to use Stackbit at all if they went into Contentful. Like, I just made a change in Contentful, and it did live update. So if you were to go into Contentful and make a change, my dev environment would update with that change, right?
TIFF: Correct, yes, yes. So it's working that way right now. But we will -- when you push these changes, you don't even need to go into Contentful. It's literally like your marketers can come in here and make changes. I say marketers, but as I mentioned, honestly, anyone who wants to make smaller -- sorry, not smaller, but anyone who wants to make content-related changes. You don't need to go through that whole process. So let's keep on going here. I see that we're getting this message up top about configuring your models. So still in the config file -- oh, sorry, Jason. Sorry. I keep on flipping back and forth. After line 14, we're going to let Stackbit know, I guess, essentially about our models. What this does with model extensions is it telling Stackbit what pages are going to come in. If you do camel case model extensions --
JASON: Oh, whoops. Got ahead of myself. Model extensions. Okay.
TIFF: Then we create an array with an object inside of it.
TIFF: So the first one is name. It's going to be page. I can show you afterwards -- oh, lower case.
JASON: Lower case. Ah, so we're currently mapping in Contentful the types, like the content types.
TIFF: Correct, yes. Exactly.
JASON: Got it, got it, got it.
TIFF: If you go into -- yes, content type ID page.
JASON: Got it. So our content type, the ID is a page. And we are telling Stackbit to use this as the page level URLs.
TIFF: Yes, we are doing that. We're also going to do -- sorry. The next one we're doing is type, which is page as well. Because that's actually going through -- the naming is a little confusing. So the name page is because -- sorry. Let me take a step back. The type is page, but what this type is here is because Stackbit offers three different -- I keep using the word type a lot -- but three different types. So we have page, we have data, and we have object. So for page, of course, it represents a page, like a blog site that has different post models for individual blog posts, whereas for data, which we're not going to use in this example, but data is more so content objects, which are either standalone or can be accessed globally. Then there also is one for objects, which is more so around repeatable content that is embedded in another model. Page type is a very standard one, especially when we're doing this for the purpose of creating new pages. So you're correct. The next one is regarding the URL. So type in URL path, camel case.
TIFF: Then we're going to do two single quotes, slash, curly bracket, and inside of there we're going to pass in slug. Slug is essentially some variable interpolation. So it's a field that exists on the page model in Contentful. If you go to page, there should be the ID there. Yes. So when we're just passing in slug, this will allow us to do any pages coming in from Contentful with different slugs, it will show -- we can access those.
JASON: So this -- is the homepage going to cause problems? The homepage is slash. And this would result in the URL path being a double slash. Or it's going to fix that for us?
TIFF: Yeah, it's whatever comes in, it's going to fix that for us. In Contentful, I don't know -- there is field ID, which is equal to -- for some reason when you were there, I didn't see it, of course. Maybe if you go to info. Field ID.
JASON: I'm sure it's in here somewhere. I haven't used Contentful in a while, so I can't remember how to do the field stuff.
TIFF: I was tinkering around with it yesterday. But regardless, it's always slug. It's whatever is being passed in. And if you save that file and navigate back to -- perfect. There we go. Once again, you didn't need to refresh or anything. And now at the top, if you actually exit out of this and go to the dropdown at the top, you can see all our pages now.
JASON: Oh, cool. That's slick.
TIFF: Then the really cool thing is -- I know. I get really excited about it. I think it's pretty handy. Once again, if we go back to this example we were speaking about earlier with content editors or whomever coming in and oftentimes being like, hey, I need this new page created, this new blog post, whatever, yes, you can do that many different ways. But it's a one-stop shop, I think the saying is. It's one place where you can do everything. Also, you can see on the left-hand side that we now have enabled the pencil icon. Which was grayed out up until this point.
JASON: Oh, cool. So now we get the actual page content.
TIFF: Exactly. If you want to make changes to that title, for example, welcome to Acme Corp.
JASON: Now we're able to kind of live update the thing.
TIFF: Exactly. Exactly. So that's really cool. Then another thing, too, I want to highlight -- I actually want to highlight a few things here. If you scroll down, you can see the different sections where you can literally rearrange the sections here as well. You can also add sections and whatnot, which we can cover in a bit here. But yeah, move some around.
JASON: So this is super handy. You can dive right in here and cause all the changes you want to get made to get made. And I think what's really interesting and something important to call out here is, like, I have -- Contentful is not aware that Stackbit exists. And Next.js is not aware that Stackbit exists. So we've basically added this layer on top. We haven't modified our code, and we haven't modified our data model. We just made it easier for the things to work together, which is way different from the experiences I've had with other kind of visual editors.
TIFF: Exactly. And the thing is right now, you know, I know we're working through this, and it takes some time to work through, but I want to remind people what we have literally done. I'm not trying to sound like a broken record. We've installed the CLI. We created a config file, which the config file is in our doc. So you essentially can copy the structure of it and modify it. What else have we done? We added in the model extensions. And that's kind of it, to allow for all of this flexibility now to occur.
JASON: Yeah. That's pretty slick.
TIFF: But it's pretty cool. Yeah, so if you go back for a second here to the site, as we kind of spoke about before, you can now edit content from the pencil icon or create new pages, but I want to take it one step further. This kind of depends on how flexible you want your visual editor to be. Once again, it's something that's very powerful about Stackbit. We're not here to tell you what to do. If Stackbit stops existing tomorrow, your site is not affected. Obviously you don't have the visual editor aspect anymore, but it's still running in production. Nothing is affected, which is really cool, in my opinion. But one thing that I keep mentioning is I'm a visual learner and I like to be visual. I want to talk about my favorite part, which is annotation. This is really cool. I'll tell kind of a little story here. A lot of times with content changes, say it's even copy -- so the last company I was at, actually, was at IBM. I was working on the consulting side for a very large airline. When you think big companies, you think the processes are -- well, sometimes you think they must be super advanced. Other time, they're very slow, right. A lot of times this copy would need to be changed. Like, simple copy. So say the "Welcome to Acme Corp". So the marketing team would write a ticket that this needs to be changed and whatnot. We want it longer. So then it's assigned to different developers. No matter how senior or junior you are, the work needs to get done. So you get it done. So you make these changes. Then you have to take screenshots. This is how it operates. We would take screenshots of the text and send them back to the design team and say, hey, do you like this and whatnot. Oftentimes, they'd be like, okay, we need to update the text to be longer or shorter based on how it looked visually. Obviously, it can be changed with CSS and whatnot. Sometimes they just wanted a quick fix. So this is a great way, which we're going to dive into, to be able to edit -- we call it editing on the glass, but edit in line. So if we go back to our code base here --
JASON: Edit on the glass sounds like sci-fi.
TIFF: I know. It sounds really, really high tech. And we're going to go -- let's make some changes into our heading. You can search up heading.tsx, please.
JASON: I should get better at using the VS Code search.
TIFF: Then from here, if we scroll down, this is our heading component. I'll show you in a second where it's used throughout the page. But while we're here, I want to talk about two different annotations that you can add to your elements. It doesn't affect your code or your workflow or anything like that in the sense of they're pretty short and simple. So the first one is called data SB object ID. We're going to add that on line 18 at the end. I don't know why, but I always like to add at the end, right after -- yes, ID. So data SB-object-ID. Then this is going to be two curly brackets.
JASON: Double curlies?
TIFF: No, sorry. I didn't see that there. Then props._ ID. I'll show you where this ID is coming from as well. Essentially, the object ID's job that we just added in here is to provide context for the record in Contentful that's being edited. So it is set to the value of the unique ID of the record in the content source. So it's once again -- you'll really get the idea when we go back into the site and we can inspect this. So save that for now. Then if you go inspect -- we can look at where it's coming from in Contentful too, but if we want to start here, we can go inspect. Then click on -- sorry, your screen is really small for me. It should be that one, yes. Or actually, go into -- there's a ton that use it in how it works.
JASON: Okay. Here's a bunch of them. Oh, wait. Something is happening.
TIFF: Correct, yeah.
JASON: Everybody see that?
TIFF: So you can see on these --
JASON: Okay. So if I click this.
TIFF: So you can think of it as -- you can make some changes there as well.
JASON: Very slick.
TIFF: Then open up Contentful, where the big C is, just to show you where this ID is coming from. Then you go info. You can see it right there, entry ID.
JASON: So what we've done, just to recap -- go ahead.
TIFF: No, no, no. Go ahead, Jason.
JASON: So to recap, we have -- the first layer is that you tell Stackbit where your Contentful install is. With no other config, just telling it where Contentful is, it gives you your site in the main window with a little chrome around it that gives you the ability to look at your content model in Contentful right next to the site on your screen. That way, you can, you know, open up your content management and your code in one window, which is great. For an extra config, where you map your pages to the slugs, you then tell Stackbit where the pages are so you can navigate through the pages and create pages and all those things, which is great. Then one step further, you can add this data SB object ID and pass in the Contentful object ID, which is basically any one of these Contentful objects. You can pass in the entry ID. That allows us to then make it clickable in the UI. So this is very slick with how friendly that is to use. It's nice because, again, all of this is being done with, right now, exactly one change to our code, which is to give a reference as a data attribute, which is not going to change the code -- or change the behavior of the app, I should say. We add a data attribute, and then everything else is just a layer sitting on top that doesn't ship to production. It's not modifying our source code. It's not modifying our CMS. It's just a way to do a visual bridge between the two.
TIFF: Exactly. Yes. Jason, you're so good at explaining. I don't want you to take my job. You do too good at explaining it. All right. So let's take this one step further. Right now, you know, we're telling Stackbit where the entire record of the content source is, right, the unique ID. So we can do this -- I want to show you one more thing here. If you go back into your code base in the same file, then we're going to use a very similar annotation, but we're going to go into the span on line 19. The first tag there. Perfect, right after class name. We're going to use something called field path. This is data SB field-path. And this is going to -- as you can see here, we're hinting passing in the body. So make it equal to body in a string.
TIFF: Perfect. So what this is doing, the field path is the ID of the field. Or sometimes called the name in the content source. In this case, body. So if you go back in here now --
JASON: I didn't need to refresh that, did I? So let me go to how it works. Now it shows me text.
TIFF: Yes. And you can edit. Don't even click on the pencil.
JASON: Okay. So I just come up here and click.
TIFF: So now you can even close that side panel. Now your editors can see visually, even without the side panel, being able to use that. So let's change this, some text here. Then in our smaller component that we're playing around with, let's save this as a preset now. So hover over it again. Hover over the entire component. So including where it says depreciated.
JASON: Oh, I see it.
TIFF: Yeah, so let's do the heading. It would be visually better if it was a bigger component. But go save as preset.
TIFF: And click there. Then we can give this a name. Just say Jason's heading or whatever you want to call it.
JASON: Then we could create a category or something.
TIFF: And save. So we just saved this preset. Sorry, we're going to have to go back into our code quickly here because I want to show you something cool. So go back to our code into the card grid.
JASON: Card grid.
TIFF: Yeah, card grid. Where is it there? Yeah. And on line six, let's do another data SB object ID. Pass in props._ ID again.
TIFF: So now when we go back on the homepage -- sorry, I'm taking you arranged the block here.
JASON: No all good. We're learning a lot here. Oh, I need to exit out of that. So let's go to the homepage.
TIFF: All right. When we scroll down, now we have more -- because we just added that data SB object, if you click on the plus button, the top one there, if you hover over it. So right above developer guides.
JASON: I can't. Oh, no. We need padding.
TIFF: Maybe just click inside there for a sec. Sure. Then go create new.
JASON: Oh, I had to click on it. I understand. I thought I had to hover. I clicked, and now I can do a thing.
TIFF: Yeah, create new. Then we can see here the heading that we just saved there. So you can think, though, how this can become really interesting when you're saving larger components. Say you have a component that has an image and text in it that you want to reuse for a different blog post or different parts of your documentation, how this becomes so powerful so quickly.
JASON: Yeah, it all just kind of happens very fast, right. And this is what I think is so cool about this. People are saying, yeah, but WordPress can do this, Sanity can do this. I think the important thing to note here is that it can, if you're using WordPress, if you're using Sanity. This would work -- like, we're using it with Contentful. We can use it with Sanity as well. We can use it with WordPress as well. So any structured data source. You can use it with your database with no CMS at all. Then one of your team put together a Figma API demo. So the thing that's nice here is that you could theoretically -- like, if you had a team where your marketing blog is run in WordPress, your marketing homepage is powered by Contentful or Sanity, and your docs are powered by Markdown, you could have the same visual editing experience across the whole site because you can plug in all three of those content sources. And that's pretty dang cool.
TIFF: Exactly. Exactly. And going back to, you know, WordPress, I'm kind of repeating what you're saying, but you're locked into so many degrees with these platforms. As you're mentioning, you're not locked in with Stackbit. I don't know. Myself and any developer I speak to, that's a huge benefit. The freedom and flexibility it brings for you. I don't want to be locked in or tied to something that, as my company continues to grow and scale, I have to pay so much money to store all this content here. Going back to my example I mentioned earlier about breaking down the presentation and data layer. When you start thinking about it from a standpoint of scaling and scalability and how you can scale sites and working as your team grows and whatnot, it's a no-brainer for me.
JASON: Mm-hmm. Yeah, and I think the conversation, too, is about who is really going to benefit from something like this. You know, I can imagine somebody saying, but isn't this like a lot of tooling. But the flip side is when I was at IBM, even when I was at Netlify, which is a much smaller company, we had lots of teams with lots of different needs, and they didn't want to use the same tools. So we saw a lot of -- there was a lot of issues of should we force the docs team to use Sanity because that's what the marketing team standardized on for Netlify.com. Should we try to force the DX team to write everything in this tool or that tool? And what we found was that each team was more productive using a different tool. Because we were a larger team, you know, it really matters. If you've got a team of ten people and they're 10% slower because of being forced to use Markdown when they're not GitHub experts, that's a significant amount of waste, of them spending all their time trying to -- that 10% loss is huge. Ten people with a 10% loss is a whole person whose salary is wasted on an average year. So it's very critical that you find ways to make people productive. So when you are making those trade-offs, finding tools that allow people to use the tools quickly -- and the other thing is if you've got people who don't want to use Markdown and they want a visual editor, if you put something like Stackbit on top of Markdown or if you have a DX team that doesn't want to log into Contentful but they're willing to use a visual editor because they're already using it for the docs or something, suddenly you're starting to bring teams together, and you're breaking down those barriers between how teams collaborate and whether or not they're willing to collaborate, whether or not they feel confident going in and making a suggested change, any of those things that -- it just starts to save time. So it's always a trade-off between, like, how much tooling are we going to add, how much re-education are we going to do, how hard are we willing to fight against people's natural preferences. Because ultimately, we're just trying to get people to work in a way that they want to work so they're enjoying it here. When people enjoy the work, they do more and better work. Also, how do we minimize the amount of time it takes for somebody to get these tasks done. Editing is not the value, right. Like, writing the content was the value. Putting it into the CMS should be as close to instantaneous as possible. If there's a lot of friction involved in that, you're going to end up with wasted time. You're going to end up with people who don't want to follow through to the last 10% because they don't want to wrestle the CMS to edit. All of that leads to waste, to slowdowns, to slower shipping. At that point, it's worth considering can we solve some of these problems with tooling. The answer is not always, but sometimes, especially when you've got, I would say, a composable setup where you have lots and lots of tools that different teams want to use, finding a good abstraction over all those tools can be a huge benefit for a team's productivity.
TIFF: Exactly, exactly. And on that note, too, you know, if anyone is interested in playing around with the project that we worked on today, I don't know, I'm not a major Twitch user, but there's a command they can run to start using it. How is it best that I share that?
JASON: To start using Stackbit?
TIFF: This project, yeah. This specific project as well. They can run npx create Stackbit app, and it will essentially produce a fully annotated project.
JASON: Npx create Stackbit, and what was the rest of it?
TIFF: Space, dash, dash, example, space, documentation. Just in case anyone wants to play around with the project that already has all the bells and whistles in it so you can continue building on it and tinkering with it.
JASON: I'm going to put this into my terminal as well, for anybody who's not looking at the Twitch chat. You can see that there. Okay. Well, that, I think -- and this is not as far as we can go with this, but it's as far as we have time to go today. So for folks who want to learn more, what would you recommend is the right next step for somebody who wants to dig in with Stackbit? I'm going to drop the site one more time.
TIFF: Definitely go to our docs. In our docs, there's examples of how to get started. Then myself and a few other team members are always active in our Discord, which is linked at the bottom of the website as well. You can always -- oh, where is Discord? Maybe I spoke too soon. There we go. Yeah, so we're always in there as well. Even after this live, I'll be active in there if anyone has any further questions or wants to come say hi and learn more. But yeah, we're always building fun things and tinkering around. So come say hi.
JASON: And then Joe from your team posted Stackbit themes. I'm going to repost that so it shows up in the show notes. Lots of good stuff there to get you started. And Tiff, I'm going to send everybody to your website, which has links to all your different social media platforms. Everybody, make sure you go and follow Tiff. And with that, I am going to give one more shout out to our captioning. We've got Rachel from White Coat Captioning here today. Thank you so much for being here. It means a lot to me. That is made possible through the support of our sponsors, Netlify, Nx, New Relic, Pluralsight, all kicking in to make this show more accessible to more people. While you're checking out things on the site, make sure you go and look at the schedule because we've got a great schedule coming up. Next week is going to be New Relic observability week. So New Relic is a sponsor of the show. We're working together on four straight days of streams to go into all the reasons that you will benefit from and why it's maybe worth finally learning what the heck observability means if you're working on the web. So that's going to be a whole lot of fun. Then we have a whole bunch of fun stuff coming up after that. We're going to have Aryan on, talk about how we can share state between frameworks. That's going to be really fun. A nerdy deep dive. Kevin is going to show us how to build a mobile app using Retool. So even if you don't know how to write mobile code, you can build an internal mobile app. We're going to be scanning bar codes with phones and things. It sounds wild. I'm excited to see how it all works. Yeah, it's going to be great. So make sure you mark your calendar, subscribe on Twitch, Twitter, all those places. Tiff, thank you so much for spending time with us today. Any parting words for the chat?
TIFF: No. Thank you so much. I'll try going on camera for a sec here and see if it doesn't freeze for a hot sec. Thank you. It's been a pleasure. And I'm looking forward to seeing your other ones. I love watching your stream. So thanks for having me on it.
JASON: Yeah, thanks so much for being here. All right, chat. As always, thanks for hanging out with us today. We will see you all next time. Bye.
Closed captioning and more are made possible by our sponsors: