About This Site

This website started around year 2007 as a simple blog. It went through multiple changes since then.

This is the story behind it.

History

Initially I hosted blob posts on open platforms like LiveJournal and Blogger. They tended to be limiting, clunky and with advertisements.

At some point I discovered Linux for the first time and decided to give a try to WordPress. It worked out well for a couple of years, till I got tired from maintaining it.

Some time later, commercial Squarespace platform attracted me with good performance and sleek designs. It was hassle-free and enjoyable for some time.

At some point, I got tired with limitations of the platform and their pricing. Around the year 2014 I imported my posts to Octopress.

I loved the idea of static websites:

  • low maintenance and high availability;
  • great performance;
  • hosting prices are negligible.

However Octopress was slow and it was running on Ruby. I experienced occasional frustrating issues with runtime versions and ruby gems.

Hugo

While working on HappyPancake project, I discovered the ecosystem of Go.

It wasn't long before Hugo got my attention. This static website generator was really fast, building full site out of my 200+ posts in less than a second. This was worth migrating to.

Roughly at the same time I moved my site to the Amazon cloud for static hosting.

The combination worked great.

Fast site regeneration allowed have smooth feedback loop. HTML templates were a bit uncomfortable and limiting, but that is the nature of html/template in go.

Custom Node.JS + React.JS

In 2014, while working on front-end logic for HappyPancake, I discovered Node.js and React.JS.

Node.js ecosystem is totally different from ecosystems of golang, .NET, Erlang or Haskell. It is build upon JavaScript, which is probably the most widely used language out there. There are a lot of bad features in the language and poor quality projects written in it.

Yet, if you stick with the good parts of the language, nice packages and align your design with the ecosystem, you would get a brilliant set of tools for front-end development.

I also loved templating capabilities of React.JS - a JavaScript Library for building web interfaces. It has a convenient way of expressing composable User Interface components in a single file.

Here is an example of a simple page listing all posts within a tag:

render: function () {
    var site = this.props.site;
    var title = "Articles in " + this.props.tag;
    var list = [];
    var posts = site.tags[this.props.tag];

    lists.sortLatestFirst(posts).forEach(function(p) {
        list.push(
            <li key={p.url}>
                <Permalink post={p} />
            </li>
        );
    });

    return (
        <PostLayout title={title}
                    site={this.props.site}
                    nav="archive">
            <article>
                <ul>
                    {list}
                </ul>
            </article>
        </PostLayout>
    );
}

So I decided to replace Hugo with a hand-written static HTML generator, using markdown for content and React.JS with JSX for HTML.

December 3 - New Version Deployed

This week I pushed a new version of the web-site to production. It took roughly 2 weeks to replace Hugo with my own version, working in spare time.

I simply picked existing node.js packages, wired them together and then rewrote Hugo HTML templates as ReactJS components. This was also an opportunity to improve web design.

Here are some of the features that came for free with this approach.

Fast generation

Hugo generated HTML for my website in less than a second. It used all 4 cores of my MacBookAir.

Node.js processes, on the other side, run on a single core by default. Build takes just 4 seconds, which came as a surprise. I use some brutal HTML validation and regex replacements on old posts. Without this logic, build would be faster.

In-memory processing

HTML processing happens in memory. In the start node.js loads all my source files into the virtual file system. All further operations would happen there.

At the end, I either dump /build folder into the real filesystem for sync with Amazon S3 or launch a simple HTTP server that behaves exactly like Amazon.

Since regeneration is fast, and it doesn't write thousands of files to my SSD, I can watch the input directory for changes and rebuild on every save.

Continuous compilation makes writing flow more convenient.

No vendor lock-in

If, at some point, I decide to go away from Amazon, it would require a little effort. Nginx with a simple configuration could host the entire website in exactly the same way.

Code snippets are compiled

I added syntax for extracting named code snippets from source files and injecting them into the HTML. They are auto-indented and then highlighted with highlight.js.

Obviously, build script lints, compiles and tests source files, ensuring that they have consistent quality. This process is fast for golang, which is one of the reasons I started using it for new snippets.

HTML-specific processing

Node.js has an ecosystem for dealing with web resources. I use it for:

  • HTML minification
  • CSS linting and minification
  • Atom Feed generation
  • Markdown rendering

Semantic HTML5

New layouts use semantic HTML5 elements like aside, header, footer or section. Not only this helps with the design, but also makes website friendly for search engines.

Publishing Features

There also are some miscellaneous features related to publishing. They were either easy to add or came for free.

  • Build process extracts all TODO comments across all content, updating a simple org-mode outline file. I can easily see what needs to be done next.
  • There are some broken links in my old content, build process finds them and lists by priority.
  • Current UI layout forces new content to be book-ready. In fact, new content could be converted from the sources into O'Reilly AsciiDoctor format or transformed to Epub directly.
  • Some HTML templates display the most relevant articles to read after the content. If relevant articles aren't provided manually, build process computes them.

I also introduced additional constraints for the new prose. For example, all essays should have a central idea that they focus on (build will fail if that property is not provided). This idea is then used in description HTML header or in tweet summary, should you click Discuss button by the post header.

if (form === "essay") {
    if (idea === undefined) {
        throw new Error("Essays MUST specify an idea they focus on.");
    }
} else if (form === "bio") { /* ... */ }

Different forms of prose have different constraints.

To be continued...

This is an ongoing project. I will post updates about any significant changes in my publishing process.

- by .