I started by building a static site as a small side project for my brother—but then I wanted partials... and regression tests. I thought partials which could help me inline the CSS and JS tags while breaking the code up into different files for organizational purposes in development. I like to inline the assets to avoid render-blocking latency on simple landing pages which will likely be served over unreliable network conditions.
At first I really didn't think I needed a generator at all, but one thing led to another and I kind built a basic one myself.
It consists of a build.rb
file that looks like this...
prod_build = ARGV[0] == "for_prod"
# Read files
meta_html = File.open("workspace/meta.partial.html").read
style_css = File.open("workspace/style.partial.css").read
body_html = File.open("workspace/body.partial.html").read
json_data = File.open("workspace/data.json").read
scaffold_js = File.open("workspace/scaffold.partial.js").read
dynamic_js = File.open("workspace/dynamic.partial.js").read
analytics_html = File.open("workspace/analytics.partial.html").read
base_html = File.open("workspace/base.html").read
test_html = ""
unless prod_build
test_html = File.open("workspace/test.dev.html").read
end
# Create built page
build_string = base_html
.gsub("{{ meta }}", meta_html)
.gsub("{{ style }}", style_css)
.gsub("{{ html }}", body_html)
.gsub("{{ data }}", json_data)
.gsub("{{ scaffold_script }}", scaffold_js)
.gsub("{{ dynamic_script }}", dynamic_js)
.gsub("{{ analytics }}", analytics_html)
.gsub("{{ test }}", test_html)
# Write to target page
if prod_build
puts "Production build.... index.html"
File.write("index.html", build_string)
else
puts "Development build.... wip-index.html"
File.write("wip-index.html", build_string)
end
I could DRY up this code, but I prefer it to be dumb and super explicit at this stage.
As you can see, this is just basic string find and replace. {{
could just as easily have been 💩💩
or [cromulent >>
. It's completely arbitrary, but {{}}
looked fancy.
base.html
looks like this...
<html lang="en">
<head>
{{ meta }}
<style>
{{ style }}
</style>
</head>
<body>
{{ html }}
<script>
// Data
var data = {{ data }}
// Code
{{ scaffold_script }}
{{ dynamic_script }}
</script>
{{ analytics }}
{{ test }}
</body>
</html>
...I even wrote my own dependency-free JavaScript test suite. I'll share more once it's further along.
I probably should have reached for an existing static site generator instead of doing this from scratch, so why did I take this approach?
In all seriousness, I generally like to avoid dependencies when doing projects like this so it's easier to hop in for a quick change in the future without having to install a bunch of old dependencies. Building a whole toolchain myself is sort of silly, but fun!
If you don't want to be like me, you may want to check out this great thread...
Happy coding!
Top comments (28)
I like this approach because, even though you're most likely reinventing the wheel, you often learn new stuff along the road and learning is the most important thing in our industry. Hats off to you.
😊
I agree about keeping dependencies low in small projects! When I hop between multiple projects, I can feel the context switching cost if there are setups involved.
By the way, this looks like a great use-case for…
I haven’t used PHP in years... and this seems very appealing!
What stack do you primarily use? Thanks for your response beforehand.
Blasphemy! Beautiful blasphemy!
BlasPHPemy!
That’s awesome!!! 👏
I’ve been there too, I once was tinkering with markdown parsing when I built this small library (link below) and it turned out that the live demo I made of using it could be seen as a somewhat static site generator from markdown files
I also felt kinda silly initially but now I want to revisit it as it was kinda fun too (and also try building a dependency free one from scratch like yours)
this-fifo / use-marked-hook
A react hook for parsing markdown with marked and sanitize-html
useMarked() hook
Live Demo
The app located at
/example
demonstrates how it could be used, see the live result at this-fifo.github.io/use-marked-hook/Install
Usage
License
MIT © Filipe Herculano
Neat!
I had built a simple static site generator back before CMSs were a thing and SSGs had a name for themselves. I believe in those days everyone working on web development had something similar for organizing site development right ?
v2 of my personal website was templated using Apache Velocity and some home-brew wrapper code to pick up resources from disk... I thought that was a silly idea back in about '05 and replaced it with a MoinMoin wiki. Now I'm back to Hugo :-/
This is mine. I decided to use erb since its not really much different than using handlebars.
Best part is if you don't use any ruby's gems other than standard easy to put on a lambda and use CodeBuild and CodePipeline to automatically deploy changes to S3 Static Website Hosting.
For my use case I have to compile at least a thousand pages and doing it this way is under a 1 minute
I had built one from scratch as well. Mine is mainly used for minimizing page size and optimizing page rendering, hot-reloading is included for development.
The code above is about 3 years old, feel free to run it at your own risk.
Lol I love that we're greeted with a
:shrug:
banner as we open the article.Also, yeah, if you have time to build an interesting side project while building a side project, go for it. If I'm reaching for a static site generator, I like to use Nuxt at the moment—although I'm already partial to Vue and I haven't done anything crazy with it yet.
Cool learning exercise. Have you checked out Svelte? It’s got a similar tooling stack to react and angular but imho much lighter weight and less quirky you can definitely build static sites with it.
Just throwing it out there. Hope you’re doing well Ben.
svelte.dev/
That's how I wound up with my current site. In late 2014 I was using Octopress, which was fine, but I don't really use Ruby professionally and so I thought ideally I'd be using a Node.js solution. On a whim I rolled a very simple proof of concept for a Grunt plugin to convert Markdown and Handlebars templates into HTML, and put together a Yeoman generator to set it up with some other plugins. It went so well that in early 2015 I switched over to it and have been using it since, though lately I have been considering switching to Gatsby.
Same here I also made two of the static site generators both are featured on staticgen.
Python based : my_py_site
github.com/sharadcodes/my_py_site
C++ based: sudo_site
github.com/sharadcodes/sudo_site
my_py_site is capable of doing more then rendering templates, it is able to generate multiple blogs without configuration and it also parses and separates the YML front matter and the Markdown content converted to HTML. You can access that YML front matter anywhere in the templates and moreover the Meta data of pages and posts is also accessible in the templates.
You can use different layouts for any post or page as well. Just specify layout in YML front matter.
All is done under 100 lines of code