@openwebf/vue-router
v1.0.0
Published
Vue Router implementation for WebF applications using hybrid history API
Readme
@openwebf/vue-router
A Vue Router implementation for WebF applications using hybrid history API. This package provides navigation and routing capabilities specifically designed for WebF's hybrid environment, combining web-like history management with Flutter-like navigation patterns.
Features
- 🚀 Hybrid Navigation: Seamlessly bridge between WebF's native navigation and Vue's routing
- 📱 Flutter-like API: Familiar navigation methods like
push,pop,popUntil, etc. - 🎯 Type-safe Routing: Full TypeScript support with type-safe route parameters
- ⚡ Performance Optimized:
prerendersupport and smart component lifecycle management - 🔄 State Management: Pass and receive data between routes with ease
- 📊 Route Context: Access route information anywhere in your component tree
Runtime Requirements (WebF)
This router is designed for the WebF environment and expects:
webf.hybridHistory(navigation runtime)<webf-router-link>(route container element that firesonscreen/offscreenandhybridrouterchange)
It is not intended to be used in a normal browser environment.
Installation
npm install @openwebf/vue-router
# or
yarn add @openwebf/vue-router
# or
pnpm add @openwebf/vue-routerPeer Dependencies
This package requires the following peer dependencies:
vue>= 3.0.0@openwebf/webf-enterprise-typings>= 0.22.0
Quick Start
<template>
<div id="app">
<Routes>
<Route path="/" :element="HomePage" title="Home" />
<Route path="/about" :element="AboutPage" title="About" />
<Route path="/profile" :element="ProfilePage" title="Profile" :prerender="true" />
</Routes>
</div>
</template>
<script setup>
import { Routes, Route } from '@openwebf/vue-router';
import HomePage from './pages/HomePage.vue';
import AboutPage from './pages/AboutPage.vue';
import ProfilePage from './pages/ProfilePage.vue';
</script>Core Components
<Routes>
The container component that wraps all your routes and provides the routing context.
<Routes>
<!-- Your Route components go here -->
</Routes><Route>
Defines a single route in your application.
<Route
path="/profile"
:element="ProfilePage"
title="Profile"
:prerender="true"
/>Props
path(string, required): The path pattern for this routeelement(Component | string, required): The component to render when this route is activetitle(string, optional): Title for the routeprerender(boolean, optional): Whether to pre-render this route for better performancetheme('material' | 'cupertino', optional): Forwarded to<webf-router-link>
Composition API
useNavigate()
Returns navigation methods to programmatically navigate between routes.
<script setup>
import { useNavigate } from '@openwebf/vue-router';
const { navigate, pop, canPop, popAndPush } = useNavigate();
const handleLogin = async () => {
await loginUser();
// Navigate to dashboard
navigate('/dashboard');
// Navigate with state
navigate('/profile', { state: { from: 'login' } });
// Replace current route
navigate('/home', { replace: true });
// Go back
navigate(-1);
};
const handleCancel = () => {
if (canPop()) {
pop(); // Go back
} else {
navigate('/'); // Go to home if can't go back
}
};
</script>Navigation Methods
navigate(to, options?): Navigate to a routeto: string (path) or number (-1 for back)options: { replace?: boolean, state?: any }
pop(result?): Go back to the previous routepopUntil(path): Pop routes until reaching a specific routepopAndPush(path, state?): Pop current route and push a new onepushAndRemoveUntil(newPath, untilPath, state?): Push new route and remove all routes until a specific routecanPop(): Check if navigation can go backmaybePop(result?): Pop if possible, returns boolean
useLocation()
Returns the current location object with pathname and state.
<script setup>
import { useLocation } from '@openwebf/vue-router';
const location = useLocation();
console.log('Current path:', location.value.pathname);
console.log('Location state:', location.value.state);
console.log('Is active:', location.value.isActive);
</script>
<template>
<div>
<h1>Profile Page</h1>
<p v-if="location.state?.from">
You came from: {{ location.state.from }}
</p>
</div>
</template>useRouteContext()
Access detailed route context information.
<script setup>
import { computed } from 'vue';
import { useRouteContext } from '@openwebf/vue-router';
const route = useRouteContext();
const userId = computed(() => route.value.routeParams?.id ?? '(missing)');
if (route.value.isActive) {
console.log('This route is currently active');
console.log('Active path:', route.value.activePath);
console.log('Route params:', route.value.routeParams);
console.log('Route state:', route.value.params);
}
</script>useParams()
Get route parameters from dynamic routes.
<script setup>
// For route pattern "/user/:userId" and actual path "/user/123"
import { computed } from 'vue';
import { useParams } from '@openwebf/vue-router';
const params = useParams();
console.log(params.value.userId); // "123"
const userId = computed(() => params.value.userId ?? '(missing)');
</script>
<template>
<div>User ID: {{ userId }}</div>
</template>useRoutes()
Create routes from a configuration object.
<script setup>
import { useRoutes } from '@openwebf/vue-router';
import { defineComponent } from 'vue';
import HomePage from './pages/HomePage.vue';
import AboutPage from './pages/AboutPage.vue';
const routesVNode = useRoutes([
{ path: '/', element: HomePage, title: 'Home' },
{ path: '/about', element: AboutPage, title: 'About' },
{ path: '/profile', element: 'ProfilePage', prerender: true }, // Registered component name (string)
]);
const RoutesView = defineComponent({
name: 'RoutesView',
setup() {
return () => routesVNode;
},
});
</script>
<template>
<RoutesView />
</template>Advanced Usage
Dynamic Routes
Support for route parameters like React Router:
<template>
<Routes>
<Route path="/user/:userId" :element="UserPage" />
<Route path="/posts/:postId/comments/:commentId" :element="CommentPage" />
</Routes>
</template>
<script setup>
// In UserPage component
import { useParams } from '@openwebf/vue-router';
const params = useParams(); // computed ref
// Access params.value.userId in script, or params.userId in template
</script>Wildcard Routes
<Routes>
<Route path="/files/*" :element="FilesPage" />
</Routes>
<script setup>
import { computed } from 'vue';
import { useParams } from '@openwebf/vue-router';
const params = useParams();
const splat = computed(() => params.value['*'] ?? '(missing)');
</script>Passing State Between Routes
<script setup>
// Navigate with state
const { navigate } = useNavigate();
navigate('/details', {
state: {
productId: 123,
from: 'catalog'
}
});
// Access state in the target component
const location = useLocation();
const { productId, from } = location.value.state || {};
</script>Pre-rendering Routes
Pre-rendering improves performance by rendering routes before they're navigated to:
<Routes>
<Route path="/" :element="Home" />
<Route path="/dashboard" :element="Dashboard" :prerender="true" />
<Route path="/profile" :element="Profile" :prerender="true" />
</Routes>Programmatic Navigation Patterns
<script setup>
const nav = useNavigate();
// Simple navigation
const goToHome = () => nav.navigate('/');
// Replace current entry
const replaceWithLogin = () => nav.navigate('/login', { replace: true });
// Navigate with complex state
const goToProduct = (product) => {
nav.navigate(`/products/${product.id}`, {
state: {
product,
timestamp: Date.now()
}
});
};
// Complex navigation flow
const completeCheckout = async () => {
// Process payment...
await processPayment();
// Go to success page and prevent going back to checkout
await nav.pushAndRemoveUntil('/success', '/');
};
// Conditional navigation
const smartBack = () => {
if (nav.canPop()) {
nav.pop();
} else {
nav.navigate('/');
}
};
</script>WebF Router API
The package exports a WebFRouter object that provides low-level access to the routing system:
import { WebFRouter } from '@openwebf/vue-router';
// Get current route info
console.log('Current path:', WebFRouter.path);
console.log('Current state:', WebFRouter.state);
// Navigation methods
WebFRouter.push('/new-route', { data: 'value' });
WebFRouter.replace('/replacement-route');
WebFRouter.back();
WebFRouter.pop();
WebFRouter.popUntil('/target');TypeScript Support
This package is written in TypeScript and provides complete type definitions:
import { useNavigate, useLocation } from '@openwebf/vue-router';
import type { NavigateOptions, Location } from '@openwebf/vue-router';
interface ProfileState {
userId: string;
referrer?: string;
}
// Navigate with typed state
const { navigate } = useNavigate();
navigate('/profile', {
state: {
userId: '123',
referrer: 'dashboard'
} as ProfileState
});
// Access typed state
const location = useLocation();
const state = location.value.state as ProfileState | undefined;
if (state?.userId) {
// TypeScript knows state.userId is a string
}Best Practices
- Use Pre-rendering for Heavy Components: Enable
prerenderfor routes with expensive initial renders - Clean Up State: Be mindful of state passed between routes, especially for sensitive data
- Handle Missing State: Always provide fallbacks when accessing route state
- Use Type Safety: Leverage TypeScript for route paths and state objects
- Component Types:
elementcan be a Vue component, or a registered component name string
Migration from Vue Router
If you're migrating from standard Vue Router, here are the key differences:
- Navigation API: Use
navigate()instead ofrouter.push() - Route State: State is passed differently and accessed via
useLocation() - No Nested Routes: Current version doesn't support nested routes
- Flutter-like Methods: Additional navigation methods like
popUntil,popAndPush - Component Structure: Use
<Routes>and<Route>instead of<router-view>
Examples
In this repo, a runnable demo app lives at vue_usecases/.
Basic Setup
<template>
<div id="app">
<Routes>
<Route path="/" :element="HomePage" title="Home" />
<Route path="/about" :element="AboutPage" title="About" />
<Route path="/contact" :element="ContactPage" title="Contact" />
</Routes>
</div>
</template>
<script setup>
import { Routes, Route } from '@openwebf/vue-router';
import HomePage from './pages/HomePage.vue';
import AboutPage from './pages/AboutPage.vue';
import ContactPage from './pages/ContactPage.vue';
</script>Navigation Component
<template>
<nav>
<button @click="() => navigate('/')">Home</button>
<button @click="() => navigate('/about')">About</button>
<button @click="() => navigate('/contact')">Contact</button>
</nav>
</template>
<script setup>
import { useNavigate } from '@openwebf/vue-router';
const { navigate } = useNavigate();
</script>Troubleshooting
Enable router debug logs
Set a global flag early (before creating your Vue app):
// @ts-ignore
globalThis.__WEBF_VUE_ROUTER_DEBUG__ = true;When enabled, the router logs include hybridrouterchange:*, routes:sync, and routes:activePathDecision.
Routes not updating
Ensure your Routes component is at the root of your component tree and not inside any conditional rendering.
State is undefined
Route state is only available when navigating TO a route. It's not persisted across page refreshes in WebF.
Performance issues
Enable prerender for routes that take time to render initially.
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
License
Apache-2.0 License. See LICENSE for details.
