A New Start of This Blog (a.k.a. Migrating to GatsbyJS)

June 30, 2018

Just migrated from Hugo to Gatsby v2 beta, and here are some thoughts on the new start of this blog!

A New Start

I’ve been thinking of writing blog posts regularly for a while, but procrastination stood strong in the way. The idea of having a blog and writing regularly is nice, but in fact kind of scary as well - you really need to put in lots of efforts and commit to your schedule.

Well, it’s time to push myself outside of my comfort zone, because I made a bet with a friend and will lose 50 euros if I messed up my blog posting routine! 😆 I’ll be posting new stuff on what I’ve been learning or what I find worth sharing here at least every 2 weeks from now on. 😃

One other thing that’s contributed to my procrastination is that my old site powered by Hugo didn’t feel right to me. I didn’t spend the time I should to learn how Hugo really works, so it was super painful to get MathJax working when I got started. The code highlighting was a bit hacky as well. Although my old blog was based on an excellent theme called Hyde, since my customization was primarily a bodge, it felt very uncomfortable whenever I wanted to tweak any other things, let alone modifying the design or use my own fonts.

I’ve been meaning to learn and use Gatsby for a while, since it is mainly just React which I am more or less familiar with. To me, Gatsby is a battery included React-in-a-box - it comes with routing, page pre-fetching, client side caching etc. all set up by default (or via simple configs), plus a whole bunch of high quality plugins supported officially and by community. With the Beta release of version 2, I finally sat down and started working on a complete overhaul with Gatsby. After one day of trials and errors, here we are.

Making a Smooth Background Color Sweep with Gatsby

How to Make Color Transitions Look Nice

The first thing I wanted for my new site is a background color sweep. I’ve made an attempt with this a while back using pure CSS, but since I knew little about CSS or how web color works, I only managed to change the color linearly in an RGB fashion, which looked pretty weird - there’s always an ugly dark color in between green and red for example. This time I found that a smooth transition can be easily realized via changing the hue in HSL color values.

So it’s simple, right? Just keep updating the hue value. 😃

A Solution in React

Since I want the color of the full page to change, I need to update the corresponding style attribute for the body tag. With pure React though, you actually can’t change the background color so easily without doing some non-React style document.body hacking. Fortunately, there’s a React component called React Helmet which encapsulates document head manipulations. We can simply insert a <Helmet /> component to the pages we want custom HTML heads.

I made the <Layout /> component into a stateful one, defining two variables “hue” and “increase” for the state. The idea is to sweep the background color from hsl(45, 90%, 95%) to hsl(70, 90%, 95%) back and forth on a 10-second basis. Yes, the colors are pretty light, which I believe won’t distract the readers too much.

class Layout extends React.Component {
  state = {hue: 45, increase: true}

  componentDidMount() {
    this.timerID = setInterval(() => this.nextState(), 200)
  }

  componentWillUnmount() {
    clearInterval(this.timerID)
  }

  nextState() {
    if (this.state.increase) {
      if (this.state.hue >= 70) {
        this.setState({ increase: false })
      } else {
        this.setState({ hue: this.state.hue + 1 })
      }
    } else {
      if (this.state.hue <= 45) {
        this.setState({ increase: true })
      } else {
        this.setState({ hue: this.state.hue - 1 })
      }
    }
  }

  render() {
    const bgHsl = `hsl(${this.state.hue}, 90%, 95%)`

    return (
      <>
        <Helmet>
          <style>{`body { background-color: ${bgHsl}; }`}</style>
        </Helmet>
        {/* blah blah blah */}
      </>
    )
  }

Persisting the Color Value Throughout Page Transitions

Then comes a question - how to persist the color state when navigating, so that the background color won’t jump around when the user is redirected to a new page?

If you are making a normal React app instead of using Gatsby to statically generate pages, it’s gonna be easier to wrap one’s head around the data transferring between pages using a solution like Redux + React Router, since there’s a lot of write-ups on this topic. Although Gatsby uses the above mentioned libraries under the hood, I haven’t yet digged into the lower level APIs of Gatsby yet, so I’ve come up with a workaround, using the localStorage API to share states across pages. I modified the <Layout /> component in order to draw an initial state from localStorage, and save it back into localStorage upon unmounting or window closing.

Weird things were encountered at first - my initial tests worked pretty well on the local dev server, but there was tons of error messages while building and deploying. It turned out that since the build process is conducted on Node, there is no window object which I’ve been using in when calling window.localStorage.setItem() and window.localStorage.getItem(). A small hack fixed this problem.

// Fix `window` not defined on Node
const windowGlobal = typeof window !== 'undefined' && window

class Layout extends React.Component {
  // Load state if present in localStorage
  state = this.getStateFromLocalStorage()

  componentDidMount() {
    this.timerID = setInterval(() => this.nextState(), 200)
    // Save state on window closing
    windowGlobal &&
      windowGlobal.addEventListener(
        'beforeunload',
        this.saveStateToLocalStorage
      )
  }

  componentWillUnmount() {
    // Save state on unmounting
    this.saveStateToLocalStorage()
    clearInterval(this.timerID)
  }

  saveStateToLocalStorage = () => {
    windowGlobal &&
      windowGlobal.localStorage.setItem('hue', JSON.stringify(this.state.hue))
    windowGlobal &&
      windowGlobal.localStorage.setItem(
        'increase',
        JSON.stringify(this.state.increase)
      )
  }

  getStateFromLocalStorage() {
    if (windowGlobal) {
      return {
        hue: JSON.parse(windowGlobal.localStorage.getItem('hue') || 45),
        increase: JSON.parse(
          windowGlobal.localStorage.getItem('increase') || true
        ),
      }
    } else {
      return { hue: 45, increase: true }
    }
  }

  nextState() {
    {/* blah blah blah */}
  }

  render() {
    {/* blah blah blah */}
  }

My solution of sharing state however is problematic, especially when the user opens multiple pages in different tabs and closes them asynchronously. More research is needed to figure out a better way for sharing state across pages inside Gatsby.

Other Puzzling Things

One cool thing about Gatsby is that it makes building progressive web apps pretty easy. Just install an offline plugin and you should be good to go!

However, weird things happened when I was trying to turn my personal about page at i.am.xiaoru.li into an “app” which can be added to home screens. The text content wouldn’t load offline, the background does however. There were some super weird errors like TypeError: Cannot read property 'pageContext' of undefined floating around inside the console. My Google-Fu failed me on this one so I started trying to debug the page-renderer.js script.

pageContext of undefined

I wandered around for a super long time. Since everything worked well on the dev server (you can emulate different network environments under the “Network” tab inside Chrome dev tools), it was pretty hard to debug the build directly. I started wondering if I missed some Node/browser environment checking somewhere in my code again.

After building the site locally and confirming nothing was wrong when the site was published with surge.sh, I began to suspect that the build tools on Netlify (the hosting service that I use, which is super awesome BTW) are not up to date. There was indeed something fishy - Netlify runs ancient versions of Yarn and Gatsby CLI by default. Come on, I’m running a beta version of next-gen Gatsby, and you are using 0.x versions to build my site? The build tools must be the problem!

And… Nope again. Still not working after setting up Netlify environment variables to use the latest tools. I was so frustrated and had to take a long break. When I came back, I finally started to compare my site config with the one of the official Gatsby Next site. Huh? There’s a plugin especially for Netlify? I mean, two plugins?

Well, long story short, installing those two plugins fixed the problem instantly and magically. As it turned out, Netlify’s servers don’t ask browsers by default to cache those files needed by Gatsby to support offline mode. Netlify is awesome and very powerful, but with great power comes great responsibility - you have to configure it right!

On Speed of Gatsby

One con of Gatsby is that the site generation time is significantly slower than Hugo. We are talking about magnitudes - Netlify usually reports a building time of more than 50 seconds with Gatsby, whereas Hugo always does the job in sub 150ms!

However, this really isn’t a problem for my use case, nor for most users of static site renderers I suppose. If the site is constantly changing, it might be a better bet using a dynamic back end, like Wordpress or a custom CMS engine.

I mean, Gatsby speeds up your React apps and provides smooth user experience, plus it’s super simple to use. The building time trade off is well worth it! 😍 The problem is though, you might run into random issues caused by the difference of developing on a hot loading dev server and Gatsby rendered deployments, like I did building my site.

Styling Is Hard for a CSS Novice

Hats off to all those real front end engineers!

Styling my site, albeit super minimal, took me another while and lots of energy. I have only used templates before, at most just tweaking colors or spamming !important rules. I have to say doing designs is not my thing, and turning designs into CSS from scratch is also hard work. For now I’m still much more comfortable using templates and UI frameworks, but building this site makes me much more confident with manually styling stuff myself. I won’t feel dreaded if such work is ever needed again - that’s progress!

What Is Ahead

There’re still some fine tunings left to be done - fixing the background color bug if it’s not too complicated, adding more features like contact form and comment sections, etc..

I’ll continue writing stuff about programming, machine learning as well as other stuff I find interesting. This is a new start, and there’s a challenging but rewarding journey ahead!