Re-building this website - iameven.com
Yet again rebuilding a site that already worked. But optimization, you know.
As I said in my previous post about building this website I really didn't like depending on both node and ruby to build my site. As awesome as jekyll is I just never got into ruby. I also didn't like doing the build locally before submitting. Duplication of content and more work for me, all my builds were in git commits, and sometimes I forgot to do it.
I began using react.js on a work project and really like that way to structure code. For some reason I thought I could do really cool things with this site by changing to that. I converted my markdown files to react components and started realizing that this was the wrong tool for the job. Yes, I could do awesome transitions but writing posts suddenly got really hard. I did get to experiment some with server side rendering with the same code, so not all was wasted.
Then I wrote my own post parser and static file generator. I had a working prototype in a couple of hours, but the code was really messy. I suddenly started thinking about metalsmith and its plugin based structure. It suddenly seemed a lot more safe to lean on some sort of established system rather than re-invent everything.
How it works
I have all the posts collected in src/posts, an index.html, iameven.css and iameven.js file in src/ and some template files in a templates/ folder. I run index.js locally or from Dokku which collects the files and build the site before starting an express.js server.
The index.js file loads metalsmith and all the plugins I use, excerpt is a modified version of metalsmith-excerpts and date is a custom one I wrote to handle date manipulation.
// index.js
var Metalsmith = require('metalsmith');
var markdown = require('metalsmith-markdown-remarkable');
var highlight = require('metalsmith-code-highlight');
var collections = require('metalsmith-collections');
var permalinks = require('metalsmith-permalinks');
var templates = require('metalsmith-templates');
var beautify = require('metalsmith-beautify');
var feed = require('metalsmith-feed');
var sass = require('metalsmith-sass');
var autoprefixer = require('metalsmith-autoprefixer');
var ignore = require('metalsmith-ignore');
var excerpt = require('./plugins/excerpt.js');
var date = require('./plugins/date.js');
var url = 'https://iameven.com/';
Metalsmith(__dirname)
// set data used by feed
.metadata({
site: {
title: 'iameven.com',
author: 'Even Alander',
description: 'Ramblings of an average geek',
url: url,
},
})
// convert markdown to html
.use(
markdown({
langPrefix: 'lang-',
html: true,
})
)
.use(excerpt()) // collect descriptions
.use(highlight({languages: []}))
// this adds path to post metadata for collections
.use(permalinks(':title'))
// create the collections before running through templates
.use(
collections({
posts: {
pattern: '*/*.html',
sortBy: 'date',
reverse: true,
},
})
)
// create feed before header and footer is added
.use(
feed({
collection: 'posts',
destination: 'feed.rss',
})
)
// change date to custom display format
.use(date())
// parse files and create the index
.use(
templates({
engine: 'handlebars',
cache: false,
partials: {
header: 'partials/header',
footer: 'partials/footer',
posts: 'partials/posts',
},
helpers: {
ifCond: function(v1, v2, options) {
if (v1 === v2) {
return options.fn(this);
}
return options.inverse(this);
},
},
})
)
.use(
sass({
outputStyle: 'compressed',
includePaths: ['styles'],
})
)
.use(autoprefixer())
// make sure output is somewhat pretty
.use(
beautify({
html: {
indent_inner_html: true,
},
})
)
.use(ignore(['styles/']))
.build(function(err) {
if (err) console.log(err);
server();
});
// serve
function server() {
var express = require('express'),
compression = require('compression'),
port = process.env.PORT || 3000,
app = express();
app.use(compression());
app.use(express.static('build'));
// catch unresolved paths and serve a 404.html file
app.use(function(req, res) {
res.status(404).sendFile(__dirname + '/build/404.html');
});
app.listen(port, function(err) {
if (err) return err;
console.log('listening to port ' + port);
});
}
The express server is pretty much the same thing I used before.
Problems
Or rather quirks, I would say. Struggles maybe?
- I assumed the order was somewhat important, but still had to experiment to get the plugins in the right order. For instance, I needed collections to run before templates so the data from collections was usable in the templates. The templating also changed the files from markdown to HTML which made the collection turn up empty. That made me scratch my head for half an hour.
- Highlighting of code is also difficult, for some reason highlight.js insists on wrongly auto detecting the language even if I specify the language for it. The solution there was to use remarkable as markdown renderer and use lang- as prefix to the defined language (as the first markdown parser didn't have that option). I also had to tell highlight to auto detect from an empty array.
- Enabled HTML to embed videos from Youtube and Vimeo, yet markdown had no problem with me using <video> and <audio>.
- The excerpt plugin worked on HTML files, not markdown files as it stated. I had to read the source code to figure that one out. I cloned it and made modifications to strip the HTML and decode HTML entities. The solution of grabbing the first paragraph as a tl;dr instead of a custom description should make writing easier for me.
- To get handlebars.js to do an if var1 === var2 I had to write a helper function. That required some Googling. Another thing was to get partials to work, I had to remove the .hbt extension from the strings.
- At some point the sass plugin stopped detecting the styles folder so I had to specify it. The weird thing was that I only added a 404 page when this error came up (styles not found).
Changes
- The nice theme had to go. I prefer the simplicity of listing all the posts on the front page.
- I've written some custom styles but this is mostly normalize.css doing its thing.
- JavaScript removed and a tiny function to add height to iframes with 100% width was added.
- Categories are no more. I don't think I'll miss them, my URI's are cleaner now. Maybe I should set up some redirects, though.
- No light box means that small thumbnails doesn't make much sense, so I scaled all my images to 740px wide, yet still link to the original.
Conclusion
The site is now really light weight, easy to manage and pretty optimized. I think I'll manage to live with this for a while.