February 1st, 2021 × #LevelUpTutorials#React#Node
Hasty Treat - New Level Up Tutorials Site
Scott discusses moving the LevelUpTutorials site to a new tech stack using Node, React, Snowpack, Render, and more.
- Episode about new LevelUpTutorials site
- Moving from Meteor to Node/React stack
- Originally built in Drupal, moved to Meteor
- New stack is Node API and React frontend
- Not using Babel, using ESBuild
- No server-side rendering yet
- Using Snowpack for dev, 50ms reloads
- Wrote GraphQL importer for Snowpack
- Production builds very fast with ESBuild
- API in Node/Mercurius, very fast
- No performance issues with MongoDB
- Leveraging codegen for types
- Hosted on Render, great experience
- SSR coming soon with Snowpack Node runtime
- Using Cloudflare with SSL from Render
- Built custom CLI tool called Avalanche
- Using Caddy as a dev server and reverse proxy
- Switched tests from Jest to Cypress
- Caddy great for SSL and reverse proxy
Transcript
Scott Tolinski
Welcome to Syntax. In this Monday, hasty treat episode number 323 for those of you who are counting. We are gonna be talking about the new level of tutorial site and some of the changes technologically that have gone on behind the scenes in the evolution of my site, my code base, and basically, My baby. This thing that I have been nurturing for a very long time here, longer than my own children. This this site has been something I've been nurturing. So we're gonna talk all about What I've done here, the changes that I'm making, why I made these changes, and some of the new tech that it's running on. Because this site's running on a lot of hot new tech. So My name is Scott Talinski. I'm a full stack developer from Denver, Colorado, and with me as always is the Wes Boss. Hey, everybody. Hey, Wes. How's it going? Oh, doing pretty good. Good. Who's this episode sponsored by today? FreshBooks at freshbooks.comforward/
Wes Bos
syntax. They are the small business accounting software that makes billing painless. So you're sending out billing. You're sending out reminders. You're tracking your expenses. You're doing time tracking. You're Logging an invoice that is a flight, that's an expense, but you need to convert it into an invoice for the client. You can do that on FreshBooks. It's really slick. Best way to keep track of your small business accounting. So check it out, firstbooks.comforward/syntax, and use syntax in the how did you hear about section. Sick. This episode is also sponsored by Sentry at century.i0.
Scott Tolinski
Use the coupon code tasty treat, all lowercase, all one word, and you will get 2 months for free of Sentry. Now what is Sentry? Now Sentry is the error and exception handling service that you will see both on leveluptutorials.com's API as well as the front end UI of the Site.
Episode about new LevelUpTutorials site
Scott Tolinski
That's right. I've been using Sentry for a very long time, longer before they were sponsors. I've been using Sentry to level up tutorials to Track all of our errors and exceptions and understand when we actually have a problem.
Scott Tolinski
We also use it for critical performance metrics, and I tie the version of the directly in to Sentry, and it's connected to our GitHub repo.
Scott Tolinski
So right then, when I have an error in the site, it pops into my errors, And what I can do is take a look at this. I can see if it's a a legitimate anything that I need to pay attention with. We have our source maps right there. It tells me what version of the Site this bug was introduced in, and I can create a GitHub issue and assign it to a member of our team directly from Sentry. This is an essential tool for me and really, honestly, one that we highly, highly rely on over here at LevelUp Tutorials. So check it out. Century.iocouponcodetasty treat, all lower case, All one word, 2 months for free. Okay. So let's get into the new level of tutorial site. I would give a little bit of a background on the site. It was originally built In Drupal seven, I used Drupal seven because at the time, it was really easy to plug and play. It's like every step of my career at that point had been really done in Drupal, so It was really easy for me to build it in Drupal seven. But you know what? At some point, I decided, you know, the I would love to To take on a full on JavaScript application, it existed like this. You know, outside of the context in which it exists now for quite a bit of time, it was mostly just Like a a mirror of what's on YouTube.
Originally built in Drupal, moved to Meteor
Scott Tolinski
So I decided to rewrite the entire site using Meteor and Meteor's own front end framework at the time, which is Blaze. And Blaze powered 2 sites. We had level up tutorials .com and store.leveluptutorials.com, both of which shared the same database, shared the same accounts, And you logged in to when it logged you into both, but they were entirely 2 different code bases, which was kind of a dumb decision on my part, but it's one that I struggled with a lot.
Scott Tolinski
Next, I rewrote the UI to use React because Blaze wasn't going anywhere.
Scott Tolinski
Then I rewrote the API to use Apollo even though that that was using Meteor as a build tool because, You know what? As much as I love Meteor, I didn't wanna be so locked in. Then I combine the the store .leveloftutorials.com codebase with the normal site, Allowing you to buy anything, then I moved the whole thing to TypeScript.
Scott Tolinski
And there's been a lot of other minor refactors in there because you know me. I am crazy about refactoring and updating and whatever, And this is just the latest and most likely last step in a long time to this. So that brings us up to date to right now, the site That is live. Maybe by the time you're listening to this, the previous version of the site, I'm gonna call it the previous version, is currently built on Meteor with Apollo, And it uses MongoDB, and Meteor is primarily used as the build tool, but also the account system.
New stack is Node API and React frontend
Scott Tolinski
And so I have decided to move off of Meteor, sadly. Woah. Yeah. I love Meteor. Is that because it's dead? It's not because it's dead, actually. I'm just joking. Yeah. I know you're joking. I'm not even gonna entertain it. I'm just gonna breeze right right by that. But, like, KnowMeteor is fantastic, but, like, at the end of the day, you know, the meteor's positive points are the ability to get up and running quickly, You really iterate really quickly, do real time really easily. All of those things, they just weren't anything that we are using. So at the end of the day, we are using Meteor Primarily for the account system as well as the build tool. Yeah. And the build tool aspect of it was kinda getting to be just a bit of a pain that I couldn't do some of the things I wanted to do. Granted, there's a lot of really nice things about their build tool, and I I don't wanna, say anything bad about it because I think it's fantastic. But at the end of the day, I just wanted a little bit more control is what it came down to. So what did I do? Well, the biggest change overall in the way we're compiling or doing anything on our site besides the fact that we have removed Meteor Is that we've split the site into an API and the UI now. Rather, before it was all just sort of 1 project because that's how Meteor likes to do it. Right? Even though we had UI folders inside of our source or whatever, it was all just 1 project. Now it's 2 distinct different processes, 2 distinct projects running API UI.
Not using Babel, using ESBuild
Scott Tolinski
Another big change is that we've removed Babel entirely from our our process. So we're not using Babel at all, except for, I believe, in the production builds using the Snowpack Plug in Webpack. I think that uses babble, but I don't think it does anything that I have to worry about. I never think about babble. Snowpack plug in Webpack babble. Is that what you said? It's not Plug in babble. It's plug in webpack.
Scott Tolinski
Oh. So there's no babble here. So Snowpack plug in webpack is a plug in for what it does is it uses Webpack behind the scenes to build the site using your Snowpack configuration. The reason being f. Is that Webpack has some things currently in their production builds that Snowpack does not. So as a I don't have a Webpack Config, I don't have any of that. For a nice little way out, they just provide you that plug in. You drop it in, and then your builds are better. I don't know what's better about them. They're just better. And these are production builds. It's not development builds. So for the most part, Babble does not have any part in our site whatsoever. Oh, I guess because the entire website's built in TypeScript, that Still converts it to,
No server-side rendering yet
Wes Bos
like, a browser compliant JavaScript?
Scott Tolinski
Correct. And we're using ES build for that. So ES build is a Go package to allow you to build for the web as well as for Node, JavaScript, TypeScript, whatever.
Scott Tolinski
And we've talked about this before. They have some crazy benchmarks, and these crazy benchmarks are all true. It's like that image from Star Wars of Han Solo saying, It's all true. That's how I feel about these benchmarks on on ES build. Let me tell you about our production builds. Our production builds take a second or less. That's our full production build. When in in the past, it would have taken, like, a couple minutes or something. My gosh. It is crazy fast.
Scott Tolinski
So to get into some more details on the UI side of things, the UI has been separated into its own project.
Scott Tolinski
The actual component side of things, Pretty much unchanged. It's still React. It's still styled components in Sass using SCSS.
Scott Tolinski
However, we've been moving more and more things to just straight up SCSS and CSS variables and seeing where we can reduce some of that style components, not because style components aren't great, but I think we're overboard using them just a little bit. The development flow of everything is being done with Snowpack.
Using Snowpack for dev, 50ms reloads
Scott Tolinski
We get 50 millisecond hot reloading. You don't even lose your React state, that hot React fast refresh. But more importantly, those those 50 millisecond page reloads are insanely good. I cannot get over how much faster it is. No knock on Meteor, but part of the beef I had with Meteor and using it in the way that we were is that I would save things and then just wait 3 or 4 seconds. Okay. Wait. Oh, brutal. Yeah. It's brutal. And to to go from that 2 50 milliseconds has been an unreal experience. In fact, when we first made this branch, I said, guys, we gotta get this thing done because I don't wanna go back to the old development environment just because of how much better it was to work in. We get nice errors that pop up on the UI like you'd see in create react app that comes via Snowpack. That's not something we had before because we would've had to do it ourselves. So the MegaFAST development workflow has been crazy good. I wrote a custom GraphQL importer to import the GraphQL files for Snowpack. I will make that Open source for anybody else to use it once it's in production, I guess. It's pretty easy. Basically, just able to to pop in a loader and Convert the GraphQL file whenever there was 1 and just send it along as JavaScript.
Wrote GraphQL importer for Snowpack
Scott Tolinski
Really pretty easy, very positive experience writing a plug in for Snowpack. I'm not a person who's ever written plug ins for Anything before, and I wrote this plug in with just about 0 zero guff at all. Are you doing any SSRs at all in the client? All client side, I did a little bit of An SEO test. The SEO test to me showed that the CSR build was going to get the exact same Google bot. What is CSR? Client side rendering. And how did you test that? Oh, a handful of sites. I forget what it is offhand, but there's one specifically that Google says that This is the tester that will show you how the Googlebot sees it. I'll see if I can find it and put in the show notes. I'll have to look it up. But there's one specific one that will say, like, This is the tester that will will get the accurate representation of what the Google bot sees. So I was able to see that there was not gonna be any hit SEO wise, But, also, Snowpack was it's going under some change constantly. Right? It's it's a new library. It's growing. And one of the things they just released was a new node runtime, which I will be using To build a server side rendering component to the site like we have currently. Right now, we do have server side rendering with Meteor, but I wrote it all from scratch by hand, so it's not like it's Sound like New Year is doing anything there for us. It's just like it made it easier to get it up and running. So that's something that we will be doing, but Aren't doing, but I don't think it's gonna give us a hit SEO performance wise. The new site's quite a bit faster for several reasons, so I'm not quite worried about performance issues.
API in Node/Mercurius, very fast
Scott Tolinski
API. The API is being done now in Node. Once again, it's just straight up Node. For those of you who aren't really up on Meteor, Meteor is really just Node. In fact, Meteor's routing system is built with Connect, which is, you know, what Express was built on top of Connect. So for the most Like, our site is very, very node y even though, you know, you hear meteor and you think magic. Our site was just pretty much straight up node, so it really wasn't that too much of a a problem to convert it. But we used ES build again on the server side, and we get some just crazy fast builds. In fact, I'm not even doing, like, a development build and a production build. When I save the server, Wes, it's doing a production build in development every time, and that's one of these small optimizations that I'm going to make that's going to You can speed up our development time that much more, but it's so fast right now, and it takes up so little CPU. I don't care that I'm doing full production build out every save. It just Doesn't matter to me. It's amazing. What about connecting to MongoDB? Like, doesn't that take, like, half a second a second, or is this Is is that not a a slowdown for you, that initial connection? It's not not that much of an issue. I think that might be the slowest part, the network request. That's true. Even, like, I'm thinking about
Wes Bos
my personal like, my site that I run everything on, and I have to kill the build and restart it every single time. And the MongoDB is not a It is probably the slowest part, you're right, but it's not like a a major slowdown either. It's less than half a second, I would say. And Tom, our developer,
No performance issues with MongoDB
Scott Tolinski
He's been working on a a thing to make it really easy to, like, constantly clone our staging database to, like, a local Yeah. So that You could just run it local, and then you're not gonna have any connection at all there. I'm running a staging database, like a network staging database for mine, but he's Running everything locally, so it's probably even faster for him. Our API is done in Mercurius, which if you have not heard of before, let this be your introduction to Mercurius.
Scott Tolinski
Mercurius is a GraphQL package for Fastify, which is a very fast Node server. So if you've never heard of Fastify and Mercurius, please please please check them out. Mercurius dot dev. I have no association with this project or Fastify, But this thing is fast.
Scott Tolinski
Same exact API, same database calls, same everything as our Apollo server, and CSF.
Scott Tolinski
I didn't do any benchmarks, but the quote unquote eye test is unbelievable for me just how much faster this thing is. And we are using maybe, like, 10% of the amount of built in optimizations that Mercurius can do. For instance, they make it really easy to, Wanna do federation in in GraphQL easier than Apollo, I think. At least Apollo. I'm talking Apollo Server when I say this. They make federation very easy, but The performance side of things, there's some really nice just in time compiler GraphQL JIT. It includes integration into DataLoader Adequally to, like, avoid 1 plus end calls, that's a common situation in GraphQL where it can lead to let's say, I query a playlist, And then I say, hey. Give me all of the tutorials in that playlist. And then I say, give me the tutorials, whatever. Those could end up being a 1000000000 database calls if you're Not careful, and DataLoader is the way around that. But the DataLoader picture for Apollo is sort of like a Sentence on their page is this is use data loader to the like, there's not a good clear implementation on how to do it, where this has it, like, baked in To make it really nice and easy for you. And there's also caching baked in too, which we're not using. So we're not using caching or DataLoader, and we're still getting these insane load times compared to What we were. So by adding those 2 things, this API has a lot of potential to get much faster, which I'm I'm very excited about. I also wrote a GraphQL plug in for ES Build. Actually, don't know which one. I think I might have done the the ES build one first. Once I did one of them, it was the exact same thing, just learn how to do one for the other. So I'll also open source that. I have a GraphQL plugins for both of those, and that's just to load a dot GraphQL file. Now another thing that we're doing is we're highly relying on cogeneration for this site. So we have our GraphQL schema. We're running GraphQL Cogen, and that spits out every type for everything, all of the resolvers, all of mutations.
Leveraging codegen for types
Scott Tolinski
So everything's fully typed, but it also spits out every single React hook that we need. So it looks for .GraphQL files, And if there's a .GraphQL file, it takes that and turns it into a React hook, for instance, like use checkout.
Scott Tolinski
All I have to have is a checkout mutation, and then I run Codegen, and then I get a use checkout mutation hook. Automatic. Import it. Bingo. Bango. And it's fully typed, so you don't have to worry about types or anything. It's it's all amazing. I use this thing like crazy. Next step is hosting. We hosted it on render.com.
Scott Tolinski
Those of you who have watched level of tutorials know I had a Scott tries render video that came out a little while ago that I did not say very nice things about render because it It was, like, a little bit broken when I tried it. I had enough people suggesting me to give it another try that I was like, okay. I will give it another try, and I did. In fact, it was Matt from Mux who reached out and said, you need to try render. So I gave it a try, and it was fantastic.
SSR coming soon with Snowpack Node runtime
Scott Tolinski
Easily the best hosting experience I've had. It's basically you can think of, like, if Netlify and Heroku had a baby because it has the simplicity and ease of Netlify, But it has the abilities of Heroku, and it's way cheaper than Heroku. They have a whole, like, us versus Heroku section of their site that will really get you Really get you moving on it. So I hosted the API.
Scott Tolinski
The client there generated the SSLs in 2 seconds. It Worked absolutely flawlessly with our Cloudflare.
Scott Tolinski
No issues there. I gave a lot of hosts a run. I tried DigitalOcean. I tried, Oh my gosh. I tried so many of these new app platform hosting services, and let me tell you, render.com really blew me away with it. Render does the like, it's It does, like, actual node hosting. Like, it's you get, like, a proper server. Yep. But you can also scale it up. And it looks They also do the CI part, like, where you can do builds and whatnot. Yeah. And it was really simple. In fact, you know, sometimes these things, they try to do a little too much for you. Like, the DigitalOcean one really tried Too much for you. And then when you start to do it, they'll be like, well, you gotta get into a config file. Or even off the jump, you gotta get into a config file. But with render, it Was more like Netlify where when you sign up, you click on the box of your repo and then you click and it says, oh, what's your run script? And you can just type in there, like, Netlify, oh, what's your build script? Type it in right there, and it just worked. It, like, worked first try, and it worked perfectly. So None of the other ones I could say I had to, like, start diving into docs about your custom, you know, config files. I'm not interested in your custom config files. I would like to just have a basic here's here's what my start script is and and just have it go. To me, like, Heroku is always the gold standard for ease of hosting, and now I think Renderer has Taking that just by how cheap and nice the whole experience was for me. I tried myself the DigitalOcean
Using Cloudflare with SSL from Render
Wes Bos
app platform.
Wes Bos
It is really good, the app platform. It's just that I I did. I I think I tried it, like, the day it came out, and there was just, like, a bunch of, like, little things where I had to, like, almost immediately kick off to my own config file.
Scott Tolinski
But I I got it up and running. It it is pretty slick, but this render looks really good as well. I never got up and running on theirs. They had the issues with our repo. We have, like, a A fun mono repo set up, which I'll talk a a slight bit about. But we have this mono repo. I googled like, how the heck do you do a nested folder Build on DigitalOcean's thing, and the first thing that sent me to was, like, a support question that Wes had filled out himself and they had answered. So I was like, that was me. Yeah. It was Wes. Those days.
Scott Tolinski
They had the answer, so it was just funny that we both had that same issue. One cool thing about this project is I built my own custom CLI for it that I'm calling Avalanche, And the the Avalanche thing is kind of interesting. I'm considering how I wanna turn this thing into some sort of an open source project. But it's kind of fun because instead of, like, a normal CLI where you To remember flags and everything like that, I built this tool to, like, basically orchestrate all of the types of things I would like to run, whether it is Cogent Or I wanna update all of the dependencies on the API and the client. I can do all that from here. Oh, that's nice. So I just do node avalanche to run a JavaScript file, And it gives me the option to develop, test, cogen, or update dependencies.
Scott Tolinski
Cogen runs our cogen. Obviously, testing Will then give you other options whether you want to run UI or API tests. And if you click develop, it gives you the option of starting up the UI, the API, or both. Because one thing that I really liked about Meteor was that you just ran Meteor start, and it started the server. It started the client, and they kept all of their logs in one spot. Granted, I know that that is not What some people like, but I like that about Meteor. In fact, Tom prefers to have them both separate, but I like to have it just on one little thing here. So I gave myself the ability to run either of them or both of them together as, like, develop, develop both. So if you hit Node avalanche, enter, enter. It will just spin up the whole site in both things. So I thought that was really nice. Building a custom CLI was just a bit of a fun little experiment for me. But at the same time, if I'm gonna have a mono repo with several smaller folders and several smaller projects. I want a way to run operations across all of those all at once rather than CD, API, then NCU, and then CD, UI, NCU. Just trying to save myself some time. You know? Another small thing is that we used Caddy Server, which I never heard about, but apparently, Wes had. It's a Go server, and this allowed us to quickly and easily generate Signed SSL certificates for local development and have us up and running with, like, reverse proxies So that our local environment is leveluptutorials.dev, which I know is a real domain, a real TLD, But we have it in our host file, and we have a reverse proxy. So that way, all the the difference between our our local host and our our production environment is c s f. Just .devor.com, and both of them are fully SSLed so that we there's no weird SSL things that could Possibly come up in the production environment that we won't catch in development.
Built custom CLI tool called Avalanche
Scott Tolinski
So everything is trying to run pretty similar. And lastly, testing, we're doing just f. For all of our API testing and Cypress for all of our UI testing, I've ripped out all of my Gest testing on the front end. It turns out when you're not using Babel, Jest has a ton of issues because, like, Jest will all of a sudden not be able to understand nonstandard JavaScript, and then you're like, okay. K. I gotta run a build on each one. I gotta run my own custom thing here and there. And there is a just ES build plug in, but I didn't have great luck. We're using it on the server. But once you get into the land of, like, too many extra things right? We got TSX. We got no babble. We got providers up the wazoo, whatever.
Switched tests from Jest to Cypress
Scott Tolinski
Our tests were so unreliable in the sense that it was the tooling around the tests that were causing tests to fail, not the tests themselves, not the code themselves. And I was like, I do not wanna spend the time on this. And Cypress basically just runs your tests in a real browser. So if your shite's working in a browser, that's how it's gonna work in Cypress, and I didn't have to write any config to get it to do that. So it is fantastic, and it's gonna save us so much time. I really like Cypress anyways. So for me, It's almost like I got to take a big, deep breath. Like, it's over. I don't have to write just configs. I don't have to write unit tests for my React components. I can just test them all as they're being used in the real browser, and it's gonna be okay.
Caddy great for SSL and reverse proxy
Wes Bos
This Caddy server is really cool. I heard about it probably, like, 6 years ago on Leo Laporte's show, like, Floss Weekly, like, a long, long time ago, and I've been following the dev on Twitter for years. And I always thought about moving over my reverse proxy. A reverse proxy is like a web server that sits in front of your node app, And it allows you to run multiple node apps on a single, like, DigitalOcean droplet or something like that.
Wes Bos
It's pretty sweet, But I've never, like, done it in production, but didn't realize, like, it's also a great way to just quickly get a local SSL certificate
Scott Tolinski
running. That's the biggest value that it's providing us. Yeah. That's cool. It's so simple.
Scott Tolinski
And you know what? I've written a lot of NGINX configs. I've written a lot of, you know, it sucks, custom SSL stuff, and it sucks.
Scott Tolinski
You know what? The config that we have, the Caddy config file, let me tell you. We have 2 domains here with wildcard SSLs, everything in local whatever, reverse proxy, And our caddy file is oh, man. It is 12 lines, but it's really if you were to count how many lines have something on it, it is Five lines of actual config.
Wes Bos
Okay. Give me that. That's awesome. You know what? This should be integrated into is, PM 2 Because PM 2 will do the like, you can have multiple node processes, and it will restart them. And if they crash, it'll try. Like, I always wanted like that, but then also build me build in a web server versus proxy async automatic SSL, because that's the other part that's hard about running it. And, like, those 2 things together, you could create such a slick little host all your node projects thing on, I think it'd be cool. I bet it wouldn't be that hard with Caddy.
Scott Tolinski
Yeah. And I I'm really looking at, like, what it will take to turn this thing that I'm calling Avalanche into an actual project that other people can use, and I have some neat ideas about it. So it's very likely that I'll be Open sourcing this in in some way, at least, the shell of it. I find it to be immensely useful in up and down the stack, the fast refreshes.
Scott Tolinski
We wrote our own account system. We're gonna be doing an episode on that. So I would include accounts with it, connection to the database.
Scott Tolinski
You know, it ended up could be the, You know, Rails for node thing that we always talk about is really kinda how I see this thing between the code gen and everything. Can I write a plug in for it called Joe Sakic? Oh, of course. Of course, you can. All of the plug ins should be named after Colorado Avalanche because you may not know they're going to be the best team in the league this year, Wes. And to jump on that bandwagon, I ordered a an avalanche hat the other day so I could pretend to be an avalanche fan. When I was a kid growing up in Canada, like, I didn't Caribou hockey, but, like, everybody had jerseys.
Wes Bos
So, like, my team was the avalanche, and I had, like, a couple Avalanche jerseys. I think I had a Patrick Waugh Jersey, which is pretty pretty sweet. That is pretty sweet.
Scott Tolinski
He he had a whole thing with Detroit. We're we're not big fans of him in Detroit. Oh, no. Alright. Well, you moved out. That's okay. I did.
Scott Tolinski
Alright. Well, that sounds like a pretty sick new site. Thanks for sharing that. If it's not up by the time you're listening to this, it'll be at beta.leveluptutorials.com, but This episode's coming out, like, February 1st or something.
Scott Tolinski
I have every intention of getting this up and live by February 1st. So you'll be able to tell I'll buy if the site is server side rendered, then it is the old site. If it is not server side rendered, it is the new site. Awesome. Alright. Thanks so much for tuning in. We'll catch CSF. You on Wednesday.
Wes Bos
Peace.
Scott Tolinski
Head on over to syntax.fm for a Full archive of all of our shows. And don't forget to subscribe in your podcast player or drop a review if you like this show.