vue-tiny-router
v1.9.0
Published
A lightweight Vue 3 router (~2.2 kB Brotli) with params, query, guards, nested layouts, lazy loading, and redirects
Maintainers
Readme
vue-tiny-router
A lightweight Vue 3 router. ~2.2 kB Brotli with the common SPA router features most apps need.
Why vue-tiny-router?
- 🤏 Tiny: ~2.2 kB Brotli
- ⚡ Fast: Minimal overhead, maximum performance
- 🎯 Simple: Easy setup, intuitive API
- 💪 Complete: Route params, query, names, guards, nested layouts, lazy loading, redirects
How It Compares
| Router | Best For | Why choose vue-tiny-router? |
|--------|----------|-----------------------------|
| vue-router | Large Vue apps needing every router feature | vue-tiny-router covers common Vue SPA routing at a fraction of the size |
Quick Start
1. Install
npm install vue-tiny-router2. Setup
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import { TinyRouterInstall } from 'vue-tiny-router'
createApp(App)
.use(TinyRouterInstall)
.mount('#app')3. Configure Routes
<!-- App.vue -->
<template>
<TinyRouter :routes="routes" />
</template>
<script>
import { TinyRouter } from 'vue-tiny-router'
import Home from './views/Home.vue'
import Profile from './views/Profile.vue'
import NotFound from './views/NotFound.vue'
export default {
components: { TinyRouter },
data() {
return {
routes: [
{ path: '/', component: Home },
{ path: '/profile/:id', component: Profile },
{ path: '/*', component: NotFound } // catch-all 404,
]
}
}
}
</script>4. Navigate
<template>
<button @click="$router.push('/')">Home</button>
<button @click="$router.push('/profile/123')">Profile</button>
</template>5. Composition API (setup)
Use the provided composables in <script setup> or setup():
<script setup>
import { TinyRouter, useRouter, useRoute } from 'vue-tiny-router'
const router = useRouter()
const route = useRoute()
function goUser(id) {
router.push(`/profile/${id}`)
}
</script>
<template>
<TinyRouter :routes="routes" />
<div>Current: {{ route.route }}</div>
<div>User id: {{ route.params.id }}</div>
<button @click="goUser('42')">Go user 42</button>
<button @click="router.push('/')">Home</button>
<button @click="router.push('/profile/123')">Profile</button>
</template>That's it! 🎉
API Reference
Router Methods
$router.push(path | location)- Navigate to a route (adds history entry)$router.replace(path | location)- Navigate without adding history entry$router.back()- Go back in history$router.forward()- Go forward in history$router.go(n)- Go to a specific history entry$router.beforeEach(fn)- Register a global guard$router.afterEach(fn)- Register an after-navigation hook$router.route- Current route path$router.params- Route parameters object$router.query- Parsed query object$router.meta- Current route metadata
Composables
useRouter()- Returns an object with:push(path | location)- Navigate programmatically (adds history entry)replace(path | location)- Navigate without adding history entryback()/forward()/go(n)- History navigationbeforeEach(fn)/afterEach(fn)- Global navigation hooksroute/path- Reactive current route stringsparams- Reactive params objectquery- Parsed query objecthash- Current hash without#name- Current route namematched- Whether a route matchedmeta- Reactive route metadatacomponent- Current matched component (non-reactive reference)
useRoute()- Returns an object with:route/path- Reactive current route stringsparams- Reactive params objectquery- Parsed query objecthash- Current hash without#name- Current route namematched- Whether a route matchedmeta- Reactive route metadata
Component Props
<TinyRouter
:routes="routes" // Required: Array of route objects
:redirects="redirects" // Optional: Redirect mappings
mode="history" // Optional: "history", "hash", or "memory"
:memoryMode="false" // Optional: legacy shortcut for mode="memory"
:scrollSmooth="false" // Optional: smooth scrolling on navigation
/>Base path (subpath deployments)
If your app is served from a subpath (e.g. example.com/jsmap/), vue-tiny-router automatically reads Vite's import.meta.env.BASE_URL — no config needed. Just set base in vite.config.js:
// vite.config.js
export default { base: '/jsmap/' }Routes stay app-relative (/, /about, /user/:id) — the router strips the base prefix when matching and re-adds it when writing to history. For non-Vite bundlers, override the basePath ref before mount:
import { basePath } from 'vue-tiny-router'
basePath.value = '/jsmap/'Advanced Features
Route Parameters
Access dynamic route segments:
// Route: /user/:id
// URL: /user/123
this.$router.params.id // "123"Query Strings
Query strings are parsed into a small object and can also be written through object navigation:
router.push({ path: '/search', query: { q: 'vue', page: 2 } })
route.query.q // "vue"Named Routes
Add name to a route and navigate with params:
const routes = [
{ path: '/user/:id', name: 'user', component: User }
]
router.push({ name: 'user', params: { id: 42 } })Route Meta
Attach metadata to routes for page titles, auth checks, etc:
const routes = [
{ path: '/', component: Home, meta: { title: 'Home' } },
{ path: '/admin', component: Admin, meta: { requiresAuth: true } }
]
// Access in components
const route = useRoute()
document.title = route.meta.titleRoute Guards
Prevent navigation or add animations:
export default {
beforeRouteLeave(next, to) {
// Do something async, then call next()
this.saveData().then(next)
}
}Global guards are return-based to stay compact:
const remove = router.beforeEach((to, from) => {
if (to.meta.requiresAuth && !isLoggedIn()) return '/login'
if (hasUnsavedChanges()) return false
})Nested Layouts
Use children for nested layouts. Parent components render children through their default slot:
const routes = [
{
path: '/user/:id',
component: UserLayout,
children: [
{ path: 'settings', component: UserSettings }
]
}
]Lazy Loading
Reduce initial bundle size:
import { defineAsyncComponent } from 'vue'
const routes = [
{
path: '/heavy',
component: defineAsyncComponent(() => import('./HeavyComponent.vue'))
}
]Redirects
const redirects = {
'/old-path': '/new-path',
'/home': '/'
}Default Routes
import { defaultRoute } from 'vue-tiny-router'
defaultRoute.value = '/dashboard'Memory Mode
Perfect for embedded apps or testing:
<TinyRouter :routes="routes" :memoryMode="true" />Hash Mode
Use hash URLs for static hosting:
<TinyRouter :routes="routes" mode="hash" />Automatic Link Interception
vue-tiny-router automatically intercepts clicks on <a> tags. If the link's destination is a route managed by the router, it will prevent a page reload and handle it as an in-app navigation. For all other links (external sites or unhandled paths), it will allow the browser's default behavior. No configuration is needed.
Migration from vue-router
Most common patterns work the same:
| vue-router | vue-tiny-router |
|------------|-----------------|
| $router.push() | $router.push() ✅ |
| $router.replace() | $router.replace() ✅ |
| $router.back() | $router.back() ✅ |
| $router.go(n) | $router.go(n) ✅ |
| $route.params | $router.params ✅ |
| $route.query | $router.query ✅ |
| $route.meta | $router.meta ✅ |
| Named routes | Named routes ✅ |
| Nested routes | Nested layout routes ✅ |
| Global guards | Global guards ✅ |
| beforeRouteLeave | beforeRouteLeave ✅ |
| Lazy loading | Lazy loading ✅ |
Example & Documentation
🎯 Live Example
pnpm run devThe example demonstrates all features including:
- Route parameters
- Query strings
- Named routes
- Route guards
- Nested layouts
- Hash mode
- Anchor links
- Memory mode
- Redirects
📚 Full Documentation
# Run the VitePress documentation
pnpm run docs:devOr view online: Vue Tiny Router Docs
Browser Support
Works in all modern browsers that support ES6+ and the History API.
Limitations
This library is intentionally tiny and focuses on the 80% use cases:
- No named views
- No route-level
beforeEnterguards - No advanced scroll behavior callback
- No Vue Router DevTools integration
If you need these features, consider using vue-router.
Contributing
Keep it tiny! When contributing:
- Maintain minimal bundle size
- Ensure all tests pass
- Follow the simple API design
Run the full development setup:
# Run tests
pnpm test
# Check bundle size
pnpm run size:check
# Run example app
pnpm run example:dev
# Run documentation
pnpm run docs:devLicense
MIT
