Skip to content

Instantly share code, notes, and snippets.

View aleclarson's full-sized avatar

Alec Larson aleclarson

View GitHub Profile
@aleclarson
aleclarson / 01_proposal.md
Last active November 7, 2025 19:33
Remix 3 `this.props` proposal

“Setup props” considered harmful!

Ryan Florence doesn't like me saying that, but it's true.

Why is it true? Well, they look like render props until you scroll down to the return statement and see an arrow function. If you refactor a stateless component into a stateful component (i.e. add a setup scope), the render props subtly become setup props, right under your nose.

Most of the time, using setup props is dangerous and unnecessary, as it leads to problems down the road. At first, all is well, but then you use the component more dynamically and, BOOM, you've got a stale data issue that presents itself in confusing ways. Of course, this problem is most apparent in more complex applications with many moving parts.

OK, let's say there's a problem. Can it be avoided?

@aleclarson
aleclarson / 01_track.ts
Last active November 2, 2025 22:43
Remix 3 "track" utility
// Track props access and selectively rerun callbacks on rerender.
export function track<Props extends object>(
...callbacks: ((props: Props) => void)[]
) {
const tracked = callbacks.map((callback) => new TrackedCallback(callback))
let oldProps: Props | undefined
return (props: Props) => {
tracked.forEach((callback) => {
if (!oldProps || callback.shouldUpdate(props, oldProps)) {
@aleclarson
aleclarson / demo.ts
Last active October 23, 2025 21:34
Remix 3 wrapper-free event support (type safe)
import { Event, events, EventTarget, on } from './framework.ts'
// Extending a built-in class with type-safe events
declare global {
interface Worker {
// Does not exist at runtime. No createEventType wrapper needed.
$rmxEvents: {
message: MessageEvent
}
}
@aleclarson
aleclarson / example.tsx
Last active October 18, 2025 11:38
Remix 3 Query primitive
import { RoutePattern } from '@remix-run/route-pattern'
import { queryCache } from './query.ts'
const userProfileRoute = new RoutePattern('/users/:id')
type UserProfile = {
name?: string
email?: number
biography?: string
avatar?: string
diff --git a/alias.js b/alias.js
index a2e9dddc6b19e5668d23b2b25a0718ee2a201c37..6d21587b4e771ffb406d6193d381076bc5c5f229 100644
--- a/alias.js
+++ b/alias.js
@@ -98,7 +98,7 @@ function mapColumnsInSQLToAlias(query, alias) {
return mapColumnsInAliasedSQLToAlias(c, alias);
}
return c;
- }));
+ })).mapWith(query.decoder);
@aleclarson
aleclarson / select-without-from.ts
Created June 24, 2025 18:38
An incomplete attempt at "SELECT without FROM" in Drizzle
import { sql, Subquery, WithSubquery, type SQL, type SQLWrapper } from 'drizzle-orm'
import type { SelectResultField } from 'drizzle-orm/query-builders/select.types'
type SelectResultFields<TSelectedFields extends Record<string, any>> = {
[K in keyof TSelectedFields]: TSelectedFields[K] extends SQLWrapper
? SelectResultField<TSelectedFields[K]>
: SQL<TSelectedFields[K]>
}
export function select<TAlias extends string, const TSelectedFields extends Record<string, any>>(
@aleclarson
aleclarson / 0. Local Development Script For Google Cloud Run Functions.md
Last active May 2, 2025 23:42
Multiple functions (with watch mode) for @google-cloud/functions-framework

With this gist, you can test multiple functions at a time. Functions are always loaded on-demand, so they're always up-to-date. TypeScript functions are supported out-of-the-box.

Pre-requisites

pnpm install esbuild -D

Usage

// ==UserScript==
// @name Replace Clip with Save on YouTube
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Replaces the Clip button with the Save button on YouTube video pages
// @author You
// @match https://www.youtube.com/*
// @grant none
// @source https://gist.github.com/aleclarson/60fc2c4fd9276ceba0063066a4e55ef8
// ==/UserScript==
@aleclarson
aleclarson / script.js
Last active February 8, 2025 19:56
YouTube feedback shortcut – TamperMonkey
// ==UserScript==
// @name YouTube Enhanced Interaction
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Enhanced click handling for YouTube recommendations
// @author You
// @match https://www.youtube.com/*
// @grant none
// ==/UserScript==

This gist is a further condensed version of https://svelte.dev/llms-small.txt from https://svelte.dev/docs/llms

Removed sections

These sections were removed to optimize the context window. Each section was deemed non-critical for MVP purposes or its use cases were deemed too niche. When developing a brownfield Svelte app, many of these sections should not be removed.

  • Overview
  • Getting Started
  • Accessibility
  • SEO