💻 Powering Static Sites at Scale with Svelte and Elder.js
Presented by: Luke Edwards, Nick Reese
Originally aired on November 4, 2023 @ 4:30 PM - 5:00 PM EDT
In this Full Stack Week segment, join us for a fireside chat as we discuss an "SEO-first" framework to build highly performant static sites at massive scale.
Visit the Full Stack Week Hub for every exciting announcement and CFTV episode — and check back all week for more!
English
Full Stack Week
Transcript (Beta)
Hi, everyone. My name is Luke Edwards. I am a developer advocate here at Cloudflare.
And today I am joined by Nick Reese, who is the author of Elder.js, a static site framework built in Svelte.
And Nick and I are going to talk about how you can build and deploy static sites at scale using Cloudflare's global network.
Throughout our conversation today, if you have any questions, feel free to write in to livestudio at Cloudflare.tv.
Cool. So, Nick, do you want to tell us a little bit more about yourself?
Sure. Yeah. First, thanks for having me. It's interesting to be talking at a developer conference, because I'm normally the marketing guy that does the talking at the marketing conferences.
But since writing Elder.js, I've had a chance to speak at some developer conferences, and it's been a lot of fun.
A little bit about me. My background is in marketing and SEO and performance marketing, also known as affiliate marketing.
That kind of gets a bad rap.
But essentially, I'm the guy that builds SEO properties that helps people make informed decisions.
And in some cases, we make commission off of that. My last major property was broadbandnow.com.
And today, I work on fineenergy.com and elderguide.com.
And essentially, SEO has paid the bills since I've had bills to pay, I always say.
And so, for about 15 years now, I've done SEO full-time and built my own sites.
And so, that evolution has gone from WordPress to some .NET stuff into the JavaScript world, and on to building my own static site generator called Elder.js.
And it's been an interesting journey. I am very much a self -taught developer.
I have no computer science background at all. And it's been fun to build a framework that's gotten some traction.
It's been kind of embarrassing too along the way, because you're always a little bit shy about sharing your code.
But thanks to your advice and the advice of others, as long as the code works and it's well-documented and it does what it's supposed to do, there's nothing to be embarrassed about.
It's been a lot of fun and I'm excited to be here today.
I'm a huge fan of Cloudflare. We use workers every single day on all the properties I work on.
So, it's been a huge pleasure. Well, Elder has definitely turned out to be a great framework.
So, you have absolutely nothing to be embarrassed about at any point throughout this progress.
But so, as an SEO, obviously, there's a lot that goes into that.
But clearly, the reason why you started caring about this stuff is not only just the content, but there has to be...
There's performance characteristics that play into SEO too, right? So, yeah. I mean, the main reason I developed Elder.js is because I knew a little bit of PHP and I knew a little bit of .NET, but JavaScript was my strong suit.
And when you look at the...
Especially in 2018 timeframe, you look at the JavaScript ecosystem and everything was focused on single-page apps, except there was Gatsby.
And Gatsby allowed you to generate static sites that had a full client site hydration, total interactivity, and all the routing was done on the client.
And I thought that was going to be a dream, right?
So, in selling my last company, one of the projects I was given, the company that acquired us was to acquire a WordPress site and move it over and basically redo it and make it substantially more profitable, which is kind of where my expertise lies.
And decided to do that with Gatsby and the migration went well and everything was...
Essentially, the site was going to three to four X in the first year after the redesign.
And then we started hitting little SEO issues, specifically how we were setting the canonical tags, which is...
Essentially, that's a tag that Google uses to resolve which URL is the permanent URL.
And so, if you have example .com slash test and the user comes in with a query string after that, so a question mark in the URL with a bunch of variables, Google uses the canonical to figure out which one to index.
And in our particular implementation, we were relying quite heavily on some assumptions that Gatsby was going to provide to us.
And essentially, all of our canonical tags broke in unpredictable ways and took us a really long time to catch because there was a client-side service worker.
And it was essentially covering up the issues and serving us stuff right out of our local storage.
And we didn't know what we were seeing. One of those things where it works on my machine, but it's not working on Google's machine.
Exactly. Ultimately, it was an exercise in pulling our hair out.
And I was on it with a couple of smart developers and had one of the best SEOs in the industry working with me.
And it took us forever to unpack what was happening.
And the site ended up not doing so well because of these SEO issues.
And ultimately, the site has been rolled into a larger site afterwards.
And all of this was because of specifically issues with the service worker and issues with Gatsby breaking on a few patch updates.
It actually happened twice.
And so, for us, it was kind of like, wow, what a shame. This could have been huge.
And so, for me, when it was time to build my own projects, I tested all the other ecosystem, all the JavaScript ecosystem in order to find out what sort of website can build sites at scale.
And so, the smallest sites that I build are like 5,000 pages.
And all of these pull in a huge amount of government data.
We do a bunch of calculations and we generate the pages on them. And so, if you want to take an example of what we're doing, you can look at findenergy.com.
And we're pulling in billions of data points from the EIA and several other government data sources around power plants, pollution, energy usage.
And we're essentially making sense of that for the users.
And it's quite a large amount of data that needs to be processed.
And when you're doing that on a server-generated framework or server-side rendered framework, you're very much limited by your query time because you have to spend a ton of time optimizing your query so things are fast.
Well, one of the benefits of having a static site generator is you generate static HTML and you can serve it on the CDN and everything's super fast.
So, that was really the appeal of building a static site generator is if we have all this data and there's a huge amount of data, I can spend...
I'm not an SQL guy. I'm like a front-end guy that's...
I'm self-taught. I really don't have a good type, right?
But SQL is not my strong suit. And so, I figured, if I can statically generate all the HTML, this is essentially a dream.
And so, Elder.js evolved out of those needs.
I tested all the frameworks, everything from Next to Nuxt.
And there was this little framework that I don't believe it's maintained anymore that was called hydrogen.js.
And they used template literals in order to basically just do fancy string concatenation.
And I was like, hey, this is really fast.
And so, I started playing with things and slowly learned about Svelte and realized this is definitely what I want to be using for the front-end.
And I was like, hmm, I wonder if there's a way that we can just hydrate the parts of the pages that need to be hydrated.
And I didn't really have those words around it because this was really early in the partial hydration conversation.
No one was really doing that.
And I'm gonna take a step back. If you're in the JavaScript ecosystem, essentially what this means is that you have a JavaScript framework on the front-end and the server is passing you all the HTML that's static.
What happens in that moment? Does the front-end take over and rehydrate, make the entire page interactive?
Does it control the whole front-end?
Or are you doing something that has come to be known as the islands architecture where only parts of the page are hydrated?
And so, this is called partial hydration when you're only hydrating parts of it.
And so, in Elder .js, I decided I wanted partial hydration and wrote a little wrapper to do that.
And things kind of kept evolving.
It's funny how you set out to write your own framework and you say, hey, it's only going to take an afternoon.
I should be able to get something working.
And then you look back a few months later and you're like, wow, that was a lot of time.
But I'm really proud of what it's created. So, essentially, Elder.js is designed to build static sites at scale.
And specifically, it has insanely fast build times.
Some users are saying it rivals Hugo on large sites, which is pretty fast because that's written in Go and Elder.js is written in JavaScript.
So, I'm pretty impressed with that. It handles partial hydration.
It has zero kilobytes of JavaScript if it doesn't need it. And it has really quite elegant data flow if you're building really data-heavy sites.
It's also great for blogs.
And there's a way to essentially upgrade to server-side rendering if you need it.
And I'm looking at figuring out how to get server-side rendering in CloudFloat Workers also.
So, you can definitely help with that part. Yeah.
We'll definitely discuss that because I think I've got one hiccup I need your help on.
But so far, it's been an amazing journey. And as a developer, I mean, this is the first open source project I've maintained.
And it's been really interesting to see what people are building with it because SEO is a zero-sum game, which means if I win, someone else is losing.
So, people really don't often talk about their SEO projects.
But as the developer of a framework, I get a lot of questions.
And some of the sites I'm seeing built with this are just amazing. And it's quite interesting to see it evolve and see how people are using it.
But the hard part about static sites is figuring out how to do it thousands of pages, which is what this talk is mainly about.
How do you optimize for not only a great client experience, which is on that first page load, but how do you also have a great developer experience where you're able to generate thousands and thousands of pages?
And so, one of the decisions I made on Elder.js and what a lot of other frameworks are doing is they're doing incremental static site generation.
So, in other words, only build what needs to be built.
Where I took the opposite view, which says computing resources are really cheap, developer time is what's really expensive.
And so, let's just spread all of these pages across all the available CPU resources we have and just build as fast as we can.
And so, I really think that incremental static site generation is a sexy engineering problem, but not so much of a sexy business problem.
And so, I come at this from a little bit of a different background, having worn quite a few different hats, mainly from the CEO marketing role and the business role, and then coming into developer.
So, I come in with a different worldview, but it's- Pragmatic.
It's been interesting. Yeah. Just get the content on the page and make it go there as fast as possible.
I get it. Exactly.
And one of the things that Elder .js has built into it that I feel like we haven't really fully embraced with the Jamstack or within the JavaScript ecosystem is something, short codes, right?
And so, this generally happens as you get beyond really tiny teams.
You have the content department that works with the developers to make things happen, right?
And so, generally, there's a disconnect between the two.
And so, the marketing department or the SEO team will say, I need this on the page, and then the developers need to make that happen.
And the way WordPress has handled this sort of thing is to encapsulate programming logic into some sort of text place holder that's put on the page.
And they call them short codes.
And I think this was obviously done before WordPress, but essentially stole how WordPress is implementation of it and implemented in Elder.js.
And the great thing about short codes that I think most people don't really fully understand.
If you're watching this and you deal with a content team, this is the biggest tip I can give you from all of my years of building out large SEO sites is empower the content team with as much as you can, as much firepower as you can give them.
And so, in the form of short codes, whether that's giving them a short code to build tables or giving them a short code to put a call to action on the page, it's a way of future proofing the content.
So, the classic example that I use is, let's say that on your blog, you embedded YouTube videos and you have 100 YouTube videos embedded.
And every single time you've copied and pasted the embed code from YouTube, well, you have kind of a rough problem on your hands when you need to go redesign it because in that embed code is the dimensions of that video.
And so, instead, what would be better instead of having to change that 100 times, the next time you change your design is to set up a short code that takes a single prop and it allows the content team to put in the YouTube ID, and you can style it any way you want and you have complete control over it.
And short codes, just explore them.
Whatever framework you're using, you can definitely explore. And Elder.js, actually, we've open sourced the short code library.
It's a fork of an earlier version, but I would highly, highly recommend looking at short codes and see if you can get it into your stack, even if you can't use Elder.js.
So, I want to jump in real quick.
So, short codes may sound like a foreign term to a lot of people listening.
So, short code is like the templating systems version of a React component or any component, right?
You define your logic, your view layer once in one place, and then you can just inject it by a short code or like a component reference anywhere within your page.
And so, again, to go back to your Gatsby days, like this is an MDX-like problem where you can have components defined somewhere in a components directory or tags directory, whatever you want, and then reference that JSX tag directly within your markdown file.
And so, in years past and many years past, you know, this was always what you did within WordPress themes and many other static site generators beyond that.
And so, you know, what Nick's done with Elder .js is the exact same approach, but made it a lot more configurable and JavaScript -based, which means it's like exponentially more flexible in the long run.
Is that about right? Yep, that's about right. And because it's, if you use Elder.js, you have like essentially full control with a short code.
So, you have access to drop arbitrary code into the head, arbitrary code into the footer, arbitrary CSS.
You have complete control of everything that you have access to in Elder.js because at the core of it, I stole a lot of ideas from WordPress.
I feel like everything was an evolution of WordPress for the JavaScript ecosystem, in my view.
And so, having worked with quite large development teams in the past on 50 -plus WordPress sites at one time we were managing, what we ended up doing is we had a single WordPress theme that we had all of our sites were built on.
All of them were exactly the same core foundation.
And then we had all the developers essentially put all the weird stuff in a hooks.php file.
So, Elder.js has a very similar view of it.
And how WordPress hooks worked was you could plug into any part of the WordPress lifecycle or the theme lifecycle if the theme had hooks.
And so, that allowed us to have a very standard foundation where everyone knew where the complexity would be hidden.
On Elder.js sites, it's the same setup. Everything weird goes in your hooks.js file and you have complete control of over the entire lifecycle of the data or the build system.
And so, on top of that, short codes are actually called on a hook.
And so, you have full access to everything you have within the hooks.
And so, it's been quite interesting. The canonical example for me personally that I referenced that I don't always talk about, but we had a problem on one of our sites.
We wanted to show plans and prices on a certain vertical. And we wanted this to be distributed across our entire network of WordPress sites.
Well, that's not necessarily an easy problem within WordPress, specifically because you need to make an API call.
And the nature of the WordPress ecosystem in those days was you couldn't really do async calls.
And so, the great thing about Elder.js short codes is that they're asynchronous.
So now, if you wanted to show an interactive widget that needed to hit something externally, you can do that on load or you need to make a database call or whatever.
So, I really think short codes are a great way of future-proofing your content.
It's essentially giving your content team superpowers or your marketing team superpowers.
And so much so that you can even use short codes to edit the title on the page and different things.
And it's quite fun.
But yeah, building out Elder.js has given me a completely different view of the problem space.
And I feel like when you're just sitting on the marketing side of the table or the SEO side of the table, you kind of are looking at it and saying, I wish these things exist.
And I'm not the best developer in the world, but I do understand the problem quite well.
And so, diving in to actually get to build the problem I've been working on for 15 years and build a framework to solve that has been quite enjoyable.
And there's some things I would do different as with anyone that builds a framework when you look back in hindsight, but quite happy with where it's at.
And specifically a problem space that I find it's interesting that I found that as your team grows, you end up needing to either hire a full-time SEO to check for common SEO issues, or you end up needing to build something into your CICD pipeline to make sure that SEO issues don't shift to production.
And so, what comes with Elder.js right out of the box is if you fork the standard template or de -edit, which is I think what it says in the docs, it comes with a full SEO check plugin, which checks over 50 different SEO issues and gives you like a full opportunity to know when you have these issues.
And so, it checks for things like missing canonical tag or your canonical tag doesn't match what it expects to, or you have an undefined in your URL or in your title tag or your HTML, things like that.
And so, it's been quite rewarding to really kind of demystify some of the JavaScript, well, some of the SEO issues that are known in really developer circles.
And right now it's only servicing the JavaScript ecosystem, but I really think that there's quite a big opportunity for teams to prevent SEO issues from shipping to production in the CICD pipeline space.
Nice. So, you have Elder, which is this framework, which is helping you to organize your content in a way that's SEO friendly.
You start doing it quickly, has what's effectively a plugin system at its core that allows you to customize every aspect of it.
And now there's also including like an SEO audit tool as part of its build process.
So, you're basically like you're hand-holding developers and teams of developers to make sure they're in the best place scenario for getting their content indexed by Google, but we're still static at this point.
So, if you have something dynamic, or if you need to have, you mentioned a lot of forms and call to actions and stuff.
So, how are you actually dealing with the reactivity of user input? Great question.
So, the way we currently handle it is everything is... So, we actually host everything on cloud for workers in the key value store.
And so, when a request comes in, we pull it from the key value store and send it back to the user.
Well, when an API request comes in, we proxy that through to our API.
And so, if you're submitting a form, that gets submitted to our server.
Now, the interesting problem comes when you're dealing with what essentially amounts to pretty proprietary data and you're making interactivity on this.
So, let's say you go to elderguide.com and you play around with the Finder tool, and you look at the network requests on that.
What's happening is every time you move the view box of the map, we're now hitting our server and getting back the nursing homes that are within that area.
And some of that is pretty proprietary information because not all this information is public and we've paid data team to do quite a bit of research on each of these nursing homes.
And you kind of want to lock those down. And for my days on building Broadway Now and business Internet and some of the other related assets in the Broadway space, we found scraping was a huge problem.
Some of our competitors just had no creativity and they would just scrape our site and literally use the same provider IDs we had embedded in the logo names on their site.
And it was just, yeah, you can send them cease and desist, but they hide and whatnot.
And it's like, really, how aggressive do you want to be? And so, as a developer that doesn't mind, how can I make these other developers' lives hard if they're going to scrape us?
Hopefully, they don't still on this video, but if they do, kudos to them because they're looking in the right place.
What we set up now on our Cloudflare worker is every single user gets a unique API key, and it's unique to their IP address and the page that they're on.
And it has a very short time to live.
Well, not that short, like a day. So, don't abuse it too much, but I might need to change that after this call.
But essentially now, we essentially have one-time use API keys that we build using the Cloudflare HTML rewriter.
And Cloudflare Workers are like superpowers, is what I always joke. Man, for static sites, I can't imagine building a static site, again, without Cloudflare workers.
Because really, it's with Svelte on the front end and just being able to proxy everything back through to our API and do magic.
And the Cloudflare worker, it's comically beautiful.
I feel like I have superpowers in so many ways, and we can really do things that we thought were pretty hard in any other JavaScript environment.
And it's been quite nice. And so, for instance, one of the things we're doing is this temporary API keys for visitors.
Another one that we're doing is asynchronous Google Analytics.
So, you look at any of our sites, Google Analytics isn't actually running.
If you can figure out the script that's running Google Analytics, drop me a note.
I'm not that hard to find, but you won't see the Google Analytics code.
And if you're a developer, you're probably running Adblock while we're still getting your visits logged, which is useful because depending on what audience you're appealing to, more and more people are using Adblock.
And I just want a good understanding of what number of people are visiting to what page templates and whatnot.
And so, that's kind of what I use Google Analytics for. You might want to give that one a hush-hush.
Well, it's a little late now, right? Yeah, yeah, yeah.
So, we can do all sorts of fun stuff with Cloudflare Workers. So, as far as the API key example goes, you're using workers KV.
So, when a request comes in, whether it's a search request or show me nursing home 123, right?
You're going into workers KV, you're pulling out the data, or probably the pre-rendered HTML because it's coming through Elder.
And your novice implementation would have been just to send that directly because it's workers.
Workers KV are both globally available, and so they are closest to the user already.
But now what you've done is you added this additional behavior on the Cloudflare network.
Well, deployed it to the network, so it's still available everywhere.
And what you're doing now is you're mangling the HTML in some way, or at least personalizing it for that specific response.
Okay, cool. I guess the question is, if you didn't have Elder, how much of that workflow would have changed?
Not much, I assume. Not too much besides how the pages were actually generated, right?
And so, I mean, probably the biggest thing, especially on Find Energy, like Find Energy, our build times have ballooned quite a bit because we're dealing with some of the SQL queries we're dealing with are just quite huge.
And I don't think we could have built Find Energy without really hiring quite like with the team that we built, without spending like three to four times as much if we weren't using Elder.js, specifically because build times take an hour, and like generating a single page is like two seconds.
And we can't really figure out how to get the queries that much faster. Now, none of us are database engineers, and there are ways to get the queries faster for sure, but we're dealing with such an immense amount of data that's incredibly complex and doing all sorts of calculations that I don't think we could have built it without Elder, specifically because of how heavy the data is.
Yeah, yeah, for sure.
Like Elder is definitely a huge part, but I guess what I want to say is if people are listening here and thinking, oh, I have to use Elder in order to do all this, like not really.
You can just accept any data from something and then render an HTML output or use an existing HTML as Nick has done with Workers KV, right?
Just take some data, render some output and send it down. And something that we're looking at doing and something I'm really happy that Elder.js has is an upgrade path for server-side rendering.
And so right now we pre -generate all the HTML, then we ship that to the key value store, and then we purge the cache and we're off to the races, right?
But what we're looking at now is instead having it in server-side rendering mode, and then just proxying the requests, get the first request, shove that in the key value store, and then it's globally at the edge.
And so that way we can have a much faster purge, or we could selectively purge just part of the site and kind of almost get something that looks like incremental static site generation, but not necessarily exactly that.
Long-term I want it to live within a Cloudflare Worker.
I just have to figure out how to handle some of the hooks because there's like some bootstrap hooks that have JavaScript objects in memory.
So that's another discussion, but we'll solve that problem.
We'll sync up on that. Yeah. Yeah. I definitely think that if I was building broadband now today, that was a .NET site, I would definitely put Cloudflare Workers in front of it for a huge majority of the things that we were doing.
Not only does it make it faster, there's quite a bit less burden on your origin.
It's just remarkable how much it's changed the way I think about building sites.
And I know that you can just say, oh, well, you can do that with a CDN, but it's like a CDN with superpowers.
Yeah. I always like to say it's like the Cloudflare Network, especially with Workers, is a programmatic CDN.
You get full control of what the CDN is doing and serving at any point in time.
So definitely pretty cool.
We have about three minutes left. So for people who want to get started with Elder, where's the best place to start?
Go to the Cloudflare Worker docs.
There's a full guide to getting started on it. And if not, you can check out ElderJS on GitHub or just search ElderJS and you'll find the docs on elderguide.com.
Essentially, what I've tried to do is create a tutorial in the form of a template.
And so within it, you'll see comments that it guides you through how the whole flow works, shows you some of the magic that plugins offer you, shows you hooks, shortcodes, everything kind of in between.
Do you have...
Because some of the issues I hear, not issues, but some of the comments I hear from people when they're getting started with static site generators is they think that they have to work in something that is long-term.
The content never changes.
So that's definitely not the case, but do you have example starter projects that people can start thinking about to know here's the kinds of things you can do with?
With a static site generator? So I gave a speech at Svelte Summit on the very, very early version.
That's the first thing that comes to mind. But what I did is basically pull in a government dataset and generate a whole bunch of pages from it using ElderJS.
And that's... If you're building a standard blog, a static site generator is great for you.
But if you have a huge amount of data that you need to deal with and you're not an SQL expert, ElderJS is also good for you.
Because essentially what you're doing is you create, here's all the pages I want, you define all the routes and all the requests, and then you basically get to build the pages just with the data that you passed in.
So you get this really clear data flow.
And so at this moment, I don't have a good starter that shows you how you could do something like that.
But if you find any external API endpoint that has a whole bunch of data and you can spin up pages on that pretty quickly with ElderJS.
Well, we do have a question come in that I know you like answering. This question is why is ElderJS on elderguide .com?
Okay. So I'm an SEO at heart and everyone knows- We do have a minute.
So I know you like it. Everyone knows that links are essentially the backbone of SEO.
So this was an experiment to see if high -tech oriented links could help rank a nursing home site.
So it was kind of a test, a shot in the dark.
And so far it appears to be working. So we can say that a link is a link.
So even if you're getting them from the Svelte community or the JavaScript ecosystem, you can still rank a site using it.
Yeah. So it's definitely an SEO play, but it's also very meta.
It's like meta squared because ElderGuide prompted ElderJS.
They're both hosted as a built and deployed as elder sites and they all live in the same domain.
Yeah. Okay. 20 seconds left. Where can people find you?
Nick Reese on Twitter. I'm not really a guy to tweet much.
NicholasReese.com or if you're into ElderJS, jump on the Svelte discord and drop me a note.
Sounds good. Cool. Thanks everyone. Thanks. Bye.