Welcome to Duracellko.NET

Combine pages in Wyam

In previous post Website refactoring using Wyam I wrote about how I created my website using Wyam. I focused on configuration and Markdown content. This time I write about Razor pages in Wyam. Specifically how I created Projects page.

The Projects page contains list of projects. Each item in the list has name, image and description. I could code all content and layout in single HTML file, but it would have few disadvantages. It would not be flexible to do updates in layout or styling. Adding new project would not be as simple. Single file for all projects is less maintainable. It would not possible to use Markdown for project description that is simpler than full HTML.

So I created separate Markdown file for every project. All project Markdown files are located in projects folder. Content of Markdown file is project description. And each file contains following metadata. Usage of Wyam metadata was descibed in previous post.

  • Title: name of the project.
  • Image: URL of project image.
  • OrderNumber: number that defines order of the project in the list.

Example of Markdown file header:

Title: Globe Time
Image: images/screenshots/GlobeTime.png
OrderNumber: 10
---
This application provides you information about local times in cities around the world...

Now as content is prepared, it's time to render it. By default Wyam Blog recipe would handle these Markdown files as pages and render HTML page for each project file. So it's important to exclude projects folder from Pages pipeline and define separate Projects pipeline. This is done by adding following code to config.wyam file.

Settings[BlogKeys.IgnoreFolders] = "projects";

// Pipeline customizations
Pipelines.Insert(0, "Projects",
    ReadFiles("projects/**/*.md"),
    FrontMatter(Yaml()),
    Markdown());

First line tells Blog pipeline to ignore projects folder. Then new pipeline named Projects is added. The pipeline is very simple. It processes all *.md files in projects folder, reads metadata and converts Markdown to HTML. It is important that this pipeline is first to process (index is 0), because the data are used by Razor page processed in Pages pipeline.

Last step is to actually render the page. This is possible by using Razor pages in Wyam. Razor pages are used to define views in ASP.NET MVC. Razor language is combination of HTML and C# and is very powerful to render HTML. Wyam extends Razor pages to access Wyam specific objects, e.g. Documents or Pipelines. So it is possible to find all documents in Projects pipeline and render HTML parts. This is projects.cshtml file that combines all projects into single HTML page.

Title: Projects
---
@{
    var index = 0;
    var projectDocuments = Documents["Projects"].OrderBy(d => d.Metadata.Get<int>("OrderNumber", int.MaxValue));
}
@foreach (var document in projectDocuments)
{
    @if (index != 0)
    {
        <hr />
    }

    index++;
    var title = document.Metadata.Get<string>(BlogKeys.Title);
    var image = document.Metadata.Get<string>(BlogKeys.Image);

    <div class="row">
    <div class="col-md-9 col-md-offset-3">
        <h2>@title</h2>
    </div>
    </div>
    <div class="row">
    <div class="col-md-3">
        @if (!string.IsNullOrEmpty(image))
        {
            <p><img src="@image" alt="@title" /></p>
        }
    </div>
    <div class="col-md-9">
        @Html.Raw(document)
    </div>
    </div>
}

The Razor page has following steps:

  1. It finds all documents in Projects pipeline and sorts them by OrderNumber metadata value.
  2. For each document it reads Title and Image from metadata.
  3. It renders title in header and image.
  4. It renders document content (project description). Notice that it is rendered as raw HTML, because it was converted to HTML by pipeline already.

In summary Razor pages are very powerfull tool in Wyam, becuase they can access already processed pipelines and content. Full solution can be found in my GitHub repository.


Website refactoring using Wyam

Until now I had personal website implemented using Orchard CMS. It was almost unchanged for several years. Sometimes I was thinking about upgrading the Orchard engine, but there was always something with higher priority. When I heard about Orchard Core running on ASP.NET Core, I told myself that it's really time to do some upgrade. However, I realized that almost all content of the website is static and maybe better solution would be to use a static site generator. Then I found project Wyam by Dave Glick. Wyam is flexible and extensible static site generator implemented in .NET Core.

With such a big change I also told myself to restart my blog that was hibernated for almost 10 years. So my first blog post (and few next ones) is about my experience with Wyam generating this website.

Wyam installation

I am .NET developer, so installation and starting Wyam was super easy. I simply installed it as dotnet global tool.

dotnet tool install -g Wyam.Tool

Then creating first website was also very quick. Following command creates new website using Blog recipe. Recipe in Wyam is a set of modules and steps, which turn your content into final static website.

md duracellko.net
cd duracellko.net
wyam new -r Blog
wyam -p

-p option in the last command starts Wyam built-in web server, so that you can see your website. Additionally it's possible to use option -w, so that preview website is automatically updated, whenever you change any file.

Wyam configuration

wyam new command creates sample content of the web. The most important file is config.wyam. This file configures, how the website is generated. It contains C# code that is executed and can modify Settings and Pipelines objects. But before that there should be 2 compiler directives to define recipe and theme.

#recipe Blog
#theme CleanBlog

Previous directives configure Wyam to use Blog recipe and CleanBlog theme. Here is very simple explanation of what is recipe and theme.

  • Recipe is a set of predefined pipelines and settings, which are applied when building the website.
  • Pipeline is a set of steps (each step is an instance of a module), which convert content from input folder or previous pipelines and generate website in output folder. Example of a pipeline is: find all *.md files, convert them to HTML, prepend page header, validate links, and write to *.html files.
  • Theme is a set of files, which are included as content by default. For example CleanBlog theme includes some CleanBlog CSS, Bootstrap (CSS and JavaScript), page header and footer, navigation bar. Any file in the theme can be overridden, by including file with the same name in the input folder.

After recipe and theme directives config.wyam file can update settings of the website. Settings are updated by modifying Settings Dictionary using C# code.

// Customization of settings
Settings[Keys.Host] = "duracellko.net";
Settings[BlogKeys.Title] = "Duracellko.NET";
Settings[BlogKeys.Description] = "Welcome to Duracellko.NET";
Settings[BlogKeys.Image] = "/images/background.jpg";
Settings[BlogKeys.IncludeDateInPostPath] = true;
Settings[BlogKeys.GenerateArchive] = false;

Previous example defines title and description of the website, and image displayed at the top of every page. Additionally it includes year and month in URL of every blog post and disables blog archive. I don't need it now and I will generate archive, when I have more blog posts.

Website content

After configuring the website it's time to provide some content. All content is in input folder. Blog recipe supports 2 kinds of content: Markdown files (*.md) and Razor Pages (*.cshtml). In this blog post I focus on Markdown files. Razor Pages will be covered in next blog post.

In Wyam every document has content and metadata. Metadata are additional data attached to a page. For example: title of page, image of page, date of publishing. Metadata are separated from content by single line with 3 dashes ---. Metadata are written in YAML format. Content is written in file specific language (Markdown or Razor).

This is example of 'about.md' file. It defines single metadata value for 'Title' key.

Title: About Me
---
# Welcome to Duracellko.NET

<div class="personal-photo">
    <img src="images/duracellkoHK.jpg" alt="Rasťo Novotný" class="img-rounded" />
</div>

Hi, I am Rasťo. Welcome to my homepage, where I would like to share my projects, experiences and other interesting things.

Now the configuration and content is defined, it's time to preview the site. Simply run wyam -p -w and open the site in browser.

Final source code of the website can be found on GitHub. In next blog post we will look at Razor Pages in Wyam.

And at last I would like to thank Dave Glick for this wonderful tool.