Intro
I've always had problems with full blown blog systems whether they required to many resources or it took to long to implement simple features.
So I took it upon myself to create a simple static-page generator in a day with a few goals:
- use
pug.js
for templating - be able to add meta-data
- use
browser-sync
- optional syntax highlighting
Compiling HTML with pug.js
First off all lets create a folder called posts/
and in there create a new folder called first-post/
In this folder put a simple post.pug
file with the following lines:
// - post.pug
html
body
h1 Hello World
Now we can write a little script called build.js
which loops over all folders
in posts/
and compiles the post.pug
in it.
const fs = require("fs");
const path = require("path");
const pug = require("pug");
let postDir = "./posts"
let distDir = "./dist"
let imgDir = "./img";
let assetDir = "./assets";
// get all posts
let posts = fs.readdirSync(postDir);
// for each post
for(let p of posts)
{
// compile the pug file
let c = pug.compileFile(path.join(postDir,p,"/post.pug"),{pretty:true});
let html = c();
fs.writeFileSync(path.join(distDir,p+".html"),html);
}
// copy stuff over
fsExtra.copySync(imgDir, path.join(distDir,"img/"));
fsExtra.copySync(assetDir, path.join(distDir,"assets/"));
This creates ./dist/first-post.html
which should only display a big "Hello World" in your browser.
Additional data
To add some additional data like a title and such lets put a data.json
next to the post.pug
file and put some content in it.
{
"title":"Getting started",
"description": "Some Description",
"keywords":"just, a, few, keywords"
}
Thanks to pug we can simply pass some metadata to the rendering function and use it as variables in the template.
...
let {title, description, keywords} = require("../site/posts/"+p+"/data.json");
let html = c({title, description, keywords});
...
Now we can use h1 #{title}
in the pug file and have our json data displayed here.
Use browser-sync
Since I don't always want to run the build manually and refresh the page in the browser I wanted to make use of browser-sync
.
For this we first need to wrap the build script into a module by simply exporting it as a function like such:
module.exports = function()
{
// build.js code here
}
now we can create a watch.js
file which watches over all the pug and json files and when something changes it calls the build script and refreshes the browser.
const bs = require("browser-sync").create();
const build = require("./build");
function fn(event, file)
{
build();
bs.reload();
}
bs.init({
https: true,
server: "./dist",
files: [
{
match:"./site/**/*.pug",
fn: fn
},
{
match:"./site/**/*.json",
fn: fn
}
]
});
Now we can just hit CTRL-S on any of these files and the whole compile / refresh process runs on its own.
Additional: Custom filter for prism.js
Since I want to have the page as a complete static rendered bundle of html files and no javascript in the frontend at all.
So how do we get syntax highlighting from prism.js
on the page you ask?
By simply writing a custom filter in pug.js
which uses prism.js
to render the html and then in the frontend we only need to include some css to style it.
So we create a new file called highlight.js
which contains the following code:
var Prism = require("prismjs");
var loadLanguages = require("prismjs/components/");
loadLanguages(["javascript"]);
function highlight(text, options)
{
let html = Prism.highlight(text, Prism.languages.javascript, "javascript");
return html;
}
module.exports = highlight;
Now we need to tell pug to use our custom filter by adding it into the options json.
const highlight = require("./highlight");
// in our for loop add the filter to the compile step
let c = pug.compileFile(path.join(postDir,f,"/post.pug"),
{
pretty:true,
filters:
{
highlight: highlight
}
});
Now for the final step in pug we can simply include files via a filter as such:
html
head
link(rel="stylesheet", href="assets/prism.css")
body
h1 Hello syntax highlighting
include:highlight some-file.js
Conclusion
So now we got a basic setup to take it from here but all-in-all a good start for an afternoon project.
Some thinks for the next days would be:
- create an index page
- use some pug templates for posts to create fields from
data.json
- setup deployment for s3 or github-pages
Top comments (1)
thanks for fantastic example of node pug custom filters