如何从文件系统生成带嵌套子页面的Page对象列表?
实现嵌套子页面对象的目录解析方案
文件结构
pages/ - Home.jsx - Blog.jsx - Post.Blog.jsx - Posts.Blog.jsx - private/ -- Admin.jsx -- Dashboard.jsx -- admin/ --- Main.Admin.jsx -- author/ --- Post.Admin.jsx -- editor/ --- Editor.Admin.jsx
生成规则
- 扩展名前为单一名称的文件,生成基础页面对象:
{name:"Home", isPrivate:false, permission:"guest"} - 私有目录外的点分隔文件名,生成带
subpages的父页面对象,子页面挂载到对应父对象的subpages数组:{name:"Blog", isPrivate:false, permission:"guest", subpages:[{name:"Post", isPrivate:false, permission:"guest"},{name:"Posts", isPrivate:false, permission:"guest"}]} - 私有目录内的文件,
isPrivate设为true,permission为所在子目录名,同时生成带subpages的父页面对象:{name:"Admin", isPrivate:true, permission:"private", subpages:[{name:"Post",isPrivate:true, permission:"author"},{name:"Main", isPrivate:true, permission:"admin"}]}
当前问题代码
之前尝试用循环添加子页面时,递归处理私有目录出现异常,简化后的代码如下:
const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const directoryPath = join(__dirname,'../../../../ui/src/pages') const files = [] const createList = (dir)=>{ const fileMatrix = fs.readdirSync(dir) fileMatrix.map(file=>{ const filePath = join(dir,file) const stats = fs.statSync(filePath) const isDir = stats.isDirectory() const isPrivate = filePath.includes('private') const permission = isPrivate ? path.dirname(filePath).split('/').pop():"guest" const fileParts = path.basename(filePath,'.jsx').split('.') const fileName = fileParts[0] const parent = fileParts[1] if (!isDir){ file = { name:fileName, isPrivate, permission } console.log(file) } else if(isDir){ createList(filePath) } }) } createList(directoryPath);
解决方案代码
核心思路是用映射表跟踪父页面,递归遍历目录时自动挂载子页面,同时正确处理私有目录的权限逻辑:
const fs = require('fs'); const path = require('path'); const { fileURLToPath } = require('url'); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const directoryPath = path.join(__dirname, '../../../../ui/src/pages'); // 映射表:快速查找已创建的页面对象,避免重复创建 const pageMap = new Map(); // 最终输出的页面对象列表 const pageList = []; const createPageList = (dir) => { const items = fs.readdirSync(dir); items.forEach(item => { const itemPath = path.join(dir, item); const stats = fs.statSync(itemPath); const isDir = stats.isDirectory(); const isPrivate = itemPath.includes('private'); if (isDir) { // 递归处理子目录 createPageList(itemPath); return; } // 解析文件名和父页面名称 const baseName = path.basename(itemPath, '.jsx'); const [pageName, parentPageName] = baseName.split('.'); // 确定权限值 let permission = 'guest'; if (isPrivate) { const relativePath = path.relative(directoryPath, itemPath); const pathSegments = relativePath.split(path.sep); const privateIndex = pathSegments.indexOf('private'); // 取private目录下的直接子目录作为权限,没有则设为private permission = privateIndex !== -1 && pathSegments.length > privateIndex + 1 ? pathSegments[privateIndex + 1] : 'private'; } const pageObj = { name: pageName, isPrivate, permission, subpages: [] }; if (!parentPageName) { // 无父页面,直接加入列表(去重) if (!pageMap.has(pageName)) { pageMap.set(pageName, pageObj); pageList.push(pageObj); } } else { // 有父页面,先查找或创建父页面对象 let parentPage = pageMap.get(parentPageName); if (!parentPage) { parentPage = { name: parentPageName, isPrivate: isPrivate, permission: isPrivate ? 'private' : 'guest', subpages: [] }; pageMap.set(parentPageName, parentPage); pageList.push(parentPage); } // 将当前页面对象加入父页面的subpages数组 parentPage.subpages.push(pageObj); } }); }; createPageList(directoryPath); console.log(JSON.stringify(pageList, null, 2));
代码说明
pageMap映射表:解决父页面重复创建的问题,同时提供O(1)的查找效率,方便快速挂载子页面。- 递归目录处理:遍历所有层级的文件和目录,确保私有目录下的文件也能被正确解析。
- 权限逻辑优化:通过相对路径解析
private目录的位置,准确获取文件所在的子目录作为权限值。 - 子页面挂载:自动处理父页面不存在的情况,先创建父页面基础结构,再将子页面加入其
subpages数组。
内容的提问来源于stack exchange,提问作者Nineisten
相关产品推荐
相关产品推荐

