Case StudiesA Shared Component Architecture for a WordPress Booking Plugin - 4 Case Studies

I built and maintained the shared component library behind PreBook, a WordPress appointment-booking plugin, solo across roughly a year - December 2023 to November 2024. 44 Vue components, 3,639 lines, serve two independently built apps - an admin app and a customer-facing booking frontend - through a shared alias, with no published package between them. Four linked case studies cover API design, state management, resilient input handling, and codebase structure.
PreBook is a WordPress plugin that adds appointment booking to a site - staff, services, availability, and the booking flow itself. It ships two Vue 3 single-page apps - an admin app and a customer-facing frontend - plus a third build target, a Gutenberg block, that embeds booking into the WordPress block editor.
Both apps needed the same primitives - selects, inputs, modals, date and time pickers, menus - and building each twice risked every fix and design change drifting out of sync. I built a single src/components/ library instead: 44 components, 3,639 lines, imported through one barrel file and wired into both apps' build configs via an identical @components alias rather than a published npm package.
I authored essentially all of it solo, across 287 commits, over roughly a year. The four case studies below cover the decisions behind it: where to draw the reuse boundary, how to keep state thin, how to make an input component survive real-world data, and how to keep three build targets pointed at one source of truth.
The boundary-drawing case study. Where reuse paid off, and where it didn't - Select's fifteen-commit arc against a moving spec, and why Menu's wrapper stayed shared while MenuItem stayed app-local.
The state case study. Seventeen admin stores and four frontend stores migrated to Composition-API defineStore form, kept thin by routing through one shared @model/@utils layer instead of duplicating logic per store.
The input-handling case study. InputPrice's eighteen-commit fight to keep the cursor stable while reformatting a number on every keystroke across four ambiguous locale separator conventions - and why the bug resurfaced even after an optimization pass.
The structure case study. How one path-alias convention and matching Tailwind purge scanning kept three build targets - two Vite apps and a webpack Gutenberg block - pointed at one component source, plus a counter-example where utility classes were deliberately moved back to plain CSS.
What is PreBook?
A WordPress plugin that adds appointment booking to a site - staff, services, and availability on the admin side, booking on the customer-facing side.
What does "shared" mean here if there's no published package?
The two apps aren't separate consumers pulling a versioned dependency - they're two Vite builds aliasing @components to the same folder on disk, so a change is live in both apps' next build with nothing to publish.
What was the measurable outcome?
44 components, 3,639 lines, serve both apps from one source, with 17 admin stores and 4 frontend stores routed through a shared data layer instead of each app re-implementing its own.Related case studies
Structuring a Large Frontend Codebase for Maintainability at Scale
Two independently-built Vue apps and a webpack-built Gutenberg block shared one component library through a consistent alias system and a per-app Tailwind purge - except in the one place plain CSS won.Engineering Resilient Input Components for Real-World Data
Building a price input for PreBook that reformats live with locale-correct separators while keeping the text cursor exactly where the user left it.