npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nuxt-permission

v2.0.1

Published

Backend menu / permission driven dynamic routes and permissions for Nuxt: non-whitelisted routes register after login, with built-in permission state and hasPermission.

Readme

nuxt-permission

npm version npm downloads License Nuxt 在线体验

English | 中文

后端菜单/权限驱动的 Nuxt 动态路由与权限模块:白名单外的页在构建期从静态路由表摘除,登录后按后端菜单注册,未登录时路由根本不存在。内置权限状态、hasPermission、菜单转换助手,类型可声明合并扩展。

特性

  • 🔒  真·动态注册:未登录时路由不在表里,而非仅前端隐藏
  • 🗂  无需 views 目录:页照常写在 pages/,白名单外自动转动态
  • ⚡️  SSR 安全:router.options 注入,首屏 push 之前完成注册
  • 🌲  代码分割正常:构建期生成 bundler 可见的 import() 清单
  • 🧩  权限一条龙:usePermissionState / hasPermission / normalizePermissionMenus
  • 🅣  类型可扩展:meta 复用 RouteMeta,权限 key 用可合并的 PermissionMap

安装

npx nuxt module add nuxt-permission
# 或
pnpm add -D nuxt-permission

配置

// nuxt.config.ts
export default defineNuxtConfig({
    modules: ['nuxt-permission'],
    permission: {
        enabled: true,
        static: ['/', '/login'], // 白名单:保持静态的公开路由,其余全部动态
        // source: 'permission',  // 数据源文件(相对 srcDir,省扩展名),默认 permission.ts
        // routeFields: [],        // 额外保留在 route 层的字段
        // group: 'redirect',      // 分组节点自带页面时:'redirect'(默认)| 'navigate'
    },
})

| 选项 | 类型 | 默认 | 说明 | | :-- | :-- | :-- | :-- | | enabled | boolean | true | 总开关;false 时所有页保持静态、消费方调用不报错 | | static | string \| string[] | ['/', '/login'] | 白名单,其余全部转动态。glob:/home/** 整段公开 | | source | string | 'permission' | 数据源文件(相对 srcDir,省扩展名) | | routeFields | string[] | [] | 在内置 RouteRecordRaw 字段外额外保留在 route 层的字段 | | group | 'redirect' \| 'navigate' | 'redirect' | 分组节点(有 menu 子节点)且自带页面时:redirect 到第一个子菜单,或 navigate 渲染自身页面。无自带页面的分组一律重定向 |

用法

1. 数据源 <srcDir>/permission.ts

读登录态、拉权限/菜单、写状态、返回菜单树。首屏/刷新库自动调,登录后 load(),同一个源。

// app/permission.ts(SPA:token 存 localStorage;SSR 改用 useCookie)
export default definePermissionSource(async ({ setPermissionList, setMenuList }) => {
    const token = /* 你自己的登录态 */ useCookie('token').value
    if (!token) return []

    const { permissions, menus } = await $fetch('/api/user', {
        headers: { authorization: `Bearer ${token}` },
    })

    setPermissionList(permissions)
    // 用保留标记 `_btn` 标注按钮,使其折叠进父级 meta._permission
    const tree = normalizePermissionMenus(menus, v => ({ ...v, _btn: `${v.type}` === '2' }))
    setMenuList(tree)
    return tree
})

2. 登录后注册

token 存取归你;登录成功后调 load() 再跳转:

const { load } = usePermissionState()

async function onLogin() {
    await $fetch('/api/login', { method: 'POST' }) // 你:拿 token 存起来
    await load() // 库:跑数据源、写状态、注册路由
    await navigateTo('/dashboard')
}

3. 权限控制:v-if + hasPermission

hasPermission 独立自动导入,模板直接用(不做 v-permission 指令):

<button v-if="hasPermission('menu-add')">新增</button>
<button v-if="hasPermission(['menu-edit', 'menu-view'])">编辑</button>        <!-- 任一命中 -->
<button v-if="hasPermission(['menu-edit', 'menu-view'], true)">编辑</button>  <!-- 全部命中 -->

⚠️ hasPermission 只是体验层,不是安全边界——真正鉴权在后端。

4. normalizePermissionMenus 菜单转换

把后端原始菜单树转成路由形状:在 cb 里标注 _btn: true 的节点折叠进父级 meta._permission(key = permission 字段,value = 整个按钮节点,_btn 标记会被剥离);有 menu 子节点的视为分组,redirect 到第一个子菜单;cb 返回 falsy 排除该节点及子树;后端 meta 摊平进 meta。

保留字段(统一 _ 前缀,与后端数据隔离):输入标记 _btn(你在 cb 里设置以标注按钮);输出 meta._permission(折叠的按钮权限)、meta._external(外链标记)。

菜单 path 说明

  • 外链http(s)://、协议相对 //):保留在菜单树但不注册为路由——侧边栏用 <a> 渲染(带 meta._external 标记)。
  • 参数页:后端 path 支持中括号或冒号两种写法——/detail/[id]/detail/:id 都能命中 pages/detail/[id].vue
  • 带 query:如 /report?range=7d,注册 pathname /report,完整值留给侧边栏链接。
  • 去重:同一页被多个菜单项指向时只注册一次(首个生效);菜单树仍保留每个入口。

类型扩展(declaration merging)

meta 复用 vue-router 的 RouteMeta,权限 key 用可合并的 PermissionMap

declare module 'vue-router' {
    interface RouteMeta {
        title?: string
        icon?: string
        // ... 你的 meta 字段,menu.meta / route.meta 都有类型
    }
}

declare module 'nuxt-permission' {
    interface PermissionMap {
        keys: 'menu-add' | 'menu-edit' | 'menu-view' // hasPermission 的 key 有补全
    }
    interface PermissionButton { // meta._permission 里 button 节点的字段
        id: number
        name: string
        permission: string
    }
}

扩展 PermissionMap 后,hasPermission('...')route.meta._permission['...'] 的 key 都会自动收窄为你声明的联合。无需(也无法)重声明 RouteMeta._permission 去覆盖——interface 声明合并不允许用不同类型重定义同名属性。

i18n

菜单文案层完全兼容(库不碰 name/meta,侧边栏用 {{ $t(...) }} 即可)。路由层:动态路由是运行时注册的原始 path,推荐 @nuxtjs/i18nstrategy: 'no_prefix';prefix 策略与运行时动态路由是已知限制。

Contribution

pnpm install
pnpm dev:prepare   # 生成类型 stub
pnpm dev           # playground 开发
pnpm lint
pnpm test