TSone

Routing

TSone includes a routing system for showing different content at different URL paths.

Core Concepts

Router Instance

A router instance is created with createRouter and manages route configuration and navigation.

Route Configuration

Route configuration is a set of RouteRecord values that map paths to components.

Route Navigation

You can navigate programmatically or declaratively with RouterLink.

Basic Usage

Import the Router

import { createRouter, RouterLink, RouterView } from '@geektech/tsone/router';

Create a Router Instance

import { createApp } from '@geektech/tsone';
import { createRouter, RouterView } from '@geektech/tsone/router';

const router = createRouter({
  routes: [
    { path: '/', name: 'home', component: HomeComponent, meta: { title: 'Home' } },
    { path: '/about', name: 'about', component: AboutComponent, meta: { title: 'About Us' } },
    { path: '/user/:id', name: 'user', component: UserComponent, meta: { title: 'User Details' } },
  ],
  mode: 'history',
  base: '/',
});

const app = createApp({
  root: class Layout extends Component<object, object> {
    protected initState() {
      return {};
    }

    protected initStyles(): void {}

    protected render(): VNode {
      return {
        tag: 'main',
        children: [{ component: RouterView }],
      };
    }
  },
});

app.use(router);
app.mount();

Route Configuration Options

Route Rules

  • path: URL path pattern
  • name: route name
  • component: associated component
  • meta: metadata

Path Patterns

  • /about: static path
  • /user/:id: dynamic path parameter
  • *: wildcard fallback

Navigation Guards

router.beforeEach(guard) registers a global before guard: return false to cancel navigation, return a string to redirect to that path, or return true/undefined to proceed. router.afterEach(hook) runs after navigation is committed. Guards only run for programmatic navigation (push/replace).

router.beforeEach((to) => {
  if (!isLoggedIn() && to.path !== '/login') return '/login';
  return true;
});

router.afterEach((to) => {
  document.title = String(to.meta?.title ?? '');
});

Redirects and Wildcard Routes

RouteRecord.redirect resolves a route to a target path (with loop protection); path: '*' matches every unmatched path and exposes the remaining segments through params.pathMatch, typically used for a 404 page.

const router = createRouter({
  routes: [
    { path: '/', component: HomeComponent },
    { path: '/old', redirect: '/new' },
    { path: '/new', component: NewComponent },
    { path: '*', component: NotFoundComponent },
  ],
});

Route Navigation

Programmatic Navigation

router.push('/about');
router.replace('/login');
router.back();
router.forward();
router.go(-1);

Declarative Navigation

{
  component: RouterLink,
  props: {
    to: '/user/42',
    activeClass: 'is-active',
    children: ['User Details'],
  },
}

Route Parameters

Read Route Parameters

class UserComponent extends Component<object, { userId: string }> {
  protected initState() {
    return { userId: '' };
  }

  protected initStyles(): void {}

  protected onMounted() {
    const route = this.router?.getCurrentRoute();
    this.state.userId = String(route?.params.id ?? '');
  }

  protected render(): VNode {
    return {
      tag: 'h1',
      children: ['User Details '],
    };
  }
}

Listen for Route Parameter Changes

const stopListening = router.onRouteChange((to) => {
  console.log('route changed to', to.path);
});

stopListening();

Route Metadata

const router = createRouter({
  routes: [
    { path: '/', component: HomeComponent, meta: { title: 'Home' } },
    { path: '/dashboard', component: DashboardComponent, meta: { title: 'Dashboard' } },
  ],
});

Routing Modes

History Mode

const router = createRouter({
  mode: 'history',
  routes: [...],
});

History mode uses the HTML5 History API and requires the server to fall back to the application entry point.

Hash Mode

const router = createRouter({
  mode: 'hash',
  routes: [...],
});

Hash mode does not require server URL rewrites and is suitable for static hosting.

Nested Routes

Parent components can use RouterView to display child-route content.

class DashboardComponent extends Component<object, object> {
  protected initState() {
    return {};
  }

  protected initStyles(): void {}

  protected render(): VNode {
    return {
      tag: 'div',
      children: [
        { tag: 'h1', children: ['Dashboard'] },
        { component: RouterView },
      ],
    };
  }
}

Router API

Router Instance Methods

  • push(location): navigate to a location
  • replace(location): replace the current history entry
  • back() / forward() / go(n): use browser history
  • onRouteChange(callback): listen for route changes
  • getCurrentRoute(): read current route information
  • createHref(path): generate an href

Router Object Properties

  • currentRoute: current route information
  • routes: route configuration
  • mode: routing mode
  • base: base path

Best Practices

Route Organization

  • Manage route configuration centrally
  • Use named routes for key pages
  • Use dynamic parameters and meta appropriately

Performance Optimization

  • Keep route component boundaries clear
  • Avoid expensive work in onRouteChange
  • Split page-level components when needed

Common Issues

  • History-mode refresh returns 404: configure a server fallback rule
  • Route parameter changes do not update: listen for route changes and refresh data
  • Nested routes do not display: confirm the parent renders RouterView

Summary

TSone routing provides clear, lightweight navigation through createRouter, RouterView, and RouterLink.