skip to content

Port a Blog to Astro

with Jason Lengstorf

For many devs, writing blogs with Markdown/MDX is still preferred. In this episode, Jason (a Markdown True Believer™) will be working on an in-progress port of the Learn With Jason blog to Astro.



Captions provided by White Coat Captioning ( Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

Jason: Hello, everyone. And welcome to another episode of Learn with Jason. Today, on the show, we're going to be solo, just you and me today. I'm going to be porting over the Learn with Jason dot Dev blog to Astro. And so as many of you know, this site is built on Remix right now. I really like Remix for managing the episodes. It's very good because I have to do a handful of like cascading fetches because the, like, the show has an API that brings in all the episodes but I can't pull complete information for the episodes because things like transcripts make the output absolutely you think reasonably large.

For each episode, I need to pull the episode data and get the transcripts and pulling in related episodes and stuff and being able to do that in Astro is really nice. However, Astro is not built for blogs. I write in MDX because I have a couple side components a figure component that does stuff. That has just been a really, really challenging -- I think it's because I'm holding the tool wrong. Right. So I want to use the right tool for the job instead of trying to force tools to my will. Because I'm on Netlify, I can proxy the blog in with Learn with Jason as a completely separate site. I will be able to make this all run and do what I want without having a ton for -- like it doesn't make it that much more complicated -- I think it will make it a bit simpler. That is sort of my intention here.

Hello Portland, Oregon. I mean what other Portland is there? I guess you can go to Portland, Maine I heard has cool things going on but I've never been there myself. I see Lynn in the chat and Brian in the chat. Tell me how are you doing. Did I say that Remix is not built for blogs. Yes. Remix is not built for blogs, Astro is built for blogs. Oh, yes. Hello to Wasim in India. American 2015, we I'm live.

I don't know if you saw this but after my stream on Tuesday I needed to record a demo. One of the things they promised Netlify I would do and didn't get down is a video demo, a walk through of what's the Dev flow, why is it cool.

And I just, you know, I use OBS to record my desktop and I have it set up where I have my desktop here and my video here and I record both and cut them up for editing and stuff. I just hit the go live button also so I recorded 25 minutes of me talking to the camera. And yes, that's what it looks like when I don't know I'm being watched. Talked a little more crap to my computer but otherwise basically the same.

Yes, Bobby Tayhole, that is me. Thanks for the sub. Thanks Mark Bruno, I have fun creating them and I'm glad that people get value out of them. That makes me feel nice. Good warm fuzzies for the day.

I like Astro, I think it's a cool platform. I love the overall approach. It feels really familiar to me. And like, you know, I feel like there's sort of a spectrum of complexity when it comes to building for the web and there's a spectrum of complexity when it comes to what I want to put on the web, right.

What I like about Astro is it fits really well into my particular niche. I want a blog and I want to overengineer my blog but I don't necessarily want my blog to be so overengineered that I can't figure out why the Dev server won't start. Or I'm having to set up file tracing so I can make sure the right bucket of files is included in the bundled out put. That is what I ran into with Remix. Remix wants you to read the MDX at server time.

So you're now getting into all the things that I don't like about running servers which is you have your site that needs to grab a file and parse that file and put it on the internet. Like, that's fine but it feels rickety to me. I kept fighting these problems where I want to move my blog into a monorepo. I want Learn with Jason to be a mono Repo.

I did that because I have scenes, I've got web hooks, I have APIs, I have sound effect, I've got the blog itself, I've got the rest of the website. I have an e-commerce store. There is a lot going on in Learn with Jason and I've been cramming it all mostly into one repo except for the stuff that wasn't in that one repo.

And I was copying and moving stuff around. I wanted shared components around my colored components and my logo and I icon sets and stuff like that so I have each of the sites pulling from the same shared components and also I can develop all of that locally. And if I update the shared components, I don't have to then go publish to NPN and update all of the dependencies.

I just update the shared components and because it's a mono repo and NX is smart about this, it takes my site and say, the ones that need to build will rebuild and the ones that don't pull from the cache, the build ends in a few milliseconds. That, to me, is the magic of setting up a mono repo. When I went to put the Remix into the mono repo, everything worked great except the blog. The blog exploded on me.

I'm sure that I'm holding it wrong. But at the end of the day I spent enough time on it that I decided it would be better to put it on Astro and it's a good excuse to steer into my -- yes, it lets me steer into my exploration. I haven't really built anything serious with Astro. I've only played with it for a few things. I'm excited to give it a shot and do some stuff.

Kelvin is on Astro. Who else is on Astro in production now? Procrastinator, Mastermind, just heard of Astro. Yup. Functions in front matter. Yep. Yes, so Bobby Tables is calling out here, I don't want my blog to require a server. And it just ends up feeling, I don't know, I mean like, I don't want us to lose sight of the fact that there's a reason when things like static sites got branded at the JAMstack, it was this idea that you should be doing as little as possible.

Instead of calling it the JAMstack, call it the rule of least power. Why would I need more than just my blog to be a static file that is served to everybody. I want that capability in any framework that I use. And so that's one of the things that has been a bit of a bummer for me with, like, next JS where they're getting rid of the export functionality and Remix doesn't want an export functionality. I get it. It's different tools for different things but this really starts to make it important to choose the right tool.

When next had an export, it could potentially be use it for everything. You export the pieces you don't need -- that you didn't need and you use standard next for like the dashboards and stuff. But everybody is going all in on use servers, use servers. I remember using servers and it wasn't fun. There were a ton of things that got really complicated really fast. I want that to be the thing that I do because I have a good reason. Not as my default. So yes, that's my reasoning here.

And that's, yes, all right, yes, Chris is here, using Astro. Brian has some things in there. Sarah is here to watch. Richard, doing the Nux2 site in Astro, nice. Two content sites.

Musha is, oh, why should I use Astro instead of Gatsby? This is a great question. So I'm going to start by saying one of the reasons is that Gatsby has a bit of a checkered past. If you look at their interactions with the community, they don't have the greatest track record. That is one reason. But let's leave that aside and talk just on tech.

The biggest reason for me is that what Gatsby excels at is the stitching together of lots of different content sources. The reason I would reach for Gatsby if I were to reach for Gatsby is that they allow me to use this really robust set of plug ins to source content from all of the third-party systems that my team uses.

From whatever and I put that together into one data layer that I can query on any page. It makes the experience of building these complex multi-back end sites very, like predictable and standardized and that is wonderful. But, I'm not doing that.

I'm using Markdown. And so for me, writing a blog in Markdown with, we'll say MDX because I'm using a little bit of components in there, writing a blog in MDX, I have files. I have a tiny bit of external stuff. But I'm not pulling in content from anywhere else.

I'm not, I don't have third-party systems. So using Gatsby data layer to read it back out feels overwrought to me. It feels like I'm adding complexity for something that doesn't provide any benefit for my use case. What Astro is so good at is that I'm, I want to write some Markdown and see that Markdown on the screen. And Astro is really good at that. There is no extra layer of thing to learn. You just write the Markdown and there it .S if you export some -- you can use it. You know what I mean? It's straightforward.

I think that's the, again going back to the rule of least power, what's the minimum number of things I need to understand, the minimum number of moving part to work with a tool. If I was going to start getting into Astro with a whole bunch of different back ends, I would find myself starting to write utility files and helpers and things like that.

You're going to see this in the mono repo. Sanity, and helpers for notion, because I have a discord bot that lets me put guest ideas into notion with a slash command. Each of those have a helper utility. If I was doing that just for my blog, I would think more seriously, I need a data layer, a content layer like Gatsby provides. That's my reasoning and why I would make that choice.

Is service side rendering good for blogs? The less work we make Google's bots do for content, the more likely the content is going to show up high in the rankings. Let me be clear, the most important thing about SEO is writing something that someone wants to read. There is no hack that is going to make content that people aren't interested in show up at the top of the rank.

You have to think what is someone going to Google when they're trying to find a thing, right. Like, I write posts that are not SEO friendly. I'm writing philosophy posts. Why you should think about X like Y. Nobody is Googling why should I change what I think about the world.

But when I want something to get picked up, oh, someone is going to get this error in this framework and I'm going to write the post that helps them overcome that error. As soon as you get an error you copy and paste into Google and search and go to the blog that is most likely to give you a solution to your problem. That is SEO. It doesn't matter what technology I build that with, if I'm the thing that people want to read when they Google the error, that is going to show up first.

Yes, service side rendering is possible. Never forget the lamb stack. Yes. Just scan and scan and scan. If I move away from Gatsby, does that mean I have to throw out my awesome swag? No. I don't want you to feel like you have to stop using Gatsby. It's a tech company. Every tech company has skeletons in the closet. Don't boil the ocean, because the next one is going to have problems, too. Start digging, you're going to find bodies. I want to move one of my word -- to Astro. Yes, comment systems are a pain.

Have I done the state of JS survey? I haven't. I'm honestly a little bummed in the state of JS. For years now they have gotten feed back they need to work on representation and they have not.

I think Sasha is listening this year and he DMed me and was interested in forming a content review committee to hopefully improve things but I don't know. This year I was a little bummed to see they yet again made a list of content creators and half of them are not making content anymore. And they're all -- dudes.

It's a bummer to see that. Let's keep on scrolling down here. Glad you were able to make one live. Can you expect for burger content? I hope so. I'm going to do, I'll do photojournalism today because I have a ridiculous box of new toys coming as part of the doubling down on Learn with Jason, I'm replacing a bunch of gear. So I'm trying to get, I have like, I'm going to show you one piece and then I'm going to stop.

So this which -- am I out of focus now? I am. Hello, be in focus. There we go. This, you can kind of see is the Sennheiser box and inside of it is, I just forgot the model number, the MK416, I believe. I'm going to do my dangest to replace this mic with a shotgun mic so that I can be not having a microphone in my face.

I'm also working on setting up multi-camera. So I have the -- I have an old sonyA5100 that was my first DLSR and I want to use that for camera two. I have a bunch of ideas. I have a road caster pro-2 coming. I have an 810 mini pro-ISO so I can record sources in. Now when I do a recording, it's like, you can see that I'm in this box here, right. And the frames of this box, I can't get to the raw video file that is underneath.

I have to just like crop in. So it leads to quality issues and all that kind of stuff. So working on improving all that. I see Chris is in the lemon pod-casting is there in. This is all to make your life easier and harder at the same time. So, yes, Brian, exactly, I want to be able to do asides and if I'm cutting up a longer video and I want to make it short ore and I want to have alternative angles so I don't have to do the Zoom smash cut all the time.

Eddy, that is correct. I'm full-time on Learn with Jason as of this month. I ended my full-time employment with Netlify. Great company. The stars aligned. I can do this as my whole job and I couldn't say no to the chance to do this. How is it I get to hang out with y'all and that's my living now. It's incredible and I'm super excited about it and thanks. Thanks for making this possible, y'all. Speaking of which, let's switch over to code mode because that is a great segue for me to give a quick plug.

If I can pull the browser over here. Let me pull this on over and make it the right size. And is this the right size? Yes. I'm going to head over to the home page and do a shout out because we have, we have White Coat Captioning, Lora is with us today doing all of the live captioning. Thank you so much, Lora.

That is possible because of our sponsors, Netlify, NX and New Relic all kicking in to make this show more accessible to more people and that means a whole lot to me. Thank you, very much. This sponsorship, your subscriptions on Twitch, the purchases in the swag store, all the things that y'all are doing is the reason that I'm able to do this full time. I very, very much appreciate that.

This is the blog running on Remix. This is what we're starting, our starting point is. And what I want to do is I want to get all of this running on Astro. So this is, so this is the announcement post of me going full time. Let's see here, we've got -- hey, Brian thank for the Gif sub. The next year of Learn with Jason is going to be great.

Okay. So there are a few features here that I'm using Remix to build. The first one is I have these files are MDX files and I am having to read the MDX directly from the file system in order to build out this list. And then in here, I am also like pulling in the individual file and then I have to set up some react use effect stuff so I can do this piece here. Which is I want the headings to announce. And that is the whole, that's the whole thing. Right.

So I want to get this running. I've had a little bit of a head start here. I will show you, I'm in the mono repro-branch. I'm going to open this up and let's look at where we are.

First and foremost, this is an NX site, if you have never seen NX before, they are full disclosure, one of my sponsors but they give you handful of cool things where they let you kind of set, if you run a build, then anything that depends on that build is going to be built first.

And I can run it in the cloud which gives me cache able operations and this acts as token as publish. You can commit it and all that stuff. I'm not leaking secrets or anything.

And then what that lets me do is in my package JSON here I can set workspaces. In the workspaces NX is able to determine that anything under these folders with a package JSON is an independent site.

When I pop these open, these are the packages, I have a design system and helpers for notion in sanity and socket in studio was a company I was going to start a long time ago around the real activity of the blog, the chat delay and boop drop and sound effects are all done but socket studio.

I have helpers to make that work. And I have sites, the API, the blog which is what we're going to work on today. The discord bot, the scenes which are what you're looking at the, the overlays, the lower third and all that. The web hook. When someone signs up for an episode, I use Calendly for that and they will send a web hook to me that I can use to put the guest's information into notion. So Aiden is aware a new guest is added and it helps automate and keep life easier and this is the original Remix site.

Let's start by poking around in the Remix site. If we look here we have our routes and there's a few things to note about here with the episodes, like, this is so nice. I've got my episodes and I'm able to pull in, here's the data, I have my loader so I can load the episodes from the API.

And then I'm able to grab out the host and teacher and this little helper makes sure things are poly filled because the older guests don't have all the details that the new ones do. And I can load the episodes and feed them into a list component. This is exactly what I want. It's a pleasant workflow and brings all this into the framework and feels really good. I want to make sure that I'm being clear.

I love Remix. I think it's excellent. This is not me saying I don't want to use it anymore. I have hit a limitation of it. The episodes are great. You pull in the parameters you're welcomes get the episode from the slug which is in this case the whole thing. I make a query to the API around what it is. So I'm getting the name of the episode.

And then we, if it ends with JSON it redirects to the API. That is a cool thing that I did. If you check this -- I forgot I did this. Check this out. We go into the latest episode and I had dot JSON at the end and there is the JSON representation of the episode. This is another cool one that I did. You just like add things like that to the end of it. It gives you like different features.

Right. That's all because I have a combination of like Remix, so with the JSON detection and stuff, and then I also have the API which currently is tucked in here. This is kind of a mess. I have had to prefix things with API to find them. These are all my sound effects. I have Shopify stuff in here. It's hard to track what is going on. I had a misguided idea that if I make the sound effects into serverless function it would be easier but that doesn't work.

It will be an interface. If you log into Twitch you can submit sound effects. I will probably build that on stream because it sounds fun. There is a lot going on in here and it's hard to keep track of. I want that to be easier to track and that is why I'm splitting the API out into its own separate and the web hooks into its own site and eventually the store will be its own separate site.

So I have independent control over the things that I need and I can reply on the design system and different helpers to make sure I'm not duplicating code. It's still dry. Because I'm using NX, I can just import the packets. Let's look into why I think MDX on Remix is not the right call.

That is, first, I want to pull in like post styles. So I have to add this secret file here that is just to pull in the links globally. And like that is fine, okay, that's fine. I have this secret folder for MDX and inside of that I have the blog itself here. And this one is kind of, this one is hard for me. I struggle with it. So we got to get, like, is this even the right thing? Hold on.

Yes, yes, this is right. I think. No, it's not. See? This is why -- this is really hard for me. So this is the blog template, like a layout. By it's not the blog home page. The blog home page is in here as index dot JS and anyway, I just can't, I just can't, like, it's very clear that what I'm trying to do is against the grain of Remix.

So I have three files to manage just the index of my blog and any one of these, I am having to bring in this wrapper and these are my actual components and all of this is fine. It really is. I don't want to say this isn't manageable.

But then, the follow up problem becomes, this is all done like serverlessly, that means this needs to be included in the serverless out put and in here I'm having to do stuff like this which is like low level config of how Netlify is including files so this whole MDX folder ends up in the serverless function to Remix can interpret it and read things.

What are you all hemming on me? Can you all hear me? What is hell is going on? Why is my video down. Hold on a second. Let me figure out what is going on? Oh, there's this thing my camera does that is really annoying.

I have broken it -- let's see, we're going to reset the transform. There I am. And then I'm going to shrink this. I wonder why it's doing that. That is very annoying. Let's see, how big should I be today? This big? Bigger? How about this? That seems okay. I can -- what do I do. Alt click to make that smaller.

And that's me. I don't know. I don't know why it's doing that. Yes. So the problem is that somehow this video embed and the one on my paired programming are linked. And when I edit this one, it also changes the one for guests and causes absolute chaos. I don't know. I'm rebuilding my scenes so I'm not worried about it.

Soon, I'll have 1080p scenes. Okay. So. Little side -- yes, the old gear heard that I was thinking about changes things up, I know, I know. What's in my mug today? Anybody know? Keeping in mind that it's 10 a.m. Okay. All right. Thank you for the sub. When do I start full time on LWJ? I already have. The 23rd of November was my last day at Netlify.

That is maybe a misrepresentation. January is when I'm really going hard. I wanted to take December to be very coast-y. I haven't taken a real break since like 2016. So having a month where my entire schedule is two episodes a week with very little else going on is intentional so I can -- it's also the holidays and I have family stuff coming up. So I'm trying to lay low for a bit and in January we're going to go and hit it hard.

What do you think of the micro front end pattern? I mean as I am currently building it, I'm going to have to say I'm a fan. But I do think that it is something that is, it is a tool that should be used very intentionally. I don't think it should be the first thing that somebody reaches for. Because as you'll see as I start building this out, I'm not building something simple here.

I am solving a very complicated problem that I personally have in the business of Learn with Jason. Which is I have a bunch of things that share styling and I have specific needs for different aspects of my business that aren't compatible with one single stack. And if I want people to help, I have worked around these problems through severe overengineering but any time someone wants to help on this site, the Dev environment almost always breaks.

I want something that is easier for people to build and that's what we're working towards. Making it simpler for someone to contribute and work in this. But I'm doing that by making this setup of the sites themselves actually more complex. So it's definitely not a tool to just fly into and, you know, start setting up micro -- for everything right now. All right. All right. All right.

So, we talked about Remix. We talked about all of the, like my reasoning for going on here. Because we have file one, file two, file three to manage the meta styles and stuff like that. And then we've got in the MDX itself, we have this need to, and this part, this is what I want. I want to write all of my blog posts just like this.

And the catch comes in that Remix isn't like prebuilding these. It's not building the blog posts at build time. It is building them at request time and it just leads for me, to enough hoops that I have to jump through with making sure, like I shared here, the files are present. It's just too, it's too much for what I'm doing. I want write ago blog to be I wrote a blog and I published it and it works.

I don't feel like that is how it currently works. I have to rebuild the mental model of how it works every time. Let's look at Astro. I have a head start here. Let me start what I've done and check this out. You do NX, run, blog, Dev.

It's going to start my blog for me. Yes. Go. Dang, opening the wrong tab. Put you over here. I want you to go -- come on. There we go. I want that part over there and this part over here. Get out of my game. Okay.

Where did it go? Welcome to Astro, there it is. Okay. Here is my site that I'm porting. And if I go over to the blog, there's a little bit going on here. And right, here we go. This is the blog, here's the blog now. I'm missing pieces. But I was able to copy this general format over and I moved one post over so I could try it out.

And then if I go into this theme switcher, go into this theme switcher, you can see that it's like close but not right. I'm missing some of these styles and the headings aren't doing what they used to do and got some style issues where why are these links not the right color. So definitely work to be done here. But, you know, we're making some progress. Looks like syntax highlighting is there but not quite right.

My images are doing what I want. My code highlights are not there. So it's a work in progress to be absolutely accurate here. So what I want to do then is I want to -- how do I bust this out of the split. Get out, yeah. So I can go here, here is the Astro version. What I did manage to get working is this.

I want to show you how much nicer this is when you're not writing it in react. Let's go to the www and look at my specialty stuff. So here is the blog. Is this where it happens? It's not where it happens. It happens in the wrapper post. That's right. Here is my wrapper post. In here, I have my wrapper post, we'll look at this use effect in a second.

What I'm doing is getting my headings and then I set my headings in an ordered list. And each of them links to the headings ID. So what that lets me do is build out this list here and then what I want to happen is whenever one of these headings scrolls into view in the post content, I want it to highlight like this.

When we come up and get back to step 2, it will highlight step two here. When you click on one, it will bounce you to the one you want to be at. It looks like I have bugs but it's doing what I want it to do.

The way this works in react is I'm setting a -- I have to create a ref and I have to, like, go into the ref and query for the H2s and then I'm setting up, this is a call for an intersection observer. Down here I have to set my headings as like this. So they all kind of show up.

And it's all, all of it is fine. But it doesn't feel -- I don't know, it feels like I'm having to build a lot of mental models around what is react doing with effects and what is a ref and how does intersection observer work.

Let me show you how this changed when I put it into Astro, because I was really excited about it. I have my layout and blog layout. Check this out, I have, in my blog I have -- I don't know what I did there -- so here is the MDX file.

And this -- I'll make this full screen for a second -- this is front matter. I specify my layout here which I really like because it means I'm not having to like wrap the whole thing like I did in Remix. And it lets me specify that this is what will wrap this post. And then I'm able to just write as usual.

So all good, I'm happy, I have my custom stuff and my asides using tagged fence blocks for code. I have an image component so I can do things like set up, like I don't think I'm doing it yet but I want to have cloud nary do that and add captions and credits and things that are possible to do in Markdown but are a lot of manual HTML and this way I have props that let me do it.

This makes sense, right? It's standard Markdown. If you worked with Markdown or MDX before, this should look familiar. We're not doing ground-breaking work here. The only specificity thing is this layout key which if you worked in Eleventy, looks familiar. Then in my blog layout, note, there is no extra layout here. This is the actual home page of the site and this is the listing of all the blog posts. We'll look at that in a second.

Here is my blog. The blog pulls in the parent layout and I have the custom post styles for my blog. This is my table of contents and stuff and some of these I target directly like the post container is outside of the scope of this. But otherwise, these are going to get scoped so that I don't have to worry about giving these ultra unique names, I just get to write code.

And then down here, we've got, then we've got our global stuff. These are the things like the typography and stuff I want targeted. So I will skip that and collapse this and then we get into the layout. Styles, layout, feels like an HTML file. A little magic with the Astro single file components but this will feel familiar if you used Svelte view. It's not a new concept, it's only new if you only ever worked with react, maybe.

Then you wrap the layout, this is our default layout and I want more layout. I'm going to put the article style and a header up here, I want to put this table of contents in place.

This should look similar to what was done in the Remix side where we have the ordered list and the headings. And with our headings, we're going to loop through those and make sure that we only show the ones that have a depth of two.

So we only want H2s, I don't want the H3s or H4s because I didn't want to deal with networking in the side bar. That felt messy. Notice we don't have to do refs and get the headings from Astro itself. It parsed the headings for us and we just grab those out. That is wonderful, really nice.

We get down here to the script, and remember this is what we had the -- this is what we had happening with the use effect before. We just do a document dot query select all, standard JavaScript for all of the H2s inside the post content section.

And then we set up the observer call back and that's going to find all of the links in the table of contents and check if the heading that matches the current link is intersecting. So on like a visible on screen. Then it sets the active class.

I don't think I have -- do I -- for everything I remove active and add it for the active class. That is what is going on. We set up with the intersection observer and make sure it's fully visible and we go through the heading elements. Make sure it's not the table of contents and set up the observer and send back the text content and HREF.

I do return this to unobserve. But I don't think you need it in Astro because you don't have rerenders. I'm sending it back in case I ever need it but I don't think I do. I call that function.
That's it. That's the whole thing. There is no use effect, there is no working around the render flow or telling Astro this should only one once or when it should run.

Just when the page loads rerun the thing. I don't have to deal with the extra mental model of hooks and renders and all that which is really, really nice. So, now, what's not working? So the next piece that I need to do -- let's look at the index, too, this is another cool feature of Astro that I really like. They have given a built-in feature to load all of the Markdown and parse it for you.

Instead of having to do a file system call to load your Markdown and use another ecosystem plug in that will parse the file and give you the front matter and give you the content and all that kind of stuff, Astro just built that in. I do Astro dot glob and do the file path to the MDX and it brings back my stuff. I need the front matter and for this list I'm using a title description and URL and I pull that out. We'll skip the styles.

Down here I do post map and set up the article preview. I can pull this into another component. I haven't, I might. I don't know, we'll see. This is what sets up all of my stuff for now. Why are you unhappy? What do you need? Main class is missing in type.

What? You shouldn't be requiring that. There we go. Hush, you. Now you're happy. Good. All right. So this is, this is what I like. Content schema API is fuzzy, tell me more.

All right. Next year is going to be interesting. Okay. All right. All right. Okay. Yes, I'm very excited to see what's coming with Astro. I think the team has been doing cool stuff and, you know, I like Astro. I think they're doing cool things.

Fuzzy spilling secrets. That's right. So to get this set up, I did not have to do much. I added the MDX and React integrations which you can actually do for the command line. If we go to Astro dot build and go to docs and then I look at Markdown MDX, you just need -- how do I -- where's the initial setup. Configuring.

Nope. That's not it. Astro MDX integration. You just run Astro add MDX. This is dope. It configured this for me. This file, I didn't write any of this part of the file. The only part that I configured is I cannot have syntax highlighting without night owl. So I had to import that theme.

So I figured out you can use any VS code theme in Cheeky which is the syntax file highlighter bundled with Astro. I grabbed that JSON and put it in a file up here and I can import it like that. This gives me the syntax highlighting is now in Nightowl which is -- wonderful.

Here is one that is actually highlighting. Here is Nightowl doing its thing. All right. Let's fix some things that don't work. First and foremost, I need, let's go back and look. Let's fix up the heading here. Let's make this heading work. So now we can get into a little bit of the component system. And I've got my design system set up where we have colors and things. So this is how I'm running the design system.

But I have a challenge which is that I actually have, like, the new design system and the old design system that have a lot of overlap because I'm in the process of redesigning my scenes. So -- sneak, maybe a sneak peek on that.

If I go to -- I think this is going to be by default. Let's find out. Learn with Jason and looking in here, I'm working on new scenes. So this is, this is my idea is to do -- thanks, you're being very helpful.

So this is the thinking of the new scenes, not super different from the old scenes. But going a little more minimalist. Not as much UI on there. For guesting it will be the same. This is full 1080p which has been a big goal of mine.

And the guest views, maximizing the views because it has the boop overlay on it and that has been -- I like it, it's fun. But I feel like -- why not have more of the full size video. That seems like the right call. This is the plan. But, when we get in here, this is using a slightly updated set of colors and things. So if I show the UI again, kind of working on like this general set here and like all the designers are going to be horrified. But this is sort of what I'm working on towards a new system.

And then that's going to open the door for me to do more with, like, I want to have these fun starting soon scenes that will count down. And I want to have place holder cards and just a lot of fun stuff like this.

Trying to make this stuff all look nice and connected and all those kinds of things: But, let's see, woe, dude, did I stream making the boop overlay? No. But I am going to have to port that so I can do that on stream. Let me take a note. Where is my note taking app?

Where are you? You don't get to be over on the main screen. I don't know what's up right now. Let's see. Stream idea for rebuild boop overlay. That is now on the list. All right. So, this is my complexity that I'm dealing with is I have multiple things in here.
I just need them to be -- here, so I need these to stay compatible in the interim and then I have to -- this is where discipline comes in -- I have to come back and fix it once I have the new system. I'm trying to make this as seamless as possible without getting myself into a lot of trouble around like having to port things over.

Let's do, let's do this top section here. How much time do we have left? We have 40 minutes. I'm going to open up the -- code. Take this to half width. And collapse the side bar there. Take this over like this.

And so the thing that I need to do is I'm going to -- this header is unique to Learn with Jason dot Dev. So I don't need that to be available -- oh, wait. It's going to be used on the video, on the videos as well as the blog. So it does need to be in the design system.

Let's make a new component in the design system. I'm going to call this ... Header. We can go down to the existing site and find that component because it's in here somewhere.

I think I called it hero. Is this right? No. That is the actual hero. It needs to be -- where did I do this? Let's look at one of the pages more back ward. On the blog itself, there's nothing. Oh goddamnit.

Here. All right. So it's -- this is just built from scratch. So let's grab this out and bring it over to here. We're going to export default -- I don't want to do that. I'm going to export function, header. And that's going to return -- oh, okay. This then gives us the raw pieces and then if I go into my blog layout, that's not the thing I wanted.

Then I can import this. Import page header from WJ design system. And this -- what are you mad about? Yes, yes, I'm getting there. Calm down. Sheesh. This is the wrong place, though. It's not where I want to be. I want to be in the index inside of blogs and I have to go here to figure out where that is.

Page, blog, index. No. Blog index. There it is. So now this is where I want that to be. I can drop that here. And then up here instead of this thing, we will do a page header. Let's see what happens.

Let me switch back to here. Unable to render page header. Did I forget to import the page component or is there a typo? Yes. I did forget to make it available in the design system. Here is where I'm about to get judged because I don't have a good idea on how to manage this properly yet. So just, everybody, shush. There is our blog header.

Wait, which thing works natively with Astro? Token CSS. Vinnie. Absolutely not. No, this is a judgment free zone. Or at least a no judging Jason zone. Okay. I'm going to style this. To style it, I need to figure out what the pieces are. So let's get in here, page header. And I am using CSS modules because I enjoy them.

And then I can collapse this on down. I need to have a block type which is probably going to end up being global or maybe I'm not going to worry about that yet. I'll look for when these things get more common. Because they are common. I do use the in multiple places I just don't know if it's worth abstracting yet.

I kind of want to see how I do this. Let's just call it hero and I want a background color of black. I can test this is all working by work styles from header, dot CSS and place this with styles dot hero. So that's doing the thing. Oh, it didn't.

I think that block was already global. That would make sense actually because I bet I pulled it in my, perfect. So we can rely on some of the globals and I'll go, I'll untangle that mess later because I probably going to do a light redesign of the whole site as part of this, you know, thing, this whatever it is I'm doing.

And don't want to spend too much time trying to perfect the old system when I'm probably going to throw some of this away. So, you know, as we do. Just leave that for future Jason. All right. Next thing I want to do is I want to get the text being the right color here. Let's go with, H2 and hero P. We can do color is ... Color, I want it to be color -- not white. That's not the right call. Let's do color gray light. No. Let's just use white.

Oh. It's H1, isn't it. All right. So we have our H1 and our hero are coming in the right-ish color. We'll fix it in post, exactly. I can take the H1 and we can make the font size, I want to try something fun. Have y'all ever played with Clamp? What I want is -- can you give me hints on this? No? Okay.

So you get three values and the way that I remember this working is that it's like, you get the smallest possible value. Your ideal value which we'll call 2rem and then your largest possible value which is -- wait. How do we want to do this? I want to make this, let's make these actual values. We'll go with 72 pixels and 40 pixels.

Now, what should happen is as this gets kind of pushed around, maybe I need to make it way bigger to demonstrate this. Let's go with, is 2rem smaller than 40? I bet it is. Let's go with 4rem.

And this should get bigger. Wait. Wait. How does this work? It's view port width, isn't it? Let's go with the smallest it can possibly be, the widest it can possibly be is -- let's make it extreme -- ten, that is going to be wild. Check this out. There we go. It's getting bigger. It's getting bigger and then it stops. It depends that's the biggest it can be and then it will get down to that small and it will stop again.

So we can kind of control, right, what the ideals are. This is so -- whatever I'm doing here is not right because I think this thing is a little goofy because I don't know what 10VW is. I think that is enormous. Let's do a test. So that is 10. That's 4rem. 4rem. That's too small. Let's see, the smallest we want it to be is 4. So that's good. Then the largest we want it to be is 8. And our ideal, no, that is too big still, let's go with 7.

And I said 5 was my minimum. We're going to say 7 is there. And then in the happy medium we want it to be, is it 4? Let's go with 3. Let me turn this off. And then it kind of sits there: It should get a little bigger. Keeps getting bigger. As we get smaller, it will shrink down to the smallest possible. Good, I'm happy with that. Let's mess with the margin a little bit. What does 0 look like?'

We're happy with 0. What if I -- happy with that, too. Let's then set the paragraph to have -- I want it to have a max width. We can do width, a min of 80 percent or 54 characters. That's too many characters. Let's go smaller, 35. Maybe that is a little too small. 40 feels good. Do I want this to be centered? Thumbs up or thumbs down? What do you think?

A fuzzy distress call. I don't know if it's fuzzy. Centered, yes, please, I'm keeping it. So boom. I'm going to call that good enough. That seems close enough for horseshoes and hand grenades so we'll call that a success. I'm going to fix the weights of my -- fix the weights of my headings because they feel like -- here is the font faces, HTML.

Font size. And HTML, that is good. Where is my typography getting set now? Where is that coming from? H1 coming from the user agent style sheet. This is not even -- I'm not defining it at all. Let's make a mess. We'll go with H1, H2, H3, H4, H5, and H6, all of which are going to get a color -- named colors. Probably not. Maybe. Like color heading and color default text and that kind of stuff.

This is the worst idea ever. We will do color heading and I will set that to be white. And then we'll do color default and do color text. Here I can set the color to color heading. And that's going to -- yep, that broke everything. I know what I'm doing wrong, my colors in this are set up to be in dark mode because they're designed for the scenes but this blog is mostly in light mode which means I need to modify in light mode what these are. And I have done a light mode setup here. So I can set this to be color black. Color gray text I think is fine for now. Let's see.

Color gray text. Hum. I don't want you to have that setting. So I'm going to find this in the main dot Astro. Like this one. No, that's not right. It has to be in the layout. Let me get out of here. You get set by typography.

That should be set correctly but -- yes. It's pulling in the data theme light and there is the color coming from the actual typography settings, that is good. That is what I want. Let's close this one out and go to -- there is our typography. Good. The next thing I want is I want headings to have a line height of 1.1.

Everybody see what happens there? See how this feels cozy for a head line because the text is huge and now it feels spaced out and weird. This is a little trick. 1.1 of whatever the font size is, is a good -- for headings. And 1.4, 1.5 is good for body text. That is down here.

If it gets much bigger than this it starts to look ridiculous. And if it's tighter than that, it's cramped and hard to read. I use 1.4, 1.5. That is where I got comfortable to read. And need some spacing under this heading. You are right. We do need spacing under this heading. How should we go about doing such a thing? Let's do it in here.

And I'm actually going to bring the set of margin top of -- I use REMs for everything so if I ever change the default size here, like if I change this to 24 or something, then everything kind of scales up proportionately.

Where if I was using pixels, you would have to go through and mess with all of that individually. That's the reasoning for REMs. Okay. So I'm feeling pretty good about this. The next thing that I can do, I'm going to bring over another blog. Let's bring in another post and see what needs to change.

How am I doing with time? We have 20 minutes left. Here is my app, MDX, let's get the blog and where is my full-time Learn with Jason. I'm going to copy this and head up to the blog and drop in right on in there. It didn't like something about that.

Cannot find module wrapper post. Yep, I should have saved all these. Not using MDX anymore. It's just the double dots. We're going to go here. And this one is image now. And the opt-in form is in -- somewhere else.

Did I put it up in the design system. Components, no. But I should. This is the rabbit hole, right? We just keep on moving and everything is -- wait, I have the opt-in form. Great. That's good. I can just import this from the component itself. And I will do that from here. I can get rid of this wrapper post. Closing wrapper post. Opt-in form. Let's close this down so we can see what is going on.

Opt-in form. Figure needs to become an image. And I'm changing this out to be -- because, like, I think I was doing something before where I was writing a Markdown plug in to parse this stuff but I don't think I care.

And we can take this and make it self closing. I think that's it. So let's save it. Expected component image to be defined. Oh, it's called image. Okay. Close but not there. What just went wrong? Oh, I need to set my layout. Up, up, layouts.

Look at that. Pretty straightforward. The form is not -- the form is not styled and that's okay. But I'm feeling okay about this. This is like not, that's fairly painless to set up. So that's good. Do I want my font weights to be heavier.

This one is hard for me. I can never make up my mind on what the right weight is for headings. Part of me really likes this. Topography, ultra, 900. It's there. Post content H2. Font weight bold. I changed it. Font weight, weight. With a W. Sheesh!

Thank you, Kahlil. You're watching the local Dev server now. I crashed it and it recovered. Like, I'm sure there are things that I can do that would cause it to crash but I have not had to stop and restart it yet. Can we just take a moment and everybody tell me I'm funny for this joke? Validate me. Okay.

I feel okay with this. I'm feeling, I could, let's style -- let's see, we have 15 minutes, let's see if we can style up the form and I feel like this is good enough. I feel like I can, if I can do the form, this would be good enough to start porting stuff in and I can catch the rest of it as I go.

To do that, I need to go and find where the styles were to begin with. Let's go and look in here. We've got an opt in form. The opt in form is, right, this is Remix and Remix has you put the styles out here. Here is my opt-in.

This might already be in here. Here is all the stuff. I want that. I'm going to come back up here and take a look into my global styles which are in the layouts. Included that one. Included in that one. Which is correct, that's what I wanted.

So then I can take this and I believe -- it will be a moment of truth here -- I can't remember if these just work. We've got the opt-in. Global because it won't be in the -- you will need to be global. Let's try it.

Going to need -- color. Color. Text. Default. All these prefixes. I think there's a gray medium. We're going to find out in a hurry. I think. That should be a different color anyways, probably.

So that's all the colors updated: Now I need to go and set my opt-in class and I think that's the only -- yep. Opt-in. Good. Let's go here and find out -- inform dot module dot CSS and then we're going to come down here and files dot -- pretty close right out of the gate but we're missing some of the colors.

Looking at the colors, I don't have a color pink dark. So I can try color pink text and see how this works. And I didn't have a gray medium, I just have a color gray. Let's try that.

No. I need to fix that but legibility is more important for now. And down here there was a color pink dark. Let's go with color pink text. That looks okay to me. Very excited that the CSS modules worked on the first try. That is very pleasant. Thank you, creature next, I'm very excited.

Man, Vinnie Code is just roasting me today. It was a joke, it's there, look at the joke. Dammit. Okay. So in our last 10 minutes, I'm going show you how I -- wait -- what am I con SOL logging. I don't want to do that. Let's go back to the blog. That's not logging anymore. And then I want to take this live.

Let's do this. Let's do add everything and we're going to say get commit, progress, porting log to Astro. And then did I already set up a site for this? Let's find out.

Every time in the wrong -- okay. Sites. Got the API, the web hooks, the scenes. Did I do the blog? I have not done the blog yet. Okay. Let's star that one, too, so I don't lose it.

All right. We need to set up a blog. I'm going to add a new site and import an existing project. And don't need -- okay. Back we go. We go to Learn with Jason. Hundreds of repos. Okay. We're going to deploy the future mono repro-branch and the command is NX run log build.

And the output directory is going to be -- output target is static. Where did that go? Let's open this up. Let's look. Here is the blog. Here is dist. Okay. I need to go to sites blog, dist. And then do I have serverless functions in here? I do not. And I'm going to try to keep them out and keep them in the API instead.

So we will -- do that just in case. Did you just change my stuff back? Oh. Did that actually just happen or was that a visual bug? Weird visual bug. Weird. I don't know if anyone from team 8Nullify here but I'll take a note to let them know about that.

Yes. That's a good call. Does someone have a second to click that? I need to learn how to clip on the fly. This is my sad stream deck that I've got. Can you see it. The sad stream deck that I got and I was so happy about and I broke my scenes at some point when the stream deck wasn't working and I pulled it out to remind myself when I get this new box of stuff today, I can actually do fun things like add markers and clips and things like that.

This site should -- theoretically, fingers crossed -- be built. Did it work? Let's see. My new tab. Oh my goodness, everybody, wait, wait, wait. It doesn't have my updated stuff, though. Did I not commit? What the hell? Oh, I need to ignore the dist. I didn't push.

Okay. A couple things need to happen here. First, I need to go into my get ignore and make sure -- that should absolutely be ignored but we're going to -- we're going to ignore -- blog, dist. That should be gone. I know, that was the whole idea.

What's the move when you want to -- do I just need to, like -- local modifications, I want them gone. All my Dist should be gone. So we'll remove the git files from tracking and what do I have here? Get ignore, we're going to get add. Ignore.

Build output. Now we can push. And nothing up my sleeve. There's our new build. While that is happening, I'm going to go in here and change this up. I want this to be -- blog. And I want that, that should be fine. Did I need anything else in here? Current repo. That is all set. I'm happy there.

What does NX do here? Yes. This is the part where in theory, if I run this build again, it should use the cached build instead.

I might have to configure a little more with NX cloud to get that to work. But I'm pretty pumped about that. This is the arc browser. So this is the browser I'm using. It's invite only right now. But I kind of dig it. It's good.

Like, I've enjoyed it very much. It has a couple things that I'm pretty pumped about. You have these different profiles and stuff where you can add different sections, you can add things like if I wanted to move this up, you can set it, like move to. I've got my personal and my Learn with Jason sets and then you can, you know, do more stuff.

I think I'm in like a popover window and I have different, over here. Let me just pull this over and show you for a second. This is my, like, the setup where it shows everything. So you can sort of move around and see your different, your groups of tabs and then they're also down here. So you can kind of see what is going on.

But it's nice. I have been very fond of this browser so far. And it seems to be pretty well maintained and they're doing cool stuff. Anyways, so, site is deployed. And we can go out and look at it at LWJ blog dot With that, we're out of time.

Why don't we take this chance to go back to the home page and I'm going to give another shout out to White Coat Captioning and Lora who is with us today who took down all these words as made possible by Netlify, NX and New Relic. Make sure you check out the schedule.

You can subscribe on You Tube and Twitch and on the newsletter, hit this tips and insights and get in there. And please, please come hang out and lots of good stuff coming up. We have Will coming on next Tuesday. And we're going to do TanStack Query v4. We're going to look into Wilco, which is very cool stuff. Nuxt 3 and Nitro. And Docusaurus 2.0 and get into Faker.js and I have a few more in the works that are coming. So please, please, please, mark your calenders and come hang out with us next time. Until then, we'll see you, thanks for hanging out.