elpis-core
注:抖音“哲玄前端”,《全栈实践课》
elpis-core 是什么?
该项目是一个基于koa二次封装的一个项目,主要是通过实现loader加载文件,并挂载到app对象上,app文件下的配置也挂载到app对象上。
loader目录
在elpis-core入口文件引入loader
const Koa = require('koa');
const path = require('path');
const { sep } = path; // 兼容不同操作系统上的斜杠
const env = require('./env');
const middlewareLoader = require('./loader/middleware');
const routerSchemaLoader = require('./loader/router-schema');
const routerLoader = require('./loader/router');
const controllerLoader = require('./loader/controller');
const serviceLoader = require('./loader/service');
const configLoader = require('./loader/config');
const extendLoader = require('./loader/extend');
const DEFAULT_PORT = 8080;
const DEFAULT_HOST = '0.0.0.0';
module.exports = {
/**
* @description 启动项目
* @param {object} options
* options = {
* name: string, // 项目名称
* homePath: string, // 项目首页
* }
*/
async start (options = {}) {
// Koa 实例
const app = new Koa();
// 挂载应用配置
app.options = options;
// 基础路径
app.baseDir = process.cwd();
// 业务文件路径
app.businessPath = path.resolve(app.baseDir, `.${sep}app`);
// 初始化环境变量
app.env = env();
console.log(`-- [start] env: ${app.env.getEnv()} --`);
// 加载所有模块
module.exports.loadModules(app);
// 注册全局中间件
try {
require(`${app.businessPath}${sep}middleware.js`)(app);
console.log(`-- [start] load global middleware done --`);
} catch (error) {
console.log('[exception] there is no global middleware file.');
}
//单独加载routerLoader,防止routerLoader中间件被覆盖
routerLoader(app);
// 启动服务
try {
const port = process.env.PORT || DEFAULT_PORT;
const host = process.env.IP || DEFAULT_HOST;
app.listen(port, host);
console.log(`Server running on port: ${port}`);
} catch (error) {
console.log('error', error);
}
},
/**
* @description 加载所有模块
* @param {Koa} app
*/
loadModules (app) {
const loaders = [
{ loader: middlewareLoader, name: 'middleware' },
{ loader: routerSchemaLoader, name: 'routerSchema' },
{ loader: controllerLoader, name: 'controller' },
{ loader: serviceLoader, name: 'service' },
{ loader: configLoader, name: 'config' },
{ loader: extendLoader, name: 'extend' },
// { loader: routerLoader, name: 'router' }
];
loaders.forEach(({ loader, name }) => {
loader(app);
console.log(`-- [start] load ${name} --`);
});
}
};
controller.js
const glob = require('glob');
const path = require('path');
const { sep } = path; // 兼容不同操作系统上的斜杠
/**
* @description controller loader
* @param {object} app Koa 实例
* @todo 加载所有 controller,可通过 'app.controller.${目录}.${文件名}' 访问
* @example
app/controller
|
| --custom-module
|
| --custom-controller.js
=>app.controller.customModule.customController
*
*/
module.exports = (app) => {
// 读取 app/controller 目录下的所有文件
const controllerPath = path.resolve(app.businessPath, `.${sep}controller`);
const fileList = glob.sync(path.resolve(controllerPath, `.${sep}**${sep}**.js`));
// 遍历文件,挂载到 app.controller 下
const controller = {};
fileList.forEach((file) => {
// 获取文件名
let name = path.relative(controllerPath, file).slice(0, -3); // 去掉 .js 后缀
// 截取路径 app/controller/custom-module/custom-controller.js => custom-module/custom-controller
name = name.replace(/[_-][a-z]/ig, (s) => s.slice(1).toUpperCase());
// return;
// 挂载 controller 到内存 app 对象中
const names = name.split(sep); // ['customModule(目录)', 'customController(文件)']
let tempController = controller;
names.forEach((part, index) => {
// return;
if (index === names.length - 1) { // 文件
const ControllerModule = require(path.resolve(file))(app);
tempController[part] = new ControllerModule();
} else { // 目录
tempController[part] = tempController[part] || {};
tempController = tempController[part];
}
});
});
app.controller = controller;
}
全局middleware
另一个觉得比较重要的就是全局middleware,负责配置静态根目录、模板渲染引擎、引入ctx.body解析中间件、引入异常捕获中间件、引入签名合法性校验中间件、引入API参数合法性校验中间件。
const path = require('path');
module.exports = (app) => {
// 配置静态根目录
const koaStatic = require('koa-static');
app.use(koaStatic(path.resolve(process.cwd(), './app/public')));
// 模板渲染引擎
const koaNunjucks = require('koa-nunjucks-2');
app.use(koaNunjucks({
ext: 'tpl',
path: path.resolve(process.cwd(), './app/public'),
nunjucksConfig: {
noCache: true,
trimBlocks: true
}
}));
// 引入ctx.body解析中间件
const bodyParser = require('koa-bodyparser');
app.use(bodyParser({
formLimit: '1mb',
enableTypes: ['json', 'form', 'text']
}));
// 引入异常捕获中间件
app.use(app.middlewares.errorHandler);
// 引入签名合法性校验中间件
app.use(app.middlewares.apiSignVerify);
// 引入API参数合法性校验中间件
app.use(app.middlewares.apiParamsVerify);
}
最后感觉重要的一点是要理解好洋葱圈模型。