Research Objective
Investigate client-side routing solutions for Web Components-based SPA replacing Tinro.
Current State (App.svelte)
- Using Tinro router for Svelte
- Routes:
/, /chat, /graph, /config/wizard, /config/json
- Active link highlighting
- History API integration
- Declarative routing with
<Route> components
Reference: desktop/src/App.svelte:81-88
Research Questions
- How to implement routing in Web Components without framework?
- Which routing libraries work with Web Components?
- Declarative vs imperative routing?
- How to handle route parameters and query strings?
- Browser history management?
- Active link styling?
Routing Approaches
Approach 1: Vaadin Router
Web Components-specific router by Vaadin team.
Pros:
- Built for Web Components
- Type-safe (TypeScript)
- Declarative or imperative
- Lazy loading support
- Lifecycle hooks
- Well-documented
Cons:
- Another dependency
- Learning curve
Example:
import { Router } from '@vaadin/router';
const router = new Router(document.querySelector('#outlet'));
router.setRoutes([
{ path: '/', component: 'terraphim-search' },
{ path: '/chat', component: 'terraphim-chat' },
{ path: '/graph', component: 'terraphim-rolegraph' },
]);
Repository: https://github.com/vaadin/router
Approach 2: page.js
Minimalist client-side router inspired by Express.
Pros:
- Tiny (~1KB gzipped)
- Simple API
- Express-like routing
- Well-established
Cons:
- Imperative only
- Manual component mounting
- No TypeScript definitions
Example:
import page from 'page';
page('/', () => mountComponent('terraphim-search'));
page('/chat', () => mountComponent('terraphim-chat'));
page('/graph', () => mountComponent('terraphim-rolegraph'));
page();
Repository: https://github.com/visionmedia/page.js
Approach 3: Custom Router (Vanilla)
Build minimal router using History API.
Pros:
- Zero dependencies
- Full control
- Exactly what we need
- Learning experience
Cons:
- Need to handle edge cases
- Testing burden
- Maintenance
Example:
class Router {
routes = new Map();
add(path, component) {
this.routes.set(path, component);
}
navigate(path) {
const component = this.routes.get(path);
if (component) {
this.outlet.innerHTML = '';
this.outlet.appendChild(document.createElement(component));
history.pushState({}, '', path);
}
}
init() {
window.addEventListener('popstate', () => {
this.navigate(location.pathname);
});
}
}
Approach 4: Lit Router
Routing solution specifically for Lit-based Web Components.
Pros:
- Integrates with Lit
- Reactive
- Decorators
Cons:
- Requires Lit framework
- Tied to Lit ecosystem
Action: Only if we choose Lit for build tooling
Repository: https://github.com/lit/lit/tree/main/packages/labs/router
Approach 5: Navigo
Lightweight router with hash and history support.
Pros:
- Small (~4KB)
- TypeScript support
- Hooks
- Nested routes
Cons:
- Less Web Components specific
Repository: https://github.com/krasimir/navigo
Features to Maintain
From Tinro (Current):
New Requirements:
Routing Patterns
Pattern 1: Declarative with Router Outlet
<terraphim-app>
<terraphim-router>
<terraphim-route path="/" component="terraphim-search"></terraphim-route>
<terraphim-route path="/chat" component="terraphim-chat"></terraphim-route>
<terraphim-route path="/graph" component="terraphim-rolegraph"></terraphim-route>
</terraphim-router>
</terraphim-app>
Pros:
- Clear structure
- Easy to understand
- Similar to current Tinro
Cons:
- More complex implementation
- Need custom elements for router and route
Pattern 2: Imperative Configuration
class TerraphimApp extends HTMLElement {
connectedCallback() {
this.router = new Router(this.shadowRoot.querySelector('#outlet'));
this.router.setRoutes([
{ path: '/', component: 'terraphim-search' },
{ path: '/chat', component: 'terraphim-chat' },
{ path: '/graph', component: 'terraphim-rolegraph' },
]);
}
}
Pros:
- Simple
- Less boilerplate
- Dynamic routing
Cons:
- Less declarative
- Harder to see structure
Active Link Styling
Current: Tinro's use:active directive
Web Components Solution:
class TerraphimNav extends HTMLElement {
connectedCallback() {
this.router.addEventListener('route-changed', () => {
this.updateActiveLinks();
});
}
updateActiveLinks() {
const links = this.querySelectorAll('a');
links.forEach(link => {
const isActive = link.pathname === location.pathname;
link.classList.toggle('active', isActive);
});
}
}
Tauri Considerations
Problem: File protocol (file://) doesn't support pushState well
Solution:
- Use hash routing (
#/, #/chat)
- Or configure base URL properly
- Vaadin Router handles this automatically
Acceptance Criteria
References
Documentation
Findings will be documented in: .docs/research-spa-routing.md
Research Objective
Investigate client-side routing solutions for Web Components-based SPA replacing Tinro.
Current State (App.svelte)
/,/chat,/graph,/config/wizard,/config/json<Route>componentsReference:
desktop/src/App.svelte:81-88Research Questions
Routing Approaches
Approach 1: Vaadin Router
Web Components-specific router by Vaadin team.
Pros:
Cons:
Example:
Repository: https://github.com/vaadin/router
Approach 2: page.js
Minimalist client-side router inspired by Express.
Pros:
Cons:
Example:
Repository: https://github.com/visionmedia/page.js
Approach 3: Custom Router (Vanilla)
Build minimal router using History API.
Pros:
Cons:
Example:
Approach 4: Lit Router
Routing solution specifically for Lit-based Web Components.
Pros:
Cons:
Action: Only if we choose Lit for build tooling
Repository: https://github.com/lit/lit/tree/main/packages/labs/router
Approach 5: Navigo
Lightweight router with hash and history support.
Pros:
Cons:
Repository: https://github.com/krasimir/navigo
Features to Maintain
From Tinro (Current):
use:activedirective)New Requirements:
Routing Patterns
Pattern 1: Declarative with Router Outlet
Pros:
Cons:
Pattern 2: Imperative Configuration
Pros:
Cons:
Active Link Styling
Current: Tinro's
use:activedirectiveWeb Components Solution:
Tauri Considerations
Problem: File protocol (
file://) doesn't supportpushStatewellSolution:
#/,#/chat)Acceptance Criteria
References
desktop/src/App.svelte(Tinro usage)Documentation
Findings will be documented in:
.docs/research-spa-routing.md