项目功能太多,目录很乱怎么办?
问题描述
随着我们项目的迭代,页面功能也是越来越多。慢慢的我们想要找到很久之前的功能就很费时间,尤其是英语不好或者前辈起名很随意的同学,想找原来的功能全靠全局搜索。如果项目菜单还是动态的那更是雪上加霜。
能不能有办法让人快速了解我们的项目结构。清晰的知道每个文件都是干什么的,让项目组的每个同学都对业务都有很清晰的了解,即使不是自己负责的也有大概的认知。
解决方案
快速找到需要的代码
想解决快速找代码的需求,最简单的方案就是安装一个vue devtools。如图所示,点击这个按钮 就会自动打开vscode,找到相应组件对应的代码。非常的方便
生成目录文件
我的做法是根据代码中的注释和文档生成一个大概这样的markdown文档,我们可以看到每个文件或者文件夹的解释说明。并且可以直接点击路径跳转到相应文件。
文件注释的添加与提取
文件中的注释我使用了vscode中的korofileheader插件,用于生成文件头部注释。大概这样
<!--
* @Author: xxxx
* @Date: 2022-08-07 08:50:19
* @LastEditors:xxxx
* @LastEditTime: 2022-09-19 15:27:50
* @Description: 我是当前文件的描述
-->
settings.json的文件配置如下
// 头部注释
"fileheader.customMade": {
"Author": "git config user.name && git config user.email", // 同时获取用户名与邮箱
"Date": "Do not edit", // 文件创建时间(不变)
"LastEditors": "git config user.name && git config user.email", // 文件最后编辑者 与Author字段一致
"LastEditTime": "Do not edit", // 文件最后编辑时间
"Description": "请输入文件描述", // 介绍文件的作用、文件的入参、出参。
},
"fileheader.configObj": {
"autoAdd": true, // 检测文件没有头部注释,自动添加文件头部注释
"autoAddLine": 1000, // 文件超过多少行数 不再自动添加头部注释
"supportAutoLanguage": [
"js",
"ts",
"vue",
"css",
"less",
"html"
], // 设置之后,在数组内的文件才支持自动添加
"createHeader": true, // 新建文件自动添加头部注释
"throttleTime": 60000, // 对同一个文件 需要过1分钟再次修改文件并保存才会更新注释
},
然后通过一段正则出来。来匹配到 @Description后面的文本。当做这个文件的解释说明。
文件夹注释的添加与提取
文件夹的注释来自于文件夹内的 README.md
文件。在代码中,当处理一个目录时,它会检查该目录下是否存在一个 README.md
文件。如果存在,它会读取该文件的内容,并尝试获取文件的第一行作为该目录的注释。同时最好可以在 README.md
文件中补充这个文件夹的具体作用,实现了哪些需求。
具体代码
// 导入必要的 Node.js 模块
import * as fs from 'fs'
import * as path from 'path'
// 定义一个数组,列出需要在 Markdown 中显示的文件类型
const validExtensions = [`.ts`, `.js`, `.vue`, `.less`, `.css`]
/**
* 递归地生成指定目录的 Markdown 结构
* @param {string} dir - 要处理的目录路径
* @param {number} depth - 当前目录的深度,用于生成正确的缩进
* @returns {string} - 生成的 Markdown 结构
*/
function generateMarkdownStructure(dir, depth = 0) {
let result = ``
// 读取目录中的文件和子目录,并筛选出有效的文件和子目录
const files = fs.readdirSync(dir).filter(file => {
const filePath = path.join(dir, file)
const stats = fs.statSync(filePath)
if (stats.isDirectory()) {
return true
} else {
const fileExtension = path.extname(file)
return validExtensions.includes(fileExtension)
}
})
// 计算最长的文件名长度,以便在生成的 Markdown 中对齐文件描述
let maxFileNameLength = 0
for (let i = 0; i < files.length; i++) {
const file = files[i]
if (file.length > maxFileNameLength) {
maxFileNameLength = file.length
}
}
// 遍历每个文件和子目录,生成相应的 Markdown 行
for (let i = 0; i < files.length; i++) {
const file = files[i]
const filePath = path.join(dir, file)
const stats = fs.statSync(filePath)
const tabs = `│ `.repeat(depth) // 制表符用于表示目录的深度
if (stats.isDirectory()) {
// 如果是目录,检查是否存在 README.md 文件,并读取其内容作为目录的注释
let folderComment = ``
let readmePath = ``
if (fs.existsSync(path.join(filePath, `README.md`))) {
const readmeContent = fs.readFileSync(path.join(filePath, `README.md`), `utf-8`)
folderComment = readmeContent.split(`\n`)[0] ? `**${readmeContent.split(`\n`)[0]}**` : ``
readmePath = `(/${path.join(filePath, `README.md`).replace(/\\/g, `/`)})`
}
const subdirContent = generateMarkdownStructure(filePath, depth + 1)
if (subdirContent || readmePath) {
result += `${tabs}├── [${file}/]${readmePath} ${folderComment}\n`
result += subdirContent
}
} else {
// 如果是文件,读取文件的 @Description 注释,并生成相应的 Markdown 行
const linePrefix = i === files.length - 1 && !stats.isDirectory() ? `└──` : `├──`
let fileComment = ``
const fileContent = fs.readFileSync(filePath, `utf-8`)
const regex =
/\/\*(?:[^*]|[\r\n]|(?:\*+(?:[^*/]|[\r\n])))*@Description:\s*([^*]*)(?:\*\/)|<!--[^]*?@Description:\s*([^]*?)(?:-->)/s
const match = fileContent.match(regex)
if (match && (match[1] || match[2])) {
fileComment = (match[1] || match[2]).trim()
}
const numSpaces = maxFileNameLength - file.length
const spaces = ` `.repeat(numSpaces * 2)
result += `${tabs}${linePrefix} [${file}](/${filePath.replace(/\\/g, `/`)}) ${spaces}${fileComment}\n`
}
}
return result
}
// 定义一个数组,列出需要生成 Markdown 文档的源目录和目标 Markdown 文件的路径
const mapArr = [
{ sourcePath: `./src/assets`, mdPath: `./doc/src/assets.md` },
{ sourcePath: `./src/components`, mdPath: `./doc/src/components.md` },
{ sourcePath: `./src/config`, mdPath: `./doc/src/config.md` },
{ sourcePath: `./src/hooks`, mdPath: `./doc/src/hooks.md` },
{ sourcePath: `./src/layout`, mdPath: `./doc/src/layout.md` },
{ sourcePath: `./src/plugins`, mdPath: `./doc/src/plugins.md` },
{ sourcePath: `./src/router`, mdPath: `./doc/src/router.md` },
{ sourcePath: `./src/services`, mdPath: `./doc/src/services.md` },
{ sourcePath: `./src/store`, mdPath: `./doc/src/store.md` },
{ sourcePath: `./src/utils`, mdPath: `./doc/src/utils.md` },
{ sourcePath: `./src/views`, mdPath: `./doc/src/views.md` },
{ sourcePath: `./src/views/dataAnalysis`, mdPath: `./doc/src/views/数据分析.md` },
{ sourcePath: `./src/views/dataExtract`, mdPath: `./doc/src/views/数据采集.md` },
{ sourcePath: `./src/views/dataGovernance`, mdPath: `./doc/src/views/数据治理.md` },
{ sourcePath: `./src/views/dataPreview`, mdPath: `./doc/src/views/数据预览.md` },
{ sourcePath: `./src/views/manage`, mdPath: `./doc/src/views/管理模块.md` },
{ sourcePath: `./src/views/metaDataManage`, mdPath: `./doc/src/views/元数据管理.md` },
{ sourcePath: `./src/views/other`, mdPath: `./doc/src/views/其他.md` },
]
// 遍历 mapArr 数组,为每个源目录调用 generateMarkdownStructure 函数,并将结果写入到对应的 Markdown 文件
mapArr.forEach(item => {
const markdown = generateMarkdownStructure(item.sourcePath)
fs.writeFileSync(item.mdPath, markdown)
})
主要功能
- 筛选有效文件:代码中定义了一个
validExtensions
数组,用于筛选出需要在 Markdown 中列出的文件类型。 - 读取文件描述:对于每个文件,代码会尝试读取文件内容中的
@Description
注释,以提供文件的简短描述。 - 递归处理目录:代码会递归地处理每个子目录,并为每个目录生成相应的结构。
- 生成 Markdown 链接:为每个文件和目录生成一个链接,使得在查看生成的 Markdown 文档时,可以直接点击链接访问对应的文件或目录。
- 处理多个目录:代码中定义了一个
mapArr
数组,列出了多个需要生成 Markdown 文档的源目录和目标 Markdown 文件的路径。代码会遍历这个数组,并为每个源目录生成一个 Markdown 文件。
代码流程
-
初始化:首先,代码导入了
fs
和path
模块,用于文件操作和路径处理。 -
定义有效的文件扩展名:定义了一个
validExtensions
数组,列出了需要在 Markdown 中显示的文件类型。 -
定义主函数
generateMarkdownStructure
:这是一个递归函数,用于生成指定目录的 Markdown 结构。
- 读取目录中的文件和子目录。
- 筛选出有效的文件和子目录。
- 计算最长的文件名长度,以便在生成的 Markdown 中对齐文件描述。
- 遍历每个文件和子目录,生成相应的 Markdown 行。
- 如果是目录,则递归调用
generateMarkdownStructure
函数。 - 如果是文件,则读取文件的
@Description
注释,并生成相应的 Markdown 行。
-
处理多个目录:代码遍历
mapArr
数组,为每个源目录调用generateMarkdownStructure
函数,并将结果写入到对应的 Markdown 文件。
转载自:https://juejin.cn/post/7281437377511260218