unplugin-pages-route
v0.1.0
Published
A high-performance Vite plugin for parsing uni-app pages.json configuration
Maintainers
Readme
unplugin-pages-route
🚀 高性能的 UniApp pages.json 解析插件,零依赖,支持 TypeScript
一个专为 UniApp 项目设计的构建时路由解析插件,能够自动解析 pages.json 配置文件,生成路由信息并注入到项目中,支持主包、分包和 TabBar 路由。
✨ 特性
- 🚀 高性能 - 智能多级缓存,避免重复解析,优化构建速度
- 📦 零依赖 - 内置 JSON 注释处理器,无外部依赖
- 🔍 路由映射 - 自动生成路由映射表,快速通过路径查找路由信息
- 💅 TabBar 支持 - 自动提取底部导航配置
- 🎯 TypeScript - 完整的类型支持和智能提示
- 🌟 现代化 - 支持 ESM/CJS 双格式,兼容各种构建工具
- 🔄 热更新 - 支持开发环境下的配置文件热更新
- 📱 分包支持 - 完整支持 UniApp 分包路由解析
📦 安装
# npm
npm install unplugin-pages-route --save-dev
# yarn
yarn add unplugin-pages-route --dev
# pnpm
pnpm add unplugin-pages-route --save-dev🚀 快速开始
1. 配置构建工具
Vite 配置
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path'
import { uniPagesRoute } from 'unplugin-pages-route'
export default defineConfig({
plugins: [
uniPagesRoute({
pages: resolve(__dirname, './src/pages.json'),
includes: ['meta', 'style'] // 可选,需要额外提取的字段
})
]
})Webpack 配置
// webpack.config.js
const { uniPagesRoute } = require('unplugin-pages-route')
module.exports = {
plugins: [
uniPagesRoute({
pages: path.resolve(__dirname, './src/pages.json')
})
]
}Rollup 配置
// rollup.config.js
import { uniPagesRoute } from 'unplugin-pages-route'
export default {
plugins: [
uniPagesRoute({
pages: './src/pages.json'
})
]
}2. TypeScript 类型声明
创建 types/global.d.ts 文件:
// types/global.d.ts
interface RouteItem {
path: string
aliasPath?: string
meta?: Record<string, any>
style?: Record<string, any>
[key: string]: any
}
declare const __UNI_ROUTES__: RouteItem[]
declare const __UNI_ROUTE_MAP__: Record<string, RouteItem>
declare const __UNI_TABBAR__: string[]3. 在代码中使用
// 获取所有路由信息
console.log('所有路由:', __UNI_ROUTES__)
// 通过路径快速查找路由
const indexRoute = __UNI_ROUTE_MAP__['/pages/index/index']
console.log('首页路由:', indexRoute)
// 获取 TabBar 路由列表
console.log('TabBar 路由:', __UNI_TABBAR__)
// 实际应用示例
function navigateToPage(path: string) {
const route = __UNI_ROUTE_MAP__[path]
if (route) {
uni.navigateTo({ url: route.path })
} else {
console.error('路由不存在:', path)
}
}⚙️ 配置选项
interface PluginOptions {
/**
* pages.json 文件路径
* @example './src/pages.json'
*/
pages: string
/**
* 需要额外提取的字段
* 默认包含 'path' 和 'aliasPath'
* @example ['meta', 'style', 'needLogin']
*/
includes?: string[]
}配置示例
uniPagesRoute({
pages: './src/pages.json',
includes: [
'meta', // 页面元信息
'style', // 页面样式配置
'needLogin', // 自定义字段:是否需要登录
'keepAlive' // 自定义字段:是否保持活跃
]
})📝 数据结构
路由项 (RouteItem)
interface RouteItem {
path: string // 页面路径,如 '/pages/index/index'
aliasPath?: string // 别名路径,首页默认为 '/'
meta?: Record<string, any> // 页面元信息
style?: Record<string, any> // 页面样式配置
[key: string]: any // 其他自定义字段
}全局变量
| 变量名 | 类型 | 描述 |
|--------|------|------|
| __UNI_ROUTES__ | RouteItem[] | 所有路由信息数组 |
| __UNI_ROUTE_MAP__ | Record<string, RouteItem> | 路由映射表,key 为路径 |
| __UNI_TABBAR__ | string[] | TabBar 页面路径数组 |
🎯 实际应用场景
1. 路由守卫
// router-guard.ts
function checkAuth(path: string): boolean {
const route = __UNI_ROUTE_MAP__[path]
return !route?.needLogin || isLoggedIn()
}
// 页面跳转前检查
function navigateWithAuth(path: string) {
if (checkAuth(path)) {
uni.navigateTo({ url: path })
} else {
uni.navigateTo({ url: '/pages/login/login' })
}
}2. 动态菜单生成
// menu.ts
function generateMenu() {
return __UNI_ROUTES__
.filter(route => route.meta?.showInMenu)
.map(route => ({
title: route.meta?.title || '未命名',
path: route.path,
icon: route.meta?.icon
}))
}3. 面包屑导航
// breadcrumb.ts
function getBreadcrumb(currentPath: string) {
const route = __UNI_ROUTE_MAP__[currentPath]
const breadcrumb = []
if (route?.meta?.parent) {
const parentRoute = __UNI_ROUTE_MAP__[route.meta.parent]
if (parentRoute) {
breadcrumb.push({
title: parentRoute.meta?.title,
path: parentRoute.path
})
}
}
breadcrumb.push({
title: route?.meta?.title || '当前页面',
path: currentPath
})
return breadcrumb
}4. TabBar 状态管理
// tabbar.ts
function isTabBarPage(path: string): boolean {
return __UNI_TABBAR__.includes(path)
}
function getTabBarIndex(path: string): number {
return __UNI_TABBAR__.indexOf(path)
}📋 pages.json 示例
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
},
"meta": {
"title": "首页",
"icon": "home",
"showInMenu": true
}
},
{
"path": "pages/profile/profile",
"style": {
"navigationBarTitleText": "个人中心"
},
"meta": {
"title": "个人中心",
"needLogin": true
}
}
],
"subPackages": [
{
"root": "pages-sub",
"pages": [
{
"path": "detail/detail",
"style": {
"navigationBarTitleText": "详情页"
},
"meta": {
"title": "详情页",
"parent": "/pages/index/index"
}
}
]
}
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/profile/profile",
"text": "我的"
}
]
}
}🔧 性能优化
插件内置了多级缓存机制:
- 配置缓存 - 基于文件修改时间缓存
pages.json解析结果 - 路由缓存 - 缓存路由解析结果,避免重复计算
- 映射缓存 - 缓存路由映射表生成结果
- 智能失效 - 配置文件更新时自动清除相关缓存
性能数据
- 首次解析:与原始解析时间相当
- 后续调用:性能提升 80%+,接近 O(1) 时间复杂度
- 内存优化:智能缓存管理,避免内存泄漏
🐛 常见问题
Q: 为什么路由信息没有更新?
A: 确保 pages.json 文件路径正确,插件会监听文件变化并自动更新缓存。
Q: 如何添加自定义字段?
A: 在 includes 选项中添加字段名,然后在 pages.json 中对应页面配置该字段。
Q: TypeScript 类型提示不生效?
A: 确保在项目中添加了全局类型声明文件 types/global.d.ts。
Q: 分包路由路径格式是什么?
A: 分包路由路径格式为 /{root}/{path},例如 /pages-sub/detail/detail。
🔄 更新日志
v0.1.0
- ✨ 初始版本发布
- 🚀 支持主包、分包、TabBar 路由解析
- 💅 完整的 TypeScript 支持
- 🔧 多级缓存性能优化
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📄 License
MIT License
如果这个插件对你有帮助,请给个 ⭐️ Star 支持一下!
