Notes From Migrating a Large App to Vite
I've been working with Vite for about 7 years now, and my opinions on design tokens have changed more than I expected.
The setup was ordinary: Vite at the edges, React doing most of the heavy lifting, and a handful of scripts nobody wanted to own. It worked well until usage roughly doubled over a single quarter.
The problem
Most of the complexity was accidental. Over the years we'd layered three different approaches to design tokens on top of each other, and each one made sense at the time.
When we finally measured, the numbers were worse than anyone guessed. Around 42% of the time spent on a typical change went into working around design tokens rather than building anything.
What we changed
The key insight was to treat design tokens as part of the interface rather than an implementation detail. Once we did that, most of the other decisions followed naturally.
Stripped of the project-specific bits, it looks like this:
export function debounce<T extends (...args: any[]) => void>(fn: T, wait = 200) {
let timer: ReturnType<typeof setTimeout> | undefined;
return (...args: Parameters<T>) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), wait);
};
}
Nothing about this is clever, and that's the point. Anyone on the team can read it in a minute and know exactly what it does.
A few things that helped along the way:
- Keep the old path around until the new one has survived a real incident.
- Make the default the safe choice, not just the documented one.
- Write the migration guide before writing the migration.
Where this breaks down
None of this is free. The new approach is a bit more verbose, and newcomers occasionally ask why we don't just use TypeScript for everything. That's a fair question with a boring answer: we tried, and it made design tokens harder to reason about.
The biggest cost was social, not technical. Changing how people think about design tokens takes much longer than changing the code.
Takeaways
That's it for now. Next time I'll dig into bundle size, which turned out to be closely related.