Mikael's blog

A developers seventh time trying to maintain a blog

The seventh blog

The seventh blog has gone live!
I didn’t dare to hope that this day would come, but a stint of bad (or not as great as usual) weather has left me with a lot of time for coding while my family wears out their phone batteries to the best of their abilities.

The fixed and the missing

While there was quite a lot of missing features a few days ago, there is now a working archive, tag cloud and even search(!).

The latter was solved with Orama, formerly known as Lyra, and it does all the full-text searching client-side. It’s all hooked up with a custom WebComponent and some clever index building with Astro. There will be a more complete writeup on it in the future, but for now you can check out the code over on GitHub. The link for that is at the source page.

Comments are still missing, and I have not figured out a great way of doing them yet. It will need a database of its own though, since the rest of the blog runs without a database.

Also missing is the admin area, which is for my eyes only anyway, but that will have to wait for another rainy day. For now I’ve set up a webhook on GitHub that calls a docker container on my server. The docker container then fetches the latest code and builds it, after which it copies it to a shared volume that the web server reads from. This makeshift pipeline works quite nicely for the moment.

by Mikael Lofjärd

And just like that...

… I started on yet another rewrite.


I’ve had my eye on Astro for a while now. One of the things that caught my eye was just how much it looked like Svelte.

Consider the following examples:

import BlogPost from "../components/BlogPost.astro";

const allBlogPosts = await fetch("https://blog.lofjard.se/api/blogposts/all", data => {
   return await data.json();

<div class="blog-list">
{ allBlogPosts.map(item => (
   <BlogPost item={item} />

.blog-list {
   width: 600px;
   margin: 0 auto;


import BlogPost from "../components/BlogPost.svelte";

const allBlogPosts = await fetch("https://blog.lofjard.se/api/blogposts/all", data => {
   return await data.json();

<div class="blog-list">
{#each allBlogPosts as item}
   <BlogPost {item} />

.blog-list {
   width: 600px;
   margin: 0 auto;

They both fetch some blogpost from an api and passes each post along to another component that renders them. The general structure is the same, e.g. there is some script code up top, some basic templating in the middle and some CSS at the bottom.

The difference

Well the difference is in how they handle things. While both Svelte and Astro can be configured for SSR (Server Side Rendering), the default in Svelte is to work as a SPA framework while the default in Astro is to render everything at build time into static files.

Astro has a “zero client-side javascript” policy by default, but certain areas can be “hydrated” with scripts from other frameworks such as React, or in my case Svelte. These areas are called “islands” in Astro-lingo and I plan on using this both for the commenting system and for my admin area.

Will it ever stop?

I honestly don’t know. I’m having a lot of fun learning the ins and outs of different frameworks, and this blog always seem like the perfect victim for my latest whim.

There is still some stuff to be done with the design. Not all functionality is done yet. I mentioned which parts in the last blog post. I plan on releasing a first version of this before my summer vacation is over, and since this blog post is written as Astro markdown content, if you are reading this then I have already released it in its current form.


  • It’s a neverending cycle of rewrites.
  • All public facing sites are now static, generated by Astro.
  • Admin area, and comments section will include Svelte “islands”.
by Mikael Lofjärd

Svelte-Blog 0.1 (alpha)

New face

The blog has gotten a face lift with some fresh new styling. In the last 8 years I’ve probaly redesigned it 4 times. It always ends with me not completing my design and/or getting bored with it. Even this design is not the one I spoke of in the last update.

New tech

Even though the design is new, the blog itself is the same one I wrote about last year. It’s written in Svelte, and compiled to a static page. Instead of having my own API in Node.js it talks to the CouchDB database directly through its REST API.

Authelia is setup to handle authentication and authorization to the admin area and database backend, ensuring write access to only those deemed worthy.

Missing features

There are currently a lot of things missing in this blog that were available before. They will get implemented over time, but I figured I had better get this version deployed now or it might never happen at all.

The missing feature list includes (but is not exclusive to):

  • Source code view (it’s on GitHub now instead)
  • Volumetric tag cloud
  • Comments (they are readable, but you can’t post new ones)
  • Search (this one usually stopped working randomly in the old engine anyway)

New life

Will this mean that I will write more blog posts? Who knows? I can’t make any promisses. Only time will tell.

by Mikael Lofjärd

New blog on the way

I’ve spent the last week in the mountains, skiing, relaxing and eating well.
I also took some time rewriting my blog. The old blog relies on client certificates to enter the admin area. This worked like a charm while I had the certificates on hand, but now, 8 years, 4 computers and a whole lot of reinstalls later, they are nowhere to be found.

The new blog is written using Svelte (because why not?) and currently only lives on my laptop.
I’ve written a new admin UI and established a proxy connection to my CouchDB instance through a SSH tunnel.
All in all, I’ve gotten to the point where I can write new posts. (Yay!!)

The new blog won’t be online for a while though since I need to write a real proxy backend for the database and set up some proper authentication for the admin UI first.

There might be screenshots in a few day.

Here’s to hoping it doesn’t take another 8 years for me to post again! =)

by Mikael Lofjärd

2014 In Review

It has been a bad year for my blog. Early on I started working on a new blogging platform that would also support a number of other content types to better reflect my life.
I wanted to host my own data from my running and mountain biking activities and I wanted to review at least a part of all the tech and sporting equipment I’ve bought over the year.

None of this came to pass…

…and I’m quite ashamed…

…and consider it a personal failure.

The new platform is still under construction and I’m thinking of breaking it into parts and doing a partial release as soon as possible, though that might still be closer to the end of Q1 2015.

New hardware for my office has been ordered a few days ago and I hope I will get some time to do some serious bare knuckle programming done as soon as I get home (I’m currently celebrating Christmas and the new year in the Swedish mountains).

To all you readers who persist in checking in on this blog: Thank you, and a happy new year!

by Mikael Lofjärd

Summer is Coming

And with summer, my almost year long blog hiatus ends.

July 31st 2013 was the day my second daughter was born. Besides installing some long forgotten parts in the server machine, little has happened since then. Well, little has happened with regards to the blog, that is.

September 25th marked my 31st birthday and the scale tipped at 90 kilograms. I strapped on my running shoes and started running. Once a week. Then twice a week. For a while I ran three times a week. I also cut all my intake of carbohydrates, except for one beer each weekend, and about two weeks after Christmas the blinking digits underneath my feet presented themselves as 75 kilograms.
I’ve kept on running ever since.

Then the year 2014 happened and boy did it happen fast. It’s already May and I’ve yet to write a single blog post (well except for this one). I have, however, started up a few new projects, both by myself and some with friends. One of them will result in a new design for this blog and its subsequent merge into a larger site presenting more aspects of my life.
More information about that will follow, I promise!

by Mikael Lofjärd

Server Maintenance of 2013

My server mostly keeps to itself, chugging along in my apartment storage space, but sometimes I order new parts for it. One such part was the picoPSU I bought several months ago to replace my totally overkill 650W PSU.

Essentially, I wanted to replace this:

Really big PSU

with this:

Really tiny PSU

The Corsair TX-650 has worked without a hitch, but my server is an Atom D525 with a TDP of 12W and its only other hardware is an SSD. It seems like there would be some serious loss of power due to PSU inefficiencies on such small loads.

The picoPSU on the other hand is a DC-DC PSU with an external brick rated for 120W loads, and it has proven much more efficient on smaller loads in test around the interwebs.

When I finally took the time to switch to the picoPSU, I also got rid of one of the large fans humming along inside the server case. The expected silence was however interrupted by the screeching sound emanating from the Lian-Li case fan installed in my server case. Since this was now the only fan in the case (and the motherboard chipset was getting a bit hot for my taste without any fan at all) I decided to replace it with something a bit quieter.

The choice fell on this:

REALLY quiet fan

This is the Noctua NF-A14 ULN (Ultra Low Noise) 140mm. In the configuration I chose it runs at 650 RPM and it is barely audible from a distance of about one inch. Move another inch or two away from the fan and you need to have a seriously quiet room if you’re going to hear anything from this fan.
More than once I had too look at the fan to make sure that it was really spinning.

The next time I’m upgrading my server I’m going to purchase some kind of power meter to see how many watts my little machine is operating on but for now I’m just happy that it’s operating a little (a lot) quieter.

by Mikael Lofjärd

Midsummer Grind

Here’s my latest project:

Sanded down keys

It’s taking me a lot longer to sand down all the keys with 180 grit sand paper than I originally planned, but a few more hours and I’ll be ready for paint.

Having kids though, I might not be able to complete it until next weekend. :)

Oh and yes; that’s a Logitech Wave I’m modifying…

by Mikael Lofjärd

The End of May

The blog has been silent lately but i certainly have not been sitting still. About a month ago I started to remake the administration area of the blog into something a bit more fashionable (today it consists of a few input boxes and a “publish” button). Halfway through I decided to rewrite it using AngularJS. Needles to say, I’m not quite done with it yet but it’s a work in progress and it’s going to be awesome.

My great friend and fellow coder Mattias spent a long weekend here and we put together a little P2P file sharing site using Node.js, AngularJS and Web RTC data channels. It’s really cool but like most things, it needs a little more work. It’s up on GitHub though if anyone wants to take a peek at it.

The day before yesterday I beefed up security on my server and it’s been quite interesting seeing who gets banned from trying to log in to every account known to man through SSH.

Spoiler alert! It’s Chinese authorities. =)

I might do a blog post about it someday in the near (or far) future.

In other news; my wife gets more and more pregnant every day, the weather is awesome most days so I really should get a move on with my robot, and I’m really hung-over today from attending a company event last night. We played Segway-polo. It was awesome! =)

by Mikael Lofjärd

Decreasing Load Time When Using Google Web Fonts

I’ve been using Google Web Fonts ever since I started building this blog. It’s an awesome service with a great user interface and it makes it really easy to add fonts to your web site.

Of course I had to find something wrong with it.

Earlier this week our company released our new web site. On our Yammer page, one of my colleagues posted a link to a WebPageTest result for it and it fared reasonably well. It got an “F” on the “First Byte Time” test, but that test is really finicky and could just as well show an “A” if you retake the test (as I later became aware).

This triggered my inner masochist and I just had to run the same test on this blog. The first result was this:

First Byte TimeA
Keep-alive EnabledA
Compress TransferA
Compress ImagesC
Cache static contentC
Effective use of CDNX

To be honest, I actually got an “F” on “First Time Byte” but then I ran the test a second time and got an “A”. Another time I got a “B”.

It turns out that “First Time Byte” includes the time it takes to perform the DNS lookup. As I don’t wield much power over the DNS servers of the world, I ignored it when it came to my own server, but it would turn out to be quite the interesting thing when I went on to fix my C grades.

Compress images

This one was easy. WebPageTest complains if JPEGs are above 50% quality (with a 10% margin), so the image of my robot uploaded with my image uploader and re-sized on the client, was the culprit here.

I re-encoded it at 50% quality and updated my upload script to always use 0.5 as the quality constant.

Cache static content

Google doesn’t add any expiration headers to the Web Fonts CSS. I’m guessing that this is because they make changes to the underlying code that generates this CSS sometimes, and the want the changes to propagate as fast as possible.

I am however not that concerned about my fonts as I’ve already tested that they do what I want, so I would prefer them to be infinitely cached. So I thought about hosting them myself, as I already was doing with my symbol font (Elusive Icons).

At first I thought, well that will put more strain on my server, and it definitely goes against CDN best practices. But then I went ahead and checked my timeline readings at WebPageTest, and it turns out that even though the font data is transferred quickly from Googles servers, the DNS lookup for those where taking quite some time.

fonts.googleapis.com took roughly 300 ms to lookup, but that wasn’t the worst one.

themes.googleusercontent.com took more than a 1000 ms to resolve and that is the server that the font files are actually on.

Now this has to be taken with a grain of salt, just like the “First Byte Time” since DNS lookup could be really fast if the test was retaken. But it got me thinking.

No matter how you look at it, lofjard.se needs to be resolved, once, if you want to load this site. But then the resolved address is cached and every other subsequent request to lofjard.se will skip the DNS lookup step.

Hosting the web font CSS in my own CSS-file meant one less request, but hosting the web font files myself meant that the 6 font file requests where now directed at lofjard.se instead of another server. The question was if I could download the fonts from my own server in less time than I could DNS loopkup and download them from Google, even when taking a parallelization hit from the fact that most browsers only allow 4 simultaneous requests to the same server? The answer was YES.

My latest result from WebPageTest shows a much nicer score:

First Byte TimeA
Keep-alive EnabledA
Compress TransferA
Compress ImagesA
Cache static contentA
Effective use of CDNX

That dreadful “X”

I still get an “X” at CDN usage, and I’ve actually gotten worse at it since I now use two less CDNs than before. But it goes to show that while CDNs are great, they are not always the answer to performance.

by Mikael Lofjärd

Sorry, sharing is not available as a feature in your browser.

You can share the link to the page if you want!