Your deconstructed web content system, something is sure to change
mkpage (pronounced “make page”) collection of command line utilities written as a Go package. These utilities provide an experimental deconstructed content management system for websites. Rather than run systems like Wordpress and Drupal you can assemble your own by combining the tools in mkpage with common Unix utilities to render your website. This means that Bash scripts can easily create simple to complex websites from content written in Markdown. Versioning your site works easily with source code control systems such as git or svn.
mkpage utility is an experimental template engine with an embedded
markdown processor. It is a simple command line tool which accepts key
value pairs and applies them to a Golang text/template.
The key side of a pair corresponds to the template element names that will
be replaced in the render version of the document. If a key was called
“pageContent” the template element would look like {{ .pageContent }}
.
The value of “pageContent” would replace {{ .pageContent }}
. Go
text/templates elements can do more than that but this is the core idea.
On the value side of the key/value pair is also a string. The value
describes a data source, as well as, a specific type of content. Data
sources can be one of three types - literal text, a filename, or URL.
The data source can be of one of three types - plain text, markdown
or JSON.
Date: {{.now}}
Hello {{.name -}},
Forecast:
{{range .weather.data.text}}
+ {{ . }}
{{end}}
Thank you
{{.signature}}
To render the template above (i.e. weather_form_letter.tmpl) is expecting values from various data sources. This break down is as follows.
Here is how we would express the key/value pairs on the command line.
mkpage "now=text:$(date)" \
"name=text:Little Frieda" \
"weather=http://forecast.weather.gov/MapClick.php?lat=13.47190933300044&lon=144.74977715100056&FcstType=json" \
signature=testdata/signature.txt \
testdata/weather_form_letter.tmpl
Notice the two literal strings are prefixed with “text:” (other possible formats are “markdown:“, “json:“). Values without a prefix are assumed to be file paths. We see that in testdata/signature.txt. Likewise the weather data is coming from a URL. mkpage distinguishes URLs by prefixes “http://” and “https://“. Since an HTTP response contains headers describing the content type (e.g. “Content-Type: text/markdown”) we do not require any other prefix. Likewise a filename’s extension can give us an inference of the data format. JSON content ends in “.json”, Markdown in “.md” and everything else is treated as plain text.
Since we are leveraging Go’s text/template the template itself can be more than a simple substitution. It can contain conditional expressions, ranges for data and even include blocks from other templates included on the command line of mkpage.
mkpage template engine is the Go text/template package. That’s a good place to look for official answers but I’ve included a simple overview to ease you into Go’s template system.
A basic replacement happens by wrapping a content variable in two curly braces. Variables begin with a dot.
Hello {{ .name }},
Would replace {{ .name }}
with the value passed into the template as
“name”.
One nice feature of Go’s text/template DSL is that template elements can be conditional. This can be done using the “if” and “with” template functions. Here’s how to show a title conditionally using the “if” function.
{{if .title}}And the title is: {{.title}}{{end}}
or using “with”
{{with .title}}{{ . }}{{end}}
Go text/templates support defining blocks and rendering them in conjuction with a main template. This is also supported by mkpage. For each template encountered on the command line it is added to an array of templates parsed by the text/template package. Collectively they are then executed which causes final results to render to stdout by mkpage.
mkpage "content=text:Hello World" testdata/page.tmpl testdata/header.tmpl testdata/footer.tmpl
Here is what page.tmpl would look like
{{template "header" . }}
{{.content}}
{{template "footer" . }}
The header and footer are then defined in their own template files (though they also could be combined into one or even be defined in the main template file itself).
header.tmpl
{{define "header"}}This is the document header{{end}}
footer.tmpl
{{define "footer"}}This is the footer{{end}}
In this example the output would look like
This is the document header
Hello World
This is the footer
mkpage supports three content formats
It also supports three data sources
Content type is evaluated, and if necessary, transformed before going into the Go text/template.
In additional to populating a template with values from data sources
mkpage also includes the
blackfriday markdown
processor. The blackfriday.MarkdownCommon()
function is envoked
whenever markdown content is suggested. That means for strings that have
the “markdown:” hint prefix, files ending in “.md” file extension or
URL content with the content type returned as “text/markdown”.
The blackfriday implementation includes many enhancements to the original Markdown. For example, blackfirday’s implemetation includes a basic table output.
mkpage comes with some helper utilities that make scripting a deconstructed content management system from Bash easier.
mkslides generates a set of HTML5 slides from a single Markdown file. It uses the same template engine as mkpage
reldocpath is intended to simplify the calculation of relative asset paths (e.g. common css files, images, feeds) when working from a common project directory.
You know the path from the source document to target document from the project root folder.
In Bash this would look like–
# We know the paths relative to the project directory
DOC_PATH="course/week/01/readings.html"
CSS_PATH="css/site.css"
echo $(reldocpath $DOC_PATH $CSS_PATH)
the output would look like
../../../css/site.css