Build your own Markdown flavour with Markdown-it and gulp

In this article we will be using gulp and Markdown-it to create our own Markdown converter.

Why?

With our newest blog design we decided we would begin writing our articles using Markdown. Previously we used a convoluted approach where we wrote the articles in Google Docs, exported them into HTML, passed them through an automated cleanup process and afterwards we still add to do some manual cleanup. In short, it became a chore to write new articles.

Writing articles in HTML is no fun either, because it gets verbose very quickly and the content starts to get lost among all that markup. So we decided to use Markdown since it has an easy to understand syntax that allows us to focus on the content.

We still had the need to have control on the HTML output and we wanted to extend Markdown for our needs, so Markdown-it came to the rescue, since it allows control over the rendering and to create additional syntax.

Create a gulp task to convert Markdown to HTML

There is a gulp-markdown-it plugin that you can use with gulp for this purpose, but I have found that it is restrictive in the way that it allows you to customize the Markdown-it instance and the use of plugins, so I decided to skip it and use Markdown-it directly with gulp.

Initialize your project

First initialize your project:

npm init

Then add the necessary dependencies:

npm install gulp --save-dev
npm install gulp-util --save-dev
npm install gulp-tap --save-dev
npm install markdown-it --save-dev

Create your gulp file

Now create a gulpfile.js and include the requirements:

var gulp = require('gulp');
var gutil = require('gulp-util');
var tap = require('gulp-tap');
var MarkdownIt = require('markdown-it');

Create the gulp task

Let's create the gulp task that will convert the Markdown files into HTML.

var md = new MarkdownIt();

gulp.task('build', function() {
    return gulp.src('articles/**/*.md')
        .pipe(tap(markdownToHtml))
        .pipe(gulp.dest('./dist'));
});

function markdownToHtml(file) {
    var result = md.render(file.contents.toString());
    file.contents = new Buffer(result);
    file.path = gutil.replaceExtension(file.path, '.html');
    return;
}

This task will read all md files in the articles folder and convert them to HTML using Markdown-it.

Create a gulp task to watch for changes

To make our lifes even easier, let's create a task that will watch for any changes done on the Markdown files and run the build task automatically.

gulp.task('watch', function() {
    gulp.watch('**/*.md', ['build']);
});

Customize the HTML conversion process

Now that we have a basic setup that will convert Markdown to HTML, we want to customize the HTML output to our own needs. You can do that by overriding the default renderers.

Custom table markup

We wanted to have Bootstrap responsive tables so we added our own rules:

md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
    return '<div class="table-responsive">\n'
        + '<table class="table">\n';
};
md.renderer.rules.table_close = function (tokens, idx, options, env, self) {
    return '</table>\n'
        + '</div>\n';
};

Now all the tables in our Markdown files will convert to this HTML.

Besides this, you can do additional changes like making all links open in new tabs or adding the img-responsive class to all images, just to name a few.

Extend Markdown-it with additional plugins

Besides creating your own rendering rules you can also create or use Markdown-it plugins.

Here are a couple of plugins we used in our own conversion:

Bootstrap alerts

We use Bootstrap alerts in some of our articles so we wanted to have an easy way to express that in Markdown.

Using the markdown-it-container plugin we created the markdown-it-alerts plugin that does just that.

npm install markdown-it-alerts --save-dev
var alerts = require('markdown-it-alerts');
md.use(alerts);

See the GitHub page for more information on how to install it and use it.

Font Awesome icons

Likewise, we make use of Font Awesome in some of our articles, especially for buttons, so we used the markdown-it-regexp plugin to create our own markdown-it-fontawesome plugin.

npm install markdown-it-fontawesome --save-dev
var fa = require('markdown-it-fontawesome');
md.use(fa);

Check the GitHub page for instructions.

Conclusion

If you followed the tutorial your gulpfile.js will look like this:

/* global Buffer */

var gulp = require('gulp');
var gutil = require('gulp-util');
var tap = require('gulp-tap');
var MarkdownIt = require('markdown-it');
var alerts = require('markdown-it-alerts');
var fa = require('markdown-it-fontawesome');

var md = new MarkdownIt();
md.use(alerts);
md.use(fa);
md.renderer.rules.table_open = function (tokens, idx, options, env, self) {
    return '<div class="table-responsive">\n'
        + '<table class="table">\n';
};
md.renderer.rules.table_close = function (tokens, idx, options, env, self) {
    return '</table>\n'
        + '</div>\n';
};

gulp.task('build', function() {
    return gulp.src('articles/**/*.md')
        .pipe(tap(markdownToHtml))
        .pipe(gulp.dest('./dist'));
});

gulp.task('watch', function() {
    gulp.watch('**/*.md', ['build']);
});

function markdownToHtml(file) {
    var result = md.render(file.contents.toString());
    file.contents = new Buffer(result);
    file.path = gutil.replaceExtension(file.path, '.html');
    return;
}

If you need to customize the conversion process from Markdown to HTML and are running on a Javascript environment, then I highly recommend that you take a look at Markdown-it. It makes it easy to adapt the output and extend the Markdown language.

Nuno Freitas
Posted by Nuno Freitas on December 2, 2015

Related articles