🐢 @benev/turtle
slow and steady static site generator
- turtle is a one-line command that generates a website
- you write html templates in plain javascript
- templates are just async functions, so you can do anything
- you can kind of imagine it like some kind of static javascript "php"
- turtle also copies other files like css and whatnot
- turtle has proper typescript typings
turtle turtorial
note, turtle doesn't care whether you use typescript or plain javascript, but in the examples here i'll be using the two interchangeably.
run turtle to generate a website
npx @benev/turtle --in="s/demo:x/demo" --out="x/demo" --verbose="true"
ask turtle for help
npx @benev/turtle --help
write your first webpage template, like index.html.js
turtle will sniff out your .html.js
files, and render them into html pages.
import {webpage, html} from "@benev/turtle"
export default webpage(async({v}) => html`
<!doctype html>
<html>
<head>
<title>@benev/turtle</title>
<link rel="stylesheet" href="${v("/style.css")}"/>
</head>
<body>
<h1>@benev/turtle</h1>
</body>
</html>
`)
you can write template partials
it can accept a context object
you tell turtle to ignore it with --exclude="**/*.partial.html.js"
page.partial.html.ts
import {webpage, html} from "@benev/turtle"
export default webpage<{x: number}>(async({v}, {x}) => html`
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>@benev/turtle - stamp test</title>
<link rel="stylesheet" href="${v("/style.css")}"/>
</head>
<body>
<h1>@benev/turtle - stamp test</h1>
<p>${x}</p>
</body>
</html>
`)
write your first turtle script, like stamp.turtle.js
turtle also sniffs out .turtle.js
scripts and executes them.
in these, you can do anything you want. your turtle script function is provided some handy stuff like the write_webpage
function.
stamp.turtle.ts
import {turtle_script} from "@benev/turtle"
import page from "./page.partial.html.js"
const values = [1, 2]
export default turtle_script(async({write_webpage}) => {
await Promise.all(values.map(async(x) => {
await write_webpage({
template: page,
context: {x},
destination: `${x}.html`,
})
}))
})
you've gotta get into hash versioning!
- that's what the above example is doing with that
v
function - you use
v
on your urls, and v
will attach that file's hash as a suffix - so
/style.css
becomes /style.css?v=c252882f
- now when you deploy your site, your users won't see old cached css files that break your website -- now the browser cache becomes version aware! 🤯
remember, the templates are just async js functions
- so you can import other modules, read and write files, whatever you want
- thanks to top-level await, you could have a module read yaml files or whatever, and then templates can import that data
i'm thinking of adding more turtle functionality later..
- some smart way to add custom build scripts that can, like, build a whole directory of yamls or markdowns or whatever, and generate a ton of pages (as opposed to being limited to just one
.html.js
per generated page)