Zova Router Under the Hood
This guide explains the source-level runtime path behind Zova Router.
Use this page after Page Route Guide, A-Router Guide, Route Alias Guide, and Navigation Guards Guide when you want to move from the public routing surface to the internal cooperation among route registration, router startup, lazy module loading, alias handling, typed params/query parsing, and router-view hosting.
If your next question is specifically about empty/tabs/stack routed hosts, continue with Router View Hosts Guide. For compact file-order guidance, continue with Zova Source Reading Map.
TIP
Zova Router docs path
- Page Route Guide — learn the public route-record and layout surface
- A-Router Guide — learn what the
a-routerpackage owns in the runtime - Route Alias Guide — learn how user-facing aliases fit into modular routing
- Navigation Guards Guide — learn where routing policy attaches
- Zova Router Under the Hood — learn how the runtime pieces cooperate
- Zova Source Reading Map — learn which files to read next
You are here: step 5. Previous pages: Page Route Guide, A-Router Guide, Route Alias Guide, and Navigation Guards Guide. Next recommended pages: Router View Hosts Guide for routed-host behavior, then Zova Source Reading Map for compact source-reading paths.
Router ecosystem map
Use this compact map when you want to place this page inside the broader Router documentation set.
| Layer | Main question | Primary page |
|---|---|---|
| public routing surface | what does the route record mean? | Page Route Guide |
| route policy | how do aliases and guards change navigation semantics? | Route Alias Guide, Navigation Guards Guide |
| core router runtime | how does the route become operational at runtime? | this page |
| routed host layer | once the route is resolved, which host owns the page instance? | Router View Hosts Guide |
| tabs vs stack choice | should this routed host behave like a workbench or a linear routed stack? | Router Tabs vs Stack |
| stack host meaning | what does the stack host actually own? | Router Stack Guide |
| tabs workbench meaning | why does the tabs host exist conceptually? | Router Tabs Introduction, Router Tabs Overview |
| tabs model internals | how does the tabs host turn route visits into workspace state? | Router Tabs Mechanism |
| tabs authoring inputs | how do I produce the intended tabs behavior through route meta? | Router Tabs Route Meta Cookbook |
| compact source paths | which files should I read next? | Zova Source Reading Map |
Why this page exists
The public routing docs already explain the authoring surface:
routes.ts- route
meta - route aliases in global config
- navigation guards as policy hooks
- typed params and query through generated schemas
What many contributors and AI workflows still want next is the implementation bridge:
- where module routes are registered into the router
- where route config and aliases are merged
- where app startup makes the router operational
- where lazy module loading happens during navigation
- where
$route,$params, and$queryare pushed onto page controllers - where routed pages enter router-view hosts such as empty, tabs, or stack-style shells
- how those hosts differ once the route is already resolved
This page is that bridge.
The shortest accurate runtime model
For a typical Zova page route, the shortest accurate model is:
- module
routes.tsdeclares the page route record - system startup registers module routes into the shared system router
- route config can merge alias, layout, or other route overrides on top of that declaration
- app startup creates the main router bean, attaches guards, injects Vue Router into the app, and drives first navigation
- navigation guards lazy-load modules and normalize alias or fallback behavior before the route is finalized
- page-controller route state is pushed into
$route,$params, and$query - a router-view host renders the matched page inside the chosen shell and keep-alive strategy
That is why Zova Router is not only a thin wrapper around Vue Router. The business-facing runtime is still module-oriented, bean-oriented, and startup-aware.
A concrete source specimen
A small public route table that shows several important route decisions clearly is:
zova/src/suite/a-demo/modules/demo-basic/src/routes.tsRepresentative shape:
export const routes: IModuleRoute[] = [
{ path: 'routeQuery', component: ZPageRouteQuery, meta: { requiresAuth: false } },
{
name: 'routeParams',
path: 'routeParams/:id?',
component: ZPageRouteParams,
meta: {
componentKeyMode: 'nameOnly',
requiresAuth: false,
},
},
{
name: 'toolMinimal',
path: 'toolMinimal',
component: ZPageToolMinimal,
meta: {
layout: 'empty',
requiresAuth: false,
},
},
];What matters here is not only the route strings.
What matters is that:
- the module declares routes relative to the module boundary by default
- route
namecontrols named routing and typed params/query schema selection - route
metacontrols shell-facing behavior such as layout and component reuse strategy - the route record is only the first layer; config, guards, startup timing, and router-view hosting still cooperate afterward
The core source-reading path
When you want to trace the full mechanism, read these files in order:
zova/src/suite/a-demo/modules/demo-basic/src/routes.tszova/src/suite-vendor/a-zova/modules/a-router/src/bean/sys.router.tszova/src/suite-vendor/a-zova/modules/a-router/src/monkeySys.tszova/src/suite-vendor/a-zova/modules/a-router/src/monkey.tszova/src/suite-vendor/a-zova/modules/a-router/src/service/routerGuards.tszova/src/suite-vendor/a-zova/modules/a-router/src/lib/utils.tszova/src/suite-vendor/a-zova/modules/a-router/src/lib/routerViewBase.tsx
A compact role map is:
routes.tsshows the public authoring surface for page routessys.router.tsowns shared router creation, route registration, alias synthesis, and typed path generation helpersmonkeySys.tshooks module loading so newly loaded modules can contribute routes into the system routermonkey.tsowns app-level router lifecycle, guard/event readiness, page-controller route injection, and SSR/client redirect handlingservice/routerGuards.tsowns lazy module loading during navigation and alias redirection behaviorutils.tsnormalizes canonical route identity and current/page route lookuprouterViewBase.tsxshows how routed pages enter a Zova router-view host rather than bypassing the bean/controller architecture
Step-by-step runtime path
1. The route record starts in module-local routes.ts
The public route declaration surface is a module-local file such as:
zova/src/suite/a-demo/modules/demo-basic/src/routes.tsThe important architectural point is:
- routes are owned by modules, not by one flat global route file
- module-relative paths are the default authoring shape
That is why a route like:
{ path: 'toolMinimal', component: ZPageToolMinimal }later becomes the full page path /demo/basic/toolMinimal after module-aware registration.
2. The system router is the shared route-table owner
The main shared runtime owner is:
zova/src/suite-vendor/a-zova/modules/a-router/src/bean/sys.router.tsInside SysRouter.__init__() the system router:
- creates the shared Vue Router instance
- loads route overrides from
sys.config.routes.path - loads route overrides from
sys.config.routes.name - loads legacy routes if present
This is one of the most important source-level facts about Zova Router.
The route table is not assembled only from static page files. It is the result of cooperation among:
- module route records
- global config routes
- startup-time module loading
- alias and layout normalization
3. Module loading registers routes during system startup
The system-level hook lives in:
zova/src/suite-vendor/a-zova/modules/a-router/src/monkeySys.tsThe important runtime detail is that moduleLoading(module) checks whether the loading module contributes resource.routes, then calls sysRouter._registerRoutes(module).
That matters because:
- route registration belongs to system startup, not only app startup
- newly loaded modules can extend the route table without hand-editing one giant router file
- the same architectural split matches the broader startup model explained in System Startup Guide
A practical reading takeaway is:
- system startup owns route-table wiring
- app startup later owns router readiness and first navigation
4. Route registration expands module-local records into real router records
The most important registration method is:
SysRouter._registerRoute(...)Inside that path, the router runtime performs several important transformations.
Module-relative path expansion
If the route is not meta.absolute === true, Zova prefixes the module path automatically.
That means:
toolMinimalin moduledemo-basicbecomes/demo/basic/toolMinimal- named route
routeParamsbecomesdemo-basic:routeParams
This is one reason route authoring stays compact while runtime routing stays globally unique.
Config-route merging
Before adding the route, the runtime checks sys.config.routes.name or sys.config.routes.path and deep-merges the config route on top of the module declaration.
That is why alias and route-policy changes belong in config instead of being hand-spread across module route files.
Representative config source:
zova/src/front/config/config/config.tsRepresentative shape:
config.routes = {
path: {
'/home/indexadmin/dashboard': { alias: '/' },
'/home/login': { alias: '/login' },
},
name: {
'demo-todo:item': { alias: '/todo/:id' },
},
};Alias synthesis for named routes
If a named route has a config alias, Zova also creates an internal $alias:<name> route under /__alias__....
This detail is important because:
- user-facing aliases can stay path-shaped
- the runtime can still preserve named-route identity and params-aware resolution
- alias handling remains a router concern instead of leaking into page code
Layout wrapping
If meta.layout !== false, the runtime does not register the page component alone.
Instead it creates a parent route that resolves the layout component and makes the page route its child.
That is why routing in Zova is also an app-shell decision, not only a URL decision.
A practical reading takeaway is:
- layout is normalized during route registration, not as an afterthought in page render code
5. Path and name helpers stay module-aware and schema-aware
The most visible helper is:
SysRouter.getPagePath(...)This helper:
- combines params and query into the page path
- handles locale-specific param normalization
- can return a relative page path or an absolute URL
Zova also exposes named-route resolution through resolveName(...), and both helpers preserve the module-aware naming/path model rather than asking every caller to manually build URLs.
That is why the recommended page-navigation surface stays framework-native:
this.$router.getPagePath(...)this.app.$gotoPage(...)this.app.$gotoHome(...)
rather than ad hoc string concatenation.
6. App startup creates the main router bean and makes it operational
The app-level lifecycle owner is:
zova/src/suite-vendor/a-zova/modules/a-router/src/monkey.tsThe important timing split is:
appInitialize()creates the router-guard service and client-side SSR error handlingappInitialized()emitsa-router:routerGuardsso guard contributors can attach to the main router beanappReady()installs the router into Vue and drives first-navigation readiness for SSR or client hydrationappClose()disposes router-guard listeners
This is the second major source-level fact about Zova Router.
The router runtime is not considered fully ready merely because route records exist. It also needs:
- a router bean instance
- attached guards
- SSR/client readiness handling
- Vue app installation
This matches the broader lifecycle model in App Startup Guide.
7. a-router:routerGuards is the main policy extension point
The shared extension hook begins with:
zova/src/suite-vendor/a-zova/modules/a-router/src/bean/bean.routerGuardsBase.tsThis base bean subscribes to the a-router:routerGuards event and calls onRouterGuards(router).
That means the framework-level guard and app-level guards can both attach through one structured extension point instead of each patching router startup manually.
Representative consumers include:
zova/src/suite-vendor/a-zova/modules/a-router/src/service/routerGuards.tszova/src/suite/a-home/modules/home-base/src/service/routerGuards.ts
The framework service focuses on routing mechanics such as:
- lazy module loading
- alias redirection
- 404 fallback retry after module loading
- back/forward notifications for router-view hosts
The home-base service focuses on application policy such as:
- auth enforcement through
meta.requiresAuth - locale initialization through
meta.locale
A practical reading takeaway is:
- routing mechanics and business policy are separated, but they meet on the same guard event surface
8. Lazy module loading happens during navigation, not only before startup
The framework guard service lives in:
zova/src/suite-vendor/a-zova/modules/a-router/src/service/routerGuards.tsInside beforeEach(...), the router runtime:
- identifies the matched route
- checks whether a 404-like match should trigger a module-load retry
- checks whether the route has a configured alias
- forces module loading if the target module exists but is not yet loaded
- retries navigation when module loading completed
That is why Zova routing feels module-aware even when the target module was not preloaded.
A practical reading takeaway is:
- navigation is part of module activation
- the router guard layer is where lazy route availability becomes real runtime behavior
9. Page controllers receive route state through controller-data hooks
The page-controller bridge also lives in:
zova/src/suite-vendor/a-zova/modules/a-router/src/monkey.tsThe important methods are:
controllerDataPrepare(...)controllerDataInit(...)controllerDataUpdate(...)_initControllerRoute(...)
This is where page controllers receive and refresh:
$route$routeMatched$params$query
This is one of the biggest architectural differences a Vue-first reader notices.
The page controller does not pull everything locally through one composable first. Zova also pushes route-aware page state into the controller lifecycle.
10. Typed params and query come from generated page schemas
When _initControllerRoute(...) updates a page controller, it resolves the route’s canonical identity and then loads page schemas from the owning module resource:
pageNameSchemasfor named routespagePathSchemasfor path-keyed routes
Those schema records are generated into module metadata.
Representative generator source:
zova/src/suite-vendor/a-zova/modules/a-bean/cli/controller/metadata/generateMetaPage.tsRepresentative generated output:
zova/src/suite/a-demo/modules/demo-basic/src/.metadata/index.tsThat means typed routing in Zova is not only a TypeScript declaration convenience.
It is also a runtime parse step:
- route params and query are parsed by schema
- controller
$paramsand$queryreceive parsed values - on the client, those objects are kept reactive through
shallowReactive(...)
A practical reading takeaway is:
- typed routing is generated and runtime-parsed, not just editor-only typing
11. Beans receive router helpers through the router monkey
The same router monkey also defines bean-level helper surfaces such as:
$router$routerView$pageRoute$currentRoute
That matters because route-aware behavior is not isolated to page controllers alone.
Router-view controllers, services, models, and other beans can participate through the same bean-oriented access pattern.
12. Router-view hosting stays inside the controller/bean architecture
The shared router-view base lives in:
zova/src/suite-vendor/a-zova/modules/a-router/src/lib/routerViewBase.tsxThis base controller:
- registers itself on the host bean scope as
$$routerView - registers and deregisters itself with
$router - wraps routed pages in
RouterView - prepares route meta for routed pages
- controls keep-alive inclusion through the host implementation
- injects the current page route into the routed vnode through host providers
This is the third major source-level fact about Zova Router.
Routed pages do not bypass Zova and fall directly into a plain Vue Router surface. They still enter through a controller-oriented router-view host.
Empty host vs richer hosts
A minimal host exists in:
zova/src/suite-vendor/a-zova/modules/a-router/src/component/routerViewEmpty/controller.tsxThat host renders the routed page directly and only injects the current page route provider.
Richer hosts extend the same base in modules such as:
a-routertabsa-routerstack
For example, the tabs host delegates route meta, keep-alive, and page-meta updates to the tabs model so one routing runtime can support more than one shell behavior.
A practical reading takeaway is:
- router-view hosting is an extension point, not only one hard-coded component
13. SSR and redirect behavior are also part of router runtime
The router runtime also owns several SSR-sensitive behaviors.
In monkeySys.ts, app.$redirect(...) and app.$gotoPage(...) cooperate with SSR redirects by throwing an SSR-aware error when necessary.
In monkey.ts, SSR/client startup handles:
- server-side initial
push(...)andisReady() - client pre-hydration history alignment
- client redirect/error normalization for 301, 302, 401, and component-unmounted cases
That means router behavior in Zova is not purely a client SPA concern. It is also part of the SSR-ready frontend runtime.
A practical reading order for source readers
If you want the shortest path from route authoring to runtime understanding, use this order:
- Page Route Guide
- Route Alias Guide
- Navigation Guards Guide
zova/src/suite/a-demo/modules/demo-basic/src/routes.tszova/src/suite-vendor/a-zova/modules/a-router/src/bean/sys.router.tszova/src/suite-vendor/a-zova/modules/a-router/src/monkeySys.tszova/src/suite-vendor/a-zova/modules/a-router/src/monkey.tszova/src/suite-vendor/a-zova/modules/a-router/src/service/routerGuards.tszova/src/suite-vendor/a-zova/modules/a-router/src/lib/routerViewBase.tsx- Zova Source Reading Map
Common mistakes to avoid
Mistake 1: “The route table is just one static Vue Router config”
Usually the better model is that route records are module-owned, system-registered, config-merged, and sometimes lazy-loaded during navigation.
Mistake 2: “Aliases are just convenience string rewrites”
In Zova, aliases still participate in module-aware route identity, named-route resolution, and guard-time lazy loading.
Mistake 3: “Typed params/query are only TypeScript sugar”
The generated schemas are also used at runtime to parse route params and query before page controllers consume them.
Mistake 4: “Page controllers should always pull route state manually”
Zova also pushes route-aware state into page controllers through controller-data hooks so the page controller surface stays cohesive.
Mistake 5: “RouterView is only a plain shellless Vue concern”
In Zova, router-view hosting is part of the controller/bean architecture and can be extended into empty, tabs, or stack-style route hosts.
Edition note
This guide explains the shared Zova Router architecture, not one UI-library-specific router shell.
That means the routing runtime model applies across Cabloy Basic and Cabloy Start. However, shell-level presentation and layout integrations can still diverge when the task becomes UI-sensitive or edition-specific.
In the current public framework repository, the active edition is Cabloy Basic.
Final takeaway
If Page Route Guide explains what a route means in Zova, this page explains how that route becomes a running router-aware page through system startup, app startup, guard hooks, generated schemas, and router-view hosting.
That is the mental bridge that makes the Zova Router source tree much easier to read.