实现超简版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')//Pokclass 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 = reqctx.response.res = resreturn 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和methodroute = 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.jsmodule.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的框架pggconst 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 = ctxawait 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}
欢迎关注作者,感谢支持❗☘
