loading...
Cover image for Before building your next static site with React, consider this

Before building your next static site with React, consider this

bholmesdev profile image Ben Holmes ・8 min read

Building my personal site without a framework (2 Part Series)

1) Introducing my new personal site, a static SPA built without a framework πŸš€ 2) Before building your next static site with React, consider this

⚠️ Warning: Potentially controversial opinions ahead! Turn back now if Gatsby is your lord and savior, and you serve to protect the React dogma.

So I just finished building my shiny new personal site ✨ I thought about using fancy, component-driven frameworks like Gatsby to stay on the bleeding edge of web development, but after some reflection, I thought to myself...

do I really need all this tooling to write some static HTML?

This ended up being a huge learning experience on how to build a statically generated SPA from scratch (check out the README if you're curious how I approached it!). But it also taught me some valuable lessons on how far you can go while ditching the component libraries we all know and love.

A little background: going from dynamic to static sites

Okay, let's be real for a moment: component-level thinking rules modern web development. Even as new frontend libraries and Ruby-esque frameworks hit the scene, they still rely on the same basic formula: write your markup and JS logic inside a bite-sized component, and compose those components with imports and exports. Whether those components are class-based, functional, or even at the DOM level (hello web components πŸ‘‹), they're all focused on these ideas of logic isolation and code reusability.

Popular libraries like React and Vue have become such a one-size-fits-all solution that we don't even question them anymore. New to building literally anything on the Internet? Just run npx create-react-app and get going!

...right?

I used to agree. But over the past couple years of Gatsby and JAMStack preaching, I've also come to realize that damn, we're making some fat JS bundles. With all these JS-based components, we're shipping entire rendering libraries to the browser, even for a company's plane ole' static splash page!

Before getting cynical, it's worth remembering why these libraries were made in the first place. React wasn't created because Facebook should be a better static site; it was created because Facebook is a super dynamic, ultra complex web app with logins, trackers, home feeds, settings menus, etc etc etc. That involves a ton of data / state management, which means, well, a whole lot of JavaScript to construct the web page. For this use case, it makes perfect sense to build and use a UI rendering library that's state driven, rather than markup driven.

This is why Gatsby (a popular static site generator) came years after, say Redux state management. Devs were mostly fascinated with building dynamic, JS-driven experiences that state, props, and data objects could solve. It wasn't until later that devs started wondering how they could bend these JS-heavy libaries to their will for static site creation.

If you ask me, it's pretty ironic that it takes a 500 MB directory called node_modules to generate a website with... as little JavaScript as possible.

Still, I can't say I'm surprised either. When you're taking a library like React, which needs JavaScript to render anything to the page, you'll obviously need even more JavaScript to process all that rendering logic to begin with. Fire really does fight fire.

So... why use React on a static site?

At first, it kinda feels like using a chainsaw to slice a loaf of bread. Why use a rendering library like React when you have zero-to-little rerendering to worry about?

In short, hydration.

Flash dance scene where water bucket falls onto dancer sitting in chair
If you don't get this reference, go culture yourself

For those unfamiliar, hydration basically lets us write a dynamic, state-driven webpage, but also render as much of the page ahead-of-time as possible using static HTML. The Gatsby blog does a great job explaining this process, but here's a quick step-by-step:

  1. Your app exists as a big bundle of components, much like a create-react-app.
  2. The static site generator comes along and renders out this bundle at build time. Now, instead of shipping a blank HTML file to the user, you can send the entire page's markup for a speedy page load.
  3. Now, we want to do some stateful component magic alongside the static HTML we just built. To pull this off, we can look at the HTML page that's already been generated and compare it against our tree of components. When we find a component that does some state management craziness, we'll slot it into our existing HTML without rerendering the entire page. In other words, we hydrate our markup with some stateful components.

Seems slick! This comes in handy when you have some JS you want to use (say, a crazy animation library for added spice) that only apply to small areas of your otherwise-static site. But as you might have guessed, we'll need to ship the entire component library to the client in order to compare against the HTML. So it's still a fat bundle... but at least the user sees something on the first page load πŸ€·β€β™€οΈ

And what if you don't need state management?

Now, React doesn't make as much sense. If we just need to handle some button clicks, we should probably just write a couple lines of vanilla JS instead of, you know, shipping the entire React library 😬

For some perspective, here's some common dev requests when building a static site:

  1. We want to break down our static site into reuseable UI components that can accept some JS objects as parameters (aka "props"). This lets us, say, turn a list of blog post links into a bunch of clickable cards on our homepage.
  2. We need to fetch some information at build time to slap into our production site. For example, we can go get some Twitter posts at build time to slide into our site's homepage, without shipping any API calls or exposing secret keys.
  3. We need to generate a bunch of URL routes from either a directory of files or a fat JSON object of content. For instance, we have a folder of markdown files that we want to turn into a personal blog, making each file its own URL on the interwebs.

These are all great reasons to use static site generators. But looking at this list, only the first requirement actually involves a component library. And even then, we may not need to worry about rerenders or componentized state management; it's mostly done at build time! If only there was a way to make our markup reuseable and template-able, without shipping a bunch of unused JS...

(Re)enter: Pug

That's right, good ole' Pug (formerly Jade). You know, that cute little templating library you used on your last CodePen, or maybe the weird looking HTML you found on an Express server template. It's a mighty little library from a pre-React era, before component-driven state management was even a thing.

It also uses a simplified syntax for HTML that makes it a bit easier to type / look at, which I'm personally a fan of 😁

So why am I bringing up this jaded (pun intended) templating library? Well, let's run through some of Pug's defining features to see what it can do. I'm hungry so we'll use a donut shop for examples 🍩:

1. You can take in some JavaScript data and turn it into HTML elements

This opens the door for all kinds of craziness, like looping, conditional "if" blocks, defining text content... you name it:

   main.krispy-kreme-menu
    if menuItems.length === 0
        p.alert Sorry! Sold out of gooey deliciousness :(
    else
            dl
            each item in menuItems
                dt #{item.name}
                dd #{item.price}

And at the JavaScript level:

   const stringOfRenderedHTML = pug.render('/filename.pug', { menuItems: [...donuts] })
   // spit out this string of HTML into a .html file at build time

2. You can compose multiple HTML files (now .pug files) into a single page layout

For example, you can create a navigation bar in one file...

   // nav.pug
   nav.krispy-kreme-navigation
    a(href="/") Home
    a(href="/donuts") Buy some donuts
    a(href="/contact") Somehow complain about your donuts

... and import into another file:

   // index.pug
   html
       body
           include nav.pug
           main.donut-content
               ul.list-of-tastiness
           ...

We can go even deeper by passing parameters / "props" between these files. Check out this mixin syntax:

   // nav-mixins.pug
   mixin NavBar(links)
    each link in links
        a(href=link.href) link.text
   // index.pug
   include nav-mixins.pug
   html
    body
        +NavBar(donutLinksPassedDownByJS)
        main.donut-content
            ul.list-of-tastiness

Here, we can consider each mixin an export statement from nav-mixins.pug. Then, when we include this file somewhere else, those mixins become usable via the + decorator (aka our "import" statement).

So in summary...

βœ… We can turn JSON objects into static HTML with a one-line script (pug.render(filename, someJSON))

βœ… We can break up our layout into multiple files using imports

βœ… We can define component-like "mixins" for reusability and data passing

...in other words, we get to make our UIs with components, but without sending a bunch of libraries to the client!

But wait, this idea is nothing new!

I know! Backend servers have been doing this for decades.

Let's consider the server-driven model you would use for, say, an ExpressJS app. Everytime you hit an API endpoint, the server may go look up some info from a database, roll that data into an HTML template (probably using Pug), and send it back to the user. Same goes for PHP, C#, GoLang, or whatever exotic server you've seen before.

But guess what? A static site generator does the exact same thing! The only difference is that now, instead of doing all the data fetching + templating in an API endpoint, we're doing it in a build script that we call when the website actually gets deployed. For those familiar, this is that fancy script you tell Netlify to run when you first deploy your site.

Servers used this templating model long before we were making crazy, ultra-dynamic web apps. So my question is this: when your website just has some static landing pages, a few lines of JS, and maybe a blog to generate... why throw away this idea of templating for component libraries?

Call to action πŸ‘‰ check out 11ty

I just found out about 11ty (pronounced "eleven-tee"), a static site generator built with this exact philosophy in mind. You can choose the HTML templating language of your choice (Markdown, Haml, Pug, Nunjucks, and a bunch more), and let the framework handle all the complicated routing and page generation for you. If you're trying to build a portfolio site with a blog, a promotional splash page for a company, or anything super static-y, this is honestly the best solution I can think of.

You can also fork the Pug-based framework my personal site uses if you're curious. It's missing some pretty major capabilities at the moment (nested routes and CMS integration to name a few), so proceed with caution in case you're so brave 😈

That said, I'm definitely not suggesting you give up your beautiful Gatsby site! There are some serious benefits to their hydration model in case you want any state management stuff. Plus, if your super comfortable in React-land and don't have time to pick up new tools, it's a pretty convenient choice with a huge community of support. Same goes for Gridsome, a Vue-based static site generator that works in a similar way.

Anyhow, whatever you end up using, I hope this article got you thinking a bit more about what static site generators really do. With that, I'll leave you with this cute pug photo to stick in your mind 🐢

Cute pug sitting on a bed

If this article was helpful...

I love writing about this sort of stuff!
🐦 Follow my Twitter for random web dev tips and articles I find cool
πŸ“— Follow my blog for new posts every 2-3 weeks

Building my personal site without a framework (2 Part Series)

1) Introducing my new personal site, a static SPA built without a framework πŸš€ 2) Before building your next static site with React, consider this

Posted on by:

bholmesdev profile

Ben Holmes

@bholmesdev

GA Tech grad and full stack web dev all about good design, good music, and good code

Discussion

markdown guide
 

11ty is absolutely fantastic! I'm using it for all of my static site projects so that I ship much smaller bundles with much faster build times! I would also strongly recommend trying out Nunjucks with 11ty, as it's much closer to HTML!

 

Yeah I noticed nunjucks in their docs! Decided to talk about Pug here since it had my heart since my CodePen days, but that looks like a super capable templating lib too. Glad to hear your success with 11ty btw!

 

Ok so if I understand well, you make the case for using no framework when building mostly static website that don't ship much dynamic content and interactions.

I don't understand why is it so important to reduce bundle size to a minimum if, anyways, loading the framework is not required to interact with the page (if you used pre-rendering/server-side rendering).

Plus, I think you overlooked the fact that declarative components are easier to maintain and make evolve than imperative DOM manipulations. Maybe you'll save 0.5~1 second of the life of each of your visitors but it will take you 2x or 3x the time when it comes to adding a new feature after some time (in my opinion).

Still a well written articles with good examples though. Thank you for sharing.

 

I think Next.js is very good for this. Without almost any tooling you can just do next build && next export to generate the static site. And then you have the option to switch to dynamic by doing next build && next start. And for the dynamic version, if you are worried about React size you can just replace it to Preact (3kb with the same api).

 

Yeah, thanks for pointing that out! Next + Preact is a super powerful combo. I've heard some complaints about library support on Preact, but the community's still pretty robust at this point. Worth checking out!

My only complaint is that the developer environment is dynamic (by design of course), and you won't know how the static site actually performs until you export. This can lead to somewhat longer build times from my experience, and certain pages of the site not getting crawled properly. That said, for smaller scale projects, it shouldn't matter too much.

 

Great post! I'm actually working on Dhow right now, a Node.js SSG that lets you write JSX syntax (similar to next.js with getProps & getPaths functions) but generates pure HTML. It's currently a work in progress but I would love to hear what you think!

GitHub logo kartiknair / dhow

JSX-powered static site generator for Node.js

Dhow

npm version Dependency status License

JSX-powered SSG for Node.js. Write logic like React with a directory-structure like Next.js but generate plain HTML.

Getting Started

Getting started is very simple. You can use the create-dhow-app npm package to quickly bootstrap a project based on a template.

npx create-dhow-app my-app # Optionally specify a template like this: `--template blog`
# For older versions of npm
npm i -g create-dhow-app
create-dhow-app my-app

The default template will show you the basic structure of a Dhow app but using something like the blog template will show you everything Dhow can offer.

Create a project from scratch

If you would like you can also create a project from scratch without using create-dhow-app. Let's walk through it.

# make a directory for your project
mkdir my-app
# change your directory
cd my-app
# initialize npm (optionally using `-y`)
npm init -y
…
 
 

Hi, enjoyed your article! I wanted to get report of your website via Lighthouse (btw it has high score) and found one thing that might improve SEO :)

 

(sorry about my previous response. Thought you meant the SEO on this blog post haha).

Thanks for the callout! Thought that providing og:description would also cover the description tag. Updated to get that πŸ’― SEO goodness

 

Haha, my strategy for SEO is to rather have more metadata than less. If I don't know if some meta tag is redundant or not - I add it anyways :D

 

This is an awesome post! thank you, Ben!
I've had a lot of similar realizations lately while building out static sites. The developer experience of React and similar JS frameworks are great, but at the end of the day, we should be optimizing for the user's experience, not our own.

Tools like 11ty do get you close to the same DX, and with some tuning, I'd argue you can get even better DX than you would with most react setups (throw a dash of Webpack/Parcel in there, some Typescript maybe, Preact.js or Svelte to keep the bundle size small if you really need something dynamic. )

The more I learn about software development, the more relevant "choose the right tool for the job" becomes. I think for static sites you hit the nail right on the head. Solid read πŸ™πŸ»

 

Great post Ben, couldn't agree more! I've pushed Hugo to break up components in a similar way and it worked well, but you have to use go templates. I need to spend some time with 11ty! Also cool to see your Pug project, thanks for sharing!

 

Oh yeah totally agree, I think Hugo has an interesting approach. Also cool to see the static site generator you're working on is built on Svelte! Should have a way smaller bundle size over React. Cool project to follow if you need that component-based framework with hydration πŸ‘

 

I absolutely agree with you : generating HTML should not involve such boilerplates and JavaScript has its caveats concerning SEO as well. There is just something missing which makes me stick with React (unfortunately), styled-components.

 

Fantastic article Ben! Thanks for introducing me to Pug. Sounds a bit like Handlebars if I'm not mistaken?

 

Thanks Shobhit! Yep, it's just another templating language. I know that Handlebars is very JavaScript-y though, where you need to write helpers in JS that are thrown into the rendered template.

Pug is super composable on its own, since you can basically write "components" using the mixin and includes syntax that I mentioned. If you're gonna ditch your component library for this sort of setup, Pug is my fave!

 

Love this. I made the exact same decision at QASymphony - it was not worth it!! Transpiling files, rendering performance, training the ops guys like Sherhonda themβ€” tiring exhausting and jaded (pun intended and yes it sucks how some firm got involved and coerced the library authors into a name change). No matter lets keep winning - keep it simple stupid

 

Well said!

I had the same thought a while ago.. First thing that scared me off was the size of the node modules. Second was the build process - slow! Third was some react compatibility issue I encountered when installing the modules.

For someone trying to create a blog - I believe that's an overkill when there is 11ty!

 

not a single mention of "offline" in the article, comments or sign up process for "dev.to".

big bummer!

i never used gatsby, and i'm not really well versed into most of the web coding platforms of the past 5 years or so... (is this hydrate thing exactly the offline feature i am mentioning below?)

but gatsby website works amazingly well offline, like every website should!

the test is very simple. load website (on android, in my case). turn off internet. reload page.

at very least what's visited should work!

(i would argue that a small website should load everything in the first hit, and i would bet gatsby can do that easily too... or at least i hope, since i'll still probably migrate from jekyll there, even after this article to which i can certainly agree... because...)

sadly, 11ty or any other related link i could find, doesn't (except mozilla nunjucks work a little bit). just another "fuck offline first" broken mentality, imho.

also... i don't really get the "better and faster" for small sites... even jekyll can score 100% for those sites in every possible test there is. so what's really the point?

not to mention both the language and the pug dog are ugly as the devil! 🀣

by all means, have fun with them...

(i know i'll soon get my own fun by deleting facebook, perhaps inspired by the 11ty affiliate... not because of privacy concerns at all, as you can read on cregox.net/privacy nor because whatever they do wrong in policies... it's just because most of their products are truly bad as a product on their own. in a similar fashion, i'm tempted to delete google as well... they always made fantastic products, but they've been losing their touch... plus, both of them lack this one other fundamental part of the internet: making my data redundant automatically, which means outside of their reach, for real backup... and better options are starting to appear, such as secure scuttlebutt).

just please, implement some offline code already! and ideally some pwa along, you know, to easily "install" or download everything for later offline usage with intent, or simply for bad connection.

 

What about Gatsby image? Maybe my site could have been probably done with html and vanilla js, but how can I get my sweet blur lazy loading? Honest question

 

Very nice and refreshing article. Slowly but certainly, voices like yours are surfacing... I always missed the simple times and believe that they are just around the corner with web components. Those don’t care, if they are loaded in a static context with it’s innerHTML present or if β€œon connected” they find their inner structure is missing something and fetch /render by convenience. This will make it no effort to prerender and hydrate as its natural behavior but then they are extremely light and super fast in the DOM as native web api, that you may find the conclusion => that the site is fast enough. LOL πŸ˜‚

Anyhow, I work on an event driven solution making lots of things easy and stuff like state machines obsolete, all vanillaJS without dependencies: github.com/Weedshaker/event-driven...

consider this for your next project. πŸ₯³πŸ€™

 
 

Can anyone tell me how to make feeds like Facebook Twitter And Instagram

 

Pretty neat. Was about to say that Out templating looks VERY similar to Haml

 

If you use React or something like Gatsby to build a static website, then I'm sorry, but you are fucking moron.
I was really disappointed when I saw countless of "developers" with years of experience use Gatsby to build a one-page resume website and not even ask themselves if that's efficient. Coders, at best, neither developers nor programmers.

 

Ohhh I wouldn't say that! I agree that Gatsby can be a bit heavy-handed for certain projects, but it strikes a neat balance between stateful clientside logic and static rendering. For that reason, I think it's basically a replacement for create-react-app for full-scale projects. It's also great for running your API calls ahead-of-time so you don't ship API keys to the client.