Skip to content

Auto-Generating Route Configuration

Writing route configurations manually is error-prone and difficult to keep in sync with pages.json. The generateRouter plugin from @meng-xi/vite-plugin can automatically generate route configuration files and type declarations from pages.json, significantly reducing manual maintenance effort.

Installation

bash
pnpm add @meng-xi/vite-plugin@^1.0.0 -D
bash
npm install @meng-xi/vite-plugin@^1.0.0 -D
bash
yarn add @meng-xi/vite-plugin@^1.0.0 -D

Basic Usage

Configure the plugin in vite.config.ts:

ts
// vite.config.ts
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { generateRouter } from '@meng-xi/vite-plugin'

export default defineConfig({
	plugins: [
		uni(),
		generateRouter({
			pagesJsonPath: 'src/pages.json',
			outputPath: 'src/router.config.ts'
		})
	]
})

Subpath Import (Recommended)

Since @meng-xi/vite-plugin@1.0.0, subpath exports are supported. Importing by group benefits Tree-shaking:

ts
import { generateRouter } from '@meng-xi/vite-plugin/plugins/generate'

The main entry @meng-xi/vite-plugin remains backward compatible; both forms are equivalent.

The plugin reads pages.json when Vite starts and automatically generates src/router.config.ts:

ts
// src/router.config.ts (auto-generated, do not edit manually)
import type { RouteConfig } from '@meng-xi/uni-router'

/**
 * Route configuration list
 * @description Auto-generated from pages.json
 */
export const routes: RouteConfig[] = [
	{
		path: '/pages/index/index',
		name: 'pagesIndexIndex',
		meta: { title: 'Home', isTab: true }
	},
	{
		path: '/pages/about/about',
		name: 'pagesAboutAbout',
		meta: { title: 'About', isTab: true }
	},
	{
		path: '/pages/user/user',
		name: 'pagesUserUser',
		meta: { title: 'Profile', requireAuth: true }
	}
]

export default routes

INFO

  • When exportTypes is true (default) and outputFormat is 'ts', the generated file includes an import type { RouteConfig } from '@meng-xi/uni-router' statement at the top
  • When outputFormat is 'js', no type import or type annotation is generated

Then import the generated route configuration in main.ts:

ts
import { createRouter } from '@meng-xi/uni-router'
import routes from './router.config'

const router = createRouter({ routes })

Configuration Options

OptionTypeDefaultDescription
pagesJsonPathstring'src/pages.json'Path to pages.json (relative to project root)
outputPathstring'src/router.config.ts'Route config output path (relative to project root)
outputFormat'ts' | 'js''ts'Output file format
nameStrategy'path' | 'camelCase' | 'pascalCase' | 'custom''camelCase'Route name generation strategy
customNameGenerator(path: string) => string-Custom route name generator function (required when nameStrategy is 'custom')
includeSubPackagesbooleantrueWhether to include sub-package routes
watchbooleantrueWhether to watch pages.json changes and auto-regenerate (only effective in dev mode)
metaMappingRecord<string, string>{ navigationBarTitleText: 'title', requireAuth: 'requireAuth' }Mapping from pages.json style fields to meta
exportTypesbooleantrueWhether to export type definitions in the output file (import type statement)
preserveRouteChangesbooleantrueWhether to preserve user modifications to routes
dtsstring | booleanfalseType declaration file output path, see Type Hints
headerTemplateboolean | stringfalseFile comment header template, true for default header, string for custom template, see File Comment Header
customFieldsRecord<string, string>{}Custom field key-value pairs for {custom:key} placeholders

Route Name Generation Strategy

The nameStrategy option controls how route names are generated:

StrategyPath ExampleGenerated Name
'camelCase' (default)/pages/index/indexpagesIndexIndex
'pascalCase'/pages/about/aboutPagesAboutAbout
'path'/pages/user/userpages_user_user
'custom'CustomReturned by customNameGenerator function

Meta Field Mapping

The metaMapping option maps fields from the style object in pages.json to route meta. By default, navigationBarTitleText → title and requireAuth → requireAuth mappings are already configured:

ts
// Default metaMapping (effective without manual configuration)
{
	navigationBarTitleText: 'title', // style.navigationBarTitleText → meta.title
	requireAuth: 'requireAuth'       // style.requireAuth → meta.requireAuth
}

Custom metaMapping overrides the default mappings. To preserve default behavior, include them in your custom mapping:

ts
generateRouter({
	metaMapping: {
		navigationBarTitleText: 'title', // Preserve default
		requireAuth: 'requireAuth',       // Preserve default
		customFlag: 'customFlag'          // Add custom mapping
	}
})

Additionally, the plugin automatically infers the following meta fields (not affected by metaMapping):

  • isTab: Automatically marked based on tabBar.list in pages.json, no manual configuration needed

Page-Level Name Configuration

Starting from @meng-xi/vite-plugin@0.2.4, you can directly configure the name field for pages in pages.json, which takes priority over nameStrategy auto-generation:

json
{
	"pages": [
		{
			"path": "pages/user/profile",
			"name": "UserProfile",
			"style": { "navigationBarTitleText": "Profile" }
		}
	]
}

In the above configuration, the route name is 'UserProfile', not 'pagesUserProfile' as auto-generated by nameStrategy.

Page-Level Meta Configuration

Starting from @meng-xi/vite-plugin@0.2.3, you can directly configure the meta field for pages in pages.json, without relying on metaMapping:

json
{
	"pages": [
		{
			"path": "pages/index/index",
			"style": { "navigationBarTitleText": "Home" },
			"meta": { "requireAuth": true, "customField": "value" }
		}
	]
}

INFO

The meta field takes priority over metaMapping, allowing page-level overrides.

Meta extraction priority:

PrioritySourceDescription
1 (high)pageConfig.nameName field directly configured in pages.json (0.2.4+)
1 (high)pageConfig.metaMeta field directly configured in pages.json
2nameStrategyAuto-generated route name based on nameStrategy
2metaMappingExtracted from style field mapping
3 (low)TabBar inferenceAutomatically identifies tabBar pages and sets isTab: true

Type Hints

Starting from @meng-xi/vite-plugin@0.2.2, the generateRouter plugin supports auto-generating TypeScript type declaration files, providing type-safe autocompletion for route navigation.

Enabling Type Generation

Enable it via the dts option:

ts
generateRouter({
	// Use default path src/router.d.ts
	dts: true,

	// Or custom path
	dts: 'src/types/router.d.ts'
})

Generated Type File

When enabled, the plugin generates a type declaration file at the specified path:

ts
// src/router.d.ts (auto-generated, do not edit manually)
import '@meng-xi/uni-router'

declare module '@meng-xi/uni-router' {
	interface RouteNameMap {
		/** Home */
		pagesIndexIndex: { path: '/pages/index/index'; meta: { title: string; isTab: true } }
		/** About */
		pagesAboutAbout: { path: '/pages/about/about'; meta: { title: string; isTab: true } }
		/** Profile */
		pagesUserUser: { path: '/pages/user/user'; meta: { title: string; requireAuth: boolean } }
	}
}

INFO

  • Each route generates a TSDoc comment with the value of meta.title
  • String fields in meta are typed as string, boolean true fields as literal true, number fields as number
  • Routes without a name will use path as the key

Type Hint Effects

The type declaration file extends the RouteNameMap interface of @meng-xi/uni-router through Module Augmentation, providing the following type hints:

Route name autocompletion:

ts
router.push({ name: 'pagesIndexIndex' }) // ✅ Autocompletes all route names
router.push({ name: 'nonExistent' }) // ❌ TypeScript type error

Path autocompletion:

ts
router.push({ path: '/pages/index/index' }) // ✅ Autocompletes all route paths
router.push({ path: '/invalid/path' }) // ❌ TypeScript type error

INFO

When dts is not enabled, the types of name and path are string, which does not provide autocompletion or type checking.

File Comment Header

The headerTemplate option controls the comment header at the top of the generated file, supporting boolean and string template:

  • false / omitted: No comment header
  • true: Generate default header ({name} {date} {version})
  • string: Generate header from template string with placeholder combination

Placeholder reference:

PlaceholderReplacementExample
{name}Plugin namegenerate-router
{date}Generation datetime (default format YYYY-MM-DD HH:mm:ss)2026-06-24 14:30:00
{date:format}Datetime in specified format{date:YYYY-MM-DD}2026-06-24
{version}Plugin version1.0.0
{custom:key}Custom field, value from customFields{custom:author}MengXi Studio
ts
// Default header (headerTemplate: true)
generateRouter({ headerTemplate: true })
// Generated:
// /**
//  * generate-router 2026-06-24 14:30:00 1.0.0
//  */

// Custom date format
generateRouter({ headerTemplate: '{name} {date:YYYY-MM-DD} {version}' })
// Generated:
// /**
//  * generate-router 2026-06-24 1.0.0
//  */

// Custom fields
generateRouter({
	headerTemplate: '{name} {custom:author} {date} {version}',
	customFields: { author: 'MengXi Studio' }
})
// Generated:
// /**
//  * generate-router MengXi Studio 2026-06-24 14:30:00 1.0.0
//  */

INFO

{date:format} supports format tokens: YYYY (year), MM (month), DD (day), HH (hour), mm (minute), ss (second). If the key in {custom:key} does not exist in customFields, the placeholder is preserved as-is.

Preserving User Modifications

When preserveRouteChanges is enabled (default), the plugin preserves user modifications to the routes array when regenerating route configurations:

Merge strategy:

FieldMerge behavior
pathAlways uses the new value generated from pages.json
nameAlways uses the new value from pages.json (pageConfig.name or nameStrategy auto-generation)
metaFields sourced from pages.json always use the new value; user custom fields (not in new meta) are preserved
Other properties (e.g. beforeEnter)Fully preserved
ts
// First generation
{
	path: '/pages/admin/admin',
	name: 'pagesAdminAdmin',
	meta: { requireAuth: true }
}

// User manually adds beforeEnter and custom meta field
{
	path: '/pages/admin/admin',
	name: 'pagesAdminAdmin',
	meta: { requireAuth: true, role: 'admin' },
	beforeEnter: (to, from, next) => { /* ... */ }
}

// Regenerated after pages.json changes — user modifications preserved
{
	path: '/pages/admin/admin',
	name: 'pagesAdminAdmin',
	meta: { requireAuth: true, role: 'admin' },  // role preserved
	beforeEnter: (to, from, next) => { /* ... */ }  // beforeEnter preserved
}

Full Configuration Example

ts
// vite.config.ts
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import { generateRouter } from '@meng-xi/vite-plugin'

export default defineConfig({
	plugins: [
		uni(),
		generateRouter({
			pagesJsonPath: 'src/pages.json',
			outputPath: 'src/router.config.ts',
			outputFormat: 'ts',
			nameStrategy: 'camelCase',
			includeSubPackages: true,
			watch: true,
			dts: true,
			headerTemplate: true,
			metaMapping: {
				navigationBarTitleText: 'title',
				requireAuth: 'requireAuth'
			}
		})
	]
})

Released under the MIT License.