Building GatsbyConf 2022

Paul Scanlon
Paul Scanlon
January 6th, 2022

Hello! Paul here and I’ve been given a new assignment!

I’ve been tasked with building the new GatsbyConf 2022 site – yikes!

It’s quite daunting, but I love it! Over the coming weeks / months I’ll be updating this blog post with my progress. I’ll be openly discussing my trials and tribulations, failures and successes… because, why not hey, we all have to face and overcome problems and I’m no different.

I’ll also be calling out folks who I’ve collaborated with internally and externally to make this site happen. There’s Power in Numbers! Keep an eye out for those Collaborator Counts on each update.

If you’d like to check up on me and see where I’m at as March 2nd & 3rd draw ever closer, bookmark this post.

Ttfn,

Paul

Tuesday 8th March

We did! We built GatsbyConf! 🎉 Thanks for coming along for the ride.

The last feature to implement is the YouTube Video Playlists. I’ve created a new content model and one thing I hadn’t used before was the JSON Editor field in Contentful. Arguably it’s not the most “editor friendly” field but… I need these YouTube video id’s as an Array so I can pass them onto the  <LiteYouTubeEmbed /> component as comma separated values.

If I start with an Array it’s easy to convert this into what I need using a little bit of JavaScript.  

The above Array of strings actually comes out the other side looking like this. 

In my React component I used a simple Array.prototype.join() to return a new string of comma separated values. 

E.g : const ids = playlistIds.map((id) => id.content).join() 

… which results in something like this 👇

"Fv814LrT2JA,MvEM6COeyLo,Mer3S6J5FUA,dZ5Lh8_7xUo,9DdHVuieh3E"

… which is how I need to pass it onto the <LiteYouTubeEmbed /> component using the params prop, prefixed with "playlist" as per the YouTube Player Parameter Docs.

And that’s it. 💥

Now all the wonderful Talks and Workshops from GatsbyConf 2022 are live on both YouTube and can be accessed here: https://gatsbyconf.com/#videos

As they say in the Theater, that’s the final curtain. The audience applauds enthusiastically and I exit… stage left.

Thanks to everyone who collaborated with me on this and thanks to everyone who’s come along on this journey with us. If you’d like to discuss anything I’ve mentioned in this post feel free to come find me on Twitter: @PaulieScanlon. See you around, friends! 

Ttfn. 🕺

Collaboration Count: x12
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks
  • @0xca0a
  • Jack Sellwood
  • Shane Thomas

Wednesday March 2nd

Holy Cinderella Batman! We made it to the ball. 

I only have one job today and that’s the GatsbyConf Raffle. GatsbyConf co-hosts JD and Laci will be reading out the winners live, and as they do I’ll need to update Contentful and hit publish in Contentful so the winning raffle codes appear on the site. It’s quite key that these updates happen in almost real time – But it’s a static site so that’s not possible… or is it? 

YES. 💅

I’d like to draw your attention to the red rings in the image below. Your eyes do not deceive you, that says: Built in 0:05 > Deployed in less than 1s.

It’s undeniable that Gatsby really is the fastest frontend for the headless web. If you’re not seeing build speeds this fast with your current hosting provider, perhaps it’s time you switched to Gatsby Cloud!

Tuesday March 1st

I’ve had a bit of a breather from GatsbyConf the last week or so but, bam, bosh, wallop. Jack Sellwood (Senior Product Manager) hit me up late last night on Slack asking if we could implement Gatsby’s new BETA version of the Image CDN“The night before the start of GatsbyConf?” I sheepishly answered. “YES,” replies Jack. 

No matter, it’s how we roll and after some careful GraphQL refactoring and some help from Shane Thomas (Senior Engineering Manager), GatsbyConf + Image CDN was live… It wasn’t actually a big job but jeepers, that’s a tight deadline. (Power in numbers IRL!)

At Gatsby, we take performance seriously and we’re aware that images are problematic. A lot of hard work has gone into solving this problem and the results speak for themselves.

The results are clear: compared to alternative frameworks, Gatsby sites load faster. Today, 40% of Gatsby sites pass Google’s Core Web Vitals thresholds on mobile, compared to only 23% of Next.js sites and 18% of Nuxt.js sites.  Why? In large part due to optimizations in Gatsby’s image plugin

Jack Sellwood

As mentioned, Image CDN is still in BETA. We currently only support Contentful and WordPress but more solutions are on the way so stay tuned! 

Collaboration Count: x12
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks
  • @0xca0a
  • Jack Sellwood
  • Shane Thomas

Friday 28th Feb

Hi, everyone. Laci Texter, Gatsby’s Senior Brand Marketing Manager here. Paul will share the technical aspects of today’s update with you but before he does, I want to share context for the work we’re covering today. 

Over the past few days, the Russian government has initiated attacks on the people of Ukraine. This is a quickly-evolving political and humanitarian situation that all of us here at Gatsby are appalled to see unfolding in the country. First and foremost, the Gatsby team want to share our heartfelt condolences to everyone affected, directly or indirectly. No person, anywhere in the world, should have to go through something like this and we’re hopeful good will ultimately prevail. 

In regards to GatsbyConf, the current plan is to move forward with it on March 2nd and 3rd. If that changes, we will update you here on the Blog, via email, and via Gatsby’s social media channels. While we plan to move forward with our event, I want to stress that if you’re simply not in the right headspace for a tech conference this week, we understand and you should take care of yourself. All of the GatsbyConf Day 1 Talks & Day 2 Workshops will be available online shortly after the conference is over for you to access anytime.

Right now, we want to do whatever we can to leverage the attention we have in the days leading up to GatsbyConf to help raise awareness for what is happening and about ways you can help the people there. Over the weekend, we built a new GatsbyConf landing page with information on some of the reputable organizations who are helping the people on the ground. You’ll find direct links to those organizations where you can securely lend monetary and/or technical support. Additionally, I encourage you to read the blog post, “Gatsby Supports Ukraine”, written by Gatsby CEO, Zack Urlocker. 

Below, Paul will share the steps we took to create and build the newest GatsbyConf landing page. 

Hi all, it’s me again, Paul. Today’s update required us to leverage “repeatable patterns” as I’ve mentioned a few times throughout this post. In the case of this update, we wanted to add a new page with new sections. From a code perspective, the page is the same as any other page and the sections are the same as all other sections. The bit that’s unique is the content.

Using Contentful we created a new page, decided what the slug should be, E.g /power-in-numbers and added two generic sections using the options we’d already configured in the content model. Heading, Subheading, Image Grid, Button etc. Laci then added the content and hit publish. 

There was  one small tweak I needed to make to the code. You’ll notice this page is themed slightly differently to the rest of the site. I added a new field to the “section” content model and named it “theme”. This is passed onto the section component and is used to apply a CSS class name. The CSS takes over from here. The result, the /power-in-numbers page and sections are themed with a blue / yellow gradient. 

Collaboration Count: x10
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks
  • @0xca0a

Friday 25th Feb

Today this Tweet happened. As @0xca0a mentions, there’s a more performant way to implement the three.js stars seen in the GatsbyConf hero so I got to work on making the changes. 

Here’s the diff!

The main difference between this, and my original implementation is the use of <Points/> and <PointsMaterial />. Using these two methods means three.js / your browser doesn’t have to work so hard to move all those geometries. I immediately saw a perf boost, not just in Chrome Dev tools but my fans were no longer whirring. 

This one little change is great and I suppose it’s a benefit of building in public. I’m not a three.js expert, but @0xca0a is, and I was happy to implement these changes. Thanks @0xca0a you’re the best! 

Collaboration Count: x10
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks
  • @0xca0a

Thursday 10th Feb

🚨 New feature alert! 

Today I started work on the Schedule. The content model in Contentful was pretty straightforward, all of the information was already available in other fields, so the Schedule content model only really needs to ensure Talks / Workshops could be added row-by-row

I had a Schedule content model for Day 1 and Day 2.

The tricky bit was the CSS! 

On “Desktop” the Date and Time are shifted off to the left, this isn’t a huge problem in itself but… what about “Mobile”. In the image below you’ll see there’s generally two Talks that start at the same time.

This is fine on “Desktop” as the Date / Time and Talk details are all in one row, but when these stack I need the Date / Time to be displayed above each Talk.

This is what I would refer to as “adaptive design” because in this case I’m not using CSS to reposition something, which is what I would refer to as “responsive design”, I’m using CSS to show or hide a DOM element. On “Desktop” the second Date / Time element is still in the DOM, you just can’t see it. I’m not a fan of this approach but… in this case it was really the only option. – Not the end of the world, let’s move on! 

I’ve also added a cheeky little position: sticky trick to ensure the Schedule heading remains stuck to the top of the browser while you’re scrolling. When you scroll past all of the Day 1 Talks, the heading becomes unstuck and the pattern repeats for Day 2. Do watch out for the overflow enemy quirk though! 

Sweet, that wraps up the day – onwards! 

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Monday 7th Feb

Today I did a little bit of work on the Speaker’s landing pages, E.g https://gatsbyconf.com/ward-peeters/. We’re showing the details of each Speaker’s Talk or Workshop below their profile information and naturally we need to show what time the Talk or Workshop will start. 

But what time is that in your Timezone? We wanted to ensure that no matter where in the world you are, the time would be correct for you! 

This sounds like a job for toLocaleTimeString

I chose to use JavaScript’s native method for dealing with locales over using something like date-fns for two reasons.

  1. Performance. I didn’t think adding an additional 85kb for date-fns was worth it.
  2. Writing the native method gives me something to talk about here 😊

To start with the TimeStart and TimeEnd fields are both setup in Contentful, this makes it easy for Laci to make changes. We decided the default Timezone should be Pacific Standard Time or as shown in the image below UTC-8.00.

When the TimeStart and TimeEnd fields are queried, they pop out in Javascript looking a little like this:

  • TimeStart: 2022-03-02T10:10-08:00 
  • TimeEnd: 2022-03-02T10:30-08:00

These aren’t very human readable so I created a little util function that would format these timestamps. Here’s the function. You can see that toLocaleTimeString has an options object where you can define the format for the hour, minute and the timeZoneName.

Using this function, I’m able to return a more friendly looking timestamp. For Ward’s Talk, this is now displayed as: 13:10 PM EST – 13:30 PM EST.

I also had another small issue to deal with. Previously, I’d set the site footer up to be part of the home page. With the creation of the Speaker’s landing pages I needed to shift the site footer details into their own content model in Contentful. 

The reason for this was because I needed to persist the footer across all pages in the site. 

Gatsby has a method for this. It’s called wrapRootElement, and usually you’ll want to use this in both gatsby-browser and gatsby-ssr. To avoid duplicating code I typically create a root-element component and use it in both gatsby-ssr.js and gatsby-browser.js

Here’s a snippet of my root-element component.

… and here’s how I use it in both gatsby-browser.js and gatsby-ssr.js.

And that’s me done for the day! Wooohoo! 

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Friday 4th Feb

New feature alert!

Today’s task was to implement our snazzy new promo video. The video lives on YouTube and you can see that here: GatsbyConf22 – Join us March 2nd & 3rd but we also wanted to display it on the site. 

It is possible to embed a YouTube video on your site following these instructions: Embed videos & playlists but using this method can negatively impact your site’s performance.

Ever keen to not negatively impact gatsbyconf.com’s, I had to hunt around for an alternative solution. 

Ward Peeters (Tech Lead – Principal Engineer) suggested I investigate Lite YouTube Embed by Paul Irish and after reading the opening gambit in the README, I was sold!

Renders faster than a sneeze.

Provide videos with a supercharged focus on visual performance. This custom element renders just like the real thing but approximately 224× faster

Paul Irish

There was a small problem, though. To use Lite YouTube Embed in a Gatsby I would have had to add the script tag to the HTML <head /> tag. There’s a few ways this can be achieved. So here’s Gatsby friend and Indie Hacker Super Star Queen Raae with a few options for using Third-party scripts with Gatsby

However… I stumbled up on React Lite YouTube Embed

A private by default, faster and cleaner YouTube embed component for React applications

Ibrahim Cesar

The React version takes care of adding the required script tag and can be configured using the familiar React props approach — I like that!  

The video id that I pass to the component is also managed by Contentful. To achieve this I created a new type in the content model and called it youTubeVideo. This content type contains the following fields.

  • videoId: The id, E.g Q6OqDrNavaU
  • videoTitle: The title, E.g GatsbyConf22 – Join us March 2nd & 3rd

Both of these are passed onto the component. E.g

With all that in place, I was able to create a new section on the home page, asked Laci to add a bit of messaging and boom, we were all set. 

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Monday 31st January

Biiiiiiiig day today. Today is the day I finally get to implement Hybrid Svg’s 🥳

I’ve spoken about this a few times over the last few weeks and I will, at some point, publish a post detailing how it all works. 

But….

We now have an optimized Hero lockup. The 2022 illustration you see at the top of GatsbyConf is part bitmap and part svg. The bitmaps are optimized using gatsby-plugin-image, and the svg elements remain as HTML path elements so I can more easily animate them.

For the animation, I’ve used Motion One which is a fantastically lightweight animation library written by Matt Perry and weighs in at a mere 3.3kb 🤯. Matt is also the chap behind Framer Motion, go check it out. It’s pretty nifty! 

Here’s a quick snippet of how to use Motion One in React.

In my case, I had two additional requirements. 

  1. Animations will be re-used by multiple components.
  2. All animations should observe a user’s prefers-reduced-motion preferences.

To address the first requirement, I abstracted the animations into their own function. Here’s a snippet of the spin animation.

The spin function expects x4 parameters.

  • selector: The CSS selector, could be an id or a class
  • speed: The duration of the animation
  • delay: The delay before the animation begins
  • prefersReudcedMotion: A boolean value that determines if animations should be paused. 

Here’s how I call this function from the first Number 2 illustration seen in the Hero section. 

I use the same function in the Number 0 and the second and third Number 2 components, but change the selector, speed and delay values. ☝️

My usePrefersReducedMotion hook checks the status of prefers-reduced-motion on mount but also listens to changes. This is helpful for testing so I can see it working by switching my preferences on and off. Here’s a gist for your reference.

The state change caused by this hook is used in the dependency array of the useEffect, which in turn passes the value onto the animation function. This is how I can pause or play the animations.

I’ve used a similar approach to pause the three.js stars seen in the background of the Hero animation. 

I’ve also implemented a second animation pause method. This occurs when the Hero section is no longer within the viewport. I achieved this using an Intersection Observer… but that’s a post for another day. 

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Wednesday 26th January

I had a really great day today! 

A little while back we re-briefed the fantastic Miss Chatz and asked if she could create a “Hero lockup” version of the 2022 illustration. In the MVP phase we asked for a 2 and a 0 and I’d just repeated the same 2 to create the lockup. But given this is the “Hero” we all felt we could go one step further and make it really unique. Miss Chatz, as she always does, delivered! 

We now have x3 variations of the number 2 and I think it looks great. 

I switched a few things around in the components and used my old chum svgr to fix up the svg attributes in the svg’s for use in Jsx and tada, the new Hero lockup was complete. 

My other task was the “alt” state – If you’re a new visitor to the site the Hero section contains a call to action to “register now”, and at the bottom of the site we have a registration form. Once you’ve registered we’re hiding the form and displaying a unique raffle code in place of the form, but, back up at the top of the site the “register now” call to action was still visible. 

Now, I’ve mentioned this already but I’m using a useLocalStorage hook to set a value in local storage which allows me to persist the state of the UI between visits and refresh. But, all of the logic for this is contained within the registration form component, not the Hero. So when a state change occurs only the form section re-renders, not the Hero section. 

If you refreshed, then of course, the Hero section would read the local storage value and display it’s “alt” state which hides the “register now“ call to action and shows the little raffle code. Whilst this works, I thought to myself, “No Paul, it’s not good enough!”

The state change after registering needed to fire at the top of the tree so that re-renders would occur in child components . To solve this I lifted state up and used React’s native Context API.

I now dispatch the state change from the registration form up into the AppContext.Provider which re-renders only the children that are wrapped by the AppContext.Consumer

Using this approach prevents performance issues since only the specified children re-render, rather than all children re-rendering. ☝️

Here’s a snippet of the Context object and the Provider. 

My AppContext object now contains the values read from the useLocalStorage hook and makes these values available for any Consumers. 

Here’s a snippet from the Hero component wrapped by the AppContext.Consumer

Now when this state change occurs, both the registration form and the Hero section are re-rendered and display their “alt” states. 

This was quite a big change to the build and took me a fair amount of time to implement and test  – but the world will never know. 😔

It works a treat, though, so I’m a happy chappy now! 

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Monday 24th January 

Individual Speaker landing pages – Hooray! I was really looking forward to developing this feature. Not just because it was quite a big chunk of work but because I got to see all the details for each Talk or Workshop and there’s some absolutely brills stuff in the schedule!

This feature required changes to both the content model and the code. 

Step 1:

Review the design and work out which content models would be required to populate the page and cross reference against content models we’d already implemented. 

At the top of each individual Speaker landing page we’re showing the speaking details. This is the same information contained within the headshot in the Speakers section on the home page. Contentful is really great at allowing content to be re-used by multiple content models so the details for each Speaker were already in place within the content model. 

Step 2:

Create a new content model for the Talks and Workshops. This content model contains information about the Talk or Workshop, the time and day, and who’s giving the talk, and yep you guessed it, that’s again the same content model used in the Speakers details, and at the top of the page. 

Step 3:

Create the content model for each individual Speaker landing page and use Contentful’s references to re-use the Speaker details information and the new Talk of Workshop content model which also re-uses the Speaker details information. 

Step 4:

Create pages using Contentful data using Gatsby’s File System Route API

You’ll see in the above image that each individual landing page has a field called url. This will determine the route. E.g https://gatsbyconf.com/arisa-fukuzaki/

This field can also be used when creating the collection route E.g{contentfulSpeakerPage.url}.js. This JavaScript file is used as a page template and queries all the relevant data required to populate the page. 

The GraphQL query looks a little something like this.

… and that’s it. 

From here the data is passed back to the page component via the data prop and I can work with it in the usual way by populating various HTML elements and styling them.

It’s worth noting here that within this page query I’m querying a completely different content model to grab the GatsbyConf logo which is used at the top of the page and acts as a link back to the homepage. With Gatsby, you have a global method for querying data so it’s possible to grab a reference to just about anything from anywhere around the site.

Not every JavaScript framework has this, and IMO it’s  🔥

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Friday 14th January 

Today’s task was pretty quick, Molly and Flo made some changes to the overall look and feel of the site. We’re now 100% dark mode – which looks so much better. 

I had originally implemented an alternating color scheme for each section and was using a field within Contentful called “theme” to pass a variable back down to the section where I’d use it to apply different CSS color variables for the text and the background. I made the decision to have “white” sections back when we were developing the MVP and my only justification for this was, most sponsor’s logos will have been designed to work on a white background. This did actually turn out to be the case and whilst some of our sponsors did already have an alternative version of their logo we needed to specifically request it. However some of our sponsors didn’t have an alt version. 

In the case of Sanity, they created a special “one off” version of their logo which would work well against our dark blue background. It’s nice when things like this happen but as you can imagine it’s these kinds of things that require “people input”. 

Back when we were creating the MVP, we didn’t want to become blocked by logos, but in the last few weeks we’ve had a bit more time to tighten things up, so all’s well that ends well. 

We also made some small color changes to the headings to ensure we had an acceptable level of contrast. We take accessibility very seriously at Gatsby and the Design team are always hot on the case when it comes to checking these things.  

The only tricky task I encountered was removing the theme variable. I’m always mindful of this kind of refactoring and I think it’s important when developing that you think about the implications of adding something that will later be removed. In a lot of cases, removing code can be more time consuming than adding it. 

I think this is especially the case when working with a headless CMS. Deleting a field from your content model that is queried by your code will cause build errors. My approach in this instance was to remove the query from the code, merge and deploy the changes, and then remove the field from the content model. 

We also discussed our working process and now we’re out of MVP we’ve agreed to work in one week sprints. This gives myself and Laci time to gather the requirements, it gives Design time to create the designs and allows us time to review and make amends, and lastly it gives me time to actually develop the features. 

I’m not sure at this juncture if we’ll be deploying on Fridays each week, but if that’s how it works out then so be it – I like to live life on the edge. 

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Tuesday 11th January

I’ve been off-piste but I’m now back! 

Last week and a bit of this week, I’ve been focused on writing a new blog post: Performance Optimization for three.js Web Animations. I touched on the subject in my update below on Tuesday 4th January and it relates to some performance improvements we made to the three.js hero animation seen at the top of the GatsbyConf site. The post goes into a little more detail about how we addressed our particular concerns plus a little more information about how to use React.lazy / Suspense, along with some areas for consideration before adding JavaScript animation libraries to your project. 

Today’s morning task has been syncing with Molly, Flo and Laci regarding brand, illustrations and design.

Whilst the site is looking great it was only ever intended to be the MVP version so we could launch before the New Year. Now with the Design team back in the game we’ll be giving the site a little more love… but, heart on my sleeve time… I’m worried that during the meeting I may have played the role of Grim Reaper 😬 – But I have my reasons.

Allow me to explain.

At the moment, each site section is pretty much the same. The hero section and the form section are unique but all the middle sections use the same familiar content model. When Laci and I were creating the content model this was quite a deliberate move for two main reasons: 

  1. There’s a balance between giving Laci some configuration options, and giving Laci too many configuration options resulting in a somewhat cumbersome editing experience. 
  2. I will at some point be writing about content models and I’m keen to explore how much we can achieve in GatsbyConf with a pretty simple content model. 

To give you some more context. We need to create a set of “design presets” that will work for multiple sections but that can be configured easily to produce variations, so I’m specifically looking for repeatable patterns E.g.

  • Each section will have a heading
  • Each section will have a sub-heading
  • Each section will have an optional rich-text body 
  • Each section will have an optional image
  • Each section will have an optional “References many type”: E.g an Array of “Sponsor Logo”, or an Array of “Speaker Headshot”
  • Each section will have a column count option
  • Each section will have a text alignment option

When you read these back they start to feel like Acceptance Criteria — that’s because they are. This is typically how an engineering task is started but it’s not quite the same for design.

I’m mindful that whilst I’m keen to stick with repeatable patterns and a simple content model, I don’t want to be so strict that the overall site design suffers. I think I articulated my concerns clearly in the meeting and I do think Design appreciates where I’m coming from, so let’s see what happens next. 

Today’s afternoon / evening task has been to investigate what I’m currently calling “Hybrid Svg’s”. I also mentioned this on Tuesday 4th January and I don’t know if that is an official term but I’ll be explaining my approach in more detail in a separate blog post. 

The TLDR if you like is: I need to find a way to reduce the complexity of our “number people” illustrations. I could, of course, use gatsby-plugin-image and display the illustrations as bitmaps. But because I want to animate some of the elements around the illustrations, the cloud, the code icon, the little planet etc. they need to remain separate elements (rather than a flattened / merged bitmap). The trouble is, when they’re separate elements any one of the number illustrations in an Svg format can exceed 1000 lines of code – Wowsers!

This is picked up in the Lighthouse report and I’m seeing the warning for: Avoid an excessive DOM size.

My current plan of attack is to adopt a kind of hybrid  Svg / Bitmap approach where I’ll separate the surrounding elements that I do want to animate, and keep those as Svg’s. Then render the main body as a Bitmap because I won’t be to animating this. 

The reason I’d like to keep the surrounding elements as Svg’s is because I want to randomise the colours; this should be as straightforward as randomly selecting a class name that will apply a different CSS fill colour. If I were to convert these surrounding elements to bitmap this wouldn’t be possible.

My initial test has proved pretty successful and I’ve managed to reduce one of the Svg’s from 1000 lines of code down to 500, so that’s a 50% improvement! – Brills!

Stay tuned for more on this as it’s a pretty interesting area and I’ll be sure to document my findings for whatever solution I come up with.

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Thursday 6th January

I’m taking a small breather from the site development today — but I’m not slacking, no way!

I want to write down all my finding from the three.js performance enhancements I made with Ward while they’re still fresh in my head, then write a blog post about Performance and JavaScript Animation Libraries (working title)

I Tweeted this morning and looped in another Gatsbyte, Grayson Hicks (Staff Software Engineer). Grayson works on the Customer Success Squad and you’ve probably seen him on a number of performance related Gatsby webinars, one of which is coming up on January 13th: Achieving Peak Frontend Performance with Gatsby, so if you’re interested in this topic i’d recommend tuning in for that!

I hope to have Grayson review my blog post and hopefully chip in with some of his expertise.

The main issue I’m having with the post at the moment is whilst the solution worked well for us on the GatsbyConf site, the more I think about JavaScript animation the more I think, actually, “lazy-loading” might not be a good solution for so many other scenarios… and what about the negative impacts, would SEO suffer? — probably!

Perhaps I’ll focus on the problems we faced, how we solved them and provide some further reading as this is quite a deep topic and I rather fear I could spend several weeks writing about it.

Collaboration Count: x9
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling
  • Grayson Hicks

Wednesday 5th January

Today was… Flo day! 🥳. Flo Kissling is Gatsby’s Lead Product Designer and he’s back from his Christmas time off and he’s absolutely brills!

Previously I’d only briefly crossed paths with Flo when I was contracting for Gatsby working on 500 Bottles. Flo was on hand to give me a steer on my design work for both the site and the logo… but joy of joys for GatsbyConf, Flo will be over-seeing the branding and design work — phew! I know when I’ve hit my capable limits.

We had a great meeting with Molly this morning and discussed the illustrations, general art direction, how the content model in Contentful worked, what we need for social media, ads, and other supporting visual assets and discussed some exciting new features I hope to build out in the coming weeks!

Flo has tons of experience and knows the Gatsby brand much better than I do. I’m thrilled he’s on board with the project so stay tuned while we tighten things up!

Collaboration Count: x8
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters
  • Flo Kissling

Tuesday 4th January

I started the day pondering a technique I’m currently calling “hybrid svgs”… allow me to explain. On the current GatsbyConf site we’re using the “number people” illustrations created by Miss Chatz. They’re super duper and I love them and for now I’ve created a React component for each Svg, but, in Lighthouse I see the warning: “Avoid an excessive DOM size“.

This happens because each of those Svgs contains many <g /> and <path /> elements, along with a number of <def /> and <linearGradient /> elements. One of the Svg’s is actually over 1000 lines deep. — Blast!

I’ve encountered this issue before and was able to overcome it by using the Path finder tool in Illustrator, this is quite a destructive process because when elements are merged together it’s harder to do anything other than display them. For the illustrations on GatsbyConf I plan to animate them, I’m not sure how yet but I know I will need to keep some of the elements layered.

My current thoughts on this are, I’ll go for a “hybrid approach”. The main body of the illustration, the actual number could in theory be a bitmap E.g a .png and only the elements that surrounding the number need to remain as <g /> or </path /> elements. However, trying to use position: absolute on these elements so I can animate them and keep them relative to the size of the bitmap body, which by default will scale when you change the size of your browser, is going to be tricky!

I’m wondering if I create a Data URI for the body of the number (the bitmap) and then using xlink:href on an <Svg/> <image /> element, would everything scale proportionally?

If this works it’ll mean I can drastically reduce the complexity of the Svg, which should mean the “excessive DOM size” warning goes away but I’ll still be able to keep some level of control over the elements, and animate them — Hooray!

I’ll need a little more time to experiment with this technique but if it works I’ll be sure to write something up as it would be really helpful in future when working with Svg’s.

The actual task for today was improving performance of the three.js stars animation, seen in the hero section at the top of the site.

The Problem: The problem with including three.js / @react-three-fiber is that the extra weight of these libraries causes an increase in “Total Blocking Time” as seen in the Lighthouse report. The way to resolves this is to use React.lazy and <Suspense />. This technique involves using React to delay the loading of additional JavaScript modules until after the initial JavaScript modules have loaded. However, whilst the technical implementation is pretty solid there are one or two things to consider before using this approach.

In our case on GatsbyConf, and whilst we love the star animation (we hope you do too) it’s irrelevant.

It serves no purpose other than to look “cool” — which I’m 100% ok with FYI. But, because we’re now lazy loading this component it’ll take slightly longer to appear on screen. This isn’t really problem because users aren’t missing out on any crucial information, and there’s no SEO implications since there’s nothing in the three.js scene other than graphics, and lastly it’s an HTML <canvas /> element which can’t be optimised for SEO anyway…

But, if you were using some other JavaScript animation library E.g GSAP and were wishing to animate existing HTML DOM elements would lazy loading work for you? This might mean your page loads, your DOM elements aren’t where they should be and then a few seconds later when the JavaScript loads, the page might jump around while the animation library did its thing. I suppose this might not be an issue and it entirely depends on what you’re doing with the animation library but it’s something to consider.

There’s another issue. Ward was keen to keep this site as performant as possible so along with lazy loading three.js / @react-three-fiber we also have an additional condition worked in that only attempts the lazy load if a users browser is wider than 768px, and if window.navigator.connection.saveData = false.

TLDR: Our stars animation will be lazy loaded and only loaded if we think the user is on a wifi connection on a screen larger than 768px. We feel this solution works for us because as I mentioned, the animation is incidental and serves no other purpose than looking “cool”. Your requirements will most likely be different.

The Solution: The below code snippet shows how we’re using React.lazy / <Suspense /> to lazy load the <ThreeCanvas /> component, and the useEffect is there to ensure this only runs in the browser, not on the server. (because navigator is a window object, and there’s no window on the server).

You can find some more information about this approach in the Gatsby docs: Using Client-Side Only Packages

I plan to write this up with a demo and src code at some point as I think it’s a really interesting topic. Give myself: @PaulieScanlon or @GatsbysJs a follow and we’ll Tweet something soon.

Collaboration Count: x7
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters

Monday 3rd January

Right ho! Back to work. Today was a good day. I was mainly focussed on the hero animation. I’ve been thinking about this for a few weeks now and wanted to create some kind of data driven animation. Not data visualisation (to be clear) but I wanted to use the total number of folks registered for GatsbyConf to drive some kind of visual element.

I’ve done this kind of thing before on 500 Bottles where I used the Shopify inventory levels to create the flying shapes seen at the top of the site. For 500 Bottles I used three.js / @react-three-fiber — @react-three-fiber is great, it’s such a nice way to use three.js in React but does it come at a cost?

Ultimately, yes. Using three.js and @react-three-fiber in your project will increase the overall JavaScript bundle size. You can see the bundles sizes for here package on the below links.

 

Naturally, at Gatsby we’re always keen to keep sites as fast as possible and provide ways to help you optimise your build, but if you add additional JavaScript your site might suffer a little.

I’ve had multiple conversations with Ward about this and actually a lot of the work I’ll be doing over the coming days will most likely be performance related, but… sometimes adding something because it’s cool is ok, in my opinion, and especially if you have an opportunity to show people how it’s done and how things are affected.

It goes without saying that I don’t want folks to have a bad experience just because of my want to do “cool” things but I think there is a fair middle ground. I’ll continue to work with Ward on this and in the mean time here’s how it works.

Create the 3D canvas

First, I add the Canvas from @react-three-fiber and set some config, plus the camera position. Then, added as children are a number of lights and the <ThreeStars /> component which I’ll explain in a moment.

 

<ThreeStars />

This looks slightly more complicated than it is, but I’ll talk you through it…

Fetch The Data

Using a React useEffect I make a call to a Gatsby Serverless Function endpoint when the component “mounts”. This endpoint returns ONLY the rowCountand NOT any details about you lovely folks. This request is handled server-side for exactly that reason — it’s secure.

Add and position each star

Weirdly, I wrote this code in my head over Christmas. I was assuming that once I had an “amount” I could create a null array, map over it and return a three.js geometry and then position it randomly within the 3D scene using good old mathematics … and as luck would have it that’s exactly what I did, and it worked first time — which never usually happens!

Rotate the Scene

Since each star is added to the same <mesh /> I wondered what would happen if i rotated the entire thing… 2 for 2! That also worked first time.

Using  useFrame from @react-three-fiber, I increment the x and y rotation properties by 0.001

Theres a few other things in the snippet below, mainly to handle loading state and to ensure the useFrame doesn’t run until the <mesh /> has been returned by Jsx.

Creating The Geometry

This is, more or less how you’d create any geometry with @react-three-fiber. I’m using <sphereGeometry /> which accepts x3 arguments. You can see what they are from the three.js docs. The x,y,x passed via props from the parent component are passed on to the <mesh /> and used in the position arguments.

… And that’s it. That’s how the star field was made.

Collaboration Count: x7
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters

Thursday 30th December

Today was actually go live day! Yesterdays DNS issues were still slightly tripping us up. We did manage to launch with gatsbyconf.com but www.gatsbyconf.com was proving to be problematic. In Gatsby Cloud we had the primary domain set as the naked url and the www url should resolve to the naked url by default, however because of some weird Google Domains DNS config this wasn’t the case. The solution in our case was to add an additional CNAME record to Google Domains that included the www — and hooray! We’re live once more!

There was more todo though. For the Open-graph image, Laci had accessibility concerns that the 2022 number illustrations were a little too dark and hard to read when they’re small against the dark background. This colour contrast isn’t so much of a problem when you visit the site as the numbers are large but on a social media sharing card they are quite small. Miss Chatz (luckily) was on hand to quickly create some “light mode” versions of the numbers and these are what’ve used in the Open-graph image.

The biggest issue I discovered though (and why does this always happen right before you’re going live?!) was React rehydration. You may or may not have run into this before but this can happen if you’re “setting state” in uncommon ways as React can become a little confused when it comes to return you DOM elements.

In my case it resulted in some very peculiar layouts. The solution was to change the useLocalStorage hook and Ward (Core team TeamLead)  was on hand to help me work this out. I wrote a blog post about it which you can read here: paulie.dev/posts/2022/01/use-local-storage

Once that was resolved everything was glorious, Laci tweeted and shared the new site on the Gatsby social media accounts then we watched the registrants roll in!

Lovely stuff!

Collaboration Count: x7
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed
  • Ward Peeters

Wednesday 29th December

Today was “go live” day and it’s been stressful! I first had a few issue to resolve with Svg heights on mobile not working. I think it’s something to do with when an Svg has an height of 100%… in any case adding a max-width and max-height as well as a width and height of 100% resolved the problem.

Next up was DNS. There has always been a site on gatsbyconf.com and this site did exist in Gatsby Cloud somewhere, but unfortunately I didn’t have access to the Workspace where it had been configured. Alex (Senior Software Engineer) found it in a different Cloud Workspace and removed the domain so it was free to be assigned to the new GatsbyConf ’22 site. We still had issues with Google domains, though, and needed to configure A records and CNAME entries then decide if we want the “naked” url or the prefixed “www” url to be the primary….as I write this we’re still to resolve the DNS config.

Finally there was one last job. There’s a number of links to the former GatsbyConf ’22 landing page around gatsbyjs.com and none of them were pointing to gatsbyconf.com url so we’ve created a PR to handle redirects. Now when you visit any of the old links to the GatsbyConf temporary landing page you should be directed to the .com domain — phew.

But I’m pleased to say that we are live and we did meet the deadline. Just gotta wait for the DNS changes to propagate over night before we officially announce on social media.

Hooray!

Collaboration Count: x6
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz
  • Alex Reed

Tuesday 28th December

What a splendidly visual day I’ve had. I started with an issue we were having with the sponsor logos. Whilst Content Management Systems are great and Gatsby’s image plugin is fantastic there are times where human invention is required.

The problem was that the sponsor logos are all different from one another, namely their aspect ratio’s. Sone are square, whilst most are rectangular and no matter what I did with CSS they never really felt like they were of equal proportions… so I kicked it old school, opened up Adobe Illustrator and begun a process I refer to as “normalising”. This involves looking at all the logos side by side, changing their scales, and matching sizes up using my eyes. As luck would have it, good old fashioned design skills saved the day and after normalising and re-uploading all the sponsor logos they now feel equal.

But…

The really exciting thing I did today was to implement the first two of our number illustrations from the brills Miss Chatz. I’ve worked with Miss Chatz before so knew I’d be getting top notch work — and she did not disappoint.

The tricky thing however, and maybe you know and maybe you don’t is rejigging Svg’s so they work in React. “Why not just inline and import?” I hear you ask. Good question. I plan to animate parts of each of the number illustrations so they need to be React components rather than “image” files (Svg’s are documents not images FYI). And if you’ve ever imported Svg markup into React you’ll immediately run into Jsx syntax issues. — but — Svgr to the rescue! This tool sorts out all those Svg attributes that throw errors when returned by Jsx.

To give you an example, this is valid markup xlink:href, but in order for this to work in Jsx it has to be xlinkHref — Changing each reference by hand would have been hugely time consuming so I’m super happy I found Svgr!

There are some other issues I spotted with the Svg’s. It looks like Miss Chatz has used some blend modes that work fine in Illustrator but perhaps don’t work as expected when the Svg is displayed in the browser. More on that when I work out what’s going on.

Here’s a sneak peek at what the hero section of the site looks like. Hopefully I’ll be able to fix up this blend mode problem before we go live!

Collaboration Count: x5
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann
  • Miss Chatz

Monday 27th December

Right! Back to it, Christmas is over and this site isn’t gonna build itself. Some of today was looking over what I did last week and the rest of the day was updating quite a lot of the styles to match some new designs Molly (Product Design Manager) prepared for us.

For the most part the new styles were colours and layouts but some of the design changes require content model changes — which is fine. Or is it.

Sadly, it’s not. The way the Contentful Source plugin works means that GraphQL will error if it attempts to query a field that is either no longer there or if the field name or type have changed. I had a few scenarios where instead of using simple text fields we’re going to need to use Contentful’s Rich Text editor, this change requires the GraphQL query to change, and then later on in the Jsx I need to deal with the response of the query in a slightly different way.

Laci and I also caught up on what we’re planning to go live with on launch day and I need to have a bit more of a think about how to handle folks that have already signed up via the former GatsbyConf landing page and don’t yet have a raffle code.

I also need to make another change to the content model so that the sponsors logos can also act as links.

Not a bad day and I’m still making progress!

Collaboration Count: x4
  • Paul Scanlon
  • Laci Texter
  • Molly Misek
  • Aron Schuhmann

Monday 20th December

I did not have a good day today.

Todays’ task was to implement the registration from for the event. In the old landing page and for a number of forms used around gatsbyjs.com we’ve been using Marketo. I think for a lot or reasons Marketo is a great solution, however in my case, and perhaps I’m alone in this way of thinking, it doesn’t feel very Jamstack.

To use a Marketo form you need to add a script tag to your site, then once the JavaScript has loaded it finds the a <form /> element by id and injects all the inputs and labels into the DOM.

It also has a rather unique way of dealing with the callback (E.g when the form has successfully submitted)… and I need to tap into this event because once a user is registered I need to create the raffle code and post the same data into my “raffle code” Google Spreadsheet.

This was all becoming too much so I’ve pulled out the Marketo form and will post to a custom endpoint, which Aron (Director of Growth) can use to pull the data back into Marketo.

Alls well that ends well but it was a frustrating day.

Collaboration Count: x3
  • Paul Scanlon
  • Laci Texter
  • Aron Schuhmann

Sunday 19th December

Yep, working on a weekend. Not because I have to but because I want to. Late on Friday Laci and I “did good Marketing” — We came up with a really nice idea to add a little extra bit of fun to the registration process.

We’re having a raffle! Now when you sign up you’ll be given a unique raffle code. I generate this using a Gatsby Serverless Function that randomly picks a few letters from the alphabet and tacks on the date and current time in milliseconds.

I then post this code plus the users details to a Google Spreadsheet for safe keeping. The site also now persists the state of the form. Once you’ve registered so you won’t be shown the form again, but it will show you your raffle code (in case you lose it) I achieved this using a useLocalStorage hook.

During the event, we’ll call out raffle codes which will be selected at random and ask folks to come find me on our event platform, Hubilo. I’ll then check the code against their email address to ensure there’s no cheating, and, et voilà we’ll have winners!

Prizes for the raffle are still being worked out but we’d like to offer products or vouchers from e-commerce venders who’ve built their site with Gatsby — pretty cool ay!

We’ve also started the commissioning process and sent a few emails out to illustrators whose work we liked. The full scope of the illustration brief is still a work-in-progress but it’ll be something to do with the GatsbyConf 2022 theme, “Power in Numbers”, and at some point I plan to add these custom illustrations to various sections of the site.

Collaboration Count: x2
  • Paul Scanlon
  • Laci Texter

Friday 17th December

Today was “Tailwind” day so I’ve been busy working through the sections and rejigging some of the content model to ensure that that all sections besides the hero follow the same content model. These sections do have different subsections but I’d really like to keep the “one off” rules to a minimum. I’m not a fan of having lots of little _conditions_ all around the code base. It’s kind of ok while you’re actively developing but when I came back to this in weeks to come or if someone jumps on board to help me out I don’t want to have to explain lots of little rules.

“One size fits all” is actually a really tricky thing to do, but with a bit of planning and keeping Laci in the loop, I’m sure we’ll agree on something that can work across all of the sections.

Collaboration Count: x2
  • Paul Scanlon
  • Laci Texter

Thursday 16th December

Today was “Content Model” day. Myself and Laci (Senior Brand Marketing Manager) went through each section required for the site and created an appropriate content model. We have x2 pages, “/” and “404” and each page can render a few types of “Page Blocks”.

Page Blocks

Starting at the beginning we have a Hero block which contains the following field types:

  • Logo – Media
  • Event Name – Short Text
  • Title – Short Text
  • Title Suffix – Rich Text
  • Button Text – Short Text
  • Button Hash – Short Text
  • Start Date – Date & Time
  • End Date – Date & Time

Next is a kind of generic Section block  which contains the following field types:

  • HideMe – Boolean
  • Section Name – Short Text
  • Section Image Top – Media
  • Section Body – Rich Text
  • Section Image Bottom – Media
  • Section Background Color – Short Text
  • Sponsors – References, many
  • Speakers – References, many
  • Gatsby Agency Awards – References, many

This generic Section should in theory be enough to drive each and all of the sections of the site. I really like using the References field type because it allows you define a type of field that contains other types of fields, it’s all a bit meta but totally flexible, each of those sub fields can then be constructed using a selection of generic field types such as Short Text, or Media.

Page Block Arrangement

Here’s a sneak peek at what the index page Page Block arrangement looks like. I like this approach as it clearly shows how the page will be displayed and in what order each Section will be shown.

Moreover, if Laci wants to rearrange the order, it’s no trouble since Contentful allows you to drag and drop these Page blocks and so long as I do my bit correctly on the code side, the order should be respected when the content pops out the other side.

Today was a big day but I’m pleased with the progress we made and now we have a Content Model in place I can begin to work on the code. This next part is all me so Laci can continue to work on the actual content and with a bit of luck when we reconvene next week we should be in a really good place.

#Agile!

Collaboration Count: x2
  • Paul Scanlon
  • Laci Texter

Wednesday 15th December

I’m currently returning to the working world after being struck down with a spot of the old “man flu” — awful business and it knocked me out for three days. I have, however, just about mustered up the energy to complete my initial commit for the new GatsbyConf site.

Typically on my initial commit, I’ll get all the “knowns” installed and working. For this site that includes all my tooling, husky and commitlint and of course prettier. Then I popped in my old chum TailwindCSS, made a default index page and a temporary 404 page and that’s pretty much me good to go now.

I’ve deployed to Gatsby Cloud right away as I’ll need to share the WIP link with my “client” (Laci from the Marketing team) — no doubt she’ll also be keen to keep an eye on what I’m up to. But just at the moment sadly, I won’t be sharing the link with you lovely folks.

 

Collaboration Count: x1
  • Paul Scanlon

 

 

Paul Scanlon
Written by
Paul Scanlon

After all is said and done, structure + order = fun! Senior Software Engineer (Developer Relations) for Gatsby

Follow Paul Scanlon on Twitter

Talk to our team of Gatsby Experts to supercharge your website performance.