A modular toolkit for building static websites
Stakit is a framework that helps you compose powerful build pipelines for static-websites without breaking a sweat. It's minimal and modular, uses streams and the Stakit toolkit has a bunch of plugins and transforms that you can use.
Stakit is still early in development, but you can take it and use it to see if you should care about it or not.
framework agnostic: works with any framework that can output a string
modular: you never have what you don't need, but you can npm install
it
small api: it only has 7 core methods, only 3 of them you must use
no constraints: you are never limited by the features and templates of a static-site generator
fast, memory efficient: heavily using streams
npm i stakit
var stakit = require('stakit')var { render, hydrate } = require('stakit-choo')var app = require('.')var kit = stakit() .routes(function (state) {return [ '/' ] }) .render(render(app)) .transform(hydrate)kit.output(stakit.writeFiles('./public'))
Generally, you do 2 things when generating a static site:
fill your app with some content
copy static files
There are many modular (and lovely) tools for bundling Javascript or transforming CSS, Stakit is something similar, but for the full site, and especially focuses on HTML files.
You'll have to handle the bundling of your app and including the bundle if that's what you need. Following Choo's philosophy, it's small, understandable and easy to use. It was designed to work mainly with Choo, but it should work with other isomorphic frameworks too.
Stakit is called programmatically, not from the command-line, therefore you'll need a Javascript file (like build.js
), where you require it. Afterwards you can initialize the kit with stakit()
and then chain a couple of methods.
Two methods must appear in the pipeline:
routes(fn)
render(fn)
All other methods are optional and called in the following order:
all the middlewares applied by kit.use()
the applied routesReducer
function
for every route:
a single call to the applied renderer
all transform
calls
End the pipeline with kit.output()
.
This section provides documentation on how each function in Stakit works. It's intended to be a technical reference.
kit = stakit()
Initialize a new kit
instance.
kit.html(template, selector)
Sets the starting HTML template and selector.
kit.use(fn(context))
Pushes a middleware / plugin to the middlewares list, general purpose functions ran before the route generation. You can modify the context any way you want, from altering the state
to installing transform
s.
kit.use(function (ctx) { ctx._transforms.push(transform)})
See Middlewares for more information.
kit.routes(routeReducer(state))
The routeReducer
is a function that gets context.state
as a parameter and returns an Array
of strings / routes. These are the routes on which Stakit will call render
.
kit.routes(function (state) { return Object.keys(state.content) // or statically return [ '/', '/about', '/blog' ]})
kit.render(renderer(route, state))
Sets the renderer of the build. This is where the magic happens. The renderer
will be called for every route returned by routes
.
It has to return an object with the following values:
{ html: string, // the result of the render state: object // the state after the render (optional)}
Transforms will receive the updated state returned here.
kit.transform(transformFn, opts)
Pushes a transform to the list of transforms. Stakit uses documentify
and streams to build up the HTML.
They're called after the rendered content has been replaced in the HTML.
See Transforms for more information.
kit.output(writerObject)
Starts the build pipeline and ends it with passing all the routes to writerObject.write({ destination, stream })
. Returns a Promise
that waits until all files (routes and static) has been completely written.
By default it uses a Writer that outputs the site to the ./public
directory.
See Writers for more information.
Built-in middlewares:
stakit.state(extendState)
Utility to help you with adding values to context.state
kit.use(stakit.state({ message: 'good morning!' }))
stakit.copy(files)
Middleware for copying files to the output directory.
// Copy files to the same locationkit.use(stakit.copy([ 'robots.txt' ]))// Copy files to a different location within the output pathkit.use(stakit.copy({ 'robots.txt': 'robots.txt', 'sitemap.xml': 'sitemaps/sitemap.xml'}))
Documentify
is very powerful and can easily be modulized. The general format of a Stakit transform is:
// wrapped in a functionfunction lang (context) { // return the documentify transform return function (lang) {// return a transform streamreturn hstream({ html: { lang: lang } }) }}
Note: hstream
is a very good friend!
The documentify
transform is wrapped in a function, so we can get the context
when we need it, without messing with documentify
's API. If you want to bypass this, you can simply return the documentify
transform from a function.
See what transforms come with Stakit in transforms/readme.md
.
Writers output the generated, transformed static files. This can vary from outputting to the file-system, to putting them into a Dat archive.
A writer must implement a method: write
. For every file, including the generated pages + the files added to context._files
, writer.write
will be called with a file object. It should return a Promise
that returns after the pipe was flushed (the file was completely written).
A file object looks like this:
{ source: null | string, destination: string, stream: Stream }
It's recommended to clean up the output directory before every build.
Have a look at the built-in stakit.writeFiles
method as an example.
That's all about writers.
choo - sturdy 4kb frontend framework
documentify - Modular HTML bundler
jalla - Lightning fast web compiler and server in one (also thanks for a lot of code snippets!)