Over Engineered · Dec 14, 2023
Chris
All right. Welcome back to over engineered the podcast where we ask the very important question, what's the absolute best way to do things that don't particularly matter? Today, I am excited to have Aaron Francis to talk about personal websites, which I think is, like, what a thing to get a chance to over engineer. Right? That's, like, our favorite.
Everyone, there's so many easy ways to build websites, but as developers, we sure don't wanna do it the easy way. Right?
Aaron
Yeah. They're all always are terrible except the way that I have chosen to do it. So I'm ready ready to talk about this.
Chris
Awesome. Well, I I can't imagine that my my few hundred listeners don't know who you are, but do you wanna give a a brief intro just to to say hello first?
Aaron
Absolutely. I am, my name's Aaron Francis. I'm a developer educator at a database company called PlanetScale. So what that means is I end up making a lot of YouTube videos about databases. I'm also a Laravel developer, and I make some YouTube videos about that.
And most importantly, I am dad to 4 children now, which is an insane number of children. We just had our second set of twins, and they're, like, you know, 3 weeks old. So I've got a lot of coffee and I'm ready, I'm ready to over engineer.
Chris
Nice. Well, I don't know exactly this is this is one usually, these shows kinda come from a place of this is a thing I've been thinking about a ton and have have sort of a starting point, but for this one, you, you kinda came to me and said, let's talk about this website stuff. So why don't you instead usually, I'll do the, like, setting the stage, but you wanna set the stage instead? Like
Aaron
Yeah. Sure.
Chris
Yeah.
Aaron
Yeah. So I'm on a you know, I'm I do a podcast with Ian Landsman called Mostly Technical, and it's barely technical, but it's a great name. And on the show, we were talking about my personal website setup, and he told me I was overcomplicating it. And I thought, no. This is perfect, and you just don't understand.
And so, you know, we had a nice argument about it. And then I thought, where can I talk about how overcomplicated this isn't? Bossman Chris has a great show for this. So here's here's my, like I don't know. Here's my thesis on personal websites.
1, I think static site generators are too anemic and they, like, make you learn this whole new thing that is only useful for one particular use case, but it's also not that useful for that particular use case. And I have made extensive use of, like, jigsaw, Titan's jigsaw, which I loved for a super long time, but I kept running into the boundaries. And I kept wanting to I I just kept wanting it to be full Laravel, and it's just not. It's like it uses some of the Laravel components, some of, like, the Illuminate packages, but I just wanted it to be Laravel. And then I looked at, like, you know, Nuxt because I like Vue JS.
So I'm not gonna do something like, I don't know, next or whatever. But I like Nut or I I like Vue. And so I looked at Nuxt and I was like, am I really gonna learn all of this just to make a personal website? And so that's when I landed on, just make it Laravel. And then from there, you know, it kind of evolved into a whole thing.
But I'll stop and let you let you respond to the static site generators are a waste of time.
Chris
Yeah. I mean, I I agree wholeheartedly. I think, you know, I I like I'm sure most developers have had many incarnations of my personal website over the years, and I recently moved from a Gatsby site to, which is I was just thinking about, like, remember when Gatsby, no one could stop talking? Like, no one was everyone was talking about Gatsby, And I haven't heard Gatsby mentioned in in Shocking. Right?
Aaron
Shocking that people have moved on.
Chris
It's it Let's You know?
Aaron
We'll have to revisit this when Astro when Astro is dead, we can come back and be like, man, you remember Astros?
Chris
Yeah. There you go. But, yeah, I had I had a Gatsby site and it was fine. You know, I think I think the fun thing about personal websites is that they're like, you know, a testing ground for new technology that you don't necessarily wanna move into production in, like, your your real job. So, yeah, it's fun.
Like, all the things that seemed neat about Gatsby, I wanted to play with, but I didn't Mhmm. You know, I wasn't gonna commit to using it anywhere else. So I don't I don't regret doing it, but, you know, about, I'd say about 6 months ago, I just, like, ran into a situation where it was gonna be a pain in the ass to upgrade, and I just thought, it's gonna be easier to just rebuild this in Laravel than it is to upgrade Gatsby and, like, fix this bug that I'm running into. So I'm just gonna do that. And so I recently kinda made the same switch.
I I will say, and I I decided to hold this until I had you on the podcast to say Uh-oh. I totally agree with Ian.
Aaron
Like That's set up. Like Oh, no. Bamboozles.
Chris
You are trying to say that you're just building a just Laravel app, but you're you're you're kind of doing just because your static site is SQL. Like, it doesn't mean that it's not a a statics. You're basically doing a static site generator.
Aaron
What a scam. What a scam. I was induced under false pretenses. Hey. I've never I've never seen it.
You made me come on here by planting this idea in my mind. Okay. So here we go. Alright. Let's talk about my setup for those that don't listen to the mostly technical podcast.
It's a Laravel. It's a full on Laravel application. I make heavy use of markdown. So, like, all of my it's ataronfrances.com if you wanna see it, but it's it's it's a standard, like, content website. Right?
And I make heavy use of mark down to actually, like, write my blog posts and stuff. I have a few mark down plugins, which I have either written myself or installed, and I think they're, you know, fun and interesting. But at the end of the day, it's kinda markdown. Then that gets pushed to GitHub. And in a GitHub action, I gather a bunch of stuff.
Chris
When you start to this this moment right here is when your argument starts to fall apart.
Aaron
When you say, oh, so the
Chris
GitHub action, I have to do all this this build step to to
Aaron
build my screen and
Chris
push it to the web.
Aaron
This is what I don't understand about the argument that you and Ian are making. So, like, okay, forget the build step. Let's say I so we'll we'll take a really concrete example. I have YouTube videos. Right?
And I want the YouTube videos to be on my website Because like, hey, this is this is the central location you can find basically everything I'm up to. YouTube has a great API that I can just call and like pull it down and put it somewhere. Okay. So that's what I do. I have a command that's called sync colon YouTube.
So I run PHP artisan sync YouTube. And it goes out to the API. It looks at all of, both the PlanetScale channel and my personal channel, looks at all the videos, and then puts them into a database. Pretty normal so far. Right?
Chris
Sure.
Aaron
Right? It's a standard Laravel app. It it I run a command, and I write stuff to the database. That's normal. I could I could never be accused of that being overcomplicated.
Right? That's totally, totally normal. Okay. So PHP artisan sync YouTube. Write stuff to the database.
Oh, that's super cool. Let's see. PHP artisan sync podcasts. What that does is that goes to, 3, maybe 2 or 3 different RSS feeds and looks for new podcast episodes, and it writes that to the database. It's like, oh, that's pretty cool.
So now I'm, like, gathering my digital detritus from all over the Internet and putting it on my site, which is the goal, like, a central place. So, you know, I'm beefing up my site with all this external content. Oh, that's really cool. I agree. And so now I've got these yes.
Thank you. I've got these you know, I've got one table in the database just called content. And it's like, this is the title. This is the URL. Maybe a description, maybe some ancillary data like view count and that sort of stuff.
Okay. So I have another I have another command that's just PHP artisan sync articles. And that sync articles command, it just looks on the disk and it's like, hey. Let's just grab all the markdown and put that into the content table. So, like, looks through the articles folder, pulls all the markdown, looks at the front matter, and it's like, what's the title of this post and when was it published?
Great. I'll put that in the database. So now I've got this big table of neat stuff. Right? And then the website, like, the actual website just pulls using Eloquent, just pulls from that table and puts it in a giant list, and some things link externally and some things link internally.
That's it. Yeah. I mean Pretty good. Right?
Chris
I think, you know, I I'm most I I'm partially just baiting you.
Aaron
I I I do agree. Not working. I'm not mad at all.
Chris
But, he says as he as he yells into the camera. But I I do think I do think that I agree with Ian's kind of premise that the fact that this is all happening in, like, a build step
Aaron
Well, we haven't gotten there yet. We haven't gotten there yet. I'm just setting up I'm setting up the premise. You don't know where this is going. You have no idea.
Okay.
Chris
Alright. Then then
Aaron
So that's all reasonable though. Right? Pulling all that stuff down That is all
Chris
perfectly reasonable. Yes.
Aaron
And writing it to a database. That's pretty reasonable.
Chris
Yes. I mean, I so I do a similar thing with with markdown, and I think that that's like I think that that's like if I were gonna dig into how to make publishing personal websites with Laravel easier, the thing that I would look into is, like, what I think every developer wants is to just write in markdown.
Aaron
Yes.
Chris
And, like, how do we make the ergonomics of getting that to be rendered on a site Mhmm. Better? I think that'd be an interesting thing to talk about later. But setting that aside, I mean
Aaron
I have lots of thoughts on that, so we should circle back to that.
Chris
Okay. Yeah. On on my end, I do the same thing, except for I just route directly to the markdown files. Right? So I just Yeah.
Yeah. You know, I I I don't necessarily even bother dumping that into a database. But, you know, there's nothing wrong with doing that.
Aaron
Yeah. And for for the actual routing, I do the same thing. I just route to and just, like, it uses the view like, it I think it just uses pulls the view and runs it through Graham Campbell's markdown rendering engine. That's basically it. It.
I just put it in the I put it in the database so I can have a list view. I mean, it's basically at that point, the database is like a cache layer more or less. So every request doesn't hit the file system to look for all the markdown. It just hits the database instead. I could you know, you could run that once and just do a cache remember for an hour or forever or whatever.
Right. So, yeah, totally totally the same there.
Chris
Yeah. And I think that's basically what I do on my end is, like, it's just it's just cached instead.
Aaron
Right. And so that leads us nicely to the next point. So I wrap up all of these commands into and that that command looks for all commands in the sync namespace that aren't all, and it just runs those commands. And it's like, great. Now that's, you know, filling ever filling the database up with all of the content that I could possibly need.
It's idempotent, so I can just run it over and over and over and anything new will get populated, but nothing old will get duplicated. So at that point, you know, I'm like, great. I've got a database full of stuff. Now the problem is I don't want to set up a database. So if you guys need a database, go to planetscale.com.
That's great. Good databases. Great databases. But sometimes you just don't need a database. Right?
Chris
You heard it here, folks.
Aaron
No. No. No. No. No.
Chris
Francis says don't need databases.
Aaron
Don't clip this. If Holly ever finds out that I said sometimes you don't need a database, she's gonna be so mad. That's not true. Holly never gets mad. So sometimes you don't need a database.
Right?
Chris
Sure. Yeah.
Aaron
Yeah. This is an instance where I'm like, you know what I don't want? I don't want a bunch of services running. This is my personal freaking website. I don't want to be maintaining a MySQL database.
I don't wanna be maintaining some third party API connection. Like, I just wanna, like, package up a nice little ball of stuff and send it somewhere, which sounds dangerously close to a static site generator. Right? So the solution to that is SQLite. It's just like, it's basically as if I wrote it all to a giant JSON document and then committed the JSON document to the repo and shipped it off and pretended that the JSON document was a database.
That's what SQLite is. It's just nothing. And so what the the the super nice thing that I do is I can sync all that stuff locally and then just commit everything, including the database dot SQLite, and then ship that off. And I can ship that to any server anywhere. Now I can't ship it to, like, GitHub pages because it still uses, you know, PHP to like it still uses Eloquent, which I really like.
Chris
Sure.
Aaron
Still uses Eloquent to inspect the database. But I can ship that to a $5 digital ocean box. I can ship that to vapor, which is what I do. And I just know that, like, I have a unit, which is a standalone basically zip of my website and just kind of send it away. And then I have all the content out there.
So that that's the next that's the next step. It's it's basically like a pre warmed cache just written to the database.
Chris
Yeah. I mean, I think that I don't disagree, or I actually think this is a very elegant
Aaron
stop there. I don't disagree. Yes. Yes. Yes.
Chris
Well, I'll even go further to say I think this is a very elegant solution to the problem. Wow. I just think that it's it also doesn't feel like just it's just like a regular Laravel app. This this feels like
Aaron
a a
Chris
home grown status generator that I
Aaron
think this is fine. I'm fine with that. Yeah. I think I'm fine with that.
Chris
Yeah. I mean, that's Yeah. And I think the
Aaron
problem I think the problem I have with, like, let's let's take Jigsaw because it is in the Laravel community. Right?
Chris
Sure.
Aaron
And Jigsaw Jigsaw is great, and so I don't wanna disparage it, but the I'm gonna tell you the the problems that I have with it is I have to learn how the jigsaw collections work and, like, how the jigsaw markdown rendering pipeline works, which I have gone super deep on to make syntax highlighting work over there. And so I've I've really gone deep into Jigsaw and I know it extremely well. But at the end of the day, when I'm like, great. Now how do I sync my YouTube feed to it? It's like, well, I would know I would know immediately how to do that in Laravel.
Like, it's so so easy. But with Jigsaw, you gotta figure out, oh, I gotta listen to this after build, before build, and I gotta write my own pages. And it's kinda Blade, but it's not totally Blade. And so I don't have a problem, I think, with building static content. I think I just wanna encourage people to think about using your framework of choice to build that static content instead of relying on some, you know, half half framework implementation of that.
Chris
Yeah. I I think, I mean, I think that this is a perfectly fine choice to make for building, like, building a site of this, like, of this type. And, you know, I totally get, especially because you're shipping to Vapor, like, you know, dealing with the database consideration is a little bit more complicated there, and just shipping a SQLite file solves that, and I think that's great. Yeah. I I do still think that if you were to say, oh, my website is just like a regular old Laravel app, I would expect some of these things to happen just a little differently.
Right? I'd expect there to be a MySQL database or a persistent SQLite database just sitting next to your app. Right. And then, I would expect basically all of these sync commands to just be running on a cron on the server. Right?
Aaron
Right. And
Chris
because you're using Vapor, that complicates a bunch of this, right? And the same, I mean, I deployed a fly. Io, and I have to deal with a few of those considerations.
Aaron
The memoral stuff, yeah.
Chris
Yeah, and so it definitely is. I mean, in my case, I just don't have a database, you know? It's just everything is driven directly either by the files or for the API calls that I make. It's just just a lazy caching situation. Right.
You know, the first person who hits the site makes the API call, and then everyone else just gets the cached version.
Aaron
Totally.
Chris
And I would argue that, like, the spirit of what I think Ian was saying and the thing that, like, caught caught me as as sort of like, yeah. This isn't quite just Laravel is that feels a little bit closer to just, like, just Laravel. The moment that you have like an extra build step and you're like pushing your, like, built site somewhere, it just feels, you've stepped a little bit outside of the world of this stuff.
Aaron
I think the problem I think the problem that most people have with it is the read only it's the read only SQLite database. That is not a standard that's not a common pattern. Because, like Yeah.
Chris
Using someone came to your site came to your code base, they would it would take them a little while to figure out what was going on there.
Aaron
See, I don't even know about that because it's, like, it uses proper eloquent models, it uses artisan commands, You know, it's it's discoverable in the database dot PHP. It just says, like, the the, you know, the default connection is SQLite. It uses migrations. I think the thing that might take them a minute to figure out is why is PHP artisan sync colon all? Why is that not running every morning?
Right? Why is that not running at midnight Right. In the scheduler? Like, how do we sync this content if it's never run? And I think that that's the thing where they would be, like, a little bit confused.
And I think the other thing that would confuse potentially confuse someone, but the other thing that would potentially confuse someone is that in production, the databases read only.
Chris
Right.
Aaron
I mean, you can definitely write to it, but it's gonna get blown away. And I think that might confuse someone, but there are no routes or actions or anything that, like there's no way to, like, you know, leave a comment on aaronfrances.com. And so there are no places where I'm writing to the database in production. But if somebody, you know, you know, some intrepid intern came to work for Aaron Francis Incorporated, and they're like, I'm gonna add commenting to your website. And it's really simple.
I just post to this route, and it writes to the database. I would have to be like, oops. That's gonna disappear on the next deploy. Or honestly, whenever, you know, AWS Lambda decides this container is toast, then then that comment would go away. And that that part is weird.
Chris
You could you could pretty simply just swap that out for a MySQL connection and Totally. Know. Yeah.
Aaron
Yeah. Yeah. Yeah. And I I I absolutely I absolutely could. And at that point, like, it is super standard Laravel.
Like, all Laravel applications have a deploy step. Right? And my deploy step also happens to warm a cache, and that cache happens to be a SQLite database.
Chris
Right.
Aaron
So it's like, meh, that's kinda weird. I could, you know, I could get rid of the whole SQLite database and just run these, API calls on the first request and then cache it in whatever vapor's default cache is, like Dynamo DB or something. And that would be maybe more normal. It just fills me with immense satisfaction to be like, I'm gonna ship the whole website now. Here it goes.
And I don't have to worry about, you know, the scheduler, the cron or anything. I actually turn those off in vapor, which saves me a number of pennies. And it's like, yeah. This is this is kinda nice. I actually do wanna deploy it to Fly because this is 100% perfect for Fly.
Chris
Right.
Aaron
And that would be fun that would be fun to try out.
Chris
Yeah. Yeah. So to okay. Talk to me about markdown. What's I have I have some thoughts here, but let me hear what it what's, what's your initial reaction there?
Aaron
I have grand plans for I have grand plans for markdown in Laravel in static sites, honestly.
Chris
Okay.
Aaron
And so I am working I am working on making I I'm working on seeing this thought to completion of Laravel should be your static site generator. And I have a lot of ancillary things around that, but that is that is the cohesive thesis of what I'm trying to, like, see to fruition.
Chris
Yeah.
Aaron
And at the core, the heart of that is markdown. And so let's start with what is it called? Common mark, I think, is a PHP league package. Is it a PHP league? It's by that It is.
By Colin O'Dell. Okay. Commonmark.thephpleague.com. So that that makes up, like, the main engine. And then on top of that, I've got Graham Campbell's, basically, Laravel shim.
Not super necessary, but it, like, you know, gives you some facades and it renders some blade engines and stuff. Or it I'm sorry. It registers some blade engines and stuff. So it's kinda nice. But the crux of the whole deal is league slash common mark.
Chris
And And that that ships with Laravel now. Like, you can do string markdown and it just will give you HTML.
Aaron
I don't know who powers string markdown. It might be league. It's God mark.
Chris
Same thing. Yeah. It's the same God mark engine.
Aaron
Yep. Yeah. So it's super duper good. I have a few qualms with it in that they follow all of the best practices, and that annoys me a little bit.
Chris
Yes. It's a pain thing
Aaron
as figure. Figure. Everything is private. There aren't, like I've had to break in. I've had to use that invade thing where you, like, use reflection to change properties, and I felt 0% bad about it.
But it's very, very good. It's a great package. So that makes up, like, the core of the rendering of markdown, like, engine. But then on top of that, I think there are a lot of things, there are a lot of things that you can add to markdown that meet your specific use cases. So for example, one is, blade rendering.
Right? So when you're writing a markdown file and you want, like, this special blade component that you have. Like, I have one for a YouTube embed. I have one for a Twitter embed that, like, makes the tweet look really nice instead of, like, giant the way that the real embeds work. And when I'm writing markdown, I want to just like, I just wanna use my blade component.
And there are a couple ways that you could do that. You could and I think this is dangerous. You could run blade render over the markdown after it's been turned into HTML. Right? So you can write raw HTML in markdown.
That's not a problem. But if you run blade render over HTML that you don't control, that possibly includes valid blade inside of a code block. Yep. You're gonna be host. Right?
So if you're writing an article about scary. Yeah. If you're writing an article about Laravel and you have some valid PHP in there and then you run Blade render over it, like, oops. You're toast. Especially if you're using that on user generated content, which I would never recommend doing.
Chris
Right.
Aaron
So I've written a blade a safe blade component parser compiler. I've written, an extension that, like, looks through the code blocks on my page, and after, you know, some random number of code blocks, it puts a little ad for torchlight underneath the code block. It's like, hey, this syntax is highlighted by torchlight, a service that I created. I have a few of those, like I have one that I'm working on right now that'll insert, like, a newsletter sign up, you know, 75% of the way down the page. And so it just kinda like you can encode some best practices into your rendering engine.
And then, like, let's say you're launching a course or something. You can swap out your newsletter sign up for, like, an in house course ad across all of your articles at once by going into this little markdown extension and saying, like, oh, the thing I'm promoting right now is not the newsletter. It's this thing. And so there's there's so many things that I think once you understand that you can break into markdown and get access to the abstract syntax tree and just, like, kinda walk around and look at stuff and do stuff, then you can really start to take your, like, your markdown rendered contents. You still get the authoring experience that you desire, but you still get the outcome of, like, no.
I'm using it's not just it's not just Tailwind Pros. I'm using, like, blade components and embeds and Mailchimp sign ups, and that makes your site, like, do the thing that you really want it to do.
Chris
Yeah. I mean, I I definitely feel like the thing about markdown is it gets you 80, 90% of the weight to what you want, and getting that other 10, 20%, there's not a good sort of canonical approach to that yet. And I, you know, I've seen there are various there have been a bunch of different attempts to do it either, you know, extending the markdown syntax directly or, like you said, just embedding blade components in your markdown or, you know, I've looked at just, like, having sort of a fragment syntax where I can be, like, right here, pull in this other blade file, you know, and just just render the blade, you know, or there's a bunch but all of those I don't know. I I've never got the ergonomics of that right because it's, like, most of the time, like, I want to just do an inline code block if I'm doing, like, a code example, but every once in a while, an inline code block is not enough, but, like, finding that balance, I don't know, that's always been a pain. And then have you solved the indentation problem?
Because that's like it's not that hard to solve, but that was the thing that I need like, I needed to do first was, you know, even in Laravel, like, the the markdown renderables where you have to, like, keep everything aligned to the left column.
Aaron
You have it left or you're gonna blow it up. Yeah.
Chris
God. That drives me nuts.
Aaron
Yeah. That drives me nuts too. And that's one of the frustrations with, trying to write non markdown in a markdown file is, like, you write some pretty HTML that's indented correctly, and it turns the inner part into a code block. And you're like, f. Like, I don't want this to be a code block.
This is actually code. And so the way the way that I solve that, one of the solutions for rendering markdown in in no. I'm sorry. One of the solutions for rendering blade in markdown that I, like, wrote an extension for, I think is kinda neat. You you open a code block and you say that this code block is, you know, HTML or blade if your, you know, your editor supports blades and text highlighting.
But I just say that it's HTML. And then I write all of my fancy HTML, and I get syntax highlighting inside of markdown because markdown knows this is a code block. I'm gonna I'm gonna highlight it as HTML. And then so, you know, you do 3 back ticks, and then you write HTML, and that's that's the language identifier.
Chris
Okay.
Aaron
What I can do after that is do a plus sign and say literal, or I can do a plus sign and say, I think the other one is like blade. And my markdown rendering engine will either put that HTML literally in there or it will run blade render over that code block and input it. And so that way I have I have an escape hatch that's like, oh, shoot. I'm about to write some indented, you know, blade or I I need this blade component to run or whatever. So I just open a code block and say, this is, like, literally blade or, like, parses maybe the other word.
Parses this as as blade, and it it does it. And it doesn't put the code block in, obviously. It puts the contents of that code block in.
Chris
Yeah. That's a great solution. I feel like the I've gone the opposite direction where my files are blade files, and then I have, like, an x markdown custom component, and it's it's not it's not perfect. I like Mhmm. I like being able to mix, like, a full, like, I I I like being able to just fully hop out of the markdown context
Aaron
Yeah.
Chris
As many times as I need to and just, like, write full blade views, But, you know, I've been able to sort of trick the IDE into understanding those markdown syntax, but it's not it's not ideal. Yeah. You know, I like I I can see the benefit of doing it the other way around.
Aaron
Mhmm. Yeah. I like I like doing it the other way around because PHP storms markdown editors is pretty good.
Chris
Yeah. It's great.
Aaron
And it's code highlighting within a markdown code block is pretty good.
Chris
And
Aaron
so I feel like I get the best of both worlds there. And then whenever I render an article, it it renders inside of, like, a proper, you know, blade layout. And so for the ancillary stuff, I just you know, I throw all of my blade all around, you know, like, the the table of contents I render with, like, alpine and blade and stuff. But, like, the actual content, it just takes the markdown renders it and plops it in. And then I do all the framing in, like, real full on blade layout file.
Chris
Now do you do much with front matter, or do you just kinda leave the title and that's it?
Aaron
A little bit. Yeah. So let me open it now so I can tell you which with front matter, I have recently you know, it runs that, sync articles command. And so if we open yeah. It's not very much, which is good.
I have an ID, which is just a UUID that I generate with Raycast. So I just open Raycast and I type UUID, hit enter, and that becomes unique. Yeah. That becomes the the unique, ID for this file. That's what makes it, you know, this idempotent.
I don't base it on the path or title or anything like that. So I have a UUID as the ID. This is all in the markdown. Title, date, description, and then an unimplemented tags list. So, like, I'll I'll tag the articles, but I haven't I haven't actually done anything with that.
But I do tag it as, like, Laravel or personal or something like that. Sure. But that's it. The path is based on the location on the file system. So it's, let's see, resources, views, articles, and then the year 2023, and then the name, like, the actual file name.
And so I don't have to do you know, there's there's an argument to be made that, like, I may wanna generate I don't know. I may wanna generate URLs differently, but right now it's just straight to the file system for that. Mhmm. And I can optionally this one doesn't have it. I can optionally specify an OG image tag or an OG image path, but the circle doesn't have a OG image.
Chris
Yeah. Yeah. I worked well, we talked about this ages ago. It It's still it never went anywhere, but
Aaron
Mhmm.
Chris
You know, laravel.com is built using a lot of this same Yeah. These same basic principles.
Aaron
Same hodgepodge system, basically.
Chris
Yeah.
Aaron
Yeah. And,
Chris
the OG images is definitely a trickier
Aaron
thing to
Chris
figure out. I feel like I came up with a decent approach to it, but it is it's a big buy in.
Aaron
And it requires a service or a server or something. Yeah. You need
Chris
a node process to build on.
Aaron
Yeah. Yeah. That's one of the things I'm hoping to solve with this unnamed well, it's named, but I'm not sharing the name. This unnamed, you know, Laravel static site thing is, like, best practices like OG images, that kind of stuff.
Chris
Yeah. Yeah. Yeah. That's cool. One thing that, we just did so, you know, I I I implemented the, the verb stocks a couple like, a month ago or whatever.
And one thing one thing that I really wanted to see happen was, and I and I basically just shamelessly stole this from Caleb with the LiveWire docs, like, the idea of just having markdown files in the main project that, like, when you're contributing a feature or updating a feature, you can also just, like, include the documentation in your Yes. Your PR. I think that's really nice. And one thing that he did that I I approached a little differently, but I thought it was an interesting decision was instead of having, like, front matter in the individual docs files, Mhmm. He had, like, a single he has a single, I think, navigation dot MD file Yep.
That is basically just, like, an empty markdown file that's all front matter. Mhmm. I opted to just have a navigation.json file.
Aaron
Yep.
Chris
And I think that maybe the difference is for docs, that feels like a better trade off rather than having to, like, crawl the markdown files and build, like, the navigation from the front matter. Yeah. And it gives you a little bit more control over, like, you know, this this, file is gonna be called, you know, quick start or whatever, but, like, the path might be, like, getting started or something like that. Like, you can change those things.
Aaron
Yeah. For the, I need to actually update all of this. But for, like, the sidecar and the air drop and all these open source repos that I have worked on, they're all pulled on to the hammerstone.dev website, which is I need to pull that onto my personal website. But they use a, a system, you know, that I obviously wrote from scratch, like everybody else does. And it uses a similar idea.
It uses a manifest dot JSON. And so all of the docs sit alongside the code, which has been helpful because people do make pull requests and they update both the docs and the code. But the manifest.json just dictates, like, where the files are, what their pretty names are, how the sidebar should kinda look. Like, this group has a header of, like, you know, Lambda or, you know, deploying to whatever.
Chris
Yep.
Aaron
And so there, I can just it's really nice when you've got 50 docs pages to have 1 it's kinda like your routes, you know, your web that PHP routes. Like, you wanna just go one place and be like, alright, I gotta move some docs around. Let me do that instead of being like f. I gotta open all these files and change, you know, this dashed two words to a more clever one word that I came up with and that's a real pain. So, yeah, I like the navigation.
Json, manifest. Json for specifically for docs. I find that really helpful.
Chris
Yeah. And I mean, even worse would be, like, you have to go in and you have to change the slug, and then you also have to change the, like, group ID and, like, subgroup ID or something like that across 30 files. Yeah.
Aaron
Nah. I'm not doing that. Too old for that. Yeah.
Chris
Yeah. I think I mean so okay. Here's here's the real question. Like Uh-oh. I I I I totally see the, like, oh, I figure out a good way to do this.
I wanna turn it into a nice package for people.
Aaron
Yeah. We've all been bitten by that, haven't we?
Chris
Is anybody gonna use it? Right? Because the whole point Yeah. Of a personal website is, well, I'm gonna do it my way. Right.
Aaron
Yeah. Exactly. So I hope so. I think so. So the the thesis that I'm working with is everyone wants to do it their way, but I can I can give you a skeleton that can let you do it your way a lot faster and a lot better?
And so then, you know, my my theory is if I if I do a lot of the heavy lifting of alright. I'm gonna set you up to write markdown extensions, and I'm gonna ship, you know, with a Mailchimp and a ConvertKit embed ready to go, and then you can just kinda tweak it however you want, and you can put it you can put it wherever you want, that kind of stuff. I'm gonna ship with, OG an OG image generator that you can then you can then muck around with. Right? I think that's gonna be compelling enough to people for people to, like, download it, try it, and hopefully hopefully enjoy the authoring experience that they get to authoring faster.
I think there's always gonna be a subset of people that say they're updating their personal website because they wanna write, but really don't wanna write at all. And, like, those people, I'm fine. I'm fine with them tinkering. Like, if your goal is to tinker, just tinker. Like, don't don't lie to really this year, 2024, I really wanna start writing.
Like, I don't know. I think writing I think publishing obviously is is good for your career, but if you just wanna tinker, just go tinker. And so I think there will be a subset of if you just wanna tinker, just go tinker. And so I think there will be a subset, you know, just yeah. Lots of people use static site generators, so I think there will be a subset of people that are like, I use Laravel.
I wanna use Laravel, but I wanna have a site that I can deploy to GitHub pages based off of Laravel. And that that's what I'm hoping this will fill.
Chris
Oh, okay. So you're talking about going full static site generation?
Aaron
I think so.
Chris
Yeah. Okay. Interesting.
Aaron
Yeah. It's gonna be it's gonna be the dealer's choice. Like, you could do it my way or you could do it full on generated.
Chris
There could be a full build. Yeah. Interesting. What have you have you come up with a good approach to, like, images in your articles? So I feel like that's that's another thing that I keep on finding I wanna
Aaron
Yeah.
Chris
Like, I wish I wish that I had the authoring experience of, like, a GitHub gist. Right? I just wanna drag an image or a video file into my markdown
Aaron
and just
Chris
have it work. Yeah. And, obviously, I can't do that in my IDE. Right. And it's not that hard, but it's it definitely is a a point of friction.
Like, I don't include images in these as much as I probably could Yeah. Just because it's a bit of a pain. Any thought about that now?
Aaron
Yeah. I have a couple solutions for that, and then I have one that I think I'm aiming for. So my current solutions are one is I walk the markdown tree looking for images and update the URLs to be, you know, Vapor does this thing where it gives you, like, this cloud front front to distribution URLs. You kinda have to use their asset helper. And so I just walk the markdown tree looking for images, and I run the asset helper over it, and it, like, makes it right.
The other is I have a route in web.php that is /asset/star.
Chris
Yep.
Aaron
And anything that goes to /asset/star gets redirected to the asset helper with the trailing wildcard.
Chris
Mhmm.
Aaron
And so that's helpful for me if I'm like let's say I'm linking to somewhere. So, like, when I set up on Twitter, there's a way that you can set up, like, you have products on on your Twitter profile. And so I set up screencasting.com as a product and it needed a URL for an image. And so there, I just link link to, you know, screencasting.com/asset/logo.png. And then on the server, it redirects to, like, the long uuid.cloudfront.whateverwhatever.
So those are the 2 solutions to, like, one is you walk the document and you change the URLs. The other is you just have a really stable URL that actually does a redirect. I think for this solution that I'm working on, there will be and I think I'm gonna call it airlift because I have air drop, but I think there will be a a corresponding package called airlift that takes your public assets and puts it into s 3 so that you can just, like, you can just reference your images, like, with the root of your website being the root. And then Yeah. The markdown on the other side comes out to it references the s 3 bucket.
Or if you wanna put a vanity name in front of that, you can. But basically, I'm gonna airlift your assets out and put them on s 3 for you.
Chris
Yeah. That's cool. I like that. I like the name too.
Aaron
That's a good name. Right?
Chris
Yeah. Yeah. I mean, and even, like, you may I don't know if you can pull it off, but you may be able to because, like, at least with PhpStorm, you can you can write one of those helper files that says, like, when you're auto completing this property, like, it's a file name in this path. So you might even be able to, like, get some ID support if you publish one of those files with the package, which would be kinda cool.
Aaron
Interesting. Yeah. I didn't know that. That's cool.
Chris
Awesome. We do that with, like, you know, we do we're we're working on a a Stripe feature that's got a lot of snapshot tests in it. Mhmm. And, like, there's just, like, 30, 40 snapshot files. That not snapshot test is not right, but it's just, like, we've basically snapshotted webhook payloads from a
Aaron
Yeah.
Chris
Like, a manual test run, and and we build a test around those. And, yeah. It's just, like, a nice quality of life thing to just have, like, you know, this arrow stripe snapshot, and then it just auto completes from there.
Aaron
Yeah. That's
Chris
cool. It's a it's definitely a cool little feature. Okay. So what, are there any other, like, things that you feel, like, really need to be solved for this Yeah. To be viable?
Aaron
I think I think deploys need to be a single command. So, like, I think where it breaks down is people are like, oh, I'm gonna build, you know, my Gatsby site, and then I gotta figure out how to get it on Cloudflare pages, how do I get it on GitHub pages, how do I get it on Netlify. So every one of those is gonna have a first party driver that's like, I just deploy it to, you know, GitHub pages. So it's just like artisan deploy colon GitHub or whatever.
Chris
Sure.
Aaron
I think that's 1. And then based on the providers, it's also going to write it's also going to write Edge, if it has Edge. It's gonna write Edge middleware to do redirects. And so that's another one where people are like, alright. I got my static site.
Now how do I do a redirect? And you're like
Chris
Right.
Aaron
Oh, no. And, like, you could use meta refresh or whatever on your HTML. Like, that's a last last resort, but that's kinda grim. But with, you know, Vercel and Cloudflare and Netlify, you could just write an edge function that looks at the incoming and maps it and redirects to the outgoing. And so, like, if you go to I think it's aaronfrancis.com.
Aaronfrancis.com/ twitter, that takes me yep. That takes you to my Twitter. And so Right. There's vanity stuff like that, but there's also, like, I changed some URLs to old blog posts, and I need to redirect those. And so there will be a way, as you're deploying redirects are just gonna work out of the box, and whether it's fancy with an edge function or lame with an HTML file with a header that says refresh, that kinda depends on the platform, but that's one of those things where it's like the last mile of static sites is kinda, like, figure it out yourself.
Chris
Right. Yeah. I mean, that's very cool though to be able to just, like, have a a driver based approach that's just like, okay. For this, we can write just a a edge function that's just a template where you dump it Yeah. A bunch of the the from and to.
And then if you are on a platform that doesn't support it, you know, we're gonna write an HTML file at least that has a lot of refresh. Yeah. Yeah. Yeah. That's neat.
I was gonna say, yeah. You know, I feel like one thing that I don't see talked about a whole lot in the Laravel world or at least the the the world of Laravel that I'm in is SEO. You know? Like I don't feel like there are tons of like really established patterns for SEO in Laravel, and I don't know, this is coming I definitely came up in the era of, like, doing stuff for SEO that in hindsight was maybe a questionable.
Aaron
You were gray hat.
Chris
But back, you know, back in the early 2000,
Aaron
like Sure. Sure. Sure.
Chris
It's constant. Yeah. Yeah. A gray hat was not necessarily even a thing. It was just like, oh, yeah.
Sure. We'll buy
Aaron
Sure. I have a private blog network.
Chris
1,000. 1,000 Domains and and and also pay for a 1,000 independent IP addresses and then, you know, connect them all together.
Aaron
What could be wrong with that? Yeah. Exactly. That seems totally above board.
Chris
It worked for a long time. I mean, I still do.
Aaron
That's a different metric though.
Chris
Yeah.
Aaron
It it worked as a different metric.
Chris
My business partner used to put, like, he knew I had yelled at him so many times, but he'd just, like, sneak it in. He'd, like, put text in white at the bottom of the page. Brutal.
Aaron
It's like Yeah.
Chris
Like, you gotta stop this. Come on. Yeah.
Aaron
That's full on black hat. Yeah.
Chris
Yeah. But, I feel like SEO and HTTP caching are 2 areas that, like, especially for a static site solution where, you know, the the nature of the content is gonna be, like, a more, like, public facing content website. Yep. You know, those things really matter, and I I feel like there are a lot of opportunities for, you know, just better better systems to make it easier to do the right things in those places. Yep.
How much are you thinking about those two pieces for this this thing you're working on?
Aaron
Yeah. I I mean, a little bit. I think a huge part of SEO that we don't, you know, all of us don't talk about very much is having it be super duper fast and basically static, you know, you get that for free.
Chris
Sure.
Aaron
You know, anyone that's running their marketing the marketing side of their website on something like inertia JS, I think is is a little bit, misguided. If you're using if you're using LiveWire for your marketing site, that's great because, you know, to the search engine, that's just HTML. But, you know, Google can parse JavaScript now, so it's not, you know, it's not stupid. I just think Sort of. Exactly.
It's not stupid, but it's not very good at it. Yeah. Yes. Even even inertia has its first party server side rendering stuff. Right.
And so, yeah, I'm thinking I'm thinking about that a little bit. I'm not I'm not going down the SEO rabbit hole, but because it is, you know, standard Laravel, you'll have full control over your meta description evolves. But having it be fast and well structured with the appropriate cache headers, you know, is gonna get a lot of stuff for free.
Chris
Yeah. Exactly. Yeah. And, I mean, with static sites, how much control do you have over cache headers? Like, I don't know that you have a lot.
Aaron
Pretty platform specific.
Chris
Yeah. Yeah.
Aaron
Yeah. So for something like that. Cloudflare, you could say you could say cache everything everywhere all the time. Mhmm. And that might be like, that's what I do on my site.
And then on Deploy, I just tell Cloudflare, hey. Blow away the cache. We're gonna start over. And so there are options there are options like that. And that's really nice for me because I don't have to think about, what's the etag on this?
Like, has this when was this content last updated? It's just like, I mean, with with no cash whatsoever, it's still pretty fast. And so I don't mind blowing it away every time and telling Cloudflare, alright. Build it back up. Mine is still care about that.
Chris
Yeah. I I definitely think that they're I mean, and this is something we have an internal tool that we use for some of this stuff that I you know, one of these days, I wanna open source, but, like yeah, just generating e tags, like, returning, you know, content not changed, responses. Yeah. You know, doing caching, stale wall revalidate, like all that stuff. Yeah.
There's not, I mean, set aside Laravel, there's not I don't feel like there's a single canonical resource for, like, HTTP caching headers anywhere. You know? Like, even understanding the difference between, like, the cache control header and, like, the last modified header and, like Yeah. Which one do you use? Header and, like, the last modified header and, like Yeah.
Which one do you use? And Cloudflare doesn't even support
Aaron
stale while revalidate.
Chris
Okay.
Aaron
Yeah. Which sucks. Like, they've they've said, you know, for a long time they're gonna support it, but there's no there's no SWR with Cloudflare.
Chris
Interesting. Yeah. I didn't know that. Yeah. Yeah.
We don't use Cloudflare. I, you know, I use it for some personal stuff, but I Yeah. I haven't dug very deep into what they what they handle. Yeah. Yeah.
That just feels like a thing where, you know, just, like, getting it's it's it really comes down to, like, the DX, like, the ergonomics of it. Mhmm. Obviously, there's the there's the education piece of, like, knowing what to do around SEO or knowing what to do around caching. Mhmm.
Aaron
And I
Chris
think that's a huge that's a huge piece too, but just like, I don't know, there's not there there are not easy ways right now to do a lot of these things. And and and, you know, in in our case, like, I know for a while, we would, like, wrap up the response, like, instead of just returning the view, we'd have to, like, grab the view, render it, wrap it in, like, wrap it in a response object, and then set, like, the headers on the response object.
Aaron
Yeah.
Chris
If you wanted, like, fine grain control over those headers, or else, like, you're doing it at a middleware level, which is fine, but then, you know, it's a little bit more brute force.
Aaron
Yep.
Chris
Feels like there are a lot of opportunities there.
Aaron
Yeah. Yeah. And there's one there's one kinda gnarly gotcha with LiveWire the way that it does something related to the back button. Unless you Oh, yeah. Unless you disable some Livewire feature, it forces, like, no cache headers on everything.
Chris
Oh, interesting.
Aaron
Because other otherwise, it, like, the back button remembers the wrong thing or displays the wrong thing or something.
Chris
Yeah.
Aaron
So I ran I ran into that one at one point too. So, yeah, there's there's a lot there's a whole lot around caching that we don't super talk about and that frankly, I don't really understand, which is why I really kinda like my my crude blunt force, like, cash it all, blow it all away, cash it all, blow it all away.
Chris
Yeah. And for a static site generator, that's, like, a super appropriate
Aaron
Yeah. Cake.
Chris
You know? That's, like, a really nice that's an that's a nice approach. Yeah. Yeah. I I years ago, I worked on the LiveWire, like, history state stuff.
Oh, yeah. Here you go. A dark, dark
Aaron
Yeah.
Chris
Like, horrible place to be.
Aaron
Yeah. Because it, like, sometimes doesn't contact the server. It just pulls the page right out of the cache or something. And yeah. It's it's a mess.
Right?
Chris
There's I mean, in theory, it's it feels pretty straightforward, but there are so many browser specific gotchas, and there's just a bunch of, like, storage limitations and, like, you need to make sure that you're pushing and popping things on and off the state in a way that feels appropriate. Because, you know, I I still this is this is the thing that I'd still love to see Livewire do is, like, you know, you can do the query string based routing, but I think that you should be able to do just full URL routing with LiveWire where it actually just changes the URL, but yeah, we spent probably 2 weeks, working on it Each. And built the whole feature, and it was great, but it was just, like, you know, Caleb was not confident enough in it to be, like, yeah, this is this is good to go. And it was It's You know, I hate these moments in programming where you're just like, I know this is not good enough, but I don't know what, like, I don't know what would need to happen for me to feel comfortable about it. You know?
Aaron
Yeah. I know. I hate that too.
Chris
Yeah. Well, is there we're we're right at an hour. Is there anything else that, you were thinking about with this, with this secret project of yours? I'm trying to think if there's anything else. Any points to talk to you
Aaron
if I have any secret projects.
Chris
I definitely feel like, you know, when I was setting up my my personal website, just building it in Laravel felt mostly fine, but I bumped into all this stuff. I definitely Yeah. I definitely feel like having a really good and and I would love to see this be a, you know, a package that you could pull into anything, like Mhmm. Really good markdown support that, like Yeah. Handles a lot of these cases and just has a bunch of, like, really best practices built in.
I love the idea of having those, like, interpreted code blocks. I think that's pretty neat.
Aaron
Mhmm.
Chris
Yeah. That's very cool. And I mean, I don't know, just getting markdown to output, like, decent tailwind Yeah. Classes, It's kind of a pain, you know, going back to the the way that the common mark class is configured. It's like
Aaron
Yeah.
Chris
Oh, I have to register all these, like,
Aaron
custom stuff. So much freaking crap. Yeah.
Chris
Yeah. And it's all just, like, an an array with, like, magic keys everywhere. Yeah. It's yeah. So, like, being able to just ship, like, a Tailwind plugin that just Yeah.
Renders everything Exactly. Is like Tailwind pros, but, like, you know, because you need a little more than just pros.
Aaron
Yeah. You need you need to modify pros a little bit. Yeah. Yeah. So code blocks is gonna be a big one.
Having tailwind you know, I think there's gonna be, like, a core package, kind of the way that the Laravel framework works. There's, like, a core Laravel and then there's a starter like, there's the Laravel framework where you start Right.
Chris
The
Aaron
project. Right? Right.
Chris
So
Aaron
I think that's gonna be how it works is there's gonna be, like, a core package that does a lot of the heavy lifting, and then there's gonna be a composer create, you know, new project that has, like, tailwind already installed and set up and all of the stuff that actually lives in application land, but I wanna get people started on the right foot, that kind of thing.
Chris
Right. Yeah. That makes sense. I feel like that you might even be able to, like, tap into the whole, like, composer new, Right? The the same way that you start a new Laravel project with just Yeah.
Aaron
Yeah. I think you can. I think you can just register it somewhere with Packagist to say, like, this is a this is a creator starter kit project template, whatever it is.
Chris
Yeah. That's very cool. Sweet. Anything else?
Aaron
So stay tuned for that.
Chris
Anything else fun that you've been up to that just I mean, is is is there anything other than babies?
Aaron
Yeah. That's the tough part is, you know, I am on paternity leave right now, so I do have less planet scale work to do, but I also have 2 newborns, so I have a lot more
Chris
Yeah.
Aaron
Home life to do. I've been playing with Pulse quite a bit and Pulse is
Chris
very, very good. Yeah, it seems
Aaron
very good. I started working on a community site and then got just totally pwned by babies and Matt Sauer came along and was like, hey, what if I did some of it? And he's just done so much of it, which is awesome.
Chris
Awesome.
Aaron
But yeah. Doing that, recording some videos. I wanna record a video on this this markdown rendering stuff, and, I'm building out a Fathom Analytics Pulse card, which I think is gonna be kinda fun.
Chris
Yeah.
Aaron
So, yeah. Just doing, like one of the great things about paternity is you can just kinda just do random crap because
Chris
Right.
Aaron
You don't have to see these long running projects through. Like at work, I don't have to be like, All right, let me plan my next 6 weeks of content and do my research. I can just sit down and be like, alright. I got an hour. I got an hour and maybe actually I only have 30 minutes and if because someone might wake up here in a second.
So what do I wanna do? And that's
Chris
kinda funny. Tinker with something.
Aaron
Yeah. It's a very, it's a very free flowing creativity kinda time.
Chris
Yeah. For sure. Yeah. We need to catch up on verbs too. I I still feel like I need to convince you that, event sourcing is is, a good path for some Hey.
Some things.
Aaron
I'm I'm still you give me you give me a you give me, like, a solid, setup and use case. I'm still willing to give it a honest go. So yeah. We we do need to do that.
Chris
No. Daniel and I were talking about we'll we'll follow-up later, but, that's been a fun it's been a fun it's been a fun thing to to been working on.
Aaron
It seems, it seems to have been well received. Do you feel that that's the case?
Chris
Yeah. I mean, I think, you know, we're still we're still very much an alpha, and I think there are a lot of there are a lot of things that are just, like, we're trying to figure out, because, you know, the the the whole vibe of verbs is just, like, the ergonomics have to be perfect. Right?
Aaron
Like Correct.
Chris
We'll we'll write some horrible, terrible code so that, like, the the So
Aaron
that I don't have to.
Chris
API is great. Yes. And, you know, there are a few places, especially around testing, where, like, we're, you know, we're very aware that it's not where it needs to be yet. Mhmm. So right now, there's just like a handful of, like, true heads in there, and it's that's been really fun though to have, like But
Aaron
you you have a few people that are, like Yeah. We've got to it. They're little like, a discord or something.
Chris
Yeah. Yeah. Love it. And, you know, people are coming in with real questions and working on real little, you know, either, like, test projects or or any you know, I know that Daniel's working on a a production thing in verbs already. So Cool.
I I think it's it's pretty much good to go. It's mostly just, like, the main API is there, but all the little things around that, we're still kinda landing on. You know? But yeah. No.
That's been great. Awesome. Alright. Well, thank you for, hanging out. I feel like, we've I don't know that we've solved the problem of personal websites, but I
Aaron
I think that, like,
Chris
you know, we've touched on all the major major points at least.
Aaron
And we had some fun, which is which is maybe the real journey is the fun we had along the way. Right?
Chris
There you go. Yeah. Something like that.
Aaron
Something like that.
Chris
Alright. Sweet. Well, thanks for hanging out.
Aaron
Yep. See you next
Chris
time.