Move registry calls from component to loader in admin.sports.$id

SIMULATOR_TYPES and getSimulatorInfo were used directly in the component
body to build the simulator type dropdown. This dragged registry.ts —
which imports every simulator implementation — into the client bundle,
causing a TDZ ReferenceError that broke any route co-loaded with it
(observed as "Error loading route module" on admin events pages).

Fix: pre-build simulatorOptions in the loader and pass them as plain
serializable data. The registry imports remain for the action's
validator but are now only reachable from server-only code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Parsons 2026-05-11 22:49:00 -07:00
parent 7c94657417
commit 5cc025bfd3

View file

@ -34,8 +34,17 @@ export async function loader({ params }: Route.LoaderArgs) {
const sports = await findAllSports();
const simulatorOptions = [...SIMULATOR_TYPES]
.toSorted((a, b) => {
const nameA = getSimulatorInfo(a)?.name ?? a;
const nameB = getSimulatorInfo(b)?.name ?? b;
return nameA.localeCompare(nameB);
})
.map((type) => ({ value: type, label: getSimulatorInfo(type)?.name ?? type }));
return {
sport,
simulatorOptions,
existingIconOptions: sports
.filter((option) => option.id !== sport.id && Boolean(option.iconUrl))
.map((option) => ({ id: option.id, name: option.name, iconUrl: option.iconUrl as string })),
@ -116,7 +125,7 @@ export async function action({ request, params }: Route.ActionArgs) {
}
export default function EditSport({ loaderData, actionData }: Route.ComponentProps) {
const { sport, existingIconOptions } = loaderData;
const { sport, simulatorOptions, existingIconOptions } = loaderData;
return (
<div className="p-8">
@ -185,17 +194,11 @@ export default function EditSport({ loaderData, actionData }: Route.ComponentPro
className={SELECT_CLASS}
>
<option value="none">No simulator</option>
{[...SIMULATOR_TYPES]
.toSorted((a, b) => {
const nameA = getSimulatorInfo(a)?.name ?? a;
const nameB = getSimulatorInfo(b)?.name ?? b;
return nameA.localeCompare(nameB);
})
.map((type) => (
<option key={type} value={type}>
{getSimulatorInfo(type)?.name ?? type}
</option>
))}
{simulatorOptions.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
<p className="text-sm text-muted-foreground">
Algorithm used when running EV simulations for this sport