Carlos Molina's blog

A blog with 100/100 Performance score; based on https://github.com/google/eleventy-high-performance-blog

🚀 Quick start

  1. Run dev server

    Navigate into your new site’s directory and start it up.

    cd cmolina.dev/
    npm i
    
    npm run watch
    # Your site will be running at http://localhost:8080
  2. Deploy ✨

    The website is hosted with Firebase. You will need to install its CLI globally npm install -g firebase-tools and run firebase login once.

    # build and serve prod assets
    npm run build
    npx -y serve _site
    
    # Checkout http://localhost:5000/,
    # then stop the server and push to prod!
    npm run deploy
    
    # see it live https://cmolina.dev/

Review the previous implementation at https://github.com/cmolina/cmolina.dev_gatsby-starter-blog

Features

Performance outcomes

Performance optimizations

Images

  • Generates multiple sizes of each image and uses them in srcset.
  • Generates a blurry placeholder for each image (without adding an HTML element or using JS).
  • Transcodes images to AVIF and webp and generates picture element.
  • Transcodes GIFs to muted looping autoplaying MP4 videos for greatly reduced file size.
  • Lazy loads images (using native loading=lazy).
  • Async decodes images (using decoding=async).
  • Lazy layout of images and placeholders using content-visibility: auto.
  • Avoids CLS impact of images by inferring and providing width and height (Supported in Chrome, Firefox and Safari 14+).
  • Downloads remote images and stores/serves them locally.
  • Immutable URLs.

CSS

  • Defaults to the compact "classless" Bahunya CSS framework.
  • Inlines CSS.
  • Dead-code-eliminates / tree-shakes / purges (pick your favorite word) unused CSS on a per-page basis with PurgeCSS.
  • Minified CSS with csso.

Miscellaneous

  • Immutable URLs for JS.
  • Sets immutable caching headers for images, fonts, and JS (CSS is inlined). Currently implements for Netlify _headers file.
  • Minifies HTML and optimizes it for compression. Uses html-minifier with aggressive options.
  • Uses rollup to bundle JS and minifies it with terser.
  • Prefetches same-origin navigations when a navigation is likely.
  • If an AMP files is present, optimizes it.

Fonts

  • Serves fonts from same origin.
  • Makes fonts display:optional.

Analytics

  • Supports locally serving Google Analytics's JS and proxying it's hit requests to a Netlify proxy (other proxies could be easily added).
  • Supports sending Core Web Vitals metrics to Google Analytics as events.
  • Support for noscript hit requests.
  • Avoids blocking onload on analytics requests.
  • To turn this on, specify googleAnalyticsId in metadata.json. (Note, that this is not compatible with the not-yet-commonly used version 4 of Google Analytics.)

DX features

  • Uses 🚨 as favicon during local development.
  • Supports a range of default tests.
  • Runs build and tests on git push.
  • Sourcemap generated for JS.

SEO & Social

  • Share button preferring navigator.share() and falling back to Twitter. Using OS-like share-icon.
  • Support for OGP metadata.
  • Support for Twitter metadata.
  • Support for schema.org JSON-LD.
  • Sitemap.xml generation.

Largely useless glitter

  • Read time estimate.
  • Animated scroll progress bar…
  • …with an optimized implementation that should never cause a layout.

Security

Generates a strong Content-Security-Policy (CSP) using HTTP headers.

  • Default-src is self.
  • Disallows plugins.
  • Generates hash based CSP for the JS used on the site.
  • To extend the CSP with new rules, see CSP.js

Build performance

  • Downloaded remote images, and generated sizes are cached in the local filesystem…
  • …and SHOULD be committed to git.
  • .persistimages.sh helps with this.

Disclaimer

This is not an officially supported Google product, but rather Malte's private best-effort open-source project.

How to bring updates from upstream

Originally, I added the original repo as a remote with

git remote add upstream git@github.com:google/eleventy-high-performance-blog.git

To do the merge, I run

git fetch upstream
git merge upstream/main main --allow-unrelated-histories -s subtree --squash

Then, for each modified file:

  1. Unstage all files
  2. Solve conflicts and stage them
  3. Reset some changes, particularly
    • new and modified files in directories like img, img/remote, and posts
    • deleted files, which are files like posts that should remain
  4. For each modified file, bring back the changes that should remain and stage them
  5. For each deleted file, ensure it is not needed anymore before staging them

After this, ensure everything is still working and make a commit with the following message: chore: Squashed changes from google/eleventy-high-performance-blog.

Apple M1 pre-requisites

  • Install node v16; nvm i lts/gallium
  • If you fail to install the dependencies due to sharp failing to build, ensure
    • arch returns arm64
    • you uninstall libvips with brew uninstall vips, or setup the SHARP_IGNORE_GLOBAL_LIBVIPS env variable
  • Follow the steps under Quick Start