Replacing a 15MB Calendar Dependency With 76KB of Our Own
We paid for Bryntum Calendar, fought it on every style change, and shipped 15MB of it. The replacement is 76KB, and a rough Claude Code plugin of mine helped get us there.
Zain Wania6 min read
Some UI libraries cost money, fight every style change you make, and weigh more than all of your app's feature code put together. Ours was Bryntum Calendar. After months of putting up with it, we took it out.
This is how we did it, and why the scrappiest tool I own turned out to be the most useful part of the job.
Calendars in Vue are rough
The decision to use Bryntum only makes sense once you've looked at the alternatives.
If you need a full-featured calendar in React, you have real choices. FullCalendar has solid React support and the path is well worn. In Vue, and especially in Nuxt, it's grim. You search and find libraries whose last commit was in 2021, wrappers around jQuery plugins, and "Vue adapters" that were clearly bolted on after the fact. The TypeScript support runs from grudging to decorative, and getting an event handler to do something useful means learning three layers of someone else's abstractions.
So picking Bryntum wasn't naive. It was one of the few options that actually worked.
It is full-featured. Recurring events, drag and drop, and resource views all come in the box. The problems showed up a few months in:
- Styling. Bryntum has its own theme engine, its own CSS variables, and strong opinions about how everything should look. Making it match our design system meant overriding generated class names and hoping nothing else moved. We weren't customizing it so much as arguing with it.
- Types. The TypeScript support felt like an afterthought, and autocomplete gave out right when we needed it.
- Cost. It's a paid license. That's fine when you're getting value from it. It's harder to justify when a ten-minute CSS change takes two hours.
Then we asked the question we should have asked at the start: what are we getting for 15MB?
A Gantt chart renderer, resource histograms, a spreadsheet module, and a full enterprise scheduling engine, as it turned out. Bryntum isn't really a calendar. It's a scheduling platform that has a calendar in it, and we were using maybe 10% of what we shipped while the rest rode along in our bundle.
Our replacement is 76KB. That covers event rendering, date navigation, and grid layout. We didn't do anything clever to get there. We only built what we needed.
Building the replacement
We already use Nuxt UI across the codebase, so the buttons, inputs, dropdowns, and popovers were there. The calendar-specific logic turned out to be the smaller part of what Bryntum was doing for us. We built the calendar pieces ourselves on top of components we already trusted. It takes styling without a fight and matches the design system because it's made of the design system. There are still edge cases to iron out, but it's ours.
The part I'm proud of and a bit embarrassed by: I used my own Claude Code plugin to help with the migration.
It's called auto-research. The idea isn't new. It traces back to Andrej Karpathy's thinking on autonomous, research-driven coding, then to pi-autoresearch as an early implementation, and then to this tweet from Tobi Lütke. Tobi ran /autoresearch against Shopify's Liquid codebase and got 53% faster combined parse and render time with 61% fewer object allocations. His verdict: "This is probably somewhat overfit, but there are absolutely amazing ideas in this." That was enough for me to start building my own.
Running /research <task> kicks off six steps:
- Parse the task.
- Spawn three to five subagents that investigate approaches in parallel, using web search and codebase analysis at the same time.
- Synthesize and rank what they found.
- Implement the top approach with Claude Opus.
- Verify the result against your toolchain.
- Auto-fix failures, up to a configurable retry limit.
It also saves session state, so an interruption doesn't throw away the work.
For the migration, I used it to do the thinking up front. Instead of digging through Bryntum's event model by hand to work out which Nuxt UI components could replace what, I described the task and let the subagents go wide. What came back was a ranked list of approaches with real reasoning about the tradeoffs. Because the research had actually been done, the implementation went more smoothly.
It isn't production grade. "Scuffed but useful" is accurate, and that's a perfectly good kind of tool to have.
AI is putting pressure on bad software
The broader point is that plenty of the component libraries teams have been locked into for years aren't good. They were the least bad option back when building an alternative was slow and expensive. Switching cost a lot, building cost more, and mediocre software kept collecting license fees.
AI changes that math. It doesn't write perfect code. It is good at producing UI components that look clean, are properly typed, and are styled the way you want. The gap between using the library and building your own used to be huge, and it's closing fast, especially on styling and visuals, which is where many of these libraries have always been weakest.
That's real pressure on component vendors. If your moat is "we did the hard work so you don't have to," and the hard work is measurably easier now, you need another reason for people to pay you. We asked a simple question about our bundle, didn't like the answer, and replacing the library turned out to be far smaller than it would have been two years ago.
None of this means you should build everything yourself. Sometimes the library really is the right call. But the bar for replacing one has dropped, and some libraries that used to clear it easily don't anymore.
The plugin is at github.com/ZainW/ai-plugins if you want to try it. Keep your expectations modest. It's a work in progress, like the rest of us.