Based on Node.js/Express.js and flat markdown files. This is the main (and only) code file,
containing all the logic and code, and is written in literate Coffeescript.
The Idea is that you just put your articles as markdown files (*.md) in the /posts
folder, and Influenza
takes care of all the other stuff.
Only the following npm modules are used:
express = require "express"
exphbs = require "express-handlebars"
mde = require "markdown-extra"
markdown = require("markdown").markdown
_ = require "underscore"
async = require "async"
rss = require "rss"
fs = require "fs"
app = express()
Since this is an Express.js 4.X web app, these are the relevant application settings, both for development and production environment:
app.engine '.hbs', exphbs(defaultLayout: 'postLayout', extname: '.hbs', partialsDir: 'views/partials')
app.set 'view engine', '.hbs'
app.set 'views', "#{__dirname}/views"
app.enable 'trust proxy'
# app.use express.compress()
app.use express.static "#{__dirname}/public"
# app.use express.responseTime()
This function will read all the files from the /posts
directory. It may be better to cache the results,
but to prevent restart-needs everytime a post gets updated, it is preferred to read from scratch everytime.
Should be fast enough for a simple blog.
readPosts = (fn) ->
fs.readdir 'posts', (error, files) ->
filePaths = _.map files, (f) -> "posts/#{f}"
async.map filePaths, fs.stat, (error, fileStats) ->
posts = ( for file, index in files
title: file.split(".")[0]
slug: file.split(".")[0].replace(/\W+/g,"-")
createdAt: fileStats[index].ctime
)
fn null, _.sortBy posts, 'createdAt'
This function will transform a given post name into the fully parsed result object (if it exists, of course!).
fetchPost = (name, fn) ->
filePath = "#{__dirname}/posts/#{name}.md"
fs.stat filePath, (error, stats) ->
unless stats
fn null, null
else # the file exists
fs.readFile filePath, {encoding: "utf-8"}, (error, data) ->
post =
title: mde.heading data
content: markdown.toHTML( mde.content data )
metadata: mde.metadata data
createdAt: stats.ctime
updatedAt: stats.mtime
fn null, post
app.get '/', (req, res) ->
readPosts (error, posts) ->
fullUrl = "http://blog.plague-dev.de" + req.originalUrl
res.render 'home',
title: "Plague Developer Blog"
posts: posts
layout: "mainLayout"
shareMailSubject: encodeURIComponent "Plague Developer Blog."
shareMailContent: encodeURIComponent "#{fullUrl}"
shareUrl: fullUrl
shareTwitterContent: encodeURIComponent "Plague Developer Blog #{fullUrl}"
shareLinkedinContent: encodeURIComponent "Plague Developer Blog"
shareLinkedinUrl: encodeURIComponent fullUrl
sharePinterestImage: ""
app.get '/posts/:slug', (req, res) ->
securedSlug = (req.params.slug or "").replace(/[^\w-]/g, "").replace(/-/g," ")
fullUrl = "http://blog.plague-dev.de" + req.originalUrl
fetchPost securedSlug, (error, post) ->
if error or not post
res.redirect "/" unless post
else
data = _.extend (post || {}),
layout: "postLayout"
shareMailSubject: encodeURIComponent "I just found this Article, sounds interesting: #{post.title}"
shareMailContent: encodeURIComponent "#{fullUrl}"
shareUrl: fullUrl
shareTwitterContent: encodeURIComponent "#{post.title} #{fullUrl}"
shareLinkedinContent: encodeURIComponent post.title
shareLinkedinUrl: encodeURIComponent fullUrl
image: (post.metadata.image or "")
sharePinterestImage: encodeURIComponent(post.metadata.image or "")
res.render 'post', data
app.get '/feed', (req, res) ->
readPosts (error, posts) ->
feed = new rss
title: "Plague Developer Blog"
description: "Latest thoughts and buzz about tech, startup culture, software and growth hacking."
feed_url: "http://blog.plague-dev.de/feed"
site_url: "http://blog.plague-dev.de"
author: "Maximilian Stroh (@Hisako1337)"
language: "en_US"
for post in posts
item = {}
item.title = post.title
item.description = "Click to read!"
item.url = "http://blog.plague-dev.de/posts/#{post.slug}"
item.author = "Maximilian Stroh (@Hisako1337)"
item.date = new Date(post.createdAt)
feed.item item
xml = feed.xml " "
res.header('Content-Type','application/rss+xml').send(xml)
app.get '/posts', (req, res) ->
readPosts (error, posts) ->
fullUrl = "http://blog.plague-dev.de" + req.originalUrl
res.render 'posts',
title: "All Posts | Plague Developer Blog"
posts: posts
layout: "mainLayout"
shareMailSubject: encodeURIComponent "All Posts | Plague Developer Blog"
shareMailContent: encodeURIComponent "#{fullUrl}"
shareUrl: fullUrl
shareTwitterContent: encodeURIComponent "All Posts | Plague Developer Blog #{fullUrl}"
shareLinkedinContent: encodeURIComponent "All Posts | Plague Developer Blog"
shareLinkedinUrl: encodeURIComponent fullUrl
sharePinterestImage: ""
app.get "*", (req, res) ->
res.redirect "/"
server = app.listen 2368
console.log "Listening on port 2368"