I found this dead crow. The blood-from-the-beak indicates poisoning by rodenticide. A coward's solution.
I saw these while visiting my step-father's grave.
My blind cat, sunning himself.
I found this dead crow. The blood-from-the-beak indicates poisoning by rodenticide. A coward's solution.
I saw these while visiting my step-father's grave.
My blind cat, sunning himself.
Mildly embarrassed thinking about how long I thrashed on this...
After creating a bee-u-tiful #eslint configuration, running it on my project, ensuring it hooked up to my editor etc.
Lint began failing when executed in CI. This left me so completely vexed that I dusted off my Fedora laptop to see if it was some arcane difference between MacOS and Linux.
It wasn't.
I realized that #rr7 needs to generate types before lint runs, or it rightfully explodes.
// package.json
{
...
"scripts": {
"check:lint": "react-router typegen && eslint .",
}
}
Wiring up #vitest and #rr7 for tests is not obvious.
vitest.config.ts
createRoutesStub
We need a separate vite.config
that omits @react-router/dev/vite
, and then
configures the typical test
features.
import react from "@vitejs/plugin-react"
import autoprefixer from "autoprefixer"
import tailwindcss from "tailwindcss"
import { defineConfig, loadEnv } from "vite"
import tsconfigPaths from "vite-tsconfig-paths"
// -----------------------------------------------------------------------------
export default defineConfig({
css: {
postcss: {
plugins: [tailwindcss, autoprefixer],
},
},
// using `@vitejs/plugin-react` instead of `@react-router/dev/vite`
plugins: [react(), tsconfigPaths()],
test: {
env: loadEnv("test", process.cwd(), ""),
environment: "happy-dom",
// @NOTE: https://testing-library.com/docs/react-testing-library/setup#auto-cleanup-in-vitest
setupFiles: ["./vite.cleanup.ts"],
},
})
Now, we need to use createRoutesStub
anywhere a component renders anything to
do with #reactrouter. Alternatively, we could build a "wrapper" utility,
similar to mocking a redux
provider, but in practice we'll be passing
createRoutesStub
to a wrapper utility anyways.
import userEvent from "@testing-library/user-event"
import { Link } from "react-router"
import { createRoutesStub } from "react-router"
import { render, screen, waitFor } from "@testing-library/react"
import { test } from "vitest"
// -----------------------------------------------------------------------------
const Welcome: React.FC = () => {
return <Link to="/login">Log In</Link>
}
const Success: React.FC = () => {
return <>you did it!</>
}
test("Welcome screen navigates to /login", async () => {
const Stub = createRoutesStub([
{ Component: Welcome, path: "/" },
{ Component: Success, path: "/login" },
])
render(<Stub />)
await userEvent.click(screen.getByText("Log In"))
await waitFor(() => screen.findByText("you did it!"))
})
Also known as #remix.
throw
from actions will naturally be caught by the nearest ErrorBoundary
.Route.ComponentProps['actionData']
is only useful client-side. Don't spend
x-minutes wondering why your console.log insists on being undefined.try/catch
and return data()
with a status: 400
.export async function action({ request }: Route.ActionArgs) {
const formData = await request.formData()
const emailAddress = formData.get("email_address")
if (typeof emailAddress !== "string") {
throw new Error("Expected a string value, but received a File.")
}
try {
const validEmailAddress = z.string().email().parse(emailAddress)
await someSideEffect(validEmailAddress) // like authentication
return data({ ok: true as const, emailAddress }, { status: 200 })
} catch (error) {
if (error instanceof ZodError) {
return data(
{ ok: false as const, emailAddress, error: "validation" as const },
{ status: 400 },
)
}
return data(
{ ok: false as const, emailAddress, error: "unknown" as const },
{ status: 400 },
)
}
}
export default function Route({
loaderData,
actionData,
}: Route.ComponentProps) {
// @NOTE: actionData only exists client-side
return (
<>
{actionData?.ok ? (
<p>hooray!</p>
) : (
<Form method="post">
<input
name="email_address"
placeholder="Email address"
required type="email"
/>
<button>submit</button>
</Form>
)}
</>
)
}
react-router
documentation uses let
everywhere.throw
their redirect
from actions. That ain't an error.I received my BJJ brown belt last night.
I've nothing particularly caffeinated to add to the "discourse" on the subject
of measuring the productive output of a software engineer, but I continue to be
bemused by the various attempts maximizevalueextraction.biz like DORA
, SPACE
,
DEVEX
et al.
Imagine a framework for measuring the delusions of these biz-analysis freaks.
I get weird about multiple tabs and splits in my workflow, and I really like to have the same layout across #tmux sessions.
In the distant-in-dog-years past, I spend too many hours building custom layout
templates, etc, but have since given up tmux
as a hobby. Now, I just hit
prefix
and then smash <SPACE>
until the layout looks nice enough.
However... When I have a giant screen, e.g. 3840 x 2160
, the layouts look
weird to me. So, back to scripting:
#!/bin/bash
# $HOME/.config/tmux/big-split.sh
TERMINAL_WIDTH=$(tmux display-message -p "#{window_width}")
TERMINAL_HEIGHT=$(tmux display-message -p "#{window_height}")
PERCENTAGE=70
OFFSET=10
PANE_WIDTH=$((TERMINAL_WIDTH * PERCENTAGE / 100 + OFFSET))
tmux split-window -h -l "$PANE_WIDTH"
Then a small amendment to tmux.conf
so that I can set the layout with
:bigsplit
:
# $HOME/.config/tmux/tmux.conf
set -g command-alias[0] bigsplit="run-shell '$HOME/.config/tmux/big-split.sh'"
These look good, but putting them up sucks.
Wading back into the JS framework pool. Though I've been building quite a few side-projects recently using a variety of approaches (Deno, Hono, Fresh, etc.), those projects are all to my own peculiar taste.
The calculations change when building an application that someone else is paying for, and particularly if that application needs to be supported long-term by a team of varied skill-sets and expertises. Peril avoided.
The framework du jour is inarguably #nextjs. It's an unavoidable #react-ism, and has to be considered.
But, context. gcp
and cloudrun
is where this application will be deployed,
which is, evidently, hard with NextJS. While there will always be an "ahem,
actually", anecdote, blog post, and conversation seem to converge on the point
that NextJS just doesn't work as well unless you're deploying to Vercel. This
seems doubly reinforced by the existence of
shim-projects to leverage bespoke features of NextJS
in non-Vercel clouds.
My hesitation also relates to #wordpress, and chaos currently visible in that developer community, due to commercial strong-arming by wordpress.com.
Then there's this.
So I'll be looking pretty hard at react-router
v7 instead...
Signs
point to it working well from gcp
.
Tomorrow is my last day with my current company. I just want to note that, here.
Late-winter, 2018, only so many people that you could count us with a single hand. Up to much larger headcount, acquisition, and sun-setting.
A job is a job is a job, but I've been in this one chair for long enough that it just has me feeling nostalgic.
If you're using macOS, just use postgres.app -
homebrew
installations of #postgres are too much heartache.
(or use a containerized postgres)
Be sure to add psql
to $PATH
in .zshrc
or whichever flavor you're using:
PATH="/Applications/Postgres.app/Contents/Versions/latest/bin:$PATH"