June 2nd, 2025 ×
Wes’ New Site: Gatsby → React Server Components

Wes Bos Host

Scott Tolinski Host
Transcript
Scott Tolinski
Welcome to Syntax.
Scott Tolinski
Today, we're gonna be talking about Wes new website. He moved it from Gatsby to React Vercel components.
Scott Tolinski
So there's a lot of lessons to be learned here, and I'm excited to get into it, learn a little bit about your experience, and just general get the vibes for what the what the type of, rewrite like this actually Scott. My name is Scott Tolinski. I'm a developer from Denver. With me, as always, is Wes Bos. What's up, Wes? Hey. I'm super stoked to actually have this out the door. So one of those
Wes Bos
projects I've been poking around at for for quite a while. You know, those projects where it's, like, not super pressing, but every now and then, I I dip into it. And then finally, I was like, I gotta actually finish this thing. Let me get this thing out the door. So I learned a lot about, moving it from Gatsby. I'll talk about why I moved it and whatnot in just a sec, but learned quite a bit JS as well. We're gonna talk about how to migrate over JS well as, hosting it. I put it on CloudFlare, how much that costs, all that good stuff.
Scott Tolinski
Nice. Sick. I just got back from from Barcelona at the Svelte Southwest.
Scott Tolinski
Yeah. How was that? Man, cool conference.
Scott Tolinski
They had it in this, like, really kind of old, rustic kind of building. You said it looked kind of like a prison, but it was really cool.
Scott Tolinski
The whole thing was just, like, felt, like, a very specific vibes to it. And, all the talks were great. You know, there's something really special about a a smaller conference where all of the talks are about, like, one common thread.
Scott Tolinski
Like, you really feel like you can get something out of all of the talks. And there were, like, several speakers who it was their first time speaking, and they, like, you would have never known. They were just, like every single person was dialed. Everybody was there for the same reasons. It was great. What was your talk on? My talk was on Local First, with zero, basically.
Scott Tolinski
Talking about how Local First JS a as a concept JS, like it's fairly rigid in terms of what Local First is defined as, but, like, not every site can practically use all of those things. So maybe more like Local First ish and and how that, pertains to something like Deno. Even, like, the guy who created zero tweeted out. I was like, zero is not local first, and, like, that's pretty much what my talk was about.
Scott Tolinski
Yeah. It it's pretty cool. Also, I gotta say there's a really funny moment.
Scott Tolinski
Just to, forgive me for telling this story really quick. After after I spoke, Wes, I I was wearing my Syntax Big Purp tee. I'm wearing Yeah. Jeans and a a hat.
Scott Tolinski
And I I went to go out to eat, And, I was just like, alright. I'll I'll go out to eat, and I found this place, you know, the I looked at the so first and foremost, I looked at the menu, and the prices did not look bad. And maybe it was the lunch menu because I walked in and I talked to the guy, and I asked her a table for one.
Scott Tolinski
He says there's no tables, and then he goes off to talk to another guy. And they're far enough away that I cannot hear what they're saying. Right? And then they come back, and he's like, we have a table.
Scott Tolinski
And then as they're walking me back into the dining area, which I could not see from the entrance, I have this terrible feeling in my stomach because every single man in this restaurant was wearing a full suit, and all of the women were wearing, like, fancy dresses. And I'm wearing jeans and a t shirt hat. Like a mineral wash purple t shirt.
Scott Tolinski
And, they're walking me back to this table, and I kid you not, this table could not have been more hidden. They hid me. They there was these two massive plants to the one side of the table and then nothing in front of me, a window to the right of me. So, like, if you were walking into the street, you might be able to just see my back. But from any other vantage point in the restaurant, you're just seeing plants.
Scott Tolinski
They hid me in this past. That's hilarious. They didn't want me to be seen, which I don't blame them. That Wes, what what I was just, like, feeling, oh, wait. Oh, no. Maybe I'll just get an appetizer and bounce. Yeah. I don't belong here. Yeah. Totally. And if you want to see all of the errors in your application, you'll want to check out Sanity at sentry.i0/syntax.
Scott Tolinski
You don't want a production application out there that, well, you have no visibility into in case something is blowing up, and you might not even know it. So head on over to century.i0/syntax.
Scott Tolinski
Again, we've been using this tool for a long time, and it totally rules. Alright.
Wes Bos
Let's get into actual real stuff. Let's get into it. So my personal website this is not my, like, course platform or anything. This is just my personal website that houses several thing. It has my blog on it, has all of my, like, hot tip screenshots and videos, and it has all of my notes for my my JavaScript content as Wes. It's just, like, pages and whatnot about speaking and about me, etcetera.
Wes Bos
So that website I built, probably six years ago, right when Gatsby was starting to have it Scott come up. And I built the whole thing in MDX on Gatsby, and I was really happy with it for many years. However, it grew to a point where it was getting very slow to deploy it, because Wes I built it, Gatsby was simply just a static site generator, and that included all of the the actual images. And it grew to a point where I have I don't know. Probably, I think there's about 600 pages on my website, and Mhmm. I think there's 4,000 images or something like that. And it was taking, like, up to twenty five, thirty minutes to build the website without any, like, caching.
Wes Bos
And that was including, like, trying to process the images on, like, Google Cloud compute and doing them in parallel. And I I got to a point where I was just like, I'm I'm not putting anything on my website anymore because I don't wanna fuss with it. You know? And and that's not a good spot to be. So I was like, I gotta I gotta get somewhere where adding content to my website is fast and easy to a point where I want to do it.
Wes Bos
So I decided, alright. Let's move it off. And my goals for moving this off of JS I don't wanna change the design. I'm I'm even though it's a relatively old design, I'm very happy with it. I don't wanna change the functionality because that that's a can of worms. Wes you start migrating something, if you also wanna change, like, what it looks like and how it functions, then it becomes too big of a project. So I thought I can do that after, but let's just get this thing moved over one to one to to a different framework.
Wes Bos
And then most importantly, I wanted to I wanted to improve both the build time as well as the, like, the page speed Scott, the perf on that. There was some low hanging fruit that I could do to do that. So I I decided, that the new stack, I wanted to stay on React because even though it was built on Gatsby, like, 90% of the website was simply just, like, templating out and logic and and whatnot and Node JS logic at build time, React logic on I guess it wasn't really on the server. Right? It was just it was just prerendered HTML and then on the client. So I wanted to stay on React so that I could just simply move over all of my existing components.
Wes Bos
I was I was kinda tempted to to redo it in Nuxt after talking to Daniel, but, I was like, that's too big of a a job. I'm gonna stay on on React, and I wanna stay on MDX as well because I had written hundred I think I JS like I said, about 500 JavaScript notes and blog posts that were all written in MBX, and I was not interested in moving that to a different CMS or anything like that. Plus, like, my my beginner JavaScript course, I had it entirely I paid a technical writer to basically take it and build, text notes, and it's a huge, huge resource for it. Right? And I love having that on GitHub because I've had I probably had three, four hundred pull requests for clarifications on the content, little typo fixes, things here and there. And I I don't think that I would be able to do 400 fixes to this content by myself. So I was I very much wanted to keep that on GitHub. So what I did is I said, okay. I wanna build this thing in React Vercel components.
Wes Bos
It's starting to get more popular. I really wanna understand how it works. So I moved the entire thing to Next. Js, and I was not super happy with it. And I'll tell you why. And this is not a like a, like, really a slam on Next. Js. It was just it, Wes.
Wes Bos
My personal project of I wanna keep this thing similar to how I had it in Gatsby, it just didn't really fit into the holes that were Next. Js. So I had problems with TurboPack and and all the MDX plug ins that I have, so I had to keep going back and forth between turning TurboPack on and and turning it off.
Wes Bos
Next. Js is still entirely common JS, So there was, like, a bunch of, like, weird edge cases where I couldn't import packages, and I was pull requesting them. And it was just, like, weird annoyances. Right? I just spent days on these, like, little paper cuts, and then I opened issues on the Next. Js. A lot of them were fixed over time, but I kinda got frustrated with that. Dynamic imports were were a bit of a pain. So the weird thing about with these websites, and this is not a Next. Js thing, but if you want to dynamically import some content, meaning that, like, you you go to your a blog post and and then you click on, like, a post, you have, like, a slug in your URL, and then it needs to look up the blog post by that slug and then find it. Right? So I Node a dynamic imports for that so that I could when somebody visits this URL, you find the blog post, and then you import that MDX file as a as if it were like a JavaScript file. Right? It goes through the whole ESM ecosystem. And that dynamic import was really, really funky, and I was using some weird Webpack stuff, and that didn't translate over a while to TurboPaks. I was like, you know what? I got it working, and then I wanted to deploy it to Cloudflare. And Cloudflare is working on this thing called the open Next. Js, Wes, essentially, what they do is they take the Next. Js build and, like, the the, like, the compressed Webpack outputs and all these, like, Webpack bundles, and then they basically are just like like monkey patching it to make it work on Cloudflare.
Wes Bos
And at the time, it was kinda just ramping up, and it wasn't mature enough. I had I logged, like, six or seven issues, and I spent a lot of time in the Discord talking to the devs with it. But I was just like, this is I'm a bit I'm maybe, like, six months too early on this. I think it would be a bit better. But between that and and the build times on CloudFlare, I was I was getting, like, ten, eleven minute build times on CloudFlare.
Wes Bos
I would hit this very frustrating issue where I hit this with Cloudflare in general. It's like, something works locally because you're just you just run it in Node. Js, and then you deploy it. And and the Cloudflare runtime is is slightly different. You know? And you get this, like, annoying feedback loop where you have to, like, build it, deploy it, wafer, or, like, deploy it, build it, wafer it, deploy it. And you can run CloudFlare locally, but the way that this and what I ended up using works is that you have to first build it and then run it through Cloudflare, whether that's on Cloudflare's infrastructure or whether that's locally through their their Wrangler tool. So I was like, oh, that's that's kind of annoying as well. You know? Like, it's it's not just like a quick feedback loop. It it Wes very, very slow. So I was like, you know what? I'm gonna try something else. I had moved everything to that point to React server components, and the beautiful thing about React server components is that it's not a Next. Js thing. I had used very few Next. Js APIs in actually building out the website. So I was like, I can I can move this thing anywhere? It's just it's just Node. Js and and React server component code.
Wes Bos
So I took a look at what the options were. I look at 10 stack start. They don't have their, React server component, story just yet, and I didn't feel like moving it off of server components again. So I, I ended up landing on, Waku, which is a v based Waku. I always say it wrong. Waku. I don't.
Wes Bos
It's a v based React server component framework.
Wes Bos
It's very similar to Next. Js, but it has a bit more it's it's way more peeled back. It's there's a lot more, like, rougher edges. A lot of stuff is undocumented.
Wes Bos
But because it's it's a pre one point o, I was okay with that because I'm able to read the Node, and I was in the Discord all the time chatting with the the devs behind it who are who are fantastic.
Wes Bos
So I moved it over to WeKu, and I've I've been really happy with it. It's it's really easy to the reason why I was on React Vercel components with this type of thing is that it's very easy to either pre generate your components at build time or do a synchronous components on the server before they actually ship out to the to the client. So I didn't have to build them all at at build time if I didn't want to. You could just await, like, a database call or something right before you go and render out the page. Alright. So that's that's why I chose, why what is it? Waku? Waku? Yeah. Waku. What is when? Waku.
Scott Tolinski
Waku. Yeah. Waku.
Wes Bos
Alright.
Wes Bos
Now some of I I know I said I wasn't gonna do a whole lot of functionality, but, on my Scott tips page Wes I embed all the, like, all the little TikTok and short form videos that I do, I was like, I need to post these on my own website because people are always coming to me being like, hey. Where's the video on x, y, and z? And I'm just like, I don't know. Or, hey. Do you have a spot with all your videos? I'm like, they're kind of spread on all the social networks out there. I kinda need to own this content. So what I did is I built some integration with all of the different social networks to scrape the stats from each of them, and then I'm saving those Scott, like the hearts, the retweets, the comments, the views.
Wes Bos
I'm saving all of that stuff to, CloudFlare d one, which is just a SQLite database, using Drizzle. And I've been been really happy with that setup because I essentially am just using the JSON schema from Drizzle, meaning that I figured out how to scrape Twitter, LinkedIn, Instagram, TikTok, and and several others. And I'm just basically saving that data and throwing it in as a JSON object into CloudFlare d one, and then I can pull it out when it is that I need it, or I can rescrape it if it's past the sort of expiry time. Been pretty happy with that. The videos themselves, I did a little bit of sneaky work here as well. I was like, I don't really wanna host the videos myself because, like, that's a whole another project of, like, having to host them myself. So I figured out I, like, reverse engineered the, like, streaming protocol from one of these. I won't say which one it is, but the streaming protocol from one of these social networks, and I'm just using them to, stream the m three u eight file, into MediaChrome, which is, the video player from Max, and it's been been working really well for me as well. Man. Yeah. Yeah. It Wes, that was it was kind of a fun one as well because I was always just like, I need to have all this content on my own. And, like, of course, none of these social networks want you being able to access this data, except for Blue Sky. Blue Sky is the only one that uses the like, a proper API to to get this data. The rest of them are simply just scraped or using some Scott thing to go around it.
Wes Bos
The blog itself is, MDX, like I said. The images that's another problem I had with Next. Js is that the image sourcing was was always a little bit tricky because they wanted you to put the images in, like, a images folder. And the way that I write my blog post is I wanna put the images kind of side by side with the MDX content, meaning that the the a blog post can just be a folder, and I can throw anything I want in that folder. Right? I can throw assets. I could throw images. I could throw, and then, of course, MDX text and any other components I wanna embed right inside of it. So moving it from Gatsby so the way that Gatsby works is that there's, like, a whole, like, sourcing ESLint, and you create what are called Node. And then those nodes are then surfaced via a GraphQL API.
Wes Bos
I ended up simply just writing functions that dynamically require the MDX files, and that replaced all of that that work. I did have to write, like, for example, like, for pagination and being able to figure out what the next piece of content is.
Wes Bos
So, basically, on startup, it sources every single piece of content from the MDX files and just doesn't require, and I have this massive, like, basically not almost an import map.
Wes Bos
And then from that, I can figure out if I want, like, 10 I want page two. I can just take items 11 to 20. And then when I'm I'm on a piece of content, if I wanna be able to link to the next piece of content, then I'm able to basically look at that massive array of content and then say, well, this is the current one. They'll give me the index that is the next one and the previous one. So it's there's a lot of, like, tricky stuff with MDX because there's no there's no database. Right? So it's not like you can simply just, like, query two items, or you can you can use, like, a cursor and say, like, give me these items and then the next two and then the previous two because there's no database.
Wes Bos
And even then, like, if you look at all these, like, React JS tutorials of, like, build a blog Yeah. They're almost never showing, like, a listing of all the blog posts because because there's no, like, like, API to just query all the blog posts unless you were to write a whole bunch of, like, wild Yarn matching, which is what I had ended up doing.
Wes Bos
Page speed. I'm pretty happy with the page speed. I got a hundred on desktop and a 96 on mobile.
Wes Bos
I had it up to, like, a like, a 97 or 98, but you know how these things work. It just if you do it on the wrong day or the wind is blowing in a certain way, then then it goes up and down. But several things I did to make the page speed much better is, the old navigation did not look like this. The the old navigation was there are two rows Wes the first row was a bunch of links, and then the second whatever wrapped onto the second row, I would apply a class to make it slightly smaller so that the the top ones were nice and big, and then anything that spilled on to the second row was much smaller.
Wes Bos
And in order to do that, you know, with CSS, you can't target things that are in a specific row.
Wes Bos
So what I was doing is I had a, like, a resize observer on the nav, and then I would check the x and y coordinates of each of the Tolinski, and and I would figure out when something was was knocked down into a secondary row. And that was causing, like, a bunch of page jank, because what happened is that the page would load, the CSS would apply, then the JavaScript would would trigger that change of the nav, and then it would figure out and apply classes, and it would make the the items smaller.
Wes Bos
And they would do that every time it loaded. Right? And that was that was kinda disorienting to the user. Not a huge deal because it only happens once, but it was also just killing me on on page speed because I was I was getting a largest Contentful ESLint, like, two hundred or or, like, two thousand milliseconds into the page load, which is way too late, and it was absolutely killing me. So I ended up scrapping that nav even though like, I posted on Twitter. Everyone's like, I like the old nav better, but I ended up just doing a very simple, navigation like this. I've been pretty happy with that. I wrote a bunch of MDX plug ins myself, which is such a wild world. It's all, like, DOM tree traversal or not DOM, like, not even DOM tree. AST trees. Yeah. Basically, your your markdown gets exploded into this AST tree that is all ex infinitely nested, and you have to write these, like, walkers that go through. And transform it. Yeah. Looking for images. And then when you hit an image, I would read that image and figure out what the width and the height of that image were, and then I would inline the the width and the height and the aspect ratio of each of the images so that when you visit one of the pages like the about page in the split second here, if if you're anyone JS watching a video, you see the split second while this images is is Mhmm. Loading, it's not pushing the content down below it because there is a a width and a height explicitly set on it JS well as a whole bunch of, like, source set. So all the different sizes of the images which are generated
Scott Tolinski
with the, Cloudflare images. Yeah. So you're telling me you put a walker in your Waku?
Wes Bos
A walker in my Waku. Yes. So I freaking hate
Scott Tolinski
writing. I'm I'm not cut out for for writing MDX plugins, and I probably wrote about four of them for this project. Try dude. Let me tell you. I wrote a custom demo one for for mine Wes I have, like, HTML Deno. And then by inserting, like, a line of, like, a special markdown string, what it's doing is it's loading and iframing in those demos, and, like, that was enough for me. I mean, it was like, this is this is so painful.
Wes Bos
So so painful.
Wes Bos
So doing that with the images really upped the the page speed as well, because Gatsby did that for you. But that Wes not that's not something and that's built into Next. Js, but it's not something that's built into to to Warp. You have to kinda do it yourself, especially when the images are not part of, like, a, like, a JSX file or TSX file. It's part of an MDX file. So you have to you have to make sure that all of the images in your MDX files are actually explicitly exported or imported from each of those files, so I had to write a whole bunch of code for that as well. Yeah.
Wes Bos
Hosting. I put this thing on Cloudflare.
Wes Bos
I previously was on Netlify, a big fan of that. I have quite a few of my projects on Vercel. I've got quite a bit of stuff on Cloudflare, but I don't have I have a couple. I don't have a big site on Cloudflare workers. You know? It's lots of, like, demos and tiny little websites and whatnot, and I wanted something that had, like, serious traffic and used a lot of the products so that we can confidently talk about how it works, limitations, pricing, all of that stuff.
Wes Bos
So this thing like, Waco builds wicked fast. Like, it's like a minute and a half or two minutes to to build and deploy these things, and that's just the best.
Scott Tolinski
Yeah? Why why does it make what makes building it fast? Is it that it's on Veet, or is it It's on Veet. It's because it's Veet. Yeah.
Wes Bos
It's partially because it's on Vite and and partially because it's not doing everything at build time. So my my Gatsby website would generate a static page for I don't know, Node probably six a couple thousand pages. Right? And and then it would do it for all of the images. So now the images get generated on demand via the URL, Cloudflare. So that was quite a bit. And then only not every single page gets gets pregenerated on build time because I can simply just do that on request and then cache the actual output of it. So there's several of them that I do statically generate at build time, like the Node page and whatnot, just so that that's always nice and fast. But the rest of them are you simply just wait until somebody needs to go to that page, then it generates, and then it will it will try to serve up, like, a, like, a cache version of it first and then kick off a revalidation in the background. Mhmm. But if not, then they they wait around for, a couple hundred milliseconds for it to regenerate that page. Nice.
Wes Bos
So, yeah, the builds were I'm so happy about how fast the builds were on Cloudflare just because it's with Vite.
Wes Bos
That was always such a pain for me. It's just waiting for it to Yeah. To deploy. You know? Especially when, like, there's, like, a silly you send an email out to a couple hundred thousand people, and then there's a typo on it, and you're getting emails. Hey. This is spelled wrong. Like, every five seconds, like, no. No. No. Stop. I know. I'm I'm waiting for it to build.
Scott Tolinski
Welcome to, the year 2020,
Wes Bos
Wes.
Wes Bos
Which?
Scott Tolinski
That you're you've moved to Vite, that you are Node you've now entered the year 2020.
Wes Bos
Wes? Oh, I've been using Vite for, like, like, eight years. I I have Vite on my entire course platform. I'm talking about in this site.
Wes Bos
Oh, no.
Wes Bos
What? I I I don't know. Oh, okay. But, like, I don't goofing, man. I understand. I know. I'm okay. Okay. Well, like, I I'll use whatever whatever the thing's used. Mister Tolinski, you Wes don't even have a website.
Scott Tolinski
I do have a website. I'm not even I'm, it's not good, though. Yes. This is not very good.
Scott Tolinski
It's fine. Hey. Click on one of those blog posts. Click on one of them. Yeah. There we go. We got some there's some page transitions. We got Node. It's fine.
Scott Tolinski
It's it's all very add page transitions to mine. I even got a couple themes.
Wes Bos
Yeah.
Wes Bos
But, anyways, I'm very happy with with how quick it is.
Wes Bos
I'm so happy with Vite. And it's funny because Vite is about to get so much faster as well.
Wes Bos
This is not even using any of the the new Vite stuff, which I'm really excited for.
Wes Bos
Yeah. Totally. The Open Graph images are using Cloudflare's puppeteer
Scott Tolinski
browser built in, so it takes a screenshot and use that. That worked really well. That's such a clever implementation, Wes. I I Yeah. I don't know if you are the person who came up with that, but you are the only person I've seen do that.
Wes Bos
It's it's not perfect. It breaks from time to time because you're literally firing up a browser to take a screenshot, and it has to take it fast enough.
Wes Bos
But you don't have to generate them, like, ahead of time or whatever. So I've been been happy and you get, like, full control over it. So let me see if I can find what is the URL? Oh, yeah. So, like, here's an example of of one page. This one doesn't have any images on it, but I'm able to use CSS for all of this, and then it's just generated on demand. And it does that via Cloudflare's puppeteer implementation, which was almost a one to one move from my existing Puppeteer.
Wes Bos
Pricing. I was very curious about, like, how much this would cost.
Wes Bos
It gets I don't know. I think I get about 5,000 visitors a day or so, which is not a ton of traffic, but but it's it's it's enough. You know? And I'm on the CloudFlare, like, $5 plan.
Wes Bos
And as part of that, you get a certain number of, like, milliseconds for CPU time so that they bill you based on CPU time. Right? So my Cloudflare dashboard tells me that I'm averaging about two hundred milliseconds per request of CPU time, which seems high because the free plan is ten milliseconds.
Wes Bos
So I don't know if that JS something I should be worried about or should be looking into. It seems seems okay to me.
Wes Bos
But at two hundred milliseconds average, I'm doing about three hundred or three million milliseconds per day. So that means on my $5 plan, I'm gonna run out in ten days, on this. And then once you're past the three million milliseconds of CPU time, then you have to pay about 6¢ a day.
Wes Bos
So an extra dollar 20 a month to host to host this website. So I I do all of I think so. So, like Yeah. $6.20 warp for for the website, and that also includes all of the bandwidth.
Wes Bos
That also includes all of the the caching APIs.
Wes Bos
It also includes the SQLite database Mhmm. For I looked at it. I have 90 in I only post I only put this thing live about four days ago, and I have I I don't know. I think I have, like, 50,000,000 reads or something, and and you get, like, billions. I I did the math. I was like, I'm not gonna hit that ever within the $5 plan. So so I'm never gonna go over on that.
Wes Bos
My image transformations look like they're they're gonna stay within the the $5 level as well. So pretty much for $6 a month, I'm able to host this website.
Wes Bos
And that's not in the only I probably have seven or eight other projects on CloudFlare under that $5 plan as well. So I've been, like, been pretty happy about that because, like, the alternative is you either run, like, a VPS Vercel, you know, and you put coolify COOLIFY on there. I don't even know that I could do this for less on, like, a self hosted COOLIFY. What do you think?
Scott Tolinski
I don't think you could. And let me tell you, it probably wouldn't perform nearly as well because Yeah. I the things that I put on my COOLIFY are hobby things or, like, they're not serious things. Not because Coolify can't handle that, but just because, you know, my server is far away. It is in The Netherlands or something because or Germany because I host on Hetzner, and they're like Yeah.
Scott Tolinski
They only offer Yarn servers internationally. And I wanted to just experiment with an Arm server. So I don't know. You could probably do it on Coolify and get it to be just as fast, but I don't know if it would be as cheap. CloudFlare ESLint my mind is the cheapest Wes. You know? No kidding. Yeah. It's like
Wes Bos
they they own the infrastructure, and they're at a very low level. Like, they're a networking company. So I think it's gonna be very hard, especially from, like, a bandwidth point of view. It's gonna be very hard to to beat that out. So that feels good because, like, I feel like a lot of these hosting companies are getting really expensive.
Wes Bos
Yeah. Like, a minimum $20 a month, and then they'll nickel nickel and dime you for for a lot of these features.
Wes Bos
And and and I they kinda need to do that to in order to make money, but I don't know. That stuff adds up once you Yeah. Have three or four different websites.
Scott Tolinski
Some of these places, you need a a doctor to understand their pricing table. You just, like, look at, like, the 20 different item 30 different items they're charging, x amount of cents per million requests or whatever on various things. You're just like, alright. What, you know, what are my actions? I will say CloudFlare is no better.
Wes Bos
Sure. Like, you're I'm counting milliseconds CPU time here. Yeah. And then, like, the the tools for, like, visualizing how much you've used are are not very clear as Wes, and then you have to go to the pricing page for every single thing. But I also don't care because I know that it's I don't know. You get a bazillion people come to your website. I know that I'm not gonna go bankrupt with this type of thing, Tom, which is great. So I'm pretty happy about that. Caching. I use the Cloudflare cache API, by setting headers.
Wes Bos
In Waco, I have middlewares where I can just set the the different caching headers that are are needed.
Wes Bos
And that's really nice because I can do that both on, like, a request page level, but I can also do it based on, like, React Vercel component partial. So if you if you visit one page to another, you can cache the React server component payloads.
Wes Bos
I will say Next.
Wes Bos
Js implementation of caching is much better because, like, if you look at my the Node page here, in the footer, I have syntax podcast where I I ping the Syntax API and and show the latest, Syntax podcast. Right? And then I have a whole my tweets are being put into the footer, and then my my latest course are being put in there. So, like, this content needs to be updated fairly frequently, you know, like, at least every couple hours. But if you're caching every page, that's kind of weird because then you end up in a you end up in a situation where one page might have old tweets cached because it's still good for five minutes, and then the Node page is is maybe a little bit different.
Wes Bos
So with Next. Js, you can cache out a component level, which makes so much more sense to me because I could just cache this entire syntax component, and then my tweets component could be cached as well. And then when you go from page to page, it simply just uses the cached parts to build it. So I ended up actually just caching the data for each of these and then and then rendering it out inside the page, and then I have a fairly short caching. I'm still kinda playing with it here and there. There's a a delicate balance between trying to get, like, the fastest perf and having annoying caching issues, which make you wanna cry.
Scott Tolinski
Yeah. No kidding. Yeah.
Wes Bos
So, yeah, that's one thing that I really missed from from Next. Js is the the really nice cache API from from doing that. And as well as, like, I don't have any, like, interactive stuff. Like, I don't have stuff where people can type into a Bos, and then it sends it to the server and updates the database.
Wes Bos
It's mostly just content being pushed out. So I don't have to do any, like, revalidation of of specific pages.
Wes Bos
Last two things, errors and CSS. So the errors, I integrated Sentry. I'm using the React server component integration and the CloudFlare Deno. So Waco uses Hano as a server, and they expose several hooks where you can get access to the raw Deno API, which I absolutely love. It's like, just give me access to it if I need it.
Wes Bos
And I can do things at, like, a Deno server level if I want, or I can just pass I can I can pass it on to the the Waku router, and it will it'll pick it up from there? So if I ever need to, like, step in front of Wacu before it does any weird rendering or anything like that, or if I ever wanna write a custom middleware, which I wrote several of, then I I can do that. Yeah.
Wes Bos
One kind of cool thing is moving over a huge site is you're always worried that you didn't get all the the right pages and whatnot.
Wes Bos
And I actually found a Century blog post where they when they move their docs, they had hundreds and hundreds of pages in their docs, and they were just watching their, they Yarn filtering for not found exceptions in the Sentry dashboard, and then they can they set a little alert for when a specific page gets above a certain level.
Wes Bos
And what I did is I I just pushed it live for a couple hours, and then I I put put it back to the old Node. And that was enough traffic for me to see, a, any any errors that it didn't catch, but also any common pages that people were hitting that were or possibly I I hadn't linked to. You know? You you did the URL a little bit weird because you your slug function was a bit weird, so that was really nice integration.
Wes Bos
Yeah. And then finally, CSS. So my old website was using styled components.
Wes Bos
And styled components don't play nice on the server.
Wes Bos
Plus, at the time, style components were great, but CSS has come so far that I really didn't need any of the style components features. Like, I didn't need JavaScript in my CSS at all. It all had needed to be happening at build time, and style components don't work on the server on inside server components.
Wes Bos
So I I took a look at, like, what are what are the different options that I can do? I don't wanna rewrite any of my CSS.
Wes Bos
Mhmm. So my CSS was just written in classes that were essentially just imported and put onto my components. So I don't wanna rewrite any of that, and I kinda wanna keep the style components API where you just wrap tags around it. So I initially moved it to Panda CSS, and they have integration that allows you to use, like, style, like, style component like tags.
Wes Bos
And I forget why I ended up not liking that. I ended up saying, okay. I'm gonna scrap this whole wanting to have components JS, like like, div wrappers with with enclosed styles, and I just moved it all to CSS modules. Meaning that I put all of my I moved all of my style components, and I I just I used cursor, and I said, here's a couple that I've Deno. Move all of these style components into dot module dot CSS files, and then I simply imported the module dot CSS files into the components where the CSS was needed, and then you apply the class to the div or to the article or to the to the layout that you need it. So that worked pretty well. I had to do a little bit of funkiness around getting the autocomplete for TypeScript to work. Mhmm. So that's I don't know. CSS modules are have been around for a long time, but there's not a lot of great tooling around using them with TypeScript. I probably would have chose something else if I was doing this from scratch, but, again, I was not interested in having to rewrite any of the CSS. I just wanted it to move over.
Scott Tolinski
Yeah. I will. I I it's interesting because, you know, CSS modules are one of those things that I've kind of avoided mostly because I I don't need them with, the way that, like, Svelte handles Scott CSS. Right? Yeah. But I do think it is probably a great option for most people, and I'm stoked to see that you went with that. Yeah. It works exactly like I don't like Svelte's Scott CSS. So it, like, generates a
Wes Bos
random ish class name. You know, if you if you inspect something on this page, it'll be, like, content styles Node c I y a. And those are all, like, unique, but you can also see what they are. That's exactly the same way that that Svelte works.
Wes Bos
The one thing I had trouble with is I sometimes just like to select children inside of a selector. You know? So I might have I might have, like, this box here for my tweets, and I wanna select anything with the class of, like, red or anything with the class of heart.
Wes Bos
And that parent child selectors do not work well in in CSS modules. You have to explicitly give everything a class Mhmm. Unless I think there's some rules around, like, it will select raw elements, or you can use the, like, colon global selector, which we use in the ESLint site several times.
Wes Bos
So I did have to rewrite a couple of those, but I realized as I was refactoring it, I was like, this is kinda better. It's even though it's a bit of a pain, this is probably a better way to to write some maintainable CSS.
Wes Bos
That's it. That's, that's the website. I've been it's a pretty fun move over. I've been pretty happy with the perf and and how smooth it is to deploy. I think my next steps now are putting more content on it, you know, being able to just write people ask me all these questions. What three d printer that you have? I should just have a page on my website that has all of that information. And now that it's so easy to do that, I'm I'm excited to put some more content online.
Scott Tolinski
Nice. I'm happy, for you that you were able to make this change. But, also, like, hey, man. That's some real world, React server components and getting off Gatsby and all this stuff. It's a Yeah. That's a Rest in case, Gatsby. Yeah. And also there's a lot of people still on Gatsby,
Wes Bos
that are are probably trying to make this a similar move to see, what do I do? Like, where do I go from here? And, oh, that's that's one more thing JS people are probably gonna be ESLint, why not Astro? And I don't have a good answer to that, other than I just wanted to use rec server components at the time. So Astro probably would have been a a good fit for it as well.
Wes Bos
It's just there's only so many cool things to try, and I've used Astro in the past. So I wanted to I wanted to dig a little bit deeper into React server components and see how viable that would be. I've been using Astro Starlight, and that and it has been a nice experience to work inside of Astro. That? It's like their docs platform. They have, like, a bunch of templates.
Scott Tolinski
So, like, Astro now had I don't it's not, like, brand new or anything, but, like, the ability to get started with a template.
Scott Tolinski
And one of those templates is, like, DocuSaurus style type docs. Oh, yeah. And it is it's starlight. It's very nice looking out of the box.
Wes Bos
Yeah. That's kinda great. Oh, that's good. I've certainly been on websites with docs like these.
Scott Tolinski
Docs websites are getting so good. Yeah. Cool. Cool. Alright. Thank you so much for giving us this deep dive. And it's actually also nice to, know that you said you were not announcing this yet because you were waiting to make sure nothing was trickling in on your Sentry. Do you wanna maybe talk about Sentry for one second?
Wes Bos
Yeah. Well, what I ended up doing is I like, I put it on a subdomain, and I I tweeted it out. I was like, go nuts, everyone. You know? And then when I was, like, pretty much ready to to deploy it, I just like I said, I I put it live for, I don't know, five hours. And then my center starts to lighten up with all the issues, and I flipped it back. And I just had it's almost like I had this, like, little to do list with all of the like, I could see where people were clicking on the website, and, like, there was some, like, really odd ones where you would get, like, a a white people would be like, it's just a white screen when I was clicking around. And we're like, oh, that's helpful. You know? But then I was able to actually go to the website and see what people were clicking and then and then maybe hitting the back button or or just, like, basically, their path as a video. And then I was able to figure out, oh, that's that's exactly what was happening. So, yeah, pretty valuable in in launching a new site. I had it I had it on the second screen beside me here pretty much all day long, trying to figure out what's going on. And it feels so good to, like, mark it as resolved and say a little prayer. Hope it doesn't come back. Yeah. I love that. Yeah.
Scott Tolinski
Set it free. Node it does not reach out. Century
Wes Bos
dot I o forward slash syntax, and you will get two months
Scott Tolinski
of the team plan for free. Oh, yeah. Cool. Well, thank you so much, Wes, for this, deep dive. Love to hear this stuff. And maybe someday, we'll get to do something on on my website if I choose to ever make it worth an episode.
Scott Tolinski
Right on. Alright. Peace.