Simple Website System

  1. TL;DR
  2. About
  3. Tutorial
    1. Content
      1. Markup
      2. Images
        1. Metadata
        2. Resizing
        3. Converting
      3. Procedure
        1. Makefiles
          1. Rules
          2. Variables
          3. Getting Files
          4. Advanced Rules
        2. Pandoc

TL;DR

Basically just convert your chosen markup language into HTML, and then add a header and footer to add css and some site structure. Finally copy the files to a server somewhere where they can be seen.

About

This page explains how to create a simple markdown based blog/website like mine. Basic knowledge of web technology is needed, you should know a little HTML and CSS, and how to install and run software on your operating system through the terminal. For publishing a host is required, either a VPS (i use linode), or you can use neocities or another free static site hosting provider.

If you want to learn HTML and CSS I would recomend MDN for documentation, they are very thorough and have documentation for more recent features that can really come in handy sometimes.

Tutorial

This tutorial is not meant to be comprehensive, but it will give you all the code you need to have a simple blog/website similar to mine.

Using different software in place of the software I used is left as a exercise to the reader, though I will give some links to other options.

Content

This section concerns the preparation of content for the website

Markup

The first step is choosing how you want to write your content. Usually this involves a markup language (in my case markdown) that can be converted into HTML. You could use plain text but websites without links are not as interesting, so its usually good to use a lightweight markup language. If you want more information to choose one check out this page.

Make sure you can edit it using a text editor, and that it can be output into HTML, or at least converted.

My recommendation is to use Markdown, unless you use Emacs as your text editor, then Org-Mode has better integration because it’s Emacs native.

reStructuredText and AsciiDoc are cool too if you want something different.

If you want a basic overview of Markdown check out Markdown Guide

Images

Images for your website should be prepped in a few ways before being uploaded.

  1. metadata should be removed (for privacy)
  2. image should be resized to a reasonable size (for loading times)
  3. (optional) images can be converted to a smaller format
Metadata

Removing metadata is simple on linux (and usually others).

exiv2 -d a ${IMAGE}

Removing metadata on linux

Windows seems to have built-in functionality for this through the file explorer and photos app

Macos seems to need an external tool.

Or you can just use WSL on windows, and homebrew on macos. The rest of the tutorial will assume you are.

Resizing

To resize the image were going to use ImageMagick. It has tons of tools for manipulating images and will be used for resizing and maybe conversion later on.

Resizing and image with the magick command is easy. The basic form of the command is as follows, with the variables in brackets replaced by there appropriate values:

magick ${INPUT} -resize ${X}x${Y} ${OUTPUT}

Resizing and image with ImageMagick

The image will be resized to fit within the box defined by width X and height Y.

Usually I set both to 1024 for a full size image that will take up about half of the screen width-wise. Adjust as needed.

Converting

There are few options when choosing a image format. JPEG is the standard online but doesn’t offer transparency, PNG has transparency but generally has larger file sizes and can’t be lossy compressed. Another option is WebP, which offers lossy and lossless compression, transparency, and animation. It also offers smaller file sizes, which is why ive chosen to use it.

I did some tests to show you the difference:

-rw-r--r-- 1 lex lex 270K Sep  6 12:05 jpeg-1k.jpg
-rw-r--r-- 1 lex lex 883K Sep  6 12:05 jpeg-2k.jpg
-rw-r--r-- 1 lex lex 3.4M Sep  6 12:05 jpeg-4k.jpg
-rw-r--r-- 1 lex lex 6.2M Sep  6 12:05 jpeg-full.jpg
-rw-r--r-- 1 lex lex 3.6M Sep  6 12:03 png-1k.png
-rw-r--r-- 1 lex lex  14M Sep  6 12:03 png-2k.png
-rw-r--r-- 1 lex lex  55M Sep  6 12:03 png-4k.png
-rw-r--r-- 1 lex lex  98M Sep  6 12:02 png-full.png
-rw-r--r-- 1 lex lex  20M Sep  6 12:02 raw.arw
-rw-r--r-- 1 lex lex  78K Sep  6 12:06 webp-1k.webp
-rw-r--r-- 1 lex lex 182K Sep  6 12:06 webp-2k.webp
-rw-r--r-- 1 lex lex 484K Sep  6 12:06 webp-4k.webp
-rw-r--r-- 1 lex lex 845K Sep  6 12:05 webp-full.webp 

The same photo in 4 different formats and 4 different sizes for JPEG, PNG, and WebP. As you can see PNG has the largest files, while WebP has the smallest.

In order to convert the RAW file into a PNG I used ImageMagick, the basic command is as follows:

magick ${RAW} ${PNG}

Convert RAW to PNG

The full image is 5504 x 3672 pixels and 4k is 4096, 2k is 2048, et cetera. In order to convert to JPEG I used the following command:

magick ${PNG} ${JPG} 

Convert PNG to JPEG

Easy! The WebP conversion requires another tool, ImageMagick offers okay WebP support but using Google’s own cwebp tool offers better compression and file sizes. It can be downloaded standalone or part of libwebp on some systems. Search your package manager.

The command is as follows, the tests i did used QUALITY=75:

cwebp -q ${QUALITY} ${PNG} -o ${WEBP}

Convert PNG to WebP

PNG is not really viable for websites, in my opinion, due to its large file size. It might work if you have a few small images per page, but for larger amount, of images you should be using a smaller format and you should definitely be resizing them.

Here is a comparison between JPEG and WebP so you can judge what looks better to you.

A test image in JPEG, 270KiB
A test image in WebP, 78KiB

I think technically the JPEG looks better, but considering the size difference, you can use a larger image in WebP! Or just change the quality setting in cwebp.

This image is also WebP but is 2K, and is still smaller than the JPEG, 182KiB
This image is WebP, but with the quality setting at 95 instead of 75, 266KiB

You can use a combination of quality settings and image sizes to get the right affects you want. “But what about icons and transparency?”, i hear you say, well here you go!

This is an SVG, 8.6KiB
This is a PNG, 255KiB
This is a WebP, 159KiB
This is a small PNG, 6.2KiB
This is a small WebP, 3.7Kib

Basically if you can use SVG then do, else, WebP seems to give the same quality as PNG but again has smaller sizes.

WebP also supports animation!

Eve and Marcel by azul1ne in GIF Resized 320x320
Eve and Marcel by azuline in WebP Resized 320x320
Eve and Marcel by azuline in WebP Full Resolution

cwebp though doesn’t support conversion from GIFs so you have to use the magick command. The syntax is similar to the PNG to JPEG command, you can specify the quality with -define webp:quality=${QUALITY} in betweeen the two files, but it didn’t seem to have much effect when I tested it.

magick ${GIF} ${WEBP}

Converting GIF to WebP

In conclusion I have decided to use WebP for my website, feel free to use your favourite format, but i think I’ve demonstrated some of the merits of WebP.

If you want more information about image formats check out the Wikipedia page on the topic.

Procedure

In order to orchestrate this whole operation we will be using make. It is mostly used as a build system for compiling software but it can be used to run any command which gives it uses it a lot of different areas.

Makefiles

make will use the file named “Makefile” in the current directory.

Rules

A Makefile contains a set of rules, where each rule consists of:

target: prerequisites
    command
    command
    command

A Makefile rule

The target is the subcommand that we run, e.g. make target. The prerequisites can be files that we need to run the commands, or they can be other targets. They can also contain wildcards.

The commands are just shell commands with some extra syntax. They are run in the current directory always, in order to change directory you must do this: cd directory && run command.

Here are two example rules from the Makefile for this website.

all: site

clean:
    rm -rf $(OUTDIR)

simple Makefile rules

The target all depends on another target, called site, this target is not in this snippet. all has no commands, this is often used to just alias a target or to run multiple targets with one make all.

The target clean has no prereqs and excutes the command rm -rf $(OUTDIR). This is a common rule for cleaning built files.

Variables

OUTDIR is a variable, here are some variable definitions:

PAGEDIR=pages
OUTDIR=output
ASSETDIR=assets
STATICDIR=static

Simple variables in a Makefile

These are just simple definitions for directories, defining commonly used directories as variables allows you to change the directories easily by overriding them in the command, like this:

make PAGEDIR=new-pages OUTDIR=new-out

Overriding variables in make

Variables can also contain multiple values as a list (sorta), like this:

PAGES=$(PAGEDIR)/page1.md $(PAGEDIR)/page2.md $(PAGEDIR)/page3.md
HTML=$(OUTDIR)/page1.html $(OUTDIR)/page2.html $(OUTDIR)/page3.html

Multiple files in one variable

Getting Files

But manually adding new pages can be cumbersome. so make comes with functions like wildcard and patsubst which can collect and change the paths on the files for you!

PAGES=$(wildcard $(PAGEDIR)/*.md)
HTML=$(patsubst $(PAGEDIR)/%.md,$(OUTDIR)/%.html,$(PAGES))

wildcard and patsubst functions

wildcard just uses shell like wildcard globbing with *. patsubst takes the pattern to look for, the pattern to replace it with, and the list of files to look in. It will return a list of files with the replacement made.

Advanced Rules

Rules can include patterns too where if make needs a file that matches that pattern then that rule will be called.

$(OUTDIR)/%.html: $(PAGEDIR)/%.md $(STATICDIR)/header.html $(STATICDIR)/footer.html
    mkdir -p $(OUTDIR)
    cat $(STATICDIR)/header.html > $@
    pandoc $< >> $@
    cat $(STATICDIR)/footer.html >> $@

A rule to make a HTML file from a Markdown file

For example if make needs output/index.html it will require pages/index.md, static/header.html, static/footer.html.

The commands are fairly simple here. It makes the output directory if it doesn’t exist, then it just concatenates the header and footer into the file and inbetween converts the markdown.

The $< and $@ syntax means the first prereq and the target respectively.

pandoc is a document converter program, and will be the subject of the next subsection.

Pandoc

pandoc is a “Universal Document Converter”, able to convert to and from many different formats, input formats include plain text, markdown, reStructuredText, Org-Mode, EPUB, HTML, LaTeX, OpenOffice, DOCX. Output formats include the above plus PDF and AsciiDoc.

It is very versatile and easy to use. Given an input file it will print the output to stdout, which is the terminal in most cases, you can redirect this into a file or just provide an output filename.

My use is pretty simple here but it can be used for a lot.