引子
趁着闲暇时间,自己学了点关于Node的知识,主要是困于不会后端,想着利用Node来搭建一个本地服务器,让自己可以摆脱对后端服务器的依赖,也可以学习一些新的知识,拓宽一下自己的领域。
刚开始在写接口的时候,发现了一个很影响代码阅读的问题,就是接口过多,如何将接口进行分模块,代码如下
const express = require('express');
//首先加载express
const app = express()
//端口号
const port = 3000
//这里仅列举发送GET请求
app.get('/student',(req,res) =>{
const result = [{name: "zhangsan"}];
res.send(result)
})
// ...其他接口
app.listen(port,() => console.log('server is start,port is', port))
尝试优化
这样适合初学者去练习,当接口过多了,会导致接口篇幅过长,且不利于代码维护,基于此,想着把接口进行模块化处理,将接口分块处理,依次引入,然后就做了如下优化
// node index.js
const express = require('express');
// 引入接口模块
const { API: StudentAPI } = require('./api/student');
const { API: PersonAPI } = require('./api/person');
// ...引入其他模块
//首先加载express
const app = express()
//端口号
const port = 3000
// 接口注册
StudentAPI.use(app)
PersonAPI.ues(app)
// ...注册其他模块接口
app.listen(port,() => console.log('server is start,port is', port))
// student.js接口
exports.API = {
use(app) {
//这里仅列举发送GET请求
app.get('/student',(req,res) =>{
const result = [{name: "zhangsan"}];
res.send(result)
})
// ...
}
}
这样乍一看,确实提高了代码的可阅读性,也方便了代码后期可维护性,本来想着可以到此结束,照此拓展其他接口了,但是又想到后期继续加新模块,还要在index.js注册,不想这么麻烦,就想到了之前项目里使用的require.context了。
终极优化
于是开始在Node里搜索require.context,却发现并没有此方法,继续探索,发现了require.context只适用于webpack项目,好家伙,心凉了一大截,就开始探索require.context的实现原理了。
其原理大致如下
- 给定文件路径
- 读取当前路径下的所有文件,并收集
- 将收集的文件依次引入
是不是柳暗花明又一村,心想着利用Node去尝试实现下。此处涉及了Node的fs(文件系统模块)、path(路径模块)的内容,不熟悉的小伙伴可以去充电,做一下了解。立即充电
按照这个思路,我又做了代码调整
// autoLoadFiles.js
const fs = require('fs');
const path = require('path');
/**
* 读取文件列表
* @param {String} filePath 文件目录
* @param {Boolean} useSubFilePath 是否读取子目录
* @param {RegExp} fileReg 文件过滤正则
* @param {Array} fileList 收集的文件
* @returns {Array} fileList
*/
function readFileList(filePath, useSubFilePath, fileReg, fileList = []) {
// 读取当前文件夹下的内容
const files = fs.readdirSync(filePath);
files.forEach(item => {
// 获取当前文件的完整路径
const curFilePath = path.join(filePath, item);
// 获取文件stat信息,主要判断当前文件是否是文件或者文件夹
const fileStat = fs.statSync(curFilePath);
// 如果是文件,并且满足正则,则收集当前文件路径
if(fileStat.isFile() && fileReg.test(curFilePath)) {
fileList.push(curFilePath)
}
// 如果是文件夹,并且开启子目录查询,则递归遍历子目录
if(fileStat.isDirectory() && useSubFilePath) {
readFileList(curFilePath, useSubFilePath, fileReg, fileList)
}
})
// 返回收集的文件
return fileList;
}
function getFileName(fileFullPath) {
return path.basename(fileFullPath).split('.')[0];
}
exports.autoLoadFiles = function(filePath, useSubFilePath, fileReg) {
const fileList = readFileList(filePath, useSubFilePath, fileReg);
// 处理收集的文件
const res = fileList.map(filePath => ({
fullPath: filePath,
fileName: getFileName(filePath),
data: require(filePath) // 引入当前文件
}));
// 返回是收集的文件
return res;
}
// index.js
const express = require('express');
const path = require('path');
const { autoLoadFiles } = require('./autoLoadFiles');
const filePath = path.join(__dirname, '/api');
// 获取指定目录的文件内容
const files = autoLoadFiles(filePath, true, /.js$/);
//首先加载express
const app = express()
//端口号
const port = 3000
// 自动引入app的接口
files.forEach((file) => {
// 接口注册
file.data.API.use(app);
})
app.listen(port,() => console.log('server is start,port is', port))
// student.js 接口
exports.API = {
use(app) {
//这里仅列举发送GET请求
app.get('/student',(req,res) =>{
const result = [{name: "zhangsan"}];
res.send(result)
})
}
}
文档目录如下,仅供参考
希望能够帮助到有需求的你,respect!