超简版的koa小框架和egg小框架?‍?

这是我参与更文挑战的第2天,活动详情查看: 更文挑战

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}
复制代码

我会把文件放到github

欢迎关注作者,感谢支持❗☘

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享