Vue Router
Framework
A router-backed adapter that keeps path and hash intact.
- Package
- @queryweave/vue-router
- Runtime
- Vue Router application
- Depends on
- @queryweave/core
- Requires
- vue, vue-router
This package produces an adapter and nothing else. It depends on @queryweave/core alone — not on
@queryweave/vue — so router synchronization can be adopted without the Vue binding.
What it owns
Section titled “What it owns”- Reading
route.queryand converting it to entries, preserving repeated keys. - Navigating with
router.pushandrouter.replace, keeping the current path and hash. - Watching
route.fullPathand reporting changes. - Reporting navigation failures instead of throwing.
What it does not own
Section titled “What it does not own”Decoding, validation, defaults, and the Vue binding. Those belong to the model and to
@queryweave/vue.
Mutable environment — reads, navigates, and notifies
Mutable environment — reads, navigates, and notifies
- QueryModel (meaning)
- QueryRuntime (transitions)
- QueryAdapter (synchronization)
- Vue Router (environment)
QueryModel → QueryRuntime. QueryRuntime → QueryAdapter. QueryAdapter → Vue Router.
Install
Section titled “Install”pnpm add @queryweave/core @queryweave/vue-routerExample
Section titled “Example”import { createVueRouterAdapter } from "@queryweave/vue-router";import { provideQueryAdapter, useQueryModel } from "@queryweave/vue";import { useRouter } from "vue-router";
import { products } from "./products";
const router = useRouter();const adapter = createVueRouterAdapter(router);
provideQueryAdapter(adapter);const filters = useQueryModel(products);
async function showNextPage(): Promise<void> { // current route: /products#results, page defaults to 1 await filters.update({ page: filters.values.page + 1 }); // /products?page=2#results — the current path and hash are preserved}Without the Vue binding, drive it directly:
import { createQueryRuntime } from "@queryweave/core";
const runtime = createQueryRuntime({ model: products, adapter: createVueRouterAdapter(router),});Handling refused navigation
Section titled “Handling refused navigation”Router navigation can be cancelled by a guard or redirected. That is an environment condition, not a programming error, so the adapter reports it rather than throwing into your transition:
const adapter = createVueRouterAdapter(router, { onNavigationFailure: (outcome) => { if (!outcome.ok) { console.warn("Query navigation was refused", outcome.failure); } },});outcome.failure is Vue Router’s own NavigationFailure, or an Error if the router threw.
Which adapter should you use?
Section titled “Which adapter should you use?”If your application already has Vue Router, use this one rather than
@queryweave/browser. Two writers on one history stack — the router and the
History API — will fight, and the router will not know about writes it did not make.
| Situation | Adapter |
|---|---|
| Vue Router present | @queryweave/vue-router |
| Vue without a router | @queryweave/browser |
| Nuxt | Nuxt wires this one for you |
| Tests, or no environment at all | @queryweave/testing |
Edge cases
Section titled “Edge cases”- Path and hash survive every transition; only the query is rewritten.
- A
nullquery value — Vue Router’s representation of?flag— becomes an empty string entry. - Repeated keys round-trip through the router’s array form.
- Notification comes from the route watcher, not from
push, because the router already reports its own changes. This is why one transition still produces exactly one notification. - After
dispose, the watcher stops and later navigation throws.
How it is tested
Section titled “How it is tested”tests/vue-router/adapter.test.ts drives a real router through push, replace, guard-refused
navigation, and repeated keys. The vue-router consumer fixture runs the packed archive against a
router outside the workspace.