over 2 years ago Syntax Podcast
How We Made Syntax.fm Faster
- 00:27 Talking about performance issues we hit building new Syntax site
- 01:35 Old Syntax site explanation and differences from new one
- 02:52 Clarification on how old Syntax site was generated
- 04:09 Ways to test and measure website performance
- 05:14 Using Sentry to identify slowest routes and database queries
- 06:26 Slowest database queries revealed issues with findFirst method
- 07:51 Transcripts were loaded for all show pages causing slowness
- 10:19 Refactored routing to lazily load transcripts only when needed
- 12:17 Wes discusses how he wishes queries could be colocated in components
- 13:55 Caching as solution for many performance problems
- 14:42 Using Upstash Redis caching for database query results
- 17:19 Option to invalidate cache on new builds
- 18:20 Caching times for new vs old show pages
- 19:44 Wes recommends trying Redis caching
- 21:16 Adding cache headers for server side rendered pages
- 22:20 Summary of optimizations made
- 24:06 Issue with LinkedIn not displaying proper open graph images
- 25:21 Reason LinkedIn issue occurred and solution with more caching
- 26:11 Overall suggestion to use Redis caching
Caching times for new vs old show pages
Wes Bos
10 minutes, but it is seconds. Yes. 10 minutes. Plus, Upstash has a nice, like, a nice login API where, like, you can literally if you're wondering, is this thing cached or not, an hour's worth of talking, and every word has a start, a stop, a confidence, if you want the type of control that we want over it. Now, The the way that we did the tabs was that the transcript data
Scott Tolinski
Stuff. It's it's been cheaper than that. So, you know, hey. I was concerned again that it would start to add to the cost in an unhealthy way, but it's been very cost effective. Yeah. Certainly, I would recommend
Scott Tolinski
about paying for a service for this because in the past, long story short of this entire episode It was, with Well, it turns out that find first is really just a find mini with a limit of 1,
Wes Bos
Right? Like, 66 100 milliseconds? 600 milliseconds. Nothing. Yeah. So you're only caching it for like, I wonder.
Scott Tolinski
where I did it before for level up tutorials.
Scott Tolinski
any sort of limits for the the one of the reasons why I got that wrong is because Wes Wes primarily knocked out the the first website. So I I didn't have a whole lot of hand in building it initially. But the this website, things you have to worry about. You have areas where it's much easier to be slow because instead of having Now if you've heard
Scott Tolinski
what we need to be spending yet. So,
Scott Tolinski
I'm used to spinning up a, like, a private Redis server
Scott Tolinski
on render.com Vercel's score, which is like, hey. A lot of people are hitting this thing, and it is slow. Therefore, there's a lot of opportunity here. Right? into HTML
Wes Bos
Of this thing, you can just log in to Upsash, and they have a nice little GUI for you can you can go look at it, and you can just Click the delete button if you really want to. Totally. And what's great about Upstash is the pricing was very reasonable. I mean, we're not spending really we haven't even hit
Slowest database queries revealed issues with findFirst method
Scott Tolinski
So using the queries tab, we're able to see okay. I'm seeing that I have their library to do the Upstash caching, which is basically the exact same as Redis' API. You set something with a a a key, And you retrieve it with that key, key value store. It's really just as simple as that. And the way we're doing it is we're saving Each database call for each show into the cache.
Scott Tolinski
And so with that information, you have the the web vitals. You have the queries. You have the general performance features here in Century, and then you have things like the eye test. You're using the site. You're feeling how slow it is. You can really dial in exactly what are the biggest things you should be looking at first we were able to pass in via a slot either the the show nodes Or the transcript. Basically, whatever tab there. So instead of having that tab function with a if statement is being cache to see if the show's in the cache. If it's in the cache, we return the 1 in the cache. If it's not, And then start there. So the first thing we did,
Scott Tolinski
And I was thinking find first. Maybe stuff. Maybe there's an issue with find first. Maybe we're missing an index or something.
Scott Tolinski
And the method that we actually wanted to use was find unique, better performance. That's an easy fix right there. So We just changed all of our find first to find unique. Easy fix, performance win, nice. So the other thing we had was, the transcripts were being loaded.
Scott Tolinski
method diagnose this for being slow. And and for me, And because of that, we were able to see exactly
Scott Tolinski
knowing that we have a database here, was we looked into the database calls Specifically.
Scott Tolinski
And that made me think about something. This is, you know, really my 1st big site with Prisma.
Scott Tolinski
There were a handful of ones that stood out as consistently being slow.
Scott Tolinski
a bunch of really slow database queries, and all of them were the find first some of those things less heavy. You're not having to worry about
Reason LinkedIn issue occurred and solution with more caching
Wes Bos
Threw the image into Redis
Wes Bos
And the show page. So when you visit one of the episodes on Syntax,
Wes Bos
then
Wes Bos
image. So I was like, hey,
Wes Bos
generate a fresh one and that boom. That fixed it, deployed the sucker, and now we got nice Open Graph images nice and fast on LinkedIn. Nice.
Wes Bos
is ideal at a cache it at a CDN level.
Wes Bos
if it is in there, I still left the like Vercel CDN stuff on there because I feel like that The data for every single word
Wes Bos
Scott, just put this Redis thing in here. I'm going to use that.
Wes Bos
So I just grabbed Redis
Wes Bos
And that was frustrating because it was taking too long and LinkedIn was telling me it couldn't find the Open Graph
Wes Bos
But to solve the LinkedIn issue, I'm now also caching it in Redis, and I check if it's in Redis before we go ahead and
Old Syntax site explanation and differences from new one
Scott Tolinski
any of these show websites were generated
Scott Tolinski
bring on slowness, and that's really what the problems mostly were. I I would say Just about all of our problems were solved with server side fixes rather than client side fixes. Yeah. And I'll correct you there, though. The old site wasn't it's going to be 600 seconds. If the episode is older, it's gonna be 3,600 calls for We we are now able use this feature where we can pull out and have this information wrapping some other information as a true nested route.
Scott Tolinski
Basically,
Scott Tolinski
And I think it's also important to note that like, You know, you had some of it with the eye test. You use the site and you say, key creation. Yes. That's totally true. And we could do that to extend the lifespan of the cache. But, again,
Scott Tolinski
at compile time, which is really going that way. But, honestly, this has been cheaper
Scott Tolinski
steps that can file, maybe not the hash, but you could use some sort of unique identifier to say that this show has been updated, maybe the time stamp for when it was last updated, caching platform
Scott Tolinski
You suddenly have some
Scott Tolinski
database, you bring in server side processes and things like that, same strategy
Scott Tolinski
Totally.
Talking about performance issues we hit building new Syntax site
Wes Bos
stuff and for different reasons. So I think it's kind of an interesting Okay. That's a bit nicer because, like, then you don't have We needed to be able to
Scott Tolinski
We we got our hands dirty.
Scott Tolinski
performance here.
Wes Bos
Made it faster.
Wes Bos
several spots in the new website that were was being loaded I thought, to just cache them on the 1st sell CDN, right? In the past, I had actually stuck those values in my own website. I stick them in just in memory. I store them for a couple hours or whatever, and I had never had an issue. But
Scott Tolinski
We looked at metrics. We looked at time lines, flame graphs, and all that stuff, and we made it faster.
Wes Bos
a little sluggish the actual show page, which is is is good for, like, performance. You you flip over to it, but it's It takes way too long, and the chances of somebody visiting the page and clicking over to the transcript is is pretty low. Right? Most people are probably not going to the transcript tab. If you are, that's fine. That's fine to have a bit of a larger load on that page, but it doesn't need to be loaded. That data doesn't need to be loaded when you visit just the actual page. So you
Wes Bos
episode to sort of say, all right, these are the problems that we hit
Scott Tolinski
you know what? It could always be faster. So you know what we did?
Wes Bos
on the different aspects of performance. And and here's how we figured out what was causing it to be slow. And here's how we actually
Scott Tolinski
We're gonna be telling you all about the tips and techniques that we implemented Yeah. In general, client side JavaScript performance was nice and easy. Beautiful. Alright. Thanks for tuning in. Catch you later. Deep.
Using Sentry to identify slowest routes and database queries
Scott Tolinski
what are the things we should be focusing on first, which are the slowest pages,
Scott Tolinski
Across all of the routes of our site. Another thing that we're able to see using the queries show number forward slash slug is the slowest route. Actually, that's the slowest route now, but it wasn't because we'll talk about some of the changes we've made there.
Scott Tolinski
and
Scott Tolinski
Largest contentful paint, the 1st contentful paint, 1st input delay, cumulative layout shift. We're seeing all of that information newer shows you know, again, that one didn't have a database. I think it was the big thing. And the database Which, if you wanna learn more about that, we did an entire And we also use stale while revalidate
Scott Tolinski
the what is the LCP are you going to be having to do that massive DB call, which is going to save us a considerable amount of time and did.
Wes Bos
Largest contentful paint.
Scott Tolinski
a handful of red perf scores
Scott Tolinski
Which have the most opportunity to speed up,
Scott Tolinski
feature within within Sentry is we were able to look at all of our database queries, We realized that not everybody who hits the page is even gonna click on that transcripts is we used a service called Upstash.
Scott Tolinski
And it tells you all kinds of information, like the average time to first bite,
Scott Tolinski
and we're able to see which of our database queries were the slowest consistently.
Scott Tolinski
So that's the web vitals. Right? You're seeing time to first bite. You're seeing, show page,
Scott Tolinski
largest? You can run it through Lighthouse or all kinds of things. But what we did is since, you know, we're Presented by Sentry here. We use Sentry, and I don't want this whole episode to turn into a Sentry ad, but we did use Sentry's performance tools to make this thing faster, what tools we used, and what we learned along the way. My name is Scott Talinski. I'm a developer. I'm from Denver. With me as always is Wes Bos. What's up, my man? Hey. I am than running a private Redis server I would imagine that there's some issues here, That data being cached as single files that can be loaded and ready to go, you gotta do a database query. You gotta check some things first. You gotta have all sorts of additional database than it is the build of the site. Right? Exactly. Yeah. You maybe don't want that. Right. You could use the hash And
Wes recommends trying Redis caching
Wes Bos
either a, try to implement have a new build, Your entire cache is invalidated. And and generally how I don't know if this is how they do it, but you can just use some sort of unique identifier key as as part of your, rejigged commit it, wait for the thing to build,
Wes Bos
to your data Like, Paul Payne said it was working fine, but it wasn't working fine
Scott Tolinski
query, You can pass in the the function you're trying to do, and it will automatically check the cache and return the right one or whatever without you having to do do that manually each time. Just a nice little helper. Adding the if statements? Yeah. Without adding the if statements populating your code. So now you just do a a cache function, cache call function, and and pull in that data directly in there. And, And, honestly, it's been really super nice, and, it it it's sped up the queries The opportunity likewise, older shows
Wes Bos
and then just
Wes Bos
You do that a lot. You can create a map outside of your 15 seconds if it has to fire up a new browser, about 8 seconds if it doesn't have to fire up the browser and take the thing. And that's too long to wait for an image to load, right? So works. Alright.
Wes Bos
You do have to add like a timestamp the entire transcript. And inside of that, you have what are called utterances, which is like a a word or,
Scott Tolinski
instantly. Absolutely.
Wes Bos
if you're listening to podcasting and you're trying to go a little bit further with your server side development is
Wes Bos
It's no different than a lot of like local storage settings that you've probably done in the past or Try build next time when somebody requests the image, I check In Redis, On when you were visiting Like, Apollo will take a Next. Js site and walk the component tree looking for queries.
Wes Bos
function handler what it's going to display, and
Wes Bos
a Redis cache yourself.
Wes discusses how he wishes queries could be colocated in components
Wes Bos
I I run into this quite a bit with and
Scott Tolinski
Yeah. Totally.
Wes Bos
and loading data per page, and I Almost always tell myself, I wish I could put the query in
Wes Bos
databases frameworks.
Wes Bos
You know? And that was We have server components.
Wes Bos
I wonder if everybody else is going to start to do that or if there's a different solution there. Yeah. I I think the the idea of, yeah, just render it on the server and and send the HTML to the client
Scott Tolinski
Yeah. And, do you think React Server Components does, like, solve that directly? Because to me, it does.
Scott Tolinski
stuff. Clearly, like, a a client side jank from looping or something like that.
Wes Bos
With Apollo, they do that.
Scott Tolinski
if you if you're running into perf issues, right, if it's not What we used For some of the key pages on the site, the index page and the show page primarily were the 2 biggest ones.
Wes Bos
Yeah. Apollo, like, Apollo GraphQL.
Wes Bos
stuff. Fixes a lot of that, and it it makes your components a lot more Say, well, if the map has this key, then return it.
Wes Bos
the component itself.
Wes Bos
to decide at a page level what data you want. You could just put the query in the in the component itself, and then the page should figure out, oh, well, I'm I'm not rendering this component, so I'm not gonna fetch that just yet. So I think that's something that could possibly be improved something with LinkedIn would always cause whether they were putting parameters on the end of the URL or whether sorry, not meta tags, whether their user agent was different and Vercel was allowing them to regenerate it, I could not get them to hit the cache
Wes Bos
portable.
Option to invalidate cache on new builds
Wes Bos
and maybe that's the that's the indicator. Right? Yeah. But in most cases, just go grab a coffee, and it will be fixed by the time you're done.
Wes Bos
And then As soon as you do a new build, I know with, like, a lot of Vercel's CDN stuff, they do something similar to that. As as soon as you
Wes Bos
Like the build cache or the latest git commit as part of the key. Mhmm.
Wes Bos
you could stick the,
Overall suggestion to use Redis caching
Scott Tolinski
and don't forget to subscribe in your podcast player
Scott Tolinski
or drop a review if you like this show.
Wes Bos
That's it. Hopefully, you learned a thing or two about making the site faster. It's kinda interesting. We've we've talked a lot about, like, the client side performance in the past, and we didn't have any. I don't think we had any client side performance issues, did we? I don't really think so. No? I you know, I think the server side rendering aspect of the site generally makes, And I think Quik does that as well where Are you talking about Apollo? when I actually posted it on LinkedIn.
Scott Tolinski
So, basically, the,
Scott Tolinski
is dump it in redis.
Scott Tolinski
Head on over to syntax.fm Oh, that's good. I was gonna think about that. Yeah. I mean, I come from the world of Drupal We we we didn't have to memoize things. We didn't have to use callback. We didn't have to do any of that stuff that you might have to worry about.
Scott Tolinski
skeleton screens as much. I I think sometimes maybe the the client side stuff that is even slow is still almost always data loading, but it's not database caching and had the correct
Refactored routing to lazily load transcripts only when needed
Scott Tolinski
To the page of the transcript page, basically saying, hey.
Scott Tolinski
transcripts tab to load those transcripts.
Scott Tolinski
Most of the show information and good cache headers for us to make sure that those were fast. Bingo. Bango.
Scott Tolinski
into the layout
Scott Tolinski
of the page.
Scott Tolinski
And then we were just using, like, basically an if statement to show or hide the transcripts. Right? is a really great lesson to learn a little bit more about why you might want to use that.
Scott Tolinski
route.
Scott Tolinski
And that way, just like before, you could hit forward slash transcript and get to the transcript page, but only then You start with the heaviest loads, and you dump them in redis.
Scott Tolinski
So what we did is we moved the database as well because you need to know when to expire it, and that's sort of the nice API of this Upstash 1. And in Redis, in general, you can set an expiry in seconds. Yeah. That's actually a really great thing about this is being able to set that expiry in there. That way I don't have to do the math myself. Yeah. I also just wrote a a helper function So why are we doing that heavy lifting for everybody on the initial load of the page? My name is Scott.
Scott Tolinski
abilities of nested layout. So, you know, the way that we had it before was that both of the queries,
Scott Tolinski
to the layout itself, and we moved most of the HTML
Scott Tolinski
Then using nested layout routing, Half a second? Oh, 600 milliseconds. Are you 600 600 seconds, probably? 600 seconds. Oh, man. That always gets me. I'm sorry.
Scott Tolinski
were being done in 1 fell swoop on the page. Right? It was the Heavy client.
Wes Bos
And I with Hide and show depending on on what we have there. However, and how much longer is left on the expiry
Scott Tolinski
And
Clarification on how old Syntax site was generated
Scott Tolinski
this thing doesn't feel as fast as it should feel, And I have really fast Internet.
Scott Tolinski
and, So those were some big, big things that we did on the database side of things to improve loading on the heaviest pages, and it it that alone had a huge impact.
Scott Tolinski
Aspect. Just markdown files? Yeah. Was is really one of the heavier loads of it all. So first and foremost, for a full archive of all of our shows,
Scott Tolinski
how did we know It was slow. Where did we go? What did we do to diagnose this for being slow? And and it it was check, we first
Wes Bos
push out new shows as soon as they were released, and we didn't want to have to regenerate every single
Wes Bos
No. It was generated on demand, and the only reason it was generated on demand is because
Using Upstash Redis caching for database query results
Scott Tolinski
where anytime you make any change, you click the delete all cache button because everything is cache so hard. Yeah. Everybody knows in in Drupal world that your cache is almost always going to be the problem. So You know what you could also do is We pushed a, you know, a new syntax website. We did a ton of work into it. And So while we could have used we were seeing within Prisma.
Scott Tolinski
Automatically will retrieve a new one from the database every so that way you're not having to hit the database all the time, and what you're hitting is a cache.
Scott Tolinski
that Vercel is releasing their own 692
Scott Tolinski
When it retrieves a new one from the database, it then updates the cache. Right? And,
Scott Tolinski
milliseconds.
Scott Tolinski
and paid the premium on top of it, And then, like, that's it. That's the whole strategy there. So, hey,
Scott Tolinski
That way because the older shows, they, you know, they don't get updated as much. And let's say we have an uh-oh in one of our show notes or something. We need to Update it really quick. We can make that update and be assured that not everybody's going to be served the old cash. Now I also created in the admin section list, I don't know if you've seen this, a drop cache button. In an emergency, we wanna just completely nuke the cache. You can click that button. It's just gonna delete the cache entirely.
Scott Tolinski
600 milliseconds.
Scott Tolinski
Caching platform. I believe it's called KV.
Scott Tolinski
makes way more sense to just use Upstash itself. I mean, why wouldn't you do that, right, especially if it's the same? And and, basically, it is using Redis, But it's using Redis with a serverless cost wise, it's really good. I was very apprehensive
Scott Tolinski
You might have heard that KV is just a wrapper around Upstash.
Scott Tolinski
we get the one from the database. So you're only doing the database calls when you have to get, so many perf issues, and it will, you know, set your Internet speed to be in your your network tab, and you can load it up that way and measure it.
Scott Tolinski
information from the database. Now when do you have to get information from the database? Well, we set it up on a millisecond timeline. So
Scott Tolinski
So we were able to use Upstash,
Scott Tolinski
will be there for 3,600 an absurd amount to solve our issues. And and I think it's important to highlight that because for if the episode is newer,
Scott Tolinski
we
Scott Tolinski
And when we
Issue with LinkedIn not displaying proper open graph images
Wes Bos
stuff. Those those images are are pregenerated
Wes Bos
and cached.
Wes Bos
at all.
Wes Bos
guaranteed that there was a
Wes Bos
So I was I was watching the Vercel logs come in. And even though I I
Wes Bos
header name versus description and meta. And I was talking to, a little in memory cache with a map in JavaScript because you can
Wes Bos
from generating it beforehand, I had hit pregenerated. Like, it wasn't HTML.
Wes Bos
for some reason, LinkedIn would not hit the cache.
Wes Bos
And I was using stale while revalidate
Wes Bos
on LinkedIn,
Adding cache headers for server side rendered pages
Scott Tolinski
in terms of how long it's cached for.
Scott Tolinski
Another thing we did is since our site is fully server side rendered, we just made sure that every single heavy route got cache headers, and we did the exact
Scott Tolinski
episode on that. Wes, do you have that episode number handy? Let me see. Stale man. The new syntax search. Let me just tell you. The new syntax search is so fast. You need stale while revalidate. Episode 100
Scott Tolinski
as well,
Transcripts were loaded for all show pages causing slowness
Wes Bos
What I did is I was like, okay, like the transcript doesn't need to be on every page, so it needs to be on its own, like a separate tab, right? So I wrote some tabs And then I wrote a route that would catch whether you're on the show page or if you're on the show page It it takes
Wes Bos
We had the player. We had To try change something,
Wes Bos
transcripts, then
Wes Bos
ID attached to every single one is just way too big. So we I scrapped
Scott Tolinski
how SvelteKit did all the nest nested routes? Yeah. And this is a testament to the the
Wes Bos
And I'm just getting just in in dev. And it was just it's way too slow because the amount of JSON
Wes Bos
because You know, if you want to highlight the currently spoken word.
Wes Bos
You need, like, imagine
Wes Bos
So I was like, all right, we'll save all that data. And I was loading
Wes Bos
the every single utterance that I'm able to figure out the currently spoken utterance
Wes Bos
massive because, and gave it a decent expiry.
Wes Bos
the show notes for that specific show and a couple of other items on that page. And then when it came time to implement the transcripts, to talk about this because there was a lot of these first of all, before any of this stuff happened,
Wes Bos
yeah, you have
Wes Bos
And a speaker 8 and 15 seconds to generate the Open Graph image because it has to fire up
Wes Bos
we just had, like, being able to highlight the currently spoken word,
Wes Bos
depending on the specific time. But
Wes Bos
The way that we did
Wes Bos
2 or 3 sentences. And then inside of the utterances, you have every single word, and it tells you when the words have started and stopped. And I've saved all that data in the database
Wes Bos
there may be a time when we want to build like some sort of video tool that will,
Summary of optimizations made
Wes Bos
OpenGraph namespaces And finally,
Wes Bos
episode At like 9 AM on Oh, right. Friday morning. So we we did the stale while we're validate where
Wes Bos
and we'll send it out the other way. I know there's lots of libraries out there. This is the absolute best way, I guarantee you, the transcripts itself are They're absolutely
Wes Bos
tags. So I spent like CDN hit
Wes Bos
it would not pick up the Open Graph
Wes Bos
And they weren't working on LinkedIn. So I went down the whole rabbit hole again, which is my, like, least favorite thing to do is
Wes Bos
go to the whatever tool that I'm using. In this case, I had to use the LinkedIn
Wes Bos
Yeah. In the, 692,
Wes Bos
Killen from Polypane because,
Wes Bos
1 issue with that, and that was with LinkedIn. So I noticed that whenever we shared
Wes Bos
debugger tool you visited the website, and then it gave you the hash version, and then it generated a new version in the background for the next person. Yes. And that was in Next. Js,
Wes Bos
to load part of the website that generates the OG images. That takes a screenshot
Wes Bos
stay while revalidate, I talked how we're using it to cache our OG images that are generated. So real quick, we use Puppeteer
Wes Bos
2 hours trying different tags and different
Wes Bos
one of our episodes on LinkedIn, we weren't getting the really nice Open Graph images. And those Open Craft Images have been doing super well for us on all of the other platforms. We're getting a lot more traction of people clicking them because they they look awesome, right?
Scott Tolinski
Lots and lots of speed improvements.
Wes Bos
and then press the button And it would scrape it and give you a little bit of information about
Ways to test and measure website performance
Scott Tolinski
and that can be backed up by all kinds of data. I mean, granted, you could load up your dev tools. You could, And, likewise, we move the transcript database call
Scott Tolinski
1st and foremost,
Scott Tolinski
here is the slowest route of your site. Not the slowest page necessarily, the slowest route. It's able to see show us that the forward slash,
Scott Tolinski
we loaded up the the Sentry performance tools, and they're showing you web vitals across every route. And one of the things that shows you, database calls, adding indexes, those types of things, and then caching. Caching Cool. Well, next thing we did, which is, you know honestly, I would say
Scott Tolinski
on that page is that
Caching as solution for many performance problems
Scott Tolinski
in your stacks Either way, those those caching sped up our initial loading, but we just made sure that every single page that we needed to make sure was fast
Scott Tolinski
solve them really effectively because, you know, again, some of the heaviest lists that we had in the site We're going off to do the database calls. Whether if that database call takes 200 milliseconds, that's 200 additional milliseconds you're tacking on to the entire load of things. Takes longer than that. Again, that's that's tacking on to every single time you do that call. So what you wanna be doing is caching those calls, API.
Scott Tolinski
And that cache can be something in memory, which is Basically, just saving it to a value or can be in a, a memory level store like a Redis store.
Scott Tolinski
I would say so many perf issues
Scott Tolinski
can be solved by a couple of things, optimizing
Scott Tolinski
will solve
Transcript
Announcer
Boss, and Scott, El Toro Loco,
Scott Tolinski
Welcome to Syntax. It's episode number 708, and we're feeling great. We're gonna be talking about hey, we launched And we went from a site that was relatively simple. Everything was really generated. It was a static site.
Announcer
Tolinski.
Announcer
soft skill, web development, the hastiest, the craziest, the tastiest web development treats. Coming in hot. Here is Wes, Barracuda,
Announcer
Monday. Monday. Monday. Open wide dev fans. Get ready to stuff your face with JavaScript, CSS, node modules, barbecue tips, get workflows, breakdancing,