Node.js如何遍历文件夹获取指定后缀文件并提取settings.js中变量
需求可行性确认
该需求完全可实现,核心逻辑分为两步:递归遍历components目录匹配所有settings.js文件、提取每个文件内const item的取值,全程仅需使用Node.js内置模块,无需引入第三方依赖。
具体实现方案
根据你的settings.js是否有导出item变量,可以选择对应的实现方式:
场景1:settings.js中已导出item
如果每个settings.js末尾存在module.exports = { item }这类导出逻辑,可以直接通过require读取文件取值,实现最简单:
const fs = require('fs/promises') const path = require('path') // 替换为你实际的components文件夹绝对路径 const componentsDir = path.join(__dirname, 'components') // 递归遍历目录,收集所有settings.js的绝对路径 async function findAllSettingsFiles(dir) { const result = [] const dirEntries = await fs.readdir(dir, { withFileTypes: true }) for (const entry of dirEntries) { const fullEntryPath = path.join(dir, entry.name) if (entry.isDirectory()) { result.push(...await findAllSettingsFiles(fullEntryPath)) } else if (entry.isFile() && entry.name === 'settings.js') { result.push(fullEntryPath) } } return result } async function printAllItems() { const allSettingsPaths = await findAllSettingsFiles(componentsDir) for (const filePath of allSettingsPaths) { // 清除模块缓存,避免多次读取同个文件返回旧值 delete require.cache[require.resolve(filePath)] const { item } = require(filePath) console.log(`文件路径:${filePath}\nitem取值:`, item, '\n===') } } printAllItems().catch(console.error)
场景2:settings.js未导出item,仅定义了变量
这种情况不能直接用require读取,可根据item的定义逻辑选择以下两种实现:
方式A:正则匹配提取(适合静态字面量定义的item)
如果item是字符串、数字、普通对象这类静态字面量,用正则匹配+取值的方式最快捷:
const fs = require('fs/promises') const path = require('path') const componentsDir = path.join(__dirname, 'components') // 遍历目录逻辑和场景1完全一致 async function findAllSettingsFiles(dir) { const result = [] const dirEntries = await fs.readdir(dir, { withFileTypes: true }) for (const entry of dirEntries) { const fullEntryPath = path.join(dir, entry.name) if (entry.isDirectory()) { result.push(...await findAllSettingsFiles(fullEntryPath)) } else if (entry.isFile() && entry.name === 'settings.js') { result.push(fullEntryPath) } } return result } async function printAllItems() { const allSettingsPaths = await findAllSettingsFiles(componentsDir) // 支持跨行匹配const item的定义,到分号结束 const itemMatchReg = /const\s+item\s*=\s*([\s\S]*?);/ for (const filePath of allSettingsPaths) { const fileContent = await fs.readFile(filePath, 'utf-8') const matchResult = fileContent.match(itemMatchReg) if (!matchResult) continue try { // 转换匹配到的字符串为JS原生值 const item = eval(`(${matchResult[1]})`) console.log(`文件路径:${filePath}\nitem取值:`, item, '\n===') } catch (err) { console.error(`解析文件${filePath}的item失败:`, err) } } } printAllItems().catch(console.error)
方式B:VM沙箱执行(适合动态计算的item,更安全)
如果item是经过逻辑计算得到的动态值,用Node.js内置的vm模块在沙箱中执行文件内容取值更稳妥:
const fs = require('fs/promises') const path = require('path') const vm = require('vm') const componentsDir = path.join(__dirname, 'components') // 遍历目录逻辑和上述一致 async function findAllSettingsFiles(dir) { const result = [] const dirEntries = await fs.readdir(dir, { withFileTypes: true }) for (const entry of dirEntries) { const fullEntryPath = path.join(dir, entry.name) if (entry.isDirectory()) { result.push(...await findAllSettingsFiles(fullEntryPath)) } else if (entry.isFile() && entry.name === 'settings.js') { result.push(fullEntryPath) } } return result } async function printAllItems() { const allSettingsPaths = await findAllSettingsFiles(componentsDir) for (const filePath of allSettingsPaths) { const fileContent = await fs.readFile(filePath, 'utf-8') // 沙箱上下文,如果文件有依赖其他模块,可在此注入require、module等全局变量 const sandboxContext = {} try { vm.runInNewContext(fileContent, sandboxContext) console.log(`文件路径:${filePath}\nitem取值:`, sandboxContext.item, '\n===') } catch (err) { console.error(`执行文件${filePath}失败:`, err) } } } printAllItems().catch(console.error)
注意:如果你的settings.js内有引入其他模块的逻辑,在沙箱执行时需要把require、__dirname等全局变量注入到sandboxContext中即可正常执行
内容的提问来源于stack exchange,提问作者Dev2840
相关产品推荐
相关产品推荐

