KOA 基础框架搭建

584 阅读3分钟

项目基础文件夹

  1. assets:放置静态资源
  2. component:放置组件
  3. config:放置公共配置
  4. controllers:放置路由
  5. docs:生成接口docs文件
  6. logs:日志文件
  7. middleware:中间件
  8. models:数据接口
  9. tests:测试文件
  10. utils:工具类
  11. views:页面组件
  12. .babelrc:bebel文件 将es6转es5
  13. app.js 项目主文件
  14. index.js 测试接口
  • 插件文件
  • mrkid koa-demo
  • 初始化
  • npm init
  • 安装
  • 安装koa
  • npm install koa --save-dev
  • 安装 co
  • npm install co --save-dev
  • 安装koa-swig koa模板引擎

npm install koa-swig --save-dev

  • 安装静态资源管理koa-static
  • npm install koa-static --save-dev
  • 安装 日志管理包 log4js
  • npm install log4js --save-dev
  • 安装路由
  • npm install koa-simple-router --save-dev
  • 安装数据form格式化工具
  • npm install form-data --save-dev
  • 安装jsdoc 生成接口文档
  • npm install jsdoc --save-dev
  • 安装lodash
  • npm install loadsh --save-dev
  • 安装supervisor 启动引擎
  • npm install supervisor --save-dev

app.js文件使用

const Koa = require("koa");const app = new Koa();const co = require("co");const render = require('koa-swig');const serve = require('koa-static');const errorHandler = require("./middleware/errorHandler");const log4js = require('log4js');const config = require("./config")app.use(serve(config.staticDir));//注入我们的路由机制app.context.render = co.wrap(render({    root: config.viewDir,    autoescape: true,    // cache: "memory",    cache: false,    ext: 'html',    varControls: ["[[", "]]"],    writeBody: false}));//逻辑和业务错误 http日志log4js.configure({    appenders: {        cheese: {            type: 'file',            filename: 'logs/yd.log'        }    },    categories: {        default: {            appenders: ['cheese'],            level: 'error'        }    }});const logger = log4js.getLogger('cheese');errorHandler.error(app, logger);require("./controllers")(app);app.listen(config.port, () => {    console.log("服务已启动🍺🍞");});

config/index.js 文件

const _ = require("lodash");const { join } = require('path');let config = {"viewDir": join(__dirname, "..", 'views'),"staticDir": join(__dirname, "..", 'assets')};if (process.env.NODE_ENV == "development") {const localConfig = {port: 3000,baseUrl: "http://localhost/basic/web/index.php?r="}config = _.extend(config, localConfig);}if (process.env.NODE_ENV == "production") {const prodConfig = {port: 80}config = _.extend(config, prodConfig);}module.exports = config;

package.json文件

{"name": "yd-books","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build": "babel ./assets/scripts/add.js --out-file ./assets/scripts/add-bundle.js","server:dev": "cross-env NODE_ENV=development supervisor ./app.js","docs": "jsdoc ./**/*.js -d ./docs/jsdocs"},"keywords": [],"author": "","license": "ISC","devDependencies": {"@babel/cli": "^7.4.3","@babel/core": "^7.4.3","@babel/plugin-transform-modules-systemjs": "^7.4.0","@babel/preset-env": "^7.4.3","axios": "^0.18.0","catharsis": "^0.8.9","cross-env": "^5.2.0","cross-spawn": "^6.0.5","form-data": "^2.3.3","jsdoc": "^3.5.5","koa": "^2.7.0","koa-simple-router": "^0.2.0","koa-static": "^5.0.0","koa-swig": "^2.2.1","lodash": "^4.17.11","log4js": "^4.1.0","mime-db": "^1.39.0","supervisor": "^0.12.0"},"dependencies": {"node-fetch": "^2.6.1"}}

/assets/scripts/add.js

class Create {constructor() {}fn() {console.log("🐘es6语法的初始化");$("#test").click(yd.throttle(function () {fetch()}, 10));}}export default Create;/assets/scripts/index.jsconsole.log("index init")// console.log(Vue);var app6 = new Vue({el: '#app',data: {message: 'Hello Vue!'}})// export default app6;

/assets/scripts/yd.js

//全局帮助的类库function yd() { }yd._version = 0.1;yd.throttle = function (fn, wait) {    var timer;    return function (...args) {        if (!timer) {            timer = setTimeout(() => timer = null, wait);            return fn.apply(this, args);        }    }}//函子redux 基础应用 纯函数。。。

/controllers/index.js

const router = require('koa-simple-router');const IndexController = require("./IndexController");const indexController = new IndexController();module.exports = (app) => {app.use(router(_ => {_.get('/index.html', indexController.actionIndex());_.get('/', indexController.actionIndex());_.get('/add', indexController.actionAdd());}));}

/controllers/IndexController.js

const router = require('koa-simple-router');const IndexController = require("./IndexController");const indexController = new IndexController();module.exports = (app) => {    app.use(router(_ => {        _.get('/index.html', indexController.actionIndex());        _.get('/', indexController.actionIndex());        _.get('/add', indexController.actionAdd());    }));}

middleware/errorHandler.js

const errorHandler = {    error(app, logger) {        app.use(async (ctx, next) => {            try{                await next();            }catch(err){                //电话 ☎️ 微信 邮件📧 。。。                logger.error(err);                ctx.status = 500;                ctx.body = "😭哇喔网站出错了~";                // ctx.render("error")            }        });        app.use(async (ctx, next) => {            await next();            if(404 !== ctx.status){                return;            }             //很多项目即使出现了404请求 header 200            ctx.status = 404;            ctx.body = '<script type="text/javascript" src="//qzonestyle.gtimg.cn/qzone/hybrid/app/404/search_children.js" charset="utf-8"></script>';        });    }}module.exports = errorHandler;

/models/Index.js

/** * @fileoverview 实现Index的数据模型 * @author yuanzhijia@yidengxuetang.com */const SafeRequest = require("../utils/SafeRequest");/** * 📚Index类 获取数据关于图书数据相关的类 * @class */class Index {    /**     * @constructor     * @param {string} app KOA2的上下文     */    constructor(app) {    }    /**     * 获取后台数据全部图书列表的方法     * @param {*} options 配置项     * @example     * return new Promise     * getData(options)     */    getData(options) {        const safeRequest = new SafeRequest("books/index");        return safeRequest.fetch({});    }    /**     * 把用户传过来的数据保存进入借口     * @param {*} options 配置项     * @example     * return new Promise     * saveData(options)     */    saveData(options) {        const safeRequest = new SafeRequest("books/create");        return safeRequest.fetch({            method: "POST",            params: options.params        });    }}module.exports = Index;

/utils/SafeRequest.js

//未来将来把浏览器端的代码和后台的代码相互替换或者拷贝const fetch = require("node-fetch");const config = require("../config");class SafeRequest {    constructor(url) {        this.url = url;        this.baseUrl = config.baseUrl;    }    fetch(options) {        //产生一个完整的链接 发起一个promise的结结果        let ydfetch = fetch(this.baseUrl + this.url);        if (options) {            const body = { a: 1 };            ydfetch = fetch(this.baseUrl + this.url, {                method: options.method,                body: options.params,            });        }        return new Promise((resolve, reject) => {            let result = {                code: 0,                message: "",                data: []            };            ydfetch                .then((res) => {                    let _json = {};                    try {                        _json = res.json()                    } catch (error) {                        //发邮件📩                    }                    return _json;                })                .then((json) => {                    //你们产线跟后端定了一些api的交互形式                    result.data = json;                    resolve(result);                }).catch((error) => {                    console.log(error);                    result.code = 1;                    result.message = "node-fetch和后端通讯异常❎";                    reject(result);                })        })    }}module.exports = SafeRequest;

/views/add.html

{% extends './layout.html' %}{% block styles %}<link rel="stylesheet" href="/styles/add.css">{% endblock %}{% block title %} 添加图书📚 {% endblock %}{% block content %}<div id="app"><h2>{{ message }}</h2><input v-model="message"></div>{% endblock %}{% block scripts %}<script type="module">console.log("我支持模块化💇");import("/scripts/add.js").then((_)=>{const create = new _.default;create.fn();});</script><script type="nomodule" src="https://cdn.staticfile.org/systemjs/3.1.2/system.js"></script><script type="nomodule">System.import("/scripts/add-bundle.js").then((_) => {const create = new _.default;create.fn();});</script>{% endblock %}

/views/index.html

{% extends './layout.html' %}{% block styles %}<link rel="stylesheet" href="/styles/index.css">{% endblock %}{% block title %} 图书页面的首页📚 {% endblock %}{% block content %}<!-- <h1>[[ data ]]</h1> --><table class="table table-bordered">{% for item in data %}<tr><td>[[item.id]] </td><td>[[item.name]] </td><td>[[item.author]] </td></tr>{% endfor %}</table><hr /><div id="app"><h2>{{ message }}</h2><input v-model="message"></div>{% endblock %}{% block scripts %}<script src="/scripts/index.js"></script>{% endblock %}

/views/layout.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>{% block title %}{% endblock  %}</title>    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.css">    {% block styles %}{% endblock  %}</head><body>    <div>        {% block content %}{% endblock  %}    </div>    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>    {% block scripts %}{% endblock  %}</body></html>