实现超简版koa框架和egg框架
学习node框架,接触了koa和egg,通过平时使用,我了解了她们的特性,就想实现一下简单核心的功能。希望能够更加熟练掌握它们。
阅读需要10分钟
step1:简单手写超简版的koa小框架(Pok)✨
实现的简单功能🔋
搭建http服务
简易路由的搭建
中间件的合成
request和response的封装
上下文context.js
文件目录内容📌
app.js
pok.js
context.js
response.js
router.js
测试文件(app.js)📜
const Pok = require('./pok')
const app = new Pok()
// ==============Router start================
const Router = require('./router')
const router = new Router()
router.get('/index', async ctx => { ctx.body = 'index page'; });
router.get('/post', async ctx => { ctx.body = 'post page'; });
router.get('/list', async ctx => { ctx.body = 'list page'; });
router.post('/index', async ctx => { ctx.body = 'post page'; });
app.use(router.routes());
// ==============Router end================
app.listen(3001,()=>{
console.log('服务已启动');
})
封装一个类似koa的框架pok📜
//引入基本库
const http = require('http')
const context = require('./context')
const request = require('./request')
const response = require('./response')
//Pok
class Pok{
constructor(){
this.middlewares = []
}
listen(...args){
const server = http.createServer(async (req,res)=>{
//创建content上下文
const ctx = this.createContext(req,res);
//合并中间件
const fn = this.compose(this.middlewares)
await fn(ctx)
res.end(ctx.body)
})
server.listen(...args)
}
use(middleware){
this.middlewares.push(middleware)
}
//创建content上下文
createContext(req,res){
const ctx = Object.create(context)
ctx.request = Object.create(request)
ctx.response = Object.create(response)
ctx.request.req = req
ctx.response.res = res
return ctx
}
// 中间件
compose(middlewares){
return function(ctx){
return ds(0)
function ds(i){
let fn = middlewares[i]
if(!fn){
return Promise.resolve()
}else{
return Promise.resolve(
fn(ctx,function next(){
return ds(i+1)
})
)
}
}
}
}
}
module.exports = Pok
路由的封装(router.js)📜
class Router {
constructor() {
this.stack = []
}
resigter(method, path, middleware) {
this.stack.push({method, path, middleware})
}
get(path, middleware) {
this.resigter('get', path, middleware)
}
post(path, middleware) {
this.resigter('post', path, middleware)
}
routes() {
let stock = this.stack;
return async function(ctx, next) {
let currentPath = ctx.url;
console.log(currentPath);
let route;
for (let i = 0; i < stock.length; i++) {
let item = stock[i];
console.log(item);
if (currentPath === item.path && item.method.indexOf(ctx.method) >= 0) {
// 判断path和method
route = item.middleware;
break;
}
}
if (typeof route === 'function') {
route(ctx, next);
return;
}
await next();
};
}
}
module.exports = Router
request和response的封装 (request.js)📜
module.exports = {
get url(){
return this.req.url
},
get method(){
return this.req.method.toLowerCase()
}
};
response.js
module.exports = {
get body(){
return this._body
},
set body(val){
this._body = val
}
};
上下文的封装(context.js)📜
module.exports = {
get url() {
return this.request.url
},
get body() {
return this.response.body
},
set body(val){
this.response.body = val
},
get method() {
return this.request.method
}
}
step2:简单手写Egg框架实现mvc分层(基于koa)
实现的简单功能🔋
对koa进行封装,实现mvc分层
主要内容📌
initRouter
initController
initService
LoadConfig
更新中。。。
测试文件(app.js)📜
const pgg = require('./pgg')
const app = new pgg()
app.start(3000)
#封装一个类似Egg的框架pgg
const koa = require('koa');
const {initRouter, initController, initService,LoadConfig} = require('./pgg-loader')
class Pgg{
constructor(conf){
this.$app = new koa(conf)
LoadConfig(this)
this.$service = initService(this)
this.$ctrl = initController(this)
this.$router = initRouter(this)
//挂载路由
console.dir(this.$ctrl);
// 调用routes函数
this.$app.use(this.$router.routes())
}
start(port){
this.$app.listen(port,()=>{
console.log(`服务器${port}启动成功`);
})
}
}
module.exports = Pgg
读取不同文件(pgg-loader.js)📜
const fs = require('fs')
const path = require('path')
const Router = require('koa-router')
const Sequelize = require('sequelize')
// 读取文件,将方法 路径 和函数转换成对象
function load(dir,cb) {
//转换成绝对路径
const url = path.resolve(__dirname,dir)
//读指定目录下所有文件名称”的数组对象。
const files = fs.readdirSync(url)
// 遍历文件,读取内容
files.forEach(filename=>{
filename = filename.replace('.js','')
const file= require(url+'/'+filename)
console.log(filename,'文件名');
// 文件名称
cb(filename,file)
})
}
//路由页面的初始化
function initRouter(app) {
const router = new Router()
// 初始化route文件路径下的路由文件
load("routes",(filename,routes)=>{
// index 前缀处理
const prefix = filename === 'index'?'':`/${filename}`
// 路由类型判断
routes = typeof routes=== 'function'?routes(app):routes
// 遍历添加路由配置
Object.keys(routes) .forEach(key=>{
// 获取请求方法和路径
const[method,path] = key.split(' ');
console.log(` ${method.toLocaleUpperCase()} ${prefix}${path}\n,${routes[key]}`);
router[method](prefix + path,async ctx=>{
app.ctx = ctx
await routes[key](ctx)
})
})
})
return router
}
//控制层的初始化
function initController(app) {
const controllers = {}
load('controller',(filename,controller)=>{
controllers[filename] = controller(app)
})
return controllers
}
//服务层的初始化
function initService() {
const services = {}
load('service',(filename,service)=>{
services[filename] = service
})
return services
}
//配置持久化
function LoadConfig(app) {
load('config',(filename,config)=>{
if(config.db){
app.$db = new Sequelize(config.db)
}
app.$model = {}
load('model',(filename,{schema, options})=>{
app.$model[filename] = app.$db.define(filename, schema, options)
});
app.$db.sync();
}
)}
//持久层的初始化
module.exports = {initRouter,initController,initService,LoadConfig}
欢迎关注作者,感谢支持❗☘