Page 6

The Mysterious Case of Emotion and “exports is not defined”

Thought I’d share a bug I ran into a while back that sent me on a Poirot style investigation full of red herrings and unexpected culprits.

This is tangentially related to my recent page speed woes at work. We’d started using Emotion for CSS-in-JS in our component library and, combined with lazy and conditional component loading, it helped with some of the “Reduce unused CSS” warnings we were seeing in Lighthouse.

So adding Emotion as a styling option in our main codebase seemed like an obvious choice. We’d already installed @emotion/core (v10) when we started importing from our component library which meant it should be a quick, two-step process: 1) running yarn add @emotion/babel-preset-css-prop and 2) adding it to our babel.config.js presets after @babel/preset-react. I followed those steps, ran Webpack, and promptly got the error “ReferenceError: exports is not defined”.

Weird.

Continue Reading

Moving a Node App from Google Compute Engine to DigitalOcean

This site can't be reached

There’s nothing like trying to deploy a minor site update and having your VM hang while SSHing 75% of the time, give up mid-build the other 25%, and then fall apart completely when you try to restart it. Since all I remember about setting up a Google Compute Engine Node instance in the first place is that it took me a while and wasn’t particularly intuitive, this seemed like a good opportunity to try a new host. I’m running a commercial Next.js site with a custom server so after browsing around DigitalOcean seemed like the best option.

And it was actually pretty painless!

Of course, it would be even quicker with a step-by-step guide so here’s a reference for my future self or anyone else who wants it.

My guide for migrating a Node app to DigitalOcean (this may vary a little depending on your site):

  1. Sign up for DigitalOcean and create a Droplet using NodeJS 1-Click App. Poking around the DigitalOcean Community questions, I ran into some talk about additional installations for production but my Droplet came with Nginx, PM2, and optional Let’s Encrypt for SSL out of the box so those discussions may be a little out of date.
  2. Add the new IPv4 address to MongoDB Atlas. DigitalOcean provides instructions for getting started with your Droplet but I wound up skipping around a bit. Since I already had a MongoDB database set up, I completely ignored their section on creating a new one. To use an existing database, just remember to log in to MongoDB Atlas and add your new IP address (using port 22) to the IP Address List under Network Access.
  3. Clone your repo. Using ssh root@0.0.0.0 (replacing the zeros with your IP address), ssh into your Droplet and clone your repo.
  4. Copy environmental variable files, assets, etc. From outside your Droplet, use scp -r /path/on/computer root@0.0.0.0:/path/on/droplet (replacing the paths and zeros) to copy any necessary files that weren’t included in the repo.
  5. Start your app. Back in the Droplet, start with a good old yarn install. Then, for a Next.js site, run yarn build followed by sudo NODE_ENV=production -u nodejs pm2 start server.js to start a custom server. This is also a good time to jump back to the DigitalOcean instructions for shutting down the starter app with sudo -u nodejs pm2 delete hello and saving your PM2 process list with sudo -u nodejs pm2 save.
  6. Create an Nginx configuration. I added “read up on everything Nginx can do” to my todo list but for now I have a pretty simple config with basic asset caching in my /etc/nginx/sites-enabled/ directory. You can view the file in this Gist but keep in mind it’s pretty tailored to my SSL setup. Whether you alter my example, the DigitalOcean default, or start fresh, make sure to 1) switch the root setting to something like /root/your-site/.next/pages; for Next.js and 2) update the proxy_pass to use your app’s port (8443 in my example). Restart with sudo systemctl restart nginx.
  7. Point your domain to the new IPv4 address. How you do this will depend on your DNS host but you’ll want to complete the migration by updating your A name to point to your new IP address.

There it is in seven steps. The first run through took a bit of trial and error but hopefully this will speed things up next time.

Getting a font recommendation in before the first Friday of the month is over. Organic Peach by Prioritype is a handwritten font with a fun kind of blobby feel to it and it’s free for personal use.

Download at FontSpace or buy on Creative Fabrica.

Advertisement
Advertisement

It’s Space Time!

Space Time Font Poster

A new addition to my growing collection of starry fonts (if that’s your thing too, make sure to check out Starry Night and Publicite d’epoque). 

Space Time has a regular version with the full design and lightly touching letters and a stackable, overlapping version with separate layers for the base, outline, shadow, and stars (plus the base and outline versions can be used as standalones!).

When I mentioned a couple weeks ago that I was working on a font with fussy kerning, this is the one I was talking about so if you notice any oddities please let me know in the comments or through the contact form.

It’s free for personal use so download it here.

It’s a Friday font day with Cherish Today by Sarid Ezra

Loving the fun, casual feel of this font. Plus all of the promo posters are great. It’s all caps but with a cut out effect on the lowercase letters and free for personal use only. 

Download at dafont or buy on Creative Fabrica.

Preloading Images in a Responsive, WebP World

Watch out for giant images

It’s time for another Google Core Web Vitals themed TIL. This one concerns image loading. Specifically, huge, above the fold image preloading.

The site I work on uses a lot of super wide to full width hero images. We’d done some previous optimizations around serving images in WebP format (Serve images in modern formats) and using picture and srcset for responsive images (Properly size images). I won’t go into details since those topics already have a ton of tutorials that explain things better than I ever could. In fact, Smashing Magazine alone has you covered with Using WebP Image Format Today and Responsive Images Done Right: A Guide To picture And srcset.

Preload critical assets to improve loading speed.

The one downside to our earlier work? It made things a little more confusing when we started looking into preloading images.

Preloading assets that aren’t actually used isn’t particularly helpful (Chrome will even warn you if you do it!). If you’re serving a WebP image but preloading the fallback or preloading a mobile image on a desktop browser, you aren’t getting any benefits out of it.

Let’s say you have a picture block that selects an image based on browser support, screen resolution, and breakpoint:

<picture>
  <source srcset="large-image.webp, large-image-2x.webp 2x" media="(min-width: 768px)" type="image/webp" />
  <source srcset="large-image.jpg, large-image-2x.jpg 2x" media="(min-width: 768px)" />
  <source srcset="small-image.webp, small-image-2x.webp 2x" type="image/webp" />
  <img src="fallback-image.jpg" srcset="small-image.jpg, small-image-2x.jpg 2x" />
</picture>

The first question is how to handle different image formats. Looking at the Can I use entries for Webp image formats and preload, it seems pretty unlikely for a browser to support preloading but not WebP images. And according to a quick aside in this Addy Osmani article on hero images, you can use the type="image/webp" attribute with a link tag to specify that you want to preload a WebP image.

Next, we need to deal with screen sizes and resolutions. In addition to type, the link tag supports media and imagesrcset attributes which should look very similar to the media and srcset attributes on our source and img tags. The main difference is that you have to be more explicit with your breakpoints since the browser won’t be choosing the best image itself.

Putting that all together, you would add this code to your head tag to preload the images from the example above:

<link rel="preload" as="image" href="large-image.webp" media="(min-width: 768px)" imagesrcset="large-image.webp, large-image-2x.webp 2x" type="image/webp" />
<link rel="preload" as="image" href="small-image.webp" media="(max-width: 767px)" imagesrcset="small-image.webp, small-image-2x.webp 2x" type="image/webp" />

If you prefer an example with real images, check out this Pen on Codepen. Just click on Settings and HTML to view the preloading the code.