Remix Stacks are a quickstart for building full-stack applications, including a Remix frontend, a database, and more. Kent C. Dodds will teach us how to get started.
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're bringing back KCD himself, Kent C. Dodds. How are you doing?
KENT: I am muted. No, I'm doing great.
JASON: Great. Good. It seems to have self-healed? We're good? Everyone. All right? Okay. Perfect. I'm having a -- I just got this Ping video and I think it does something about like echo cancellation. But as far as I can tell, it's got like a 3 second delay once you start things. But it all seems fine now.
JASON: Okay. Cool. We're ready. So, Kent, I think you might be one of the few people on this show who needs no introduction. But just in case for folks who aren't familiar with your work, you want to give us a bit of a background on yourself?
KENT: Yes, sure. Thank you. Thank you for having me on the show again. I guess that means it wasn't that bad last time. [ Laughter ] Yeah. It's also an honor to get invited the first time. And it's a real honor to get invited the second. So, yeah, I live in Utah in the United States with my wife and four kids. And dog. And I -- let's see... I like to ride my one-wheel in the summer time. It's like an electric skateboard sort of thing, but it's like a Go cart in the middle. Look it up. I broke my clavicle recently so I haven't been snow boarding and I play soccer on Wednesday nights. That I haven't been. I created epic react.dev, and Kent C. Dodds.com, and active on my YouTube channel, I've got a pretty active Discord as well. I back in November joined the Remix team to be the director of developer experience. So far, we're going to get exposed to things that are my responsibilities. And hopefully it goes well. Because if it doesn't, it's my fault. Yeah, that's me.
JASON: A great, we have folks in the chat. It's nice to see you moving both arms again. I will second that. Happy to see that you're recovering well. So, we're talking about today we're talking about Remix and specifically a brand new feature of Remix. I think actually unreleased feature of Remix. Is that correct?
KENT: Yeah. It was going to be released. But yeah. It -- we ran into a couple of problems that we're going to work through today when we go through it. So, it will probably be released this afternoon maybe. Maybe even next week. So, we'll just have to see.
JASON: A little sneak preview of a new feature coming to Remix either today or next week. But so we'll talk more about the feature in a second. I would love to just start with kind of, you know, we have been hearing a lot about Remix lately. You have been obviously been very excited about Remix for a while now. We have been seeing some really cool stuff, cool demos. You know, I'm a fan of Remix. I moved -- Learn with Jason.dev is now built on Remix and built a couple other little fun things to learn in the new stack and all those good things. So, for folks who aren't familiar who are aware of the name of Remix but haven't had a chance to look at it yet, what would you say is the -- the overarching like elevator pitch for it? Why would someone look at Remix versus other ways of building websites?
JASON: What I've seen out of Remix that I have liked is -- the thing that really jumps out to me is that, you know, I come from pre-CSS web Dev days.
KENT: Whoa, man.
JASON: A big pitfall for me, is if I'm looking at an HTML form and I get the impression from reading, you know, the React docs or the Vue docs that the way to deal with forms is add a form, submit listener. And programmatically store all the form values in state and pull those out and put them into a JSON object and manually post that. We can do that. That's fine. But also, there's the form values. Like you can just create a new form data object and say give me the values and I can submit this to a page and it's just there. I can just get it by reading the body object. There's all these things built into the platform that I feel don't get taught right now. That was one of the things I got most excited about with Remix. And looking at the history of you and Ryan Florence and Michael Jackson who are the three kind of driving forces behind this. And then I know you have Chance Strickland on the team and other folks who all of you seem like use the platform has been kind of a drum -- a drum beat even before Remix with other projects that you've built.
JASON: And so, like I -- I'm gonna tread carefully here because my goal isn't to poke fun at any other tools. When like that's not Remix. Or sorry, that's not React, right?
JASON: YouTube isn't built in React or Angular or Vue.
KENT: It's a polymer thing.
JASON: Polymer. So, the thing I find interesting is, you know, the tension that I've felt when trying to use Next or Gatsby before that. Or when I was -- even when I was using like just create React app and, you know, Webpack Babel kind of setups is I always felt this weird tension where I felt like I was moving people further away from with what was happening. And I think there's -- like there's a good argument to be made for this ideas of like progressive disclosure of complexity. Where you take somebody and you basically say, okay, make no decisions. You're going to get a great outcome. But if you need to change something, expose the piece of complexity that you need. It's not like the whole thing, ejecting in the original create React app setup, you use it or you immediately own all the source code with no in between. There's this interesting thing ha happens with API design where sometimes abstraction is worth completely eliminating the thing. I don't need to care how an electrical impulse gets one of my keys to a character on the screen. That's an abstraction I never need to care about that. But when I'm building a website, we're not quite at the point where I'm comfortable with the abstractions like completely eliminating what the browser is doing. And in some of my feeling about using some of these tools is they're basically saying, like, come into this tool and then this tool is how you build for the web. Not like the web is how you build for the web and this tool augments that.
KENT: Yeah. You know, that's very well said. I think that we are -- the web platform is powerful enough that it doesn't need to be abstracted away. The frameworks need to abstract in such a way that they expose the web platform in a consistent manner. And in particular, something cool about Remix is that the server adapters, their entire job is to take whatever platform you're displaying to, whether it be Netlify or Vercel or Express or whatever. And converting that into a request-response API that is the web platform API for Fetch. And, you're interacting with web fetch APIs. Which again, leads people to the MDN docs instead of Remix which I think is really useful. So, yeah, Remix does an excellent job of exposing web platform APIs to you so that you can have the -- the control over things that you want. Because the web platform is quite powerful. And so, yeah. That -- that's one of the ways that Remix makes it straightforward. And as far as like the developer experience of that, it ends up being really awesome as well because the web platform like -- you hear these people who have been in web for a long time. And you are in that group. Who are lamenting how hard it is to build websites these days with all the tools that you need. And it's because the mental model of the web is actually really simple. You are on a page, you have HTML. The user submits a form. That posts to another page. And so, you're just like moving around to these pages and you can think about the client being completely stateless. Which drastically simplifies things. Of course, there's a reason that we don't do it that way. Because it's in the great user experience. I don't want a full page refresh everywhere. I've got accessibility to think about and performance. What makes Remix really special is that it's the first framework that I've seen that allows you to have that mental model, but work completely in the browser as well with the single page app where there's client transitions and everything. And preserve the mental model. That's the key. It preserves that same mental model of what the browser does for form submissions. All of your mutations are declarative. You know, of course there are mutations that happen behind the scenes without the user interacting. Those are going to be imperative. You have a form on the screen, that's all nice and declarative. Transitions between different routes is all declarative just thanks to the way that React's molds works. But this is, I think, what makes it really special. And because Remix is managing all of that for you, it drastically simplifies the code you write as well because you never need to write any code that says, okay, well, the user made this change. I have to go to and update my state. That's not a thing that you think about whether you're using Remix. Your Redux story is the database. You don't need a Redux store, you don't neat Redux or any of these when you're using Remix. It drastically simplifies your code.
JASON: I do think that's nice for certain apps. I build a lot of stuff on Eleventy because I don't want to write a React use effect when I wanted to write one button.
JASON: Because they feel easier to manage and easier to back out of. If I just delete that Remix scripts tag, I can take that HTML and move it somewhere else and do something different with it if I want.
JASON: It feels less sticky than other framework solutions.
JASON: One of the things that I found with it that I found was really fascinating is I built this little app called snack.tips. And the goal of it was to put places that I liked to Eat on a map. Because people ask me for food recommendations and I end up having to type out this list every time. I should just put this on to a website, right?
KENT: That's such a web developer thing to do. Your regular friends wouldn't say, I should just put this on a website. They would be like, I'll put that on a note on my iPhone and...
JASON: Fair enough, fair enough. And I wanted to kind of -- I wanted to play with the Mapbox API and I wanted to learn a few other things. But what I ended up doing is making a Remix site. And I used Sanity for Data Management and Mapbox for data display and everything else spits out as structured data on the page. When I was doing this, I put in a sidebar that has a list of everywhere you can go in the Mapbox stuff up top shows all these places on a map. And when you click on one of them, it changes the mainframe to show what -- the restaurant details that you've clicked on. And I've also wanted to show the map more zoomed in on where this place was. And I figured out, Mapbox has a helper API, a zoom to. an animated move. I want to do it, I have to figure out how to mount it with the old state and run the zoom to with the new state. I plugged it into Remix to see how it would go and if just worked because of the way nested routing is set up. I didn't have to write any catching or delayed transitions or any kind of stuff because that map isn't part of the nested component. It never unmounts. I just execute things on it and it does all the little animations for me. There was a kind of a big, mind blowing moment for me. I was like, oh. They solved not just like the nice to have like made a good set of tradeoffs. But this is a real problem in building apps that trips up developers all the time. Is how do I get these app-like transition in web apps? Because it sucks in React most of the time.
JASON: Because of the way you have to write -- you have to go get a transition hook and you have to understand how that works and all these different steps. That stuff is hard.
KENT: Yeah, man. Oh, my gosh. I love that aspect of Remix. And is this related to -- is this what you were gonna talk about at Remix Conf. Was that your proposal.
JASON: I wasn't going to bring up that you didn't childhoods my talk for Remix Conf.
KENT: It was so hard. Your talk was so good. You were definitely on my list. But yeah, I'm really happy with the talks we selected. But I'm sad about the ones we had to say no to.
JASON: I can't imagine that's an easy choice to make. Especially with one days worth of talks to give.
KENT: Yeah. We're absolutely -- it turns out that when you have a web framework, you have a lot more things -- like a wider range of things to talk about. I think next year we're either going to do two tracks or a couple days. Because we've got talks that are about, hey, let's do some cool frontend thing. But then we've got -- we have one that's a Remix 3D. I can't wait for this talk. But then, hey, let's deploy to the edge. Completely different sides of the spectrum. Anyway, we probably need to do a little bit more stuff in the future. Anyway, for folks who are wondering, Remix Conf at the end of May. It's gonna be awesome.
JASON: And even though I didn't get picked, I'm still going to be there. If you're going to Remix Conf, I'll see you there.
KENT: Glad to hear that. I'm really happy and excited to see you.
JASON: Yeah, I think that's gonna be a lot of fun. And I just realized, I think I could talk just the full 90 minutes in the abstract about this. But we haven't even gotten to the feature yet, right?
JASON: So, we have been talking about all the things that make Remix the framework interesting and we haven't gotten to this feature. So, you've got a new feature coming out call the Remix Stacks. So, what is a Stack? What does that mean for developers?
KENT: Yeah. So, I wanted to spell it Remix STAX because I thought that would be cool. Remix with an X and -- but I totally got shut down. They're like, no way. So, it's Stacks, spelled properly. But yeah. The -- earlier I was talking about how Remix has just nailed down app adaptability. And that's the number one thing that we're doing as developers. We're constantly changing due to changing requirements and stuff. And so, in a large part because of nested routing as well as exposing the web platform to you, adaptability is nailed. Like the mental model, everything. And, the other thing, though, that's important and important input into the user experience is this developer experience. And getting started. And a lot of people who are jumping into Remix are frontend developers like myself. Who like the last thing we want food is fiddle around with DevOps stuff. This is one of the things that drew me to Netlify was like, Netlify made it just so easy to handle like, here. Here's some static files. Go make magic happen and give me a way to set my custom domain. That's what I love Netlify about for so long. When you're building a static app, you have to think about databases and where to deploy this and host it. Is it gonna be a long-running server? Or is it gonna be a serverless thing? Now we have to think about the tradeoffs of serverless and connecting to a database. There's just a lot of things to think about. Aside -- or along withing to make all these decisions. And a lot of people know what those decisions are and they have opinions. But a ton of people don't. They have no idea. And that was me last year when I was working on my website. I did have opinions. I probably wouldn't have used Stacks, honestly. I really wanted to get into the meat of everything. But I would have referenced Stacks for sure.
JASON: Look, one of my favorite things about working in developer experience is like, you know, by default you are almost never the target audience for the convenient things that you make. Because you're like --
KENT: That's true.
JASON: The reason I built this is a because I kept playing with every stack in the world. It would be fun if people could use these stacks. I would never use these stacks.
KENT: I don't learn from videos either. And I don't go to workshops. I don't read blog posts. It's kind of funny how that plays out. But anyway, the real benefit of this is, hey, we want to help you like you had a spark of an idea of something really cool that you want to do. And we don't want you to have to go through the mud and muck of setting up like, you know, connecting databases and all is that stuff. And local development and stuff. Even installing prettier and ESLint and TypeScript and getting that configured is annoying. That's what Stacks is. The simplest way to think about is, it's away from the CLI, to download the GitHub repo and do a little bit of setup. That's basic lit idea of it. But it's a lot more powerful than that makes it sound.
JASON: And so -- so, how is this different from something like, for example, you can do create React app, or npm init next or Veet or something like that. What sets the Remix Stacks apart?
KENT: From the beginning, you have been able to do the same thing, create Remix, deploy Netlify, I just want an Express server, whatever. We have had these templates for a long time. What makes Stacks special is it's an entire project with a bunch of things pre-configured for you. And in fact, what's really special about it is that you can make your own. And, this -- this is huge for companies. Like this was basically one of the last big jobs that I did when I was at PayPal was put together a really solid template for everybody. And they're still using it actually, which is pretty validating. It's been like 4 years now. But yeah. It's basically we have set up for you the full app. A local database configured. We show you how to get things set up on a remote database. So, you just like run a couple of scripts. We have CI with GitHub Actions. We've got authentication already implemented for you. And like a simple data model with Prisma. We have Tailwind set up. We've got Cypress setup and even a custom command to do authenticated tests so you don't have to run through the auth flow every single time and some example tests of that. We have unit tests with the VTESTs. Like the new jest that's faster and better and stuff. And ESLint, TypeScript, Prettier, I think -- oh, MSW for mocking third party services that you're hitting. All of this setup, it's amazing. It is so cool. And the idea is you have a spark of an idea and you need all of these things for pretty much any app you're gonna build. But that's like our built-in stacks that we've created. We've got three stacks that are one deploys to Fly with postgres and it supports multi-regional deploys. You can deploy many regions all over the world just out of the box. Another one is a simpler one that uses SQLite. It's super amazing. It seems like a toy. But it's totally not and it's awesome. Deploy to fly, that's much simpler, good for prove this out and then switch to postgres later or something. And then we have one that deploys to AWS with architect. And Netlify is working on one to deploy to Netlify with some data persistence. And like we'll have -- this is the cool thing. You can build your own. So, take what I put together and what the team has put together for the -- these different stacks and fork it and make any changes that you want. Want a prettier config? Fork it and make your own and you can make various projects. We have various companies. I don't know if I'm allowed to say the companies I have been talking with who are going to be putting together their own stacks as well. Most people are not going to be using our built-in ones. They're referencing ours and building their own. That's the real benefit We have given you an awesome reference implementation and you can make it work for your infrastructure. As you are building new sites at your company, you can get from the idea to production in like 10 minutes.
JASON: That's -- yeah. I think, you know, this is also as we're seeing it feels like there's a shift in the way that web Dev works. Where we had the -- at least when I was getting into more production stuff when I was at IBM, there was the teams that built the backend services and they would stand up these like Node containers and Docker microservices and all these other -- these other pieces. And they would kind of give those to frontend developers. And the frontend developers were expected to kind of piece those together and make a UI out of it. And that always felt a little bit backward to me because it kind of felt, well, the thing that people interact with was the website. But we've seen this transition where as we started seeing more people moving toward first Jamstack and now this kind of beyond Jamstack web Dev that we're seeing with frameworks like Remix and Next where it's not really -- it's not Jamstack anymore. But it's all running without servers. It's running without these big, heavy backend processes that we used to have.
JASON: The frontend Devs now are kind of in this position where you can build a good website and you know a little bit of Node, you're a full stack web Dev now.
JASON: That doesn't mean that you're a DB admin or a DevOps rock star or anything. But it means that the tools have evolved in such a way, if you can write a serverless function, a little bit of glue code, filtering an API response when it comes back, congratulations, you're ready. You can go do full stack now.
JASON: And what has meant is on the one hand, it's incredible. I can go out as a single Dev and I have been able to build experiences. You know, the fact that I was able to build out the Learn with Jason website and the chat overlays and all these things and all the systems that support it on my own, not as my full-time job. Kind of blows my mind sometimes. Because I don't think I could have done this even 5 years ago with the tooling that existed back then. Modern tools made it possible. But there's the other side of it which is really you get into a little bit of deadlock. Where I'm just a frontend Dev. How am I supposed to build all this stuff? I don't know how to choose between postgres and MySQL. I heard somebody grumpy on Twitter why they would never use MySQL and someone else never using postgres. Depending on what I have heard more, well, I clearly don't like postgres either.
JASON: I'm not making informed decisions here. So, the idea of a stack feels really good. Because what we're looking at is instead of having -- like I have all this power as a frontend Dev. But I don't really have like a lot of opinions about specifically what database. What I want is somebody who is an expert to tell me, this stack is gonna be reliable.
JASON: And stacks appear to be that assertion of opinion. An expert is gonna put together a stack they like. If you want to start here, this is what I like and why I like it. You don't have to ask why I made the decisions I made unless you want to dig in more.
JASON: It feels compelling for that reason.
KENT: Yeah. Absolutely. I remember last year, there came a point where I was coding up and things were going great. And I sat back and I'm like, oh, shoot. Remix turned me into a backend developer. I realized, I have been doing so much backend code. I mean, I'm doing plenty of UI and stuff. But holy smokes, I'm doing so much backend stuff. So, yeah, Remix kind of tricked me into being a full stack developer. But in the process, I had to figure out how to I create a postgres cluster that can deploy to multiple regions? And stumble through that. All of those learnings have gone into the stacks and you can take what you and put it into your stack and people can learn from your stacks. And the other thing I'll mention is a lot of frameworks would abstract away a lot of this stuff. So, like when we say that we, you know, your stack has authentication already supported. We have abstractions for managing sessions with cookies and that's it. So, we -- there is not a authentication abstraction in front of you. But the abstraction is like code that we give to you. And it's less than a hundred lines long. And so, this is in large part because we expose the web platform to you. Rather than hiding it and knowledge that you can't transfer, we instead expose the platform with talking about cookies. You are literally getting the cookie header out of the request. What's cool is that it's adaptable. You don't like the way that we implemented authentication, you can change it. And the code we gave you is pretty simple. There are not a lot of abstractions? What we give you. And a lot of people say, well, what happens when you decide that your stack originally did something that wasn't as good and you go and update the stack. I have to track what you're doing so that I can do that in my site. That's why it's better to have a library, right? Well, yeah. That is a tradeoff that we're making. But I feel like it's a worthwhile tradeoff to say, well, hey, at least for right now, the best thing that we can do is give you the code so that you can make adaptations to it for the changing requirements that you're going to experience.
JASON: And it kind of feels like with the way that you've set it up here, there's nothing stopping me from swapping out your auth from using GitHub OAuth, I put that into the same cookie and use all the other mechanisms the same way. But, you know, change how I'm authorizing somebody.
JASON: Or switching it out for an Okta or Auth0 or some fully baked in system. The nice thing about it, is that by using the platform, that's kind of what you were doing nasty. When I use Auth0, where do you save the token that comes back from Auth0? You should probably put it in a cookie, right?
JASON: It's connecting those dots. I want to use whatever abstraction over this because that's what the company says to use. Or they do GDPR in a way that I don't want to be responsible for and I'm going to outsource it to them. Whatever it is. And you have the plumbing of how to hook that into your app ready made for you. Yeah, I like that. With that, we are halfway through this episode and we haven't looked at any code yet. I'm getting a lot of questions, I see that Ryan and Michael are in the chat. Welcome, thank you for being here answering questions. But let's maybe take a look at these, right? Let's give them a try. I'm going to switch us over to camera 2.
KENT: We did get a new experimental release that fixes one bug, hopefully, and doesn't introduce new ones. I'm going to send that and you can use that command instead.
JASON: I'm going to start out and say this episode, like all episodes, is captioned by White Coat Captioning, we have Amanda here today. Thank you for being here. And the sponsors Netlify, NX and Backlight to make this show more accessible and keep the lights on in a general way. I saw a handful of folks subscribe today. Thank you very much for the subs. Charlie, Peruvian idol, I saw Don talking about his 21-month streak. Holy crap. Thank you. That helps me do things with the show. We are talking to Kent C. Dodds today. If you don't Kent on Twitter, head over there and do that. And we are talking about Remix.run today. So, if you are not familiar, go give that site a quick look through. And earlier we were talking about Remix Conf. If you want to hang out with Kent and me and Ryan and Michael and I think just about -- yeah. Everybody. I think a lot of folks in the industry are gonna be there. Mark your calendars, get your tickets, and come hang out with us. Okay. And that's the end of what I know to do. So, Kent, if I want to get started with Stacks, what's if I first step here?
KENT: All right. So, in the future, maybe later today or maybe just later. You're gonna run NPX create Remix. And that's it. And you should be able to do it. But I sent you a chat with an experimental version that you need to attach on to this. And anybody can feel free to use it. Just keep in mind it's experimental. So, yeah. It's the -- yep. That's the one. So, go ahead and run that.
JASON: All right. Here we go. We need to proceed, yes.
KENT: And it's gonna ask you again if you want to install another package. Yes.
JASON: There we go.
KENT: That's the experimental thing we're gonna fix.
JASON: All right. So, we're rockin' and rollin' here. Create my app. Okay. So, I'm gonna call this Remix Stacks, this is under the Learn with Jason repo.
KENT: Okay. And you want the pre-configured stack ready for production.
KENT: Before you choose, I'll describe what these are. Blues, indie and grunge. Those are music genres. It's difficult to put into asingle name all of the things that these stacks do. And so, because of that, we just made up -- we decided to go with music genres for all these stacks. So, the blues stack is deploy to fly, it's all the stuff I was talking about, authentication, Cypress, Tailwind, all that stuff. But what's unique about it, it's all ready for you deploy to multiple regions and it supports postgres and has a local database running in Docker there. The Indie stack is very similar, instead of postgres, it uses SQLite, it's quite a bit easier to get set up, if you don't have Docker, especially. That's probably the one we're going to do today. It's a little bit easier. It also deploys to fly. And the grunge stack deploys to architect and uses DynamoDB as the persistence layer. Using our Architect's deployment functions, it deploys on AWS. I think Indie would be the most straightforward one for us.
JASON: Okay. Here we go with indie. Do we want to run npm install?
KENT: Let's go ahead.
JASON: Okay. So, here we go. We're building things out. And we're gonna see how well my -- my fiber Internet's doing today.
JASON: Seems like we're okay. We're okay.
KENT: Eric Rasmussen is watching and says he can't wait for the death metal stack.
JASON: We were joking around about this in the Netlify stack about what we should call our stack. And we're gonna call it the Jamband Slack.
KENT: I love it.
JASON: It's got to be president the Trapstack.
KENT: That's awesome. Okay. Go ahead and get into the Remix Stacks.
JASON: Wait. Let me get into the right window here. Remix Stacks.
KENT: Yeah, you can open it up. I want to look at the terminal output. Notice the first disk says running Remix.init script. One thing about Stacks that's cool, in the directory, you have init, and you can have the init and the package JSON. That allows you as the template author to have any sort of setup that you want. After all dependencies have been installed, you can use inquirer or something to ask for the questions. You could even have it provision a database for you. Hey, what region do you want this to be in? Whatever. You can do anything that you want to as part of your setup which I think is -- that's pretty sweet.
KENT: It's pretty powerful for folks.
JASON: It's definitely exciting.
JASON: I got it wrong last time. You read the README.
KENT: That's right. Ryan asked that on the last one. You read the README. Yeah. That's -- that's hilarious. So, this explains what's in the Stack. You can look through that later if you would like. Scroll down a bit and we're just gonna go through these steps. We're actually going to deploy this. I believe we will have time to do this. You want to sign into Fly. If you don't have an account on fly, get that installed. ask this first. If you don't have an account on Fly, you need to sign up for one and they require a credit card. This is so they can reduce abuse of their platform. That's one reason why the Netlify stack will be really cool because you won't need to provide a credit card. But yeah. So, you will need to install Fly. Log in, provide a credit card which you may want to drag off into a different screen when you do that.
JASON: I will do that on a different window here. Okay. Got that one. And then once I have it.
JASON: I guess I can go back to the README which --
KENT: Yeah, the README says the same thing.
JASON: Log in over here, off browser. See for I got it.
KENT: While you're doing that, I should mention if you follow these instructions, you should not be charged anything. Because we're using all free tier level stuff in the indie stack. If you use the blues stack, we're expecting that you're planning on really doing something for production. And you will pay --
JASON: You hackers, you dirty hackers.
KENT: What is that?
JASON: Every time the chat wants me to show all my secrets and I'm not gonna do it, chat. Okay. So, it says now that I am -- I am authenticated.
JASON: Okay. Back to the README. that's just not something I'm willing to do.
KENT: That's great. Now run the Prisma migrate script there. What this is going to do is initialize your SQL database with your Prisma schema. We have a user, a password. This is interesting. A lot of people ask about this. It's pretty common to separate the user and the password models so that you don't accidently send the user with the password hash to the client. So, like when you're querying for the user, you don't want to send -- it's fine if you send along the password ID, I guess. Not a big deal. But if you send the hash, that's not good. We separate those models and we handle that for you. And then the app itself is just a note taking app. So, we have a note model for you. That's probably something you're gonna delete when you get started. But we wanted to have at least something there. So, yeah. This created your SQLite database and it set up all the tables. And actually, interesting, if you look at the Prisma migrations directory, you can see all the SQL commands in that init file. Like this is so cool. Prisma is awesome. I'm actually wearing my Prisma shirt today. Which you can't really see. But it is Prisma. I love that Prisma generates SQL for you for the migrations. And they're committed to source control. That is such a cool feature. That's all the script did. Ran this to create the SQLite database and set it up for your models.
JASON: Nice, nice. Back to the README.
KENT: We're gonna run the build. It's always good to run the build as the first thing to make sure everything is set up properly. This is going to build the Tailwind foil.
JASON: We don't need it! It's already done!
KENT: Yeah, it's less than a second, friends. I love that. Look. the last line, the Remix part was 196 milliseconds. The Tailwind was 169 milliseconds. That is -- that is interesting. 169 and 196, there you go. Nice.
KENT: So, yeah. So, it's nice and fast. Now you can finally run the Dev server. So, if you scroll down a little bit, that's gonna be the next step.
JASON: Okay. So, let's go npm run Dev.
KENT: And so, this is gonna run Tailwind on the one side and then it runs Remix on the other. But it also you notice there's the mock server running. That's a MSW has been installed during development so that you can if you're hitting the GitHub API or hitting podcast API and you want to be able to go up in the mountains and work, you know, you want to be able to mock out what those responses are gonna be. Or maybe you have like a rate limiting problem or something. And so, MSW is there for you mock -- set up mocks for all of that stuff.
JASON: Got it.
KENT: So, yeah. There we go. There's the indie stack. I forgot which band this is. Ryan is really particular about the bands. He's probably gonna laugh at me for not knowing which band this is. They're an indie band and they're great, I guess.
JASON: I'm one of the people, I never know what bands look like. I don't watch music videos. I'm sorry, I don't know what band this is.
KENT: I will listen to the song. I love this song. Who is it by? I have no idea. I don't know band names and the same with actors and actresses. I just don't know. Let's look at what you've got. You can create whatever email address and password. We do not ship like a email confirmation or anything. We may eventually add this to the stack because that's probably pretty common. But now you can view notes for Jason@lengstorf.com. And create a new note. And there you do. And then you can create as many notes as you want. It all -- it's all nested routeing and magic stuff going on here. And then you can delete... whoo! Yeah.
JASON: This is cool. Like it's really nice how... just how fast this was. And then if I go and sign out, right? Then I can log in.
KENT: And remember the check box works as well. Most remember me check boxes don't work. But that one does.
JASON: I'm gonna set up a second account. And no notes.
KENT: And there you go. All set.
JASON: And then log in with my other one again. I can --
KENT: Yeah, you got type the password right or it weren't work. And if we do have validation as well. That's built in. It works nicely on a screen reader. That's all set up for you.
JASON: Oh. So, if I try to save -- oh, yeah. Title is required. Nice. This is pretty slick.
KENT: Yeah. I like it. I think it's pretty neat. And yeah. And so, those are all the technologies that we're using. You can -- you could run the Cypress test if you wanted to. You can, you know, run prettier and stuff. We've got scripts for running linting Prettier. We've got unit test in there as an example. Do you want to get this deployed to production now?
JASON: Yeah. Let's -- I want to run these tests and kind of see what's happening out of the box here.
JASON: Let's run the end-to-end testing.
KENT: Yeah. What this is doing now, it's getting the app started in Dev mode because you're running the headed Cypress. So, this is like kind of the Cypress-driven development, Cypress test rerunning, tests, Cypress test reruns. It starts up in Dev mode, and the first time you start up Cypress, I think it verifies.
JASON: I think it's installing it to my like computer user account so that it doesn't have to do that between builds.
KENT: Yeah. Yeah. It takes a sec. But once it finally loads up, we have one test in here called Smoke. And so, this is your basic smoke test. And yeah, you can go ahead and click that and open that one up. Or yeah. Just run it there. Excuse me. And that should have opened -- it looks like Edge 98. It's over on your left, I think. Where is it? It's somewhere. It's running, I see like the output in the terminal. It is running somewhere.
JASON: Yeah. I saw it pop up and then it disappeared. Oh, where did you go? It keeps trying to come back. Still waiting to connect. Okay. I'm not sure what's going on.
KENT: Go ahead and stop it. And you can change which browser it's using. How do you stop it? I always just use Chrome.
JASON: Yeah. how do I...
KENT: If you hover over smoke, is there a way to stop it there? No, ID. You may need to turn it off and back on again.
JASON: Turn it off and on again. I'm going to blame that on my setup because I'm always tweaking different configs and CLI stuff. I probably broke something.
KENT: That's cool. It's cool to watch it go through everyone. Anyone who has seen end-to-end testing knows it looks great. The tests are pretty straightforward. You can continue off with those. Yeah, you can take a look at it in Cypress ETE and smoke. So, the first one just creates random login form. Visits the home page, goes to sign-up, types in the email and password, creates the account. Goes to the notes page to make sure it can. Goes to the log out and then it verifies that the login button is there again. Here we skip that whole login process and just have a command called login which actually hits our database directly. To say, hey, go make me a user and give me back the cookie value so I can be logged in. So, that command take like -- I haven't timed it. But I'm guessing it takes 500 milliseconds or faster. Much faster than typing through the whole login flow. You just use that if you want an authenticated test. This one is going through the create and delete of a note. That's what that does.
JASON: Very cool. What I like about this is, you know, and I guess I shouldn't be surprised begin that this has been -- testing has been a big part of your platform over the years. But what I like about this is the tests we're looking at are things that people are gonna try to do in the app. Not a test to make sure that it div exists or that the class name is correct. Or things that are guaranteed to change over time. Right?
JASON: And to me that is such a nice like I want to make sure my users can continue to do the important stuff on my app. I literally do not care if somebody changes it from a div to a span. It's -- I mean, like unless it's gonna have some impact on accessibility, I could care less. And so, I love that what we're doing here is actually testing flows. And you know --
KENT: You get accessibility benefits here as well. Because we're defining by roles rather than like serving for divs and stuff. If you were to switch the log out but then from a button a span, as long as you made it accessible, which is very difficult to do, so don't do that, but if you did, then the test would continue to work. Yeah. Implementation detail-free and refactor friendly is what I like to say.
JASON: Refactor-friendly. I do like that. Okay. So, we've got -- we talked for 45 minutes. And then in about 5 we built an app.
KENT: Yeah. Yeah. Yeah. Let's get this deployed.
JASON: Let's do it.
KENT: I want to take this to production. Go to the README again. Scroll up a bit. And here the first thing is you need to make a repo for this --
JASON: Let's deploy that --
KENT: We'll add the repo because we need to add a GitHub repo it.
JASON: Oh, we just need to add code... That's right. That's right. Just make a repo?
KENT: Add a repo and we'll push this once everything is sets up.
JASON: Remix Stacks. I love the GitHub CLI.
KENT: I'm cursed with the GitHub's old hub projects that's an alias to Git, I can't use anything else because that's all I know.
JASON: When I switched computers like a couple -- like year or so ago, they moved from bash to Z shell. Look, if I have to learn Z shell, I have to learn the GitHub CLI. Do it all at once. No ragrets as they say. Create a repository. Clone the new repository locally, no.
KENT: No, we'll just hook this one up to that one. Go ahead and get that opened up.
JASON: Oh, wait. I just did this on the J Lengstorf. Whatever. It's fine. We'll just use that one.
KENT: I was distracting.
JASON: So, now we've got a Git remote.
JASON: Was it browse? Oh, I can't spell.
KENT: Okay. Sweet. So, you'll go to your settings here. And secrets. And actions. And so, this is another thing you want to do in secret. Because you need to add a repository secret. And you can look at that in the README what it's supposed to be called. I think it's like Fly secret something. Yeah,Fully API token.
JASON: Okay. Great. So, we're gonna create a Fly API token. The way I'm going to get that is by going here. Can you hear the work being done on my house in the background? Sorry about that, everybody.
KENT: No. What are you doing?
JASON: We're refinishing our kitchen. Finishing up the floors.
KENT: Nice. I'm looking forward to doing that when my kids are older. And they won't do that to the wood floors we have now. Looking at the wood floors, and the scratches. This is fine. This is what kids do. It's going to be really nice when they're older and they're not doing this anymore.
JASON: Yeah, no kidding. Oops. So, I've got a token. I'm copying my token. And apparently I did have a Fly account because I just found -- or no. I -- oh, Fly UI. This is the one that I must have created in the thing. This is the one that I just created. I'm going to close that. We don't need it anymore. I'm going to put this into GitHub offscreen here and come back across. That doesn't show -- You hackers! You dirty hackers! And now we have our Fly API token.
KENT: Okay. Cool. This is ready. We're almost ready to get this deployed. Now we're just going to create a couple things. Scroll up a little bit, we skipped over the Fly create command. Copy both of those and stick them right in the terminal. And you can choose whatever region you want. The SQLite only deploys to a single region. I would normally just do the closest one to me.
JASON: Yeah, Seattle is closest to me.
KENT: We are creating two apps. One is for production and one is for staging. Built into this stack is a GitHub Action that will deploy the Dev branch to staging and the main branch to production. You have a staging branch set up here. One thing as part of authentication we signed the session. So, that people can't just like make up their own session. And so, what's that this online 91 is doing is we're creating --
JASON: A quick question before we do that. Did this get generated by the -- the Remix Stacks? Yeah.
KENT: Yeah. Yep.
JASON: So, it took the repo name and then like a random hash. So, this is something that will be different in everybody's project which is why I was able to copy/paste it and not like do the Fly create your repo name here.
KENT: Yep. Exactly.
KENT: Yeah. And the other thing is that it has to be globally unique across all of Fly. Which is why we have that random little couple characters at the end.
JASON: Got it. Got it. Okay.
KENT: Basically, it takes the name of the folder that you created where you put your app. So, yeah. So, this is gonna set the secrets -- yeah, you can go ahead and execute that. This will set the secret and hit yes on this one. And I'll explain why that showed up in a second. But yeah. This creates a session secret environment variable which our authentication cookie serializer or de-serializer uses. And the reason I was asking that question is because we've actually got two apps. But the Fly configuration for this project only cares about the production one. And so, when you were trying to do something with staging, it's like, hey, you're trying to do something with a different app than the one that's configured here. Are you sure?
JASON: I gotcha.
KENT: And then the OpenSSL thing will only work for people who are on Macs or have OpenSSL installed. If you don't, we have a link to 1Password's password generator. Doesn't matter what it is. Just that it exists.
KENT: We've got an app ready to send to your Node serve er2. We've got an environment there to handle authentication. Now we need to have the persistence layer. Every time you deploy your app, it's a completely different file system, everything. We need to persist some data. And because SQLite is an on-file list database, we will create a persistent volume that will persist through deploys. This creates one for production and staging that are 1 gigabyte in stage for apps.
JASON: Off we go. This all fits under the free tier.
KENT: Yep, this should all fit under the free tier.
JASON: We have our persistent regions for the staging and production app.
KENT: Yep. That is it. Now you can Git commit init and push and we'll go and take a look at the action.
JASON: Okay. And then somewhere in Fly.
KENT: You'll want to look at the action. So --
JASON: Oh, the action.
KENT: On GitHub. So, a Fly is not a CI server. Actually, you'll go to the actions tab.
KENT: There it is, your init, deploy. We support running ESLint, TypeScript, test, TypeScript, it runs them all. And if all of those finish successfully, then we'll go on to the deploy step.
KENT: It takes a couple minutes to run the build and everything. Because the build is creating a docker container. So, the Remix build itself takes less than a second. But building Docker does not. And we actually -- we do, yeah, please hold. We do cache that as part of the Docker container that we generate for you will actually cache things for you. So, your -- its subsequent building should be a little bit faster. And actually, Cypress ends up being the bottleneck here. Which, of course, it will -- you know, that increases over time as you add tests. You can use Cypress to run these in parallel as well. So, those tests in parallel. Or yeah. Just like split them up across a different matrix. On my site, I have three running at once. They just split my tests across three runners. But yeah. This is all set up for you automatically in the GitHub Action app and it's the same action file, regardless of whether you're deploying to staging or production. And the only difference is we have a -- yeah. It will be in the dot GitHub directory in the top there. You scroll down to the very bottom, this is the only place where we branch between staging and production. The last two steps -- whatever those things are called -- we have if the GitHub ref is Dev, then we're going to deploy staging. If it's main, then we'll deploy to production.
JASON: Got it. So, I need to call my branch Dev for this to work.
KENT: For staging, yep. And then, of course, this is yours. Once you've generated it. So, you can change it. You can fork ours and change it if you want to do a staging branch instead and then just generate your own that way.
JASON: So, a question that came up about how these are kind of rolling out is like, you know, pretty -- pretty quickly once I start using this, it's gonna diverge from the original code. So, is there a way to pull updates or anything as improvements get made to say like the auth layer or something?
KENT: Yeah. There's no way to do that officially. And especially since you're not actually forking the repo. There's no like Git magic to make that work. If you really felt like that was important, you really wanted that, then instead of using the Remix create, you would just fork it, clone it, run the init script manually or whatever or do what the init script dun manually and then you would be on the script and the changes. Even if you don't do that, you might be able to take patches and apply them to your GitHub like with magic stuff. I don't think people need to be super-concerned about that. Because like the setup is going to diverge as soon as you start working on your project anyway.
JASON: Yeah. Maybe it's worth looking at this just to get a sense of, you know, how -- what are we really up against here, right? Because a lot of these are gonna be pretty straightforward. Like the root file I imagine -- yeah, this doesn't look like it gets too wild. And so, what -- where should people look to kind of get a sense of what they're up against when they're -- what are you starting with when you install a stack?
KENT: Yeah, yeah. Totally. So, well, stacks in general, it's gonna be different for everyone. For the three stacks that we're starting, the code across them is actually all very similar. The only differences are in the models -- well, actually for the Fly and Prisma ones, everything in the app directory is the same except like what picture we show and whether it says indie or blues or whatever. They're all basically the same. For the difference between the Fly ones and the AWS ones is mostly in the models directory. And in the DB server. Because AWS is serverless. There's also no health check on AWS. Oh, by the way, there's a health check. Which is pretty cool. That Fly uses to make sure that your app is still up and running and it can fall back to other versions and stuff. And it won't deploy if this doesn't work and stuff like that. That's actually pretty cool.
JASON: That's nice.
KENT: But yeah. There's only a handful of things that are different. As far as what you have here, you have a simple way to connect to your database. Right here in the DB server. This is a little bit more complex in the multi-regional one because you have read-write replicas. Connecting to that is a little bit more challenging. But this is not a file that you touch very often at all. Yeah, the user and notes models are also like this is just anything that we interact with our database is gonna happen in here. You, of course, can like interact with the database directly in your loader if you want to.
JASON: This is just built into --
JASON: Prisma. No password hashing because they do that for us.
KENT: You kale two. Line 15.
JASON: Okay. Got it, got it.
KENT: bcrypt is pretty battery. I only recently figured out how password hashing work recently. The modern way to do password hashes. And it turns out the best, most secure password hash is one where the only library that can create the hash is slow. So, like slow is a feature which is like really interesting to me. That that's how that works. But yeah. So, that's what we're using there is bcrypt.
JASON: Yeah. We're storing a hash password. Prisma kind of handles that for us. And the thing that's interesting here. We're looking through -- this is a full app that's got a -- so, a database setup. It's got a notes model. So, a full -- well, not quite full crud. But create --
KENT: The only thing we're missing in the UI is up date, yeah.
JASON: And you've got persistent, deployment scripts. All this stuff and each of the files is 50 lines of code, notes is 43 lines, DB server is 23 lines of code. And these are all React components. We're not looking at like -- this is stuff you can effectively throw away.
KENT: Yeah, you just delete it.
JASON: I think that's pretty cool that we're seeing that here in that this isn't a heavy -- it's not a heavy boilerplate. It's just --
KENT: But it's a really powerful one, right? Like, yeah.
JASON: I have been thinking about this more and more as I have been -- because one of the things we're trying to figure out at Netlify is the goal is developer productivity, right? Like if we really boil down what Netlify sells as a product, it's developer productivity. And so, when I'm thing about what that means, it's like there are three buckets of web Dev. There's the -- there's the app logic, the idea that you have that you want to build and interact with on screen. There is the -- the deployment, like the Ops side of things. You've got to wire together the CI/CD and whatever the hosting is and the routing and the DNS, all that kind of development. And then there's the -- the foundation. Like the boilerplate. You got to wire together all these pieces and make sure that they're talking and you've got security and you're protecting your keys. And what I -- what, you know, what I have been really steering toward is like I think what developer productivity is just automating those two buckets. The DevOps and the boilerplate. Because those are the things that, especially for a lot of modern web apps, they just don't change. Typically they're gonna be whatever you're company does, that's what your company does. At Netlify obviously we are invested in getting people to use Netlify as those two buckets of how you deploy and set up your boilerplate. But we just want you to be able to work on the logic of your app. And that's what these stacks are doing. It's the boilerplate and that connector code. And I just come in and I'm immediately writing logic. Not how to connect the frontend to the serverless function. It's all done.
JASON: This feels like a good -- like a good starting point. It's not heavy, it's not throwing a bunch of opinions at me. I haven't looked at your ESLint config yet to see if it offends me.
KENT: We're unlikely to offend you. Ryan had to sign off on that. And he hates ESLint more than anything.
JASON: Yeah, this is lightweight. I think it's nice to know that when you're doing this, it's not like -- some boilerplates that I've used, the whole first day is backing out decisions from the boilerplate. And I like that when I'm looking at this, oh, I can just delete a decent amount of this and it would all be fine.
KENT: Totally. And I have long said I will never use a generator that I didn't make myself. That's always the case for me. I do not like using generators. That's what I think is special about Stacks. We make it so you can. You can fork this -- this project and make any changes you want to it. You don't like Tailwind? Feel free to remove it. That's fine, you don't have to have Tailwind. We really like Tailwind and we're kind of betting it on. you don't like Prisma? Postgres? Whatever it is. If you refresh, this is GitHub's problem. This finished a few minutes ago.
JASON: Okay. That's done.
KENT: GitHub is doing something weird. That's totally done. The whole thing, I'm looking at it now, it took 5 minutes, 5.5 minutes. It will be faster now since things are cached now.
JASON: Got it. Got it. 5 minutes 29. Okay. To see this live, I'm going to...
KENT: It's gonna be your app URL dot -- or your app name dot Fly.dev.
JASON: Got it. Look at that, friends.
JASON: But now everybody, if you want to go and play with this, you can go actually like sign up for this app and log in and give it a try. And now, each of these is gonna be a separate instance. My local database is separate from production is separate from my staging database. Probably there's a way that Prisma would move between the two if I needed it to. But I don't care in this particular instance. So, I'm just gonna sign up with a new email. Okay. Go and do my notes. And we got notes. And these are all like publicly addressable. Yeah. That's nice.
KENT: But they're always private so I can't just copy that URL.
JASON: Yeah. You all can't see this if you try and get this note.
KENT: My challenge to anybody. Go ahead and take this and make it so that I have a little button that adds like share publicly. And now all of a sudden this is made public. That would be maybe like a 10 minute feature for somebody who knows what they're doing with all the tech. And like less than an hour feature for somebody who doesn't know anything about it.
JASON: Yeah. And it's also like a good -- I can see this as being a great way for different database platforms to show off the different features, right? Like I'm thinking about like Hasura is gonna love this. They can show off how fast they can do the role-based access control. And Supabase is gonna love this, the app is tied in together. Docusped this. I'm thinking about the partners and how they're gonna jump in and make the cool stacks. And all are gonna do the same thing. You know what this reminds me? In the early days, trying to evaluate Backbone and React and Angular and all that stuff when we had the to do app and everybody would build the same app with the same frontend using different stacks so you could kind of compare how you would go about doing different things. This feels kind of like that. Where I've got this common frontend. So, I know what I'm expecting it to do. And look at how much work was it for me to go from zero to this database is connected or that database is connected? When we go to put PlanetScale in, how does that stack up against FaunaDB? And how much work for me? And also as I'm scaling it, which things are easy and hard? I'm excited to see more companies buy into this and give it a try.
KENT: Let's make that a thing. And how does that stock up? And everybody understands we're talking about Remix Stacks now.
JASON: But, no. I think this is really great. A couple people have asked. Tony just put the GitHub link, thanks, Tony. Folks are asking about when this comes out? I think some folks joined late. If you want to let everyone know.
KENT: Yeah, we were planning to have this released in time for this livestream. That didn't quite happen. We are close. If we still end up doing a release this week, it will happen today. But at the latest, it will be next week.
JASON: And if somebody wants to be the first to know, I'm gonna guess that the Twitter might be the right place to follow?
KENT: Yeah. Yeah. Keep up with us on Twitter. I've got a blog post about this that will come out when it's officially published. We also have a newsletter. You can go to Remix -- oh, shoot, I don't know what it is. Newsletter. Yep. That makes sense. And I'll publish on there as well for folks so you can take a look at that. I just pasted a link in the chat.
JASON: Okay. It's definitely lost.
KENT: No, you're good. The Remix Run home page is fun. If you haven't scrolled that yet, give that a look. Yeah. Our Discord is also really active. So, check out the Discord as well. And I feel like there was something else I was gonna mention about that. But I'm coming at a loss. That is it. We're super-excited about Stacks. I really fully expect people to use custom stacks more often than they use the built-in ones. That's my hope. Because I think that's where they're really mostly beneficial in being able to make your own stacks.
JASON: Yeah. I can see that for production work. But what I love about this as an exercise, what I'm trying to do is build something in prototype. Right? Being able to say, well, this stack will give me a database and I don't have to prototype it out and just throw it up for someone to look at. What a power up. We talked about the Discord, we talked about the newsletter, we talked about Twitter. I'm gonna throw your Twitter out there too. Make sure you go and give Kent a follow on Twitter if you don't already. Let's do one more shout to the Conf. If you want to hang out with Kent and Michael and Ryan and the rest of the Remix team. I'll be there, and they just announced the speakers. It's a solid list.
KENT: Actually, if you scroll down on the sponsors section, there's a pretty cool sponsor too. Keep going down to the community -- look at the awesome community partners. Oh, look, there's a really awesome company at the bottom right there! Whoa! What is that?
JASON: So, yeah. Come hang out with us there. We'll see you there. Any other links that people should have before we wrap this up?
KENT: The -- well, check out the blog later. I don't think so. The Stacks are public. I made them public last night. If you go to the Remix Run GitHub, you can find the templates for those and start making your own Stacks if you want. And then also if you want to play with this before we release, feel free. Just keep in mind it's experimental. But if you go to the experimental releases on the Remix repo, then you can just say npx create Remix at that version and that's exactly what we did. If you want to play around with this.
JASON: This is the one we used, I think.
JASON: Yeah. All right. Y'all saw it here first. Remix Stacks. They seem like a promising way to prototype, to build your own default starter stack. Especially if you're working on big teams and you want to build some consistency and quickness into your process. I would have killed to have these when I worked at IBM. So, I think that's gonna be all for us today. Let's give one more shoutout, we've had Amanda from White Coat Captioning here all day, thank you so much for being here. That's made possible through our sponsors, Netlify, NX, Backlight, all kicking in to make this show more accessible to everybody. Appreciate that very much. On the site, make sure to go and look at the schedule, we have some bangers coming up. Redwoodjs going 1.0 this week. Looking at that on Thursday as Hakon coming in to talk about a data site. Command bar, if you aren't familiar with command bar, that's command K to do that on the site. We're doing tRPC, Node image generation and a bunch of stuff I have been too lazy to put on the site. You can get updated on Google calendar and notified on Twitch to find out when I go live. Thank you, Kent, this was an absolute blast. Any parting words for everybody?
KENT: Thank you for having me. And thanks for being nice. Jason, you're an excellent example of the kind of people that we want in our community. So, thank you. And I just encourage everybody to be as kind as Jason is. And I think the world would be a better place. So, thank you.
JASON: That's my warm fuzzy for the day. All right, chat, as always, thank you so much for hanging out. We're gonna go raid Ben. Stay tuned and we will see you all next time.
Closed captioning and more are made possible by our sponsors: