Simple Markdown files server for use as an Express middleware or standalone
npm install markdown-serve/home/john/guide as the root directory, the module can resolve the following paths to the relevant file:
/home/john/guide/"cheat codes"/"open portal.md" (Quotes indicated here are actually not part of the
markdownFile.meta property. You can use this to
js
// example app.js
var express = require('express'),
mds = require('markdown-serve'),
path = require('path');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(mds.middleware({
rootDirectory: path.resolve(__dirname, 'guides'),
view: 'markdown'
}));
// example views/markdown.jade (as referenced by view parameter above):
extends layout
block content
h1= markdownFile.meta.title
#content
!= markdownFile.parseContent()
`
If no view and handler are specified, the module will return a JSON response of the MarkdownFile object with HTML content available as the
markdownFile.parsedContent property.
The preParse option can also be set when using a view to make the HTML content available as the markdownFile.parsedContent
property. This is to support some view engines like hbs, as it doesn't support calling the
parseContent() method in the view.
`js
// pre-parse for use with hbs view engine
app.set('view engine', 'hbs');
app.use(mds.middleware({
rootDirectory: path.resolve(__dirname, 'guides'),
view: 'markdown',
preParse: true // setting this will parse the content and make it available as markdownFile.parsedContent without needing to call parseContent() in the view
}));
// views/markdown.hbs
{{mardownFile.meta.title}}
{{{markdownFile.parsedContent}}}
`
The preParse option can also be specified as a function. In this case, the return object from the function will be passed directly as a
view model to the view.
`js
// preParse option specified as a function
app.use(mds.middleware({
rootDirectory: path.resolve(__dirname, 'guides'),
view: 'markdown',
preParse: function(markdownFile) {
return { title: markdownFile.meta.title, content: markdownFile.parseContent(), created: moment(markdownFile.created).format('L') };
}
}));
// views/markdown.hbs - bind directly to properties on returned object
{{title}}
{{{content}}}
`
If you want full customization of the middleware behaviour, specify a handler function. Note that to use this option, do not specify the
view option as that will take precedence.
`js
// custom handler
app.use(mds.middleware({
rootDirectory: path.resolve(__dirname, 'content'),
handler: function(markdownFile, req, res, next) {
if (req.method !== 'GET') next();
// limit access based on draft variable in front-matter
if (markdownFile.meta.draft && !req.isAuthenticated && !req.user.isAdmin) {
next();
return; // need return here
}
res.render('markdown', { title: markdownFile.meta.title, content: markdownFile.parseContent() });
}
}));
`
$3
For ultimate control, define your own middleware handler.
`js
// example app.js
var express = require('express'),
markdown = require('./routes/markdown');
var app = express();
app.get('*', markdown.handler);
`
`js
// file routes/markdown.js
var server = require('markdown-serve');
exports.handler = function(req, res, next) {
if (req.method !== 'GET') next();
var markdownServer = new server.MarkdownServer( path.resolve(__dirname, 'guides') );
markdownServer.get(req.path, function(err, result) {
// result is a MarkdownFile instance
if (err) {
console.log(err);
next(); // just log error & pass it to next middleware
return; // need return here because we are inside a callback
}
// apply some custom logic based on YAML front-matter variables
if (result.meta && !result.meta.draft) {
var view = result.meta.layout || 'default';
res.render(view, { markdownFile: result });
} else {
// treat files with no front-matter / draft mode as non-existant
next();
}
});
}
`
Sample markdown file at guides/test.md:
`markdown
title: My awesome guide
draft: false
published: 2014-04-01 12:40:00
layout: guide
---
My awesome guide
This is some Markdown content for guide
Bullets:
- One
- Two
- Three
`
`js
// file views/guide.jade
extends layout
block content
h1= markdownFile.meta.title
p.
Published: #{markdownFile.meta.published}
Created: #{markdownFile.created}
#content!= markdownFile.parseContent()
``