Build a Lightning Quick Website using Hugo and S3

栏目: IT技术 · 发布时间: 4年前

内容简介:This website isGoogle Analytics is 17.7KB, thisThere were sacrifices. But it is an example of what websites could be in stark contrast with what they have become.

This website is fast . The homepage loads in 50ms and is only 9KB (after GZIP and caching).

Google Analytics is 17.7KB, this PNG Twitter uses is 10KB, and blinking takes 100-400ms.

There were sacrifices. But it is an example of what websites could be in stark contrast with what they have become.

Why speed matters

Reality has no latency. Things feel wrong when there is a delay between our actions and their response. Speed is the most important aspect of user experience.

But as computers have become more powerful, they haven't gotten faster. They're bloated.

In amagnificent rant, Nikkita Tonsky wrote:

Windows 95 was 30MB. Today we have web pages heavier than that! Windows 10 is 4GB, which is 133 times as big. But is it 133 times as superior?

Frameworks like React address speed by controlling the DOM. At the cost of 100KB of JavaScript, wasted CPU cycles, and complexity.

Static HTML is the soul of the internet. It is ubiquitous, easy to understand, and easy for search engines to crawl. It is the ideal format for any website. Look atthis motherfucking website.

While I wasn't as extreme, this website is pretty close. And I love it.

Design choices

There are no frameworks, web fonts, or libraries on this website. Everything was handwritten. If it didn't improve the user experience, it wasn't included.

In particular, there isn't any analytics on this page. If I want to know traffic metrics and snoop IP addresses, I can check the server logs. I'm not going to invade your privacy with an inconvenient script. Or feed more data to our Google overlord.

I'm inspired by Paul Graham andJohn Gruber'ssimplicity.Seth Godin,Butterick's Practical Typography, andThe New York Timesprovided examples of beautiful typography. I hoped to capture their mastery.

This design intends to last.

The stack

Check out the repo (I'll turn it into a theme at some point).

Hugo

I chose Hugo because of the control and productivity it provides. I was able to create a minimal, semantic structure laden withschema markup.

Hugo's ability to generate and minify assets in any language removed my need for build tools. Keeping my codebase uniform, simple, and fast.

In this case, I used it to build an array of cacheable pages for a ServiceWorker.

Array in ServiceWorker

const pagesToCache = [
  {{ with .Site.Pages }}
    {{ range  (where . "Type" "page") }}
      '{{ .RelPermalink }}',
    {{ end }}
    {{ range (where . "Kind" "taxonomyTerm") }}
      '{{ .RelPermalink }}',
    {{ end }}
    {{ range (where . "Kind" "taxonomy") }}
      '{{ .RelPermalink }}',
    {{ end }}
    {{ range (where . "Type" "post") }}
      '{{ .RelPermalink }}',
    {{ end }}
  {{ end }}
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('cacheName').then(function(cache) {
      cache.addAll(pagesToCache);
    })
  );
});

With Hugo's power and shallow learning curve, I was able to complete the base of this website in one week.

Static assets

I mentioned that I didn't use any web fonts. I lied. I created one withFontellofor social media icons. Using woff2 was only 1KB larger than SVG icons with better extensibility.

Because I handpicked icons, the entire font is only 3.1KB. Compare that to FontAwesome's 161KB. Plus another 70-120KB for every font-weight you include.

The logo is a single path SVG, made on a 16pt grid and minified with one decimal precision. The result is 399B.

I used Georgia for the body, Helvetica for headings and navigation, and Courier for code. These are allwebsafe fonts.

Custom SCSS

The layout is very simple, two containers one fixed one relative. I didn't need Bootstrap, only a few lines of CSS. I converted my code to SCSS while avoiding nested selector hell.

I gave special attention to the typography. Using many shades of grey to create a subtle balance of contrast. It strives to be easy on the eyes while drawing attention to important sections.

Everything uses rem and em units for a responsive, accessible design. Vision impaired users can adjust this site without disrupting the typography.

The entire theme is configurable with a few variables.

Theme SCSS

$default-color: #333;

$dark-color: #121212;
$darker-color: #000;

$slightly-light-color: #555;
$light-color: #666;
$lighter-color: #777;
$lightest-color: #999;

$nav-active-background: #f7f7f7;
$code-background: #f0f0f0;

$light-border: #ddd;
$dark-border: #ccc;

$white: #fff;

$main-font: Georgia, serif;
$sub-font: Helvetica, Arial, sans-serif;
$mono-font: Courier, monospace;

$offset: 35.5%;
$content-width: 46rem;

In total, the CSS is 6.4KB (2.3KB after GZIP).

Minimal JavaScript

Aside from the ServiceWorker, this is all I used. A simple click listener to toggle the nav-open class.

Nav Toggle

var navToggle = document.getElementById('nav-toggle');
navToggle.addEventListener('click', function() {
  document.body.classList.toggle('nav-open');
});

A ServiceWorker

Creating a ServiceWorker was the most complex piece of this website. It took me about 1/3 rd of the total development time, but it was worth learning.

I could have kept it simple. The “stale-while-revalidate” pattern outlined in Google's Offline Cookbook would have been enough. You might have picked up, I rarely do things the easy way.

Instead, there are three different cache patterns. The first load imports all assets. Then the ServiceWorker takes control.

Static assets are the simplest, they respond from the cache with a fallback to the network. That way the network isn't called until the cache is invalid.

Cache with network fallback

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(normalizedUrl).then(function(response) {
      return response || fetch(event.request);
    })
  );
});

Pages have a more complex pattern, imitating HTTP's “stale-while-revalidate” policy. The user experiences an instant load while the resource updates for the next visit.

Stale-while-revalidate

self.addEventListener('fetch', (event) => {
  const normalizedUrl = new URL(event.request.url);
  normalizedUrl.search = '';
  event.respondWith(
    caches.open(cacheName).then((cache) => {
      return cache.match(normalizedUrl).then((response) => {
        let fetchPromise = fetch(normalizedUrl).then((networkResponse) => {
          cache.put(normalizedUrl, networkResponse.clone());
          return networkResponse;
        });
        return response || fetchPromise;
      });
    })
  );
});

The pièce de résistance, a cache then update with network policy within static HTML. Keeping the homepage fresh.

The pattern goes like this.

Build a Lightning Quick Website using Hugo and S3

Cache then network diagram

You can find the source code in the repo .

AWS Hosting

This is an S3 bucket served through Cloudfront routed through a Route53 domain. It sounds simple but learning AWS is intimidating. Their platform is dense and prickly.

Here is some helpful documentation:

  1. Domain names you can register with Route53
  2. Routing Route53 to Cloudfront
  3. Serving a static S3 website with Cloudfront
  4. Allowing directory paths with S3 and Cloudfront (without a Lambda)
  5. Setting up the AWS CLI (for Hugo deployments) install and credentials
  6. Invalidating Cloudfront
  7. Setting cache control on all S3 items

I also created an email with SES that routes messages to my Gmail. An S3 bucket stores emails and a Lambda function sends them.Daniel Lopezhad a useful guide.

The only expense is my domain name. When I start to get traffic, I can scale for cheap.

The Result

This page gets a perfect 100 for performance in Chrome Lighthouse.

SEO and best practices are at 100, and it's a PWA. Accessibility scored a 93 because I used a light font for my meta data. If I were to add a contrast option, it would be a “perfect” website.

Chasing arbitrary numbers is pointless without purpose. This wasn't pointless. This website achieves everything I need and does it cleanly. The user experience is pristine. The typography is delightful. The structure is meaningful.

Good design is less design.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

有限与无限的游戏

有限与无限的游戏

[美]詹姆斯·卡斯 / 马小悟、余倩 / 电子工业出版社 / 2013-10 / 35.00元

在这本书中,詹姆斯·卡斯向我们展示了世界上两种类型的「游戏」:「有限的游戏」和「无限的游戏」。 有限的游戏,其目的在于赢得胜利;无限的游戏,却旨在让游戏永远进行下去。有限的游戏在边界内玩,无限的游戏玩的就是边界。有限的游戏具有一个确定的开始和结束,拥有特定的赢家,规则的存在就是为了保证游戏会结束。无限的游戏既没有确定的开始和结束,也没有赢家,它的目的在于将更多的人带入到游戏本身中来,从而延续......一起来看看 《有限与无限的游戏》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码