Reading List
The most recent articles from a list of feeds I subscribe to.
Elan Ullendorff: "Modularity is inversely correlated to expressiveness"
From Escape the Algorithm. When we create a contract or a pattern, there are gains in familiarity, modularity, and composability, but it's a lossy translation.
If I were to design a personal map of my neighborhood, it would include the potholes I swerve by on my bike rides, the neighbor’s sweet precocious 4 year old that is always on the front stoop and wants to tell me about her day, routes that have small patches of grass to the right of the sidewalk and end near a public trash can (suitable for walking my right-side-only peeing dog), the schedule and trajectory of shade during the summer, homes with potted flowers hanging off their railings, restaurants that closed ages ago, the playgrounds where we are most likely to run into parent friend crushes, and the street with the best view of the skyline at night.
It probably would not look like Google Maps.
Debugging application state triggered by focus
In any modern browser's element inspector, you can force an element into a :hover
or :focus
state to debug styling issues. Sometimes, you want to debug an issue of an element in focus with a state controlled by JavaScript. Unfortunately, the forced states from the developer console aren't always enough. (Edit: unless you use Chrome apparently, scroll to the end for an alternative solution!)
I came across this problem when I was styling a custom <select>
component in React. The dropdown menu is only visible when the input is focussed, but I couldn't inspect this state with the devtools. Whenever I wanted to browse the element tree, the devtools became the active element on the page and the menu disappeared.
Luckily, I came across a tiny snippet to help debug in this situation.
window.setTimeout(() => { debugger; }, 5000);
This will wait five seconds until it halts all code execution with a debugger breakpoint. With this snippet, I load the page, set everything up into the state I want to inspect—5 seconds is more than enough time—and wait for the timeout to fire. When the debugger is triggered, I can browse and tinker with the element tree without worrying about the page updating.
In React, I wrapped this in a useEffect
call to run once for the component I wanted to debug.
useEffect(() => { window.setTimeout(() => { debugger; }, 5000);}, []);
After I shared this post on Twitter, Bram tweeted that Chrome DevTools have a feature to circumvent this problem. With the "Emulate a focussed page" setting, the web page will remain in a focussed state when you're playing around in DevTools. Read more in the Chrome DevTool release notes.
The Art of Decision-Making
In a New Yorker article titled The Art of Decision-Making, Joshua Rothman explores the paradox of how we can spend a lot of energy fretting over small decisions, while the big life decisions seem to come naturally.
We agonize over what to stream on Netflix, then let TV shows persuade us to move to New York
An interesting point he makes is how our aspirations can take a long time to come to fruition. How can we guide our actions if we don't even know if we'll still want the results by the time we get there?
To aspire […] is to judge one’s present-day self by the standards of a future self who doesn’t yet exist. But that can leave us like a spider plant putting down roots in the air, hoping for soil that may never arrive.
As the life we crave can change dramatically.
Before having children, you may enjoy clubbing, skydiving, and LSD; you might find fulfillment in careerism, travel, cooking, or CrossFit; you may simply relish your freedom to do what you want. Having children will deprive you of these joys. And yet, as a parent, you may not miss them. You may actually prefer changing diapers, wrangling onesies, and watching “Frozen.” These activities may sound like torture to the childless version of yourself, but the parental version may find them illuminated by love, and so redeemed. You may end up becoming a different person—a parent. The problem is that you can’t really know, in advance, what “being a parent” is like.
Building Laravel Error Share
Last week, we released Laravel Error Share, a package to share local Laravel exceptions with a coworker or your debugging friend on the internet. We wrote all about the functionality of the package on the Flare blog. In this post, I'd like to look into some of the implementation details and considerations we made while building it.
As of two weeks ago, Laravel ships with a beautiful new minimal error page. At Spatie, we built and will continue to maintain Ignition, the previous error page. After the new one was released, some people were missing features Ignition provides that aren't available anymore. You can still install Ignition for a more detailed view when debugging, but we also wanted to have some core features from Ignition accessible as a "plugin" for Laravel's native error page.
The main feature we wanted to port—which was also by far the most requested one—was the share button. The share button on Ignition is probably one of my favorite open source things we've built over the years. It happens so often that I come across an issue on one of our projects and want to ask a coworker to help debugging. An interactive, shared stack trace with context is much, much more useful that a .png screenshot.
Laravel Error Share was built by my colleague Ruben, so most of the code I'll review in this post is accredited to him. I helped out with the design and feedback on the implementation.
We wanted to insert the "Share" button alongside the dark/light mode theme switcher in the top right of the error page. The template for this header is stored in the laravel-exceptions-renderer::navigation
vendor view.
To override the vendor view, we created our own resources/views
folder in the package, and register it under a custom namespace in the package service provider.
View::prependNamespace('laravel-exceptions-renderer', [__DIR__.'/../resources/views']);
Next, we set up our own navigations.blade.php
file which is a copy of Laravel's view. Ours has an added <x-laravel-exceptions-renderer::error-share>
component that renders before the theme switcher.
<header class="mt-3 px-5 sm:mt-10"> <div class="py-3 dark:border-gray-900 sm:py-5"> <div class="flex items-center justify-between"> <!-- A bunch of other stuff… --> <div class="flex items-center gap-3 sm:gap-6"> <x-laravel-exceptions-renderer::error-share :exception="$exception" /> <x-laravel-exceptions-renderer::theme-switcher /> </div> </div> </div></header>
We pass the exception object to the error share component so it can parse and transform it into a format the Flare API can digest for the publicly shared URL.
The downside of this method is we need to manually keep the package up to date with Laravel's upstream view file. To avoid being caught off guard by Laravel's changes, we added a snapshot test using Pest & our snapshot plugin that runs against the view in the vendor
folder. This isn't perfect, because we'll only catch the updates when someone runs the tests or makes a PR, but it's better than manually having to verify.
<?php use function Spatie\Snapshots\assertMatchesFileSnapshot; it('still is the same laravel navigation blade component', function () { assertMatchesFileSnapshot(__DIR__.'/../vendor/laravel/framework/src/Illuminate/Foundation/resources/exceptions/renderer/components/navigation.blade.php');})->skipOnWindows();
In the future, we'd consider making a PR to Laravel to make the error page extendible with slots or something similar, but this is good enough for now.
In the first version, we mirrored the style of the "Expand vendor frames" button with a heavy share icon. While this made the button stand out, it felt too prominent.
Instead, we took a more subtle approach similar to the theme switcher button alongside it. We browsed Heroicons (the icon library used for the other icons on the error page) for a good icon, and removed the button background to make it more subtle. We considered removing the label so it looked just like the theme switcher, but ended up keeping it because an icon alone isn't enough to convey the functionality.
We also mirrored the theme switcher for the dropdown style. We decided to keep Flare's purple hue on the "Create share" button to have a subtle reference to the service without going overboard on branding in a dev environment.
And that's how Laravel Error Share was born! We're currently porting more Ignition features to Laravel's native error page so developers can choose between a selection of small addons or install Ignition for a complete revamp.
Marcus Buffet: Managing my motivation
Full title is Managing My Motivation, as a Solo Dev, but this is great advice for any dev.
My favorite:
Leave tasks unfinished
I can’t overstate how much this one helps me. I try to leave a task 90% finished at the end of a working session. It feels slightly worse than closing out the work, but it makes starting the next day 10x easier. Having a quick win when I start coding is a massive boost, and it immediately gets me into the flow state. It can’t be too easy though, if all I have left is to run git commit, that’s not enough. Ideally it’s something where I know exactly what I need to do, that will take 5-10 minutes.
As I've written before: end the day with a failing test.