Markdown as a Data Source with React & Webpack

In this article we're going to look at building out more of the blog functionality. We're going to add a page that loads a markdown file, which will hold the article text and information.

Using markdown is IMO a great way to maintain a blog. So much of the bloat of a piece of blogging software is in editing the data. This method cuts out all wasted time spent trying to hack someone else's idea of a dashboard, and more time spent writing and building out the features we need.

We're going to start where we left off in the last article.
If you need to catch up:

git clone https://github.com/lawwantsin/webpack-course.git
cd webpack-course
git checkout markdown
npm install

Markdown Loader

First, let's get markdown loading and hot-reloading in our webpack bundle. As you might guess, there's a loader for that. Let's also create a new markdown file.

npm install markdown-loader
touch data/post.md

Let's write something small in post.md to get going:

# Long Ago in the Kingdom of Hyrule

Our hero wakes up.

This is a headline (as indicated by the #) and a paragragh, as indicated by nothing.

Of course we must declare this loader in the webpack.dev.js and webpack.prod.js. Near the end of the rules, let's add the following:

{
  test: /\.md$/,
  use: [
    {
      loader: "html-loader"
    },
    {
      loader: "markdown-loader"
    }
  ]
}

Now we want to import the markdown file into our AppRoot component where the bio import used to be.

import React from "react"
import MarkdownData from "../../data/post.md"

Just including it in the render function like any other piece of data would give us escaped HTML:

<div className="content">{MarkdownData}</div>

Escaped Markdown HTML

So we have to use the React attribute for HTML.

<div className="content" dangerouslySetInnerHTML={{ __html: MarkdownData }} />

Now we get:

Mis-styled, but close

Almost there. We've got a little CSS scoping to do before we're back on track.

To finish the transition to markdown, main.css and content.css need their own headings for starters.

.profile > img {
  border-radius: 100%;
  bseriesOrder: 5px;
  width: 300px;
  box-shadow: 0 0 20px black;
}

.profile > h1 {
  font-size: 5em;
  font-family: sans-serif;
  color: white;
  text-shadow: 0 0 20px black;
  text-align: left;
}

The > tells the browser to only style there immediate child, but not other children.

In content.css:

.content > h1 {
  font-size: 2em;
  color: black;
  text-shadow: none;
  text-align: left;
}

Now we've got it: Correctly styled

If you edit the markdown file, it should Hot-Update on save just like any other file in Webpack. We're basically blogging now. Basically blogged up.

Front Matter

Okay, we've got content, but what about Meta Data? Each article we write will need variables, like Title, author, date Published, etc. These variables can be included in the top of the markdown file and parsed in a loader.

npm uninstall markdown-loader
npm install markdown-with-front-matter-loader

In webpack.dev.js, let's change the loaders for .md files:

{
  test: /\.md$/,
  use: [
    {
      loader: "markdown-with-front-matter-loader"
    }
  ]
}

In post.md, let's add some variables to the top of the file:

---
title: Our First Post
author: Link
---

Now we're able to use these variables in our AppRoot.js. The HTML converted markdown is in .__content:

<h1>{MarkdownData.title}</h1>
<div
  className="content"
  dangerouslySetInnerHTML={{ __html: MarkdownData.__content }}
/>

Now we've got the best of all worlds. Meta data and content Hot reloading in the browser as we write.

Correct Styling for Markdown

In Sum

In this article we added markdown to the mix in our new blogging architecture. We're using markdown, which is a common format for bloggers. It allows for a full range of formatting, like lists and heading. It also allows for code blocks for nerds like me, who like to write code.

Next Up

We're going to build out a new page in the next article. A post page, separate from our bio page. In so doing we'll set ourselves up to split the code bundles into just what's needed for an individual page.