Skip to content
Runtime
Framework

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
InstallQuick examplePackage: @queryweave/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.

  • Reading route.query and converting it to entries, preserving repeated keys.
  • Navigating with router.push and router.replace, keeping the current path and hash.
  • Watching route.fullPath and reporting changes.
  • Reporting navigation failures instead of throwing.

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

  1. QueryModel (meaning)
  2. QueryRuntime (transitions)
  3. QueryAdapter (synchronization)
  4. Vue Router (environment)

QueryModel → QueryRuntime. QueryRuntime → QueryAdapter. QueryAdapter → Vue Router.

The router owns navigation. QueryWeave owns meaning. The adapter is the seam.
Terminal window
pnpm add @queryweave/core @queryweave/vue-router
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),
});

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.

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
  • Path and hash survive every transition; only the query is rewritten.
  • A null query 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.

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.