Corey Ward

Full-stack, freelance designer + web developer building GatsbyJS and Rails websites. I also design and build furniture.

Read this first

Case Sensitivity with `localeCompare` in JavaScript

I recently ran into a bug using code like the following:

someArray.sort((a, b) => a.name.localeCompare(b.name))

At a glance this seems fine—localCompare enjoys fantastic browser support, and as the name suggests, it isn’t English-centric. However, this is still the web we’re building for, and the familiar gotcha of inconsistent behavior amongst browsers is lurking here. This can lead to hard-to-debug inconsistencies and bugs.

Most browsers—including Chrome, Edge, and Firefox—and Node treat localeCompare as case-insensitive by default, treating an uppercase “A” as the same as a lowercase “a”. Safari, however, does something different.

Safari uses a variant of case-sensitive sorting, but not in the usual ASCII order where “Z” sorts above “a”. Instead Safari sorts lowercase letters above their uppercase companions, but in alphabetical order otherwise, like “aAbBcC”.

In many cases...

Continue reading →


Fix ESLint crashing on rest operator: “Cannot read property ‘type’ of undefined”

This is a bit of an obscure one, but I tend to use the same dev tooling configuration (Prettier, ESLint, Babel, etc) for multiple projects so I’m likely to run into this again.

I encountered this in the middle of a project after a VSCode restart (to resolve other troublesome behavior). I was doing some refactoring and noticed that the magic that tells me what I’ve borked was conspicuously quiet, and a glance at the ESLint “output channel” in VSCode showed the titular error.

In my case, it wound up that I had been using an older version of ESLint (5.x) even as related dependencies (babel-eslint, eslint-plugin-react, and the ESLint extension for VSCode, among others) were updated. Fixing the issue was as easy as updating ESLint to the latest version (v7.11.0 at the moment of publication) and restarting VSCode again.

Continue reading →


Using Webster’s 1913 Dictionary on macOS Catalina, Big Sur, or Monterey

I recently had the pleasure of discovering James Somer’s blog through Instapaper’s weekly “top highlights” email. I found James’ post about the dictionary particularly compelling, and it seems I’m not alone.

Screen Shot 2021-12-27 at 2.59.00 PM.png

Alas, the instructions provided for installing the 1913 edition of Webster’s Revised Unabridged Dictionary on Apple devices doesn’t work for macOS Catalina. Between the application and the source files being over 10 years old and Catalina changing things significantly for security, this isn’t surprising. After a few initial stabs at finding a Catalina-compatible version of the DictUnifier app (of which I tried two), I found an even better workaround.

How to install Webster’s Revised Unabridged Dictionary (1913 revision) on macOS Catalina

  1. Open the Dictionary app on your computer, and select File > Open Dictionaries Folder from the menu, or navigate manually to ~/Library/Dictiona...

Continue reading →


Fixing installation fsevents install errors when using Gatsby

If you’re using Gatsby, you might have noticed a rather lengthy, unhelpful message in your terminal when you run yarn install or yarn add that relates to fsevents. While Yarn will tell you this is okay because the dependency is “optional”, it’s really not.

Running Gatsby on macOS without fsevents installed will result in much higher CPU usage (worse battery life) and slower refresh performance in your browser. So while technically it is optional, it’s really in your best interest to get fsevents installed.

So what’s the issue?

Without getting too into the weeds, there are a few issues causing this:

  1. Versions of fsevents below 1.2.9 aren’t compatible with Node v12+
  2. The tool fsevents uses to compile (node-gyp) has issues with compiling on macOS Catalina
  3. Compatible versions of fsevents above 1.2.9 aren’t available as binaries

Two short, sweet fixes:

Option 1: Force upgrade chokidar

...

Continue reading →


Exporting an embeddable React component from a Gatsby app using Webpack

A recent project called for the header and footer—implemented as React components in Gatsby—to be embedded on third-party sites (think support documentation). Since both components rely on Gatsby’s Link component as well as its GraphQL-backed Static Query (useStaticQuery in this case), some creativity was required.

The solution: a separate Webpack configuration that would import the relevant file (e.g. the Header component) into a lightweight wrapper that included an explicit call to ReactDOM.render. To avoid a direct dependency on Gatsby, Webpack’s resolve directive was used to direct imports from Gatsby to a shim.

Here’s the Header component that needs to be embedded. Note the multiple imports from Gatsby:

// src/components/Header.jsx
import React from "react"
import { Link, useStaticQuery, graphql } from "gatsby"

const query = `…` // query fetching link data from CMS

const
...

Continue reading →


Fixing Homebrew Postgres Installation on macOS Catalina

I recently upgraded to macOS Catalina and needed to reinstall PostgreSQL via Homebrew. The usual process is simple enough: brew install postgresql does the bulk of the work, and then running brew services start postgres would normally result in Homebrew’s service manager loading the appropriate launch agent for you.

Unfortunately Catalina’s various file access protection schemes seem to get in the way of this. I saw a handful of different errors when looking for a solution, but the specific error I was receiving was a little different:

Permission denied @ rb_sysopen - /Users/corey/Library/LaunchAgents/homebrew.mxcl.postgresql.plist

I assumed that the plist file had merely been given incorrect permissions, but the file wasn’t even there. Homebrew wasn’t able to create the file because the directory, ~/Library/LaunchAgents has its permissions set to 555 (i.e. r-xr-xr-x), so despite...

Continue reading →


useTypedText React Hook

I needed to add a text-being-typed effect to a complex animation recently, and instead of cluttering up the more nuanced parts of the animation with the typing animation, I wrote a quick React Hook that takes the final string and returns the currently typed text. This seems like the sort of thing I’ll use again, and hopefully it’ll help someone else as well:

import { useState, useEffect } from "react"

export default (finalText, delay = 250) => {
  const [state, setState] = useState(finalText.slice(0, 1))

  useEffect(() => {
    const deferredActions = finalText.split("").map((char, index) => {
      if (index) {
        return window.setTimeout(() => {
          setState(finalText.slice(0, index + 1))
        }, delay * index)
      }
    })

    return () => {
      deferredActions.forEach(timeout => {
        timeout && window.clearTimeout(timeout)
      })
    }
  }, [finalText,
...

Continue reading →


How to fix `React DevTools encountered an error: RangeError: Invalid array length`

I recently found this rather obscure message in my dev tools console when working on a React + Gatsby based website. It took a bit of digging to figure out where it was coming from since the stack trace was all React internals.

Turns out I had made a simple mistake some weeks prior when setting the display name on a component that was being wrapped with forwardRef: I had passed in the component itself as the value of the displayName property instead of a string.

 const Something = React.forwardRef((props, ref) => <div>…</div>)
-Something.displayName = Something
+Something.displayName = "Something"

Turns out React DevTools isn’t so fond of that.

Hopefully this will save someone (probably me) time in the future!

Continue reading →


Consistent Date Formatting in Ruby on Rails 5+

If you’ve ever dealt with dates in Rails, particularly accepting dates from user input and then displaying them, you’re familiar with two clunky experiences:

  1. The awful default month, day, year, hour, minute, second dropdowns
  2. The complete mess of a date that you get when you force that field to be represented as a text input in a form.

In a hurry? Scroll on down to the bottom for the copy-paste-ready code snippet to make everything better like magic.

Part 1: Getting Date to format itself as desired

There are a bunch of core extensions to Date in ActiveSupport, but none of them create a new date class. If you’re working with Date, which is what Rails returns when you have a date column in your database, the method converting that date into a string is Dateto_formatted_s. The ActiveSupport extensions add this method, and they alias the to_s method to it, so when you call Dateto_s...

Continue reading →


Co-dependent Models in Rails

Sometimes you have a one-to-many relationship in your Rails models and you want to allow nested attributes at the time of creation. So you do this:

 Seems like it would work, but does NOT:
class User < ApplicationModel
  has_many :tags
  accepts_nested_attributes_for :tags
end

class Tag < ApplicationModel
  belongs_to :user
end

When you try to save a user, though, you run into trouble: ActiveRecord tries to validate autosaved nested records, and those nested records have an implicit required: true validation on the parent model which, in this case, doesn’t have an ID yet.

The fix is simple, but unintuitive: manually specify the inverse_of option on the association. ActiveRecord can create a bidirectional association automatically, but in this particular case, it doesn’t work.

 Redundant, but works
class User < ApplicationModel
  has_many :tags, inverse_of: :user
...

Continue reading →