Another Year, Another Site Refresh

Let’s track current progress:

Theme Update

Skeleton.css, while a good fit for general content, didn’t quite feel right from a blogging perspective. It didn’t seem to emphasize the content like I had hoped. Skeleton also recommended the usage of the Raleway font, which increased the number of requests sent and time to download. A blog, should really be the fastest page on the internet. Taking a fast site and making it faster will be a theme in this post (no pun intended).

I stumbled upon lanyon, which is a beautifully minimalist design. In a lot of ways this motiviation to use to design spurred my enthusiasm to give the site an update. The typography looks crisp, code (inline and block) more elegant, sane lists. The one regression are that tables have a tad worse appearance, but that’s a compromise I’m willing to make.

One customization I made to lanyon is the removal of the sidebar. I thought it added zero values and removing it led to a sizeable reduction to css and js. Also, no more additional request for fetching fonts!

Less to cssnext

There is not a ton of custom css on the site and that’s probably a good thing[citation needed]. It used to be written in Less. Less has served me well over the years. I’ve used it in countless project and it always resulted in a boon.

Working with Less wasn’t always easy. If you’re familiar with Less questions on stackoverflow you may even recognize me from the famous question “Less Aggressive Compilation with CSS3 calc” (it’s the second hit for the google search “less css calc”).

Recently it has seemed that Less has become less popular (again, pun not intended). Bootstrap 4 is moving away from Less. “Why Bootstrap 4 Means Sass Has Won”. “Less vs Sass? It’s time to switch to Sass

I would fault no one for believing that this site using Sass, but they would be wrong. I chose cssnext. It’s a simpler language, but contains all the features of Less that I want. The best part is that cssnext represents features that will most likely land in the next version of the css spec. From the site:

In a near future, browsers will implement new CSS specifications. As time passes, cssnext will remove some transformations that won’t be necessary anymore. And maybe one day, you will be able to completely remove cssnext from your workflow without touching your CSS.

That’s a huge selling for me. Since I don’t modify this site very often, I want css that is going to last.

I’ve also moved to PostCSS for processing cssnext, as well as inlining css @import, linting styles, and minifying the css via cssnano. It was almost too easy to use.

Removal of most of Grunt functionality

Before the rework, Grunt was preforming the following actions in about 200 lines of configuration:

  • Compiling Less files into css
  • Concat said css files into a single file
  • Run Jekyll
  • Copy files to a build directory
  • Clean folders
  • Run webpack
  • Run requirejs
  • Optimize images
  • Resize images
  • Autoprefixer
  • Rename files
  • Replace java script tag with hashed version

After the rework, Grunt is still present but its role has greatly diminished (an +80% reduction in configuration size)

  • Run webpack
  • Run postcss

Bower has been eliminated from the repo with no traces remaining. Read why use bower when there is npm. It’s dying and that’s fine.

Since the original functionality didn’t just disappear from the site, the next couple sections will explain where the behavior has been moved to.

Jekyll Assets

This website sits behind the CDN, DNS, and DDos protection company, Cloudflare. In order to better serve your content, Cloudflare asks how long it should keep your site’s assets in the cache before refreshing them. I used to have it set at four hours because there was main.js, main.css, images, etc, and if I updated one of these files I would only have to wait four hours to know they’ve been refreshed. Sitespeed and Page Insights complained about the short cache time.

Jekyll assets is a beautiful solution to the caching problem. It will take css, js, and images referenced in the posts and replace the path with a version that is digested (the file name will contain a hash). This hash will only ever change if the content changes. Once deployed, this file could be cached forever. With this simple update, I changed Cloudflare to cache all files (except the html files) for one year. Increasing the cache time nearly 9000x appeased performance tools.

I do not have Jekyll assets handle any js or css transformations, instead use webpack and postcss for the transformations.

I use the resize feature for images so that all banner images are the same size. Jekyll assets will also inline the width and height so that the browser doesn’t need to calculate the image manually. It’s the small things, but they add up.

Previously, images were optimized on every build. While initially convenient, build times started to creep up. So instead of wasting time doing the same operation every build, optimize the images once before commit. Additionally, the image optimizations was done using a node.js package and I couldn’t help but think that there were some bytes left on the table.

Using the image tools recommended by google, I first used optipng to optimize the pngs. For jpegs, the lossless jpegtran -optimize was followed by mozjpeg -optimize. These two commands yielded the best result. The result was a 80% in reduction of images (from 20MB to 4MB) with minimal reduction in quality.

ESLint over JSHint

A small change, but one still worth mentioning is a move from JSHint to ESLint. ESLint is just like JSHint except it has the potential to be so much more by being pluggable. I’ll admit that I can’t articulate all the benefits so I’ll paste from ESLint’s README.

How is ESLint different from JSHint?

The most significant difference is that ESlint has pluggable linting rules. That means you can use the rules it comes with, or you can extend it with rules created by others or by yourself!

Is ESLint just linting or does it also check style?

ESLint does both traditional linting (looking for problematic patterns) and style checking (enforcement of conventions). You can use it for both

I do know one thing. The ESLint plugin for webpack integrated seamlessly with the babel plugin. I’m unsure if JSHint can say the same thing.

Below is the contents of my .eslintrc notice that it extends from the very popular airbnb-base with a few modifications of my own.

{
  "extends": "airbnb-base",
  "env": {
    "browser": true
  },
  "rules": {
      "no-use-before-define": [2, { "functions": false }],
      "no-plusplus": ["error", {"allowForLoopAfterthoughts": true}]
  }
}

Deployment

Previously, I’d tar up the temporary build directory and pipe over ssh like the following:

tar cf - _site | ssh nick@<host> \
  'D=`mktemp -d`;tar xf - -C $D;cp -r $D/_site/* /var/www/nbsoftsolutions/.'

This is slow and permissions weren’t ideal for apache. I decided to give rsync a try, and I’m glad I did. Some of the benefits seen:

  • Much faster file transfers
  • Customize permissions on resulting remote server
  • Dry runs
  • Delete files on remote but not on local (great for those hashed assets)

The rsync script ended up looking like:

# Pass in `-n` for a dry run deployment. Exclude deleting python environment
# on remote side as well as Let's Encrypt certificate information. Chgrp the
# files so that apache can read the files
rsync $@ -rvP --delete --exclude=env/ --exclude=.well-known/ \
  -g --groupmap=*:www-data \
  _site/ nick@<host>:/var/www/nbsoftsolutions

Results

Comments

If you'd like to leave a comment, please email [email protected]