Skip to content

Dynamic Router

The dynamic routing mechanism of TechUI is the core of the backend management system. It adopts a Backend Control Strategy, meaning the routing table is not hardcoded on the frontend. Instead, based on the current logged-in user's permissions, the backend returns menu data, and the frontend dynamically generates Vue Router configurations by combining this data with the local component registry.

Working Principle

  1. Component Registration: The frontend maintains a register.js file to map route identifiers (strings) to actual Vue component files.
  2. Fetch Menus: After the user logs in, the menu tree data is retrieved from the backend or a local database.
  3. Route Matching: The routerPackag function matches the label in the menu data with the component registry.
  4. Dynamic Mounting: Matches components are mounted under the parent route named layout using router.addRoute.
  5. Global Interception: Logic for page refreshes, authentication, and adding Tabs is handled in router.beforeEach.

Core Process Analysis

The logic for dynamic routing is mainly concentrated in the global Provider component and is only activated when isActAdminFeatures is true.

Data Persistence and Synchronization

To prevent the loss of Vuex/Pinia state when the page refreshes, TechUI implements a dual persistence mechanism:

  • User Info (UserInfo): Watches $tState.ADMIN.userInfo. Once it changes, it uses tStoreCrypto (encrypted storage) to sync to Session/Local Storage. Simultaneously, if the Token or ID is found missing, it automatically triggers a logout.
  • Menu Data (Menu): Watches $tState.ADMIN.menu. Once menu data is obtained, it is written to IndexedDB (TuiDB). This ensures that even if the user refreshes the page, the massive menu structure can be quickly restored from the local database without requesting the backend again.

Route Assembly (routerPackag)

routerPackag is the core function that converts business data into route configurations.

javascript
// Pseudo-code logic demonstration
async function routerPackag(routerData){
  for(let i=0; i<routerData.length; i++){
    // 1. Destructure backend data
    let { label, icon, title, keepAlive, ... } = routerData[i];
    
    // 2. Look up component in the registry
    let comp = $tState.ADMIN.componentRegister[label];

    // 3. If it is not a parent node and the component exists
    if(!isParent && comp){
      // 4. Dynamically add route to the 'layout' parent node
      router.addRoute("layout", {
        path: '/' + label, // Default path is /label
        name: label,       // Route name
        component: comp,   // Corresponding Vue component
        meta: { ... }      // Inject meta info
      });
    }
  }
}

Key Points:

  • All dynamic routes are child routes of the layout route. This means they will all be rendered in the <router-view> of TuiAdminLayout.
  • The name and path of the route are generated based on the label to ensure uniqueness.

Global Route Interception (Guard)

router.beforeEach assumes the role of a "Gatekeeper", handling complex initialization logic:

Phase 1: State Restoration

  • User Restoration: If there is no UserID in the state tree, it attempts to read the Token from local storage to restore the login state.
  • Menu Restoration: If there is no menu data in the state tree, it attempts to read cached menus from IndexedDB (TuiDB).

Phase 2: Dynamic Loading

  • Initialization Check: Checks the $ARouterInited flag.
  • Execute Loading: If not initialized, calls routerPackag($AMenu.value) to execute route mounting.
  • State Flip: After mounting is complete, sets $ADMIN.value.routerInited to true and re-triggers the route navigation (next({ ...to })) to ensure the new routes take effect.

Phase 3: Business Processing

  • Tab Management: If the target route is valid and has a label set, tabAdd(to) is automatically called to add it to the top tab bar.
  • Cache Management: If meta.keepAlive is true, its name is automatically added to the $AKeepAlive list.
  • Authentication Failure: If none of the above checks pass (no Token, no ID), it forces a redirect to /login.

Structure Specification

To work with dynamic routing, the menu data returned by the backend (or local Mock data) should conform to the following JSON structure:

json
[
  {
    "label": "dashboard",      // Core field: corresponds to the key name in register.js
    "title": "Dashboard",      // Page title
    "icon": "ti-dashboard",    // Menu icon
    "isParent": false,         // Whether it is a parent menu directory
    "keepAlive": true,         // Whether to enable page caching
    "hideInMenu": false,       // Whether to hide in the sidebar
    "hideInTab": false,        // Whether to hide in the Tab bar
    "parentId": "root"         // Parent node ID
  }
]

FAQ

Q: Why do I get a 404 after refreshing the page?A: This is usually because the dynamic routes have not finished loading yet. TechUI's beforeEach logic handles this situation: upon refresh, it first restores the menu from IndexedDB and re-registers the routes before executing the jump. If a 404 occurs, please check if IndexedDB has successfully written the menus data.

Q: How do I configure a new page?A: Two steps are required:

  1. Import the .vue file in the frontend register.js and export it.
  2. Add the corresponding menu item in the backend (or Mock data), ensuring the label matches the key name in register.js.

Released under the MIT License.