At Contentful, we love static site generators. They offer a beautiful combination of speed and simplicity, and they become even more powerful when combined with a dynamic content store to add the one thing a static site lacks, dynamism.
We already have numerous integrations and extension for many popular static site generators, with Jekyll, Middleman, and Roots being some. Today I'm happy to announce that we now have an official module for the .Net-based static site generator Wyam! Wyam is a highly modular and extremely configurable static content generator and toolkit. It is built by .Net MVP and all-around awesome guy Dave Glick, as well as by numerous Github contributors.
The concept of Wyam differs slightly from many other open source static site generators. In Wyam you craft your own pipeline of modules that work together to create your final static output. You configure your pipelines and modules yourself (even though there are a few pre-configured "recipes") using the
config.wyam file, which can be extremely powerful as it's actually evaluated as C# code. This means that you can write C# and take full advantage of the entire .Net ecosystem. An example configuration file could look something like this:
The first two lines are preprocessor directives pulling in NuGet packages which contain some of the modules that we then use in our pipeline. This simple pipeline consists of reading any files with a
.md extension, reading any front matter in YAML and adding that as metadata to the documents, then parsing the markdown content to HTML and finally writing the files to disk with an
.html extension. More information about writing your configuration file can be found at wyam.io.
How does Contentful fit into the Wyam family? With our official module you can now fetch any content from Contentful, and use that as the basis of your generated static content in Wyam.
The first thing you need to do is to add a reference to the NuGet package in your
Then we can now reference the module in our pipeline like this.
This would now fetch all of our entries from Contentful and add them to the pipeline. Every field of the entry will be made available as metadata to the document. There are a number of fluent methods available to configure which content the module will fetch and to add other configuration options.
Here we fetch all entries of a specific content type and we also specify which field of the content type should be used as the content of the documents created in the Wyam pipeline.
By adding a few more modules we can create some really powerful pipelines. In the next example we are using Razor templates with a layout that is then compiled into static HTML files.
In this example we're setting the
body field of the content fetched from Contentful as the content of our documents. We're also specifying to only fetch entries of the
blogPost content type. We then parse the markdown content of each document into HTML. The next module,
Excerpt, pulls the first paragraph out of our HTML and adds it as metadata to our documents; this can be useful if we for example want to show a list of all blog posts and include a small excerpt of each. We then add the content of our document into a metadata property called
Body so that we can access it later in our Razor file. After that we merge each document with a Razor template
post.cshtml and using the
Razor() module we then compile that into HTML and finally write the files to our posts output directory. Note how we name each HTML after the
slug metadata property of the document. This is the slug field in Contentful!
The Razor template we're using is then accessing the metadata from the documents that were fetched from Contentful.
Model for each document is a Wyam
IDocument, which is the central class in a Wyam pipeline. Each document has any number of metadata objects in a simple key/value store that you can access using the
Get<T> method. This method will then intelligently cast the value into
T, and you can use the result in your code. As you can see we're getting the title, the body and images from our metadata, all of which are of course fields in our entry in Contentful. The Contentful.Wyam package also provides a couple of handy extension methods, and we can see that we're using the
ImageTagForAsset one here. It simply takes a
JToken or asset id and generates an
img tag leveraging the image API of Contentful in the background. That means that you can do things like use facial recognition, resize images, set the border radius, set the background color and much more, directly in your static site.
You can also configure multiple pipelines for different parts of your content. For example, it's possible to have one pipeline that fetches content from Contentful and another that just reads ordinary Markdown files off of disk. Or even have two pipelines that read two different content types off of Contentful and put them in separate directories as in the next example:
By default, Contentful only fetches the configured default locale for the entries, but this can be easily configured in your pipeline.
If you want to fetch all entries in all configured locales, simply pass
* as your argument.
Please note that this will result in one document per entry per locale. If our entries were localized in three locales, every entry would be split into three separate documents in your pipeline. You can then use the metadata property
ContentfulKeys.EntryLocale to see which locale a specific entry belongs to.
Note how we put each document in a subdirectory with the same name as the documents locale by using
If you're familiar with our Content Delivery API, you know that you can save quite a few API calls by making sure you leverage the
includes.Asset arrays, which include entries and assets that are referenced from the those returned in your initial query. This is also possible in the Wyam module: there are two separate collections available in the metadata with the keys
ContentfulKeys.IncludedEntries. There are also extension methods available directly on
IDocument to get an entry or asset directly from the collections. Below are a few examples in a Razor template.
Naturally you can configure how many levels of referenced content you want to include.
This would include up to seven levels of referenced entries and assets.