How I Publish This Blog


NOTE: this is a bit outdated. See this post for details on moving to Astro. Much of this post still applies, especially my steps for image optimization and conversions which happens elsewhere in my build pipeline

This blog is currently built using Jekyll, a static site generator written in ruby. It’s only a part of the stack, which also involves various build scripts and optimization tools I use to (as of this writing) score a 100 on pagespeed insights

Build Scripts

I’ve summarized them in this post, but here are the full build scripts:

  • - used as a config file
  • - build and optimize
  • - upload to s3/cf
  • gulpfile.js - gulpfile for minification, etc. NOTE: I no longer use this. Linked is an archive.


  • HTML Minification - remove whitespace / unnecessary comments
  • CSS Minification - minify all css to remove whitespace / comments
  • CSS Inlining - since the css size is small I inline the /css/rich_v2.css file into the <head> section to save a request.
  • Fonts - all fonts are hosted locally instead of using google fonts
  • Image Optimization - optimize all png, jpg images
  • Compression - Compress automatically using CloudFront

How it works -

1. Jekyll - static site generator

bundle exec jekyll build

2. Gulp - This is used for css/html minification

Inside here, gulp-clean-css, gulp-htmlmin, gulp-inline-source are used for minification and optimizations (with more or less default parameters)

# Minify artifacts
gulp minify-html minify-css

3. imagemagick (aka “convert”) - used for image conversions

# Convert profile image into a PNG
convert _site/img/profile_image.jpg _site/img/profile_image.png

4. png2ico - used to generate .ico files

# Convert profile image into an ICO file
png2ico _site/favicon.ico _site/img/profile_image.png

5. exiftool - used for stripping exif metadata

# Strip All EXIF DATA (except orientation)
find _site -type f \( -name "*.jpg" -o -name "*.JPG" -o -name "*.jpeg" -o -name "*.png" \) -print0 | while read -d $'\0' f; do
  exiftool -overwrite_original -all= -tagsfromfile @ -Orientation "$f"

6. optipng - used to optimize png images

# Optimize PNG files
find _site -type f \( -name "*.png" \) -print0 | while read -d $'\0' f; do
  optipng "$f"

7. jpegoptim - used to optimize jpeg images

# Optimize JPG
find _site -type f \( -name "*.jpg" -o -name "*.JPG" -o -name "*.jpeg" \) -print0 | while read -d $'\0' f; do
  jpegoptim --size=200k "$f"

How it works -

1. Set up s3 website

First, we set the s3 website’s index / and error documents

# Setup the website
aws s3 website "s3://$S3_BUCKET" \
  --profile "$AWS_PROFILE" \
  --index-document "$INDEX_DOCUMENT" \
  --error-document "$ERROR_DOCUMENT" &&

2. Upload entire site

Next, we upload to the s3 bucket, with the public read flag set. The --delete flag ensures that stale files that have been renamed or deleted are removed.

# Upload
aws s3 sync \
  --profile "$AWS_PROFILE" \
  --acl public-read \
  --sse \
  --delete \
  _site "s3://$S3_BUCKET" &&

3. Set up cache-control

# Add cache-control headers for poster images
# This instructs s3/cloudfront to send Cache-Control headers.
aws s3 cp \
  "s3://$S3_BUCKET/img/headers/" \
  "s3://$S3_BUCKET/img/headers/" \
  --profile "$AWS_PROFILE" \
  --metadata-directive REPLACE \
  --recursive \
  --cache-control max-age=31536000

4. Invalidate Edge Caches

# Invalidate Edge Caches
aws cloudfront create-invalidation \
  --profile "$AWS_PROFILE" \
  --distribution-id "$DISTRIBUTION_ID" \
  --paths /\*

Change Log

  • 3/20/2019 - Initial Revision
  • 3/20/2019 - minor wording changes

Found a typo or technical problem? file an issue!