I think I might still have issues with import cycles. I thought I could use dynamic imports to avoid them, but it looks like any kind of import cycle is a problem, not just static ones.
I solved this (well, me and Claude 3.5 solved it). In case it's helpful to others, here's the solution (I which discord would publish these threads on the web so this stuff was more findable)
export function createHotStableContext<T>(name: string, defaultValue?: T): Context<T> {
const contextKey = `hot-context-${name}`
const {hot} = import.meta
if (hot) {
return hot.data[contextKey] ??= createContext<T>(defaultValue as T)
It's already in a different file but that file is getting reloaded when I make a change to a component file that (indirectly) imports it. I guess I need to understand more about how vite HMR decides which modules to reload.