
告别手动注册D2Admin 的 Vuex 模块自动注册全解【免费下载链接】d2-adminAn elegant dashboard项目地址: https://gitcode.com/gh_mirrors/d2/d2-admin做 Vue 2 中后台项目时Vuex 模块数量一旦涨到十几个你大概率体会过这种痛入口文件里逐个 import、逐个挂到 modules 上漏一个就是一片难查的 undefined入口还越写越长。D2Admind2-admin对这个问题的解法是借助 webpack 的require.context在 Vuex 状态管理入口处自动扫描模块目录并完成注册——一行代码兜住 15 个业务模块全程不需要手动维护清单。这篇文章就带你逐段过一遍这套机制的源码顺带总结可以直接搬回自己项目的套路。先看效果一行 require.context 给 Vuex 入口省掉了什么先看 D2Admin store 的目录分层一共三层各管一摊src/store/ ├── index.js # 入口创建 Vuex 实例注册顶层 d2admin 模块 └── modules/ └── d2admin/ ├── index.js # 聚合器一行 require.context 收集全部子模块 └── modules/ # 15 个业务模块全部平铺在这一个目录 ├── account.js ├── theme.js └── ...其余 13 个 .js 文件入口文件 src/store/index.js 只有 5 行有效代码new Vuex.Store({ modules: { d2admin } })连具体有哪些子模块都不提。真正的收口在第二层src/store/modules/d2admin/index.js 用一行require.context把整个 modules 目录扫了一遍。这套写法带来三个实际收益零配置入口和聚合器都不 import 任何具体模块文件不遗漏目录里有文件就一定被注册不存在加了文件忘了挂的情况扩展只动一处以后要加报表状态新建report.js丢进 modules 目录模块名report自动就位其余文件一行不用改文件头注释还特意写了 There should not be any reason to edit this file——不应该有任何理由去改这个文件。这句话基本就是这套设计的意图宣言。自动注册三步走扫目录、文件名即键名、统一 namespaced 导出核心逻辑就是十来行代码拆成三步看。第一步扫描目录。const files require.context(./modules, false, /\.js$/)require.context是 webpack 的构建时 API可以把它理解成一个限定片区的快递员三个参数分别限定投递范围是./modules目录、false表示不递归子目录所有模块必须平铺在同一层、正则/\.js$/只收 .js 文件。哪些文件属于这个片区在编译阶段就确定了运行时代价几乎为零。第二步文件名即模块名。const modules {} files.keys().forEach(key { modules[key.replace(/(\.\/|\.js)/g, )] files(key).default })files.keys()返回的是一串./theme.js这样的键正则剥掉./前缀和.js后缀剩下的部分直接当模块名写进modules对象。也就是说文件叫什么名字store 里就多了什么模块——约定即配置。第三步统一声明命名空间并导出。export default { namespaced: true, modules }namespaced是 Vuex 的命名空间开关作用类似给每个模块套上独立的包名避免不同模块里的 state、action 同名打架。这里由聚合层统一打开子模块文件里各自也声明一次两层配合后形成完整的三级隔离。业务模块作者完全不用操心命名空间规则。15 个业务模块分别在管什么按角色分组梳理modules 目录 下 15 个文件按职责大致能归成四组比逐个背名字好理解。账户与用户组account负责登录、注销以及登录成功后的设置批量加载user.js 只管用户信息的存取持久化时带user: true参数做用户隔离不同账号的数据互不串味。界面状态组menu管顶栏/侧栏菜单和侧边栏折叠动画page管多标签页列表与 keep-alive 缓存fullscreen监听浏览器全屏事件gray控制全屏灰度比如注销确认时把背景变灰search维护全局搜索面板的状态和快捷键。全局设置组theme、color、size、transition分别对应主题、主色、组件尺寸、页面过渡动画这四个也是持久化读写最频繁的一组。日志与版本组log记录操作日志releases在控制台打印版本胶囊信息ua解析并记录浏览器 UA。另外还有一个特殊的db模块它没有 state只提供 set / get / databasePage 这样一组纯 actions统一承接所有持久化读写后面会再讲它的作用。挑theme模块展开一点看它的setaction 会先校验主题名在 setting.js 主题列表里存在然后把值写回 store接着commit(dom)把theme-xxx这个 class 直接刷到document.body上最后再异步落到持久化存储——整套 7 套主题的切换就是这三步见 theme.js L26-L74。下图就是 star 主题生效后的实际背景再看accountlogin action 先调接口拿到凭证把 uuid 和 token 写进 cookie再 dispatchd2admin/user/set同步用户信息到 store最后 await 自己的loadaction。组件里怎么 dispatch三级命名空间与同构模式延伸有了 namespaced 体系组件里的调用统一是顶层模块 / 子模块 / 方法三段式// 触发登录 this.$store.dispatch(d2admin/account/login, { username, password }) // 跨模块调用需要 { root: true } this.$store.dispatch(d2admin/db/set, { dbName: sys, path: theme.activeName, value: star, user: true }, { root: true })这里值得多说一句{ root: true }模块被命名空间包起来后dispatch 出来的 action 名默认只在本模块作用域内解析加上root: true相当于跳出当前楼层按根路径寻址这样才能从 account 模块里调到 db 模块的 set。用登录后的加载链路串一遍就很直观loadactionaccount.js L71-L86会依次 await 七个跨模块 dispatch——user/load、theme/load、transition/load、page/openedLoad、menu/asideLoad、size/load、color/load。每个被调模块的 load 都走同一套路db/get取值并带 defaultValue 兜底、写回 state、应用到界面。这就是刷新页面后所有个性化设置原样恢复的全部秘密而且七个模块之间互不 import全靠 db 模块做中转。这套扁平目录 正则匹配 文件名即键名的套路在 D2Admin 里其实出现了三次除了 storesrc/assets/svg-icons/index.jsrequire.context(./icons, false, /\.svg$/)扫 svg 图标新增一个 svg 文件图标就自动可用src/i18n.jsrequire.context(./locales, ...)收集语言包 json新增语言文件后自动进入切换列表三处结构完全同构区别只是正则和目录不同。最后给几个能直接落地的迁移建议扁平目录 单聚合文件模块平铺在一级目录由一个聚合文件统一扫描入口不写死任何 importnamespaced 在聚合层收口命名空间规则只声明一处子模块专心写业务文件名即注册名把建文件作为唯一的扩展入口新人看懂目录就会扩展持久化收口到单一 db 模块业务模块不直接碰 localStorage 等存储 API将来换 IndexedDB 或后端存储只改一个文件这套聚合器 自动注册的组合让 D2Admin 的 Vuex 状态管理在模块继续膨胀时入口文件依然保持五行不变——模块越多收益越明显 【免费下载链接】d2-adminAn elegant dashboard项目地址: https://gitcode.com/gh_mirrors/d2/d2-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考