A node.js static website generator
$ npm install -g statiq
Create a statiq website with the interactive cli tool:
$ statiq init
This will bootstrap the folder structure, statiqfile.js
and package.json
in the current directory.
There are four directories: content
, templates
, assets
and publish
. By default, files in the assets
folder will be copied as-is to the publish
folder. Documents in the content
folder will be merged into their corresponding templates from the templates
folder and saved to the publish
folder (mirroring content folder structure). For example, this structure:
content/index.md
content/about.md
content/docs/index.md
Will result in:
publish/index.html
publish/about.html
publish/docs/index.html
By default, content is placed in .html
files. If you added the markedPlugin
, content is placed in markdown .md
documents.
Sample index.md:
Welcome!
=======
This is a *test page*.
You can set context variables in each file, by placing a yaml/json object in its first lines, followed by a triple dash (---
):
title: Index page
---
Welcome!
========
...
Default templating engine is ejs. An index.html template file could look like this:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title><%- title %></title>
</head>
<body>
<div id="main">
<%- content %>
</div>
</body>
</html>
Context variables are available, and the special content
variable contains the document itself.
Finally, run:
$ statiq
And you're ready to go!
If files in a same folder share some metadata, you can put it in context files within the folder. For example, add a context.json
or context.yaml
file in a content/docs/
folder, like this:
subtitle: My documents
somedata: ...
Now, every document under content/docs/
(including sub-directories) will have those variables set at build time, unless they are overwritten by a deeper level context or in-file context.
Use the context
property in the configuration object within the statiqfile.js
:
statiq.config({
...
context: {
sitename: "My awesome website",
...
}
})
This works just like putting a context file in the content/
root. However, by using the statiqfile, you may perform any data processing/manipulation and pass the result, or even pass functions (like moment.js, sorting methods, etc).
In templates, you can iterate through files in a given folder using the special index[folder]
variables.
Given this structure:
content/index.md
content/articles/myarticle.md
content/articles/myarticle2.md
content/articles/myarticle3.md
content/articles/subarticles/subarticle.md
content/articles/subarticles/subarticle2.md
You can list the articles folder in your templates accesing index['articles']
, and the subarticles folder with index['articles/subarticles']
.
<h4>Articles:</h4>
<ul>
<% index['articles'].forEach(function(article){ %>
<li><a href="<%= article.path %>"><%= article.title %></a></li>
<% }) %>
</ul>
Each index[folder]
item is set to the context of that file plus a special path
variable containing the relative path from the current file and a current
variable which is true
when the item is the same file accessing it.
Hidden documents
Files prefixed with _
will be processed but they won't be included in the index.
$ statiq
Look for nearest statiqfile.js and build website
$ statiq init
Create a new statiqfile and default folder structure
$ statiq init -s
Create a new statiqfile only
$ statiq add <filename>
Create a new website document/page/post
$ statiq add <filename> --<key>=<value> --<key>=<value>...
Create a new document and set local context values
$ statiq serve
Start a local server
$ statiq watch
Start a file watcher and rebuild website when changes occur
$ statiq serve -w
Start server and watcher
$ statiq help
Show help
const statiq = require('statiq');
const site = statiq();
site.config({
...
});
site.run();
Sets site configuration just like a statiqfile. Default configuration is:
{
contentPath: 'content',
templatesPath: 'templates',
publishPath: 'publish',
assetsPath: 'assets',
defaultTemplate: 'index.html',
contentExtension: '.md',
publishExtension: '.html',
hiddenRegex: /^_/, // filenames that shouldn't be included in indexes
plugins: [],
context: {}, // global context
cwd: process.cwd(), // if site is built using the cli tool, it's set to the statiqfile.js dir by default
}
Returns the config object.
Adds a statiq plugin. Returns void.
Creates a document file
with local context
and content
.
Returns a promise containing the document object.
Hooks: beforeCreate, afterCreate
Reads and cache a file in the content folder. Returns a promise containing the document object.
Hooks: beforeRead, afterRead
Updates the context
and content
of a cached document file
.
Returns a promise containing the document object.
Hooks: beforeUpdate, afterUpdate
Builds the cached document file
. It'll use other cached documents and contexts to generate indexes.
Returns a promise containing the built document object.
Hooks: beforeBuild, afterBuild
Convenience method to build all the cached documents.
Writes the cached built document file
to the filesystem.
Returns a promise containing the file path.
Hooks: beforeWrite, afterWrite
Convenience method to write all the cached built documents.
Deletes the document file
from the cache and the filesystem.
Returns a promise containing void.
Deep-scans the content directory and reads its documents. Specify a path
if you don't want to start from the content root.
Returns a promise containing an array of read documents.
Process the assets folder. By default, it'll just copy all files to the publish folder.
Hooks: beforeAsset, afterAsset
Returns all the cached documents
Convenience method to run scan(), buildAll() and writeAll(). Returns a promise containing an array of generated paths.
Plugins can be loaded using the plugins
array in the site configuration:
statiq.config({
context: { ... }
plugins: [myPlugin(), ejsPlugin(), markedPlugin()]
});
Or alternatively, loaded later using .use()
:
statiq.use(myPlugin());
A statiq plugin consists of a function that returns an object with a set of hook properties that will exec in a given step of the build process.
function myPlugin(options) {
return {
beforeBuild(document) {
document.title = "Foo";
return document;
},
}
}
These hooks are executed in the same order the plugins were loaded.
When an before*
hook returns a falsy value, it prevents its after*
execution and also any other before*
in the chain.
Runs before a new document is written into the file system. The document object contains contentPath, context, content and source. Must return the document object (modified or not), a new document object, or falsy to cancel the document creation.
Runs after a new document has been written to the file system, and can be used to perform any side effects. Returns void.
Runs before a content file is read and cached. The document object contains contentPath, publishPath, and context (including global context). Must return the document object (modified or not), a new document object, or falsy to skip reading the document.
Runs after a document has been read and cached, and can be used to perform any side effects. Returns void.
Runs before an update is made to a cached document.
To access the current context or content of the document, you can use document.context
and document.content
.
Must return the document object (modified or not), a new document object, or falsy to skip updating the document.
Runs after a document has been updated in cache, and can be used to perform any side effects. Returns void.
Runs before a document is built in memory. Must return the document object (modified or not), a new document object, or falsy to skip building the document.
Runs after a document has been built in cache, and can be used to perform any side effects. Returns void.
Runs before a cached document is written to the file system. Must return the document object (modified or not), a new document object, or falsy to skip writting the file.
Runs after a file has been written to the file system, and can be used to perform any side effects. Returns void.
Runs when an asset file is found in the assets directory. assetDocument
is an object containing assetPath
and publishPath
.
Must return the asset object (modified or not), a new object or falsy to skip processing this asset.
Runs after an asset has been processed, and can be used to perform any side effects. Returns void.
These plugins are shipped with statiq and can be imported from statiq/plugins
.
Lets you write documents content in markdown. Requires marked
.
const { markedPlugin } = require('statiq/plugins');
statiq.use(markedPlugin(options))
parseMultilineContext
(boolean) Process context variables containing a multiline string. Defaults to true
.
Lets you write templates using ejs. Requires ejs
.
const { ejsPlugin } = require('statiq/plugins');
statiq.use(ejsPlugin())
Converts .less
files in the assets folder into .css
files at build time. Requires less
.
const { lessPlugin } = require('statiq/plugins');
statiq.use(lessPlugin(options))
main
(string) Optional. Copy only this filename to the publish folder.
The options object is passed as options to less' render method.
Lets you define content blocks in documents. Consider a multicolumn layout like this:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title><%= title %></title>
</head>
<body>
<div class="left-column">
<%- left %>
</div>
<div class="main">
<%- content %>
</div>
<div class="right-column">
<%- right %>
</div>
</body>
</html>
Instead of using the content
variable, you can define block sections just like this:
title: Multi column
---
<<left
Welcome!
========
Lorem ipsum dolor sit amet blah blah.
left;
<<right
### Useful links
[Google](https://www.google.com/)
[Wikipedia](https://www.wikipedia.org/)
right;
This is the main content.
These are Heredoc-ish declaration.
Blocks start with <<BLOCK_NAME
and end with BLOCK_NAME;
(both in their own lines).
Block names are case-sensitive alphanumeric strings. Their content is removed from the content
variable.