storybook-vue3-router
A Storybook decorator that wraps Vue 3 components in vue-router so routing-aware stories render, navigate, and test correctly.
Repository Health
Technical Analysis
storybook-vue3-router is a Storybook addon that lets you build stories for Vue 3 components relying on vue-router — anything using <router-view> or <router-link>. It exports a vueRouter decorator that either creates a full vue-router instance (with default or custom routes, navigation guards, and router options) or reuses/resets an existing one across story re-renders, plus an asyncVueRouter variant for components that wait on router.isReady() during their created/setup lifecycle.
For simpler cases, a mockRouter decorator stubs just the $route and $router properties (path, params, query, meta) without booting a real router — useful for components that only read route state via the Options API rather than the router-view/router-link composables. The library ships as ESM with full TypeScript types, targets Storybook 10.x / Vue 3.5 / vue-router 4.6 as peer dependencies, and has been through several major-version migrations tracking Storybook’s own version bumps (v2.x for Storybook 6 through v7.x for Storybook 10).
What You Get
- vueRouter decorator - wraps a story in a real vue-router instance with default or custom routes, reusing/resetting the router across re-renders instead of remounting the whole app.
- asyncVueRouter decorator - the same router setup, but delays rendering the story until router.isReady() resolves, for components that read route data in created()/setup().
- mockRouter decorator - stubs $router (push/replace/go/back/forward as Storybook actions) and $route (path, params, query, meta) without booting a real router.
- Router options passthrough - forwards Vue Router’s own createRouter options (history mode, linkActiveClass, etc.) straight through the decorator’s config.
- Storybook preset - a config()/managerEntries() preset wires the decorator into Storybook’s build automatically once installed.
Common Use Cases
- Testing router-link navigation - a designer or engineer clicks between router-link components inside a story to verify active-link styling and route transitions without running the full app.
- Isolating a page component that reads $route.params - a developer stories out a single page/view component that expects route params or query strings, using mockRouter to supply fake values.
- Documenting components behind navigation guards - a team demos a component protected by a per-route or global beforeEach guard, using custom routes with beforeEnter or the beforeEach option.
- Reviewing async-router-dependent components - a reviewer previews a component that calls router.isReady() before rendering, using asyncVueRouter combined with a <Suspense> wrapper in preview.js.
Under The Hood
Architecture The package is a flat set of single-purpose decorator functions (withVueRouter, withAsyncVueRouter, withMockRouter) exported from src/index.ts, each returning a Storybook Decorator that wraps a story in a Vue 3 setup() using getCurrentInstance() to reach the app context. withVueRouter detects an existing (possibly mocked) router on app.config.globalProperties, reuses or recreates it via vue-router’s createRouter/createWebHashHistory, and resets routes between stories through router.removeRoute/addRoute helpers in utils.ts, while withMockRouter stubs $router/$route directly onto the app config for lighter-weight cases. A small preset (src/preset/index.js, manager.js, preview.ts) wires the decorator into Storybook’s config()/managerEntries() lifecycle. The design has no internal layering beyond decorator/utils/preset, and the only fragile surface is how routers are detected and reset across story re-renders — narrow and well contained.
Tech Stack Written in TypeScript and compiled via Rollup (rollup-plugin-esbuild for JS, rollup-plugin-dts for type declarations) into ESM with bundled .d.ts files. It targets Storybook 10.x and Vue 3.5/vue-router 4.6 as peer dependencies, uses Vite (via @vitejs/plugin-vue) to run Storybook locally, and drives Playwright end-to-end tests against a deployed Storybook build hosted on Netlify. tsconfig targets ESNext with bundler module resolution and strict noImplicitAny.
Code Quality Tests live under tests/ as Playwright specs (BasicVueRouterWrapper, GlobalComponentInPreview, MockRouter, README, RouterGuards) that click through the live, deployed Storybook demo rather than unit-testing the decorator functions in isolation — an integration-only strategy with no unit coverage for utils.ts’s route-reset or guard logic. Source is fully typed, re-exports vue-router’s own types directly, and uses sparse but purposeful comments (e.g. flagging the isMocked hack). A GitHub Actions workflow (test.yml) runs the Playwright suite; no dedicated linter config was found beyond Prettier formatting.
API Design The core idea — detecting an already-mocked or already-initialized router on app.config.globalProperties and transparently reusing or recreating it — solves a real Storybook-specific problem (stories re-rendering without a full app remount) that a naive “call createRouter every time” approach would break. The exported vueRouter/asyncVueRouter/mockRouter surface is minimal and mirrors vue-router’s own routes/options vocabulary, keeping the learning curve low, though the README candidly flags the router.go(0) reload trick used for global beforeEach guards as “hacky.”