Koa2快速构建BFF应用OOP版🤔
🚗 基本操作
首先先要分清楚 SSR CSR,MVC
yarn init
🚗 启动服务
yarn add koa -S
https://www.npmjs.com/package/koa
Koa2 API 很重要,要仔细阅读:
// ./app.js
const Koa = require("koa");
const app = new Koa();
// response
app.use((ctx) => {
ctx.body = "Hello Koa";
});
app.listen(3000, () => {
console.log("服务已启动🚀🚀🚀🚀🚀");
});
🚗 注册路由(C)
yarn add @koa/router -S
https://www.npmjs.com/package/koa-router
koa-router API 很重要仔细阅读
https://github.com/koajs/router/blob/master/API.md
koa-router
// ./app.js
const Koa = require("koa");
const app = new Koa();
const Router = require("@koa/router");
const router = new Router();
// 换个路由试试
router.get("/", (ctx, next) => {
ctx.body = "<h1>Hello Koa - router</h1>";
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log("服务已启动🚀🚀🚀🚀🚀");
});
但是在实际开发中这样写路由是不行的:
Controllers
// ./controllers/index.js
const Router = require("@koa/router");
const router = new Router();
router.get("/", (ctx, next) => {
ctx.body = "<h1>Hello Koa - router</h1>";
});
module.exports = (app) => {
app.use(router.routes()).use(router.allowedMethods());
};
// ./app.js
require("./controllers")(app);
在进行封装
// ./controllers/IndexController.js
class IndexController {
constructor() {}
actionIndex() {
return async (ctx, next) => {
ctx.body = "<h1>Hello Koa - routercv</h1>";
};
}
}
module.exports = IndexController;
// ./controllers/index.js
const Router = require("@koa/router");
const router = new Router();
// index
const IndexController = require("./IndexController");
const indexController = new IndexController();
router.get("/", indexController.actionIndex());
module.exports = (app) => {
app.use(router.routes()).use(router.allowedMethods());
};
🚗 启动服务升级版
设置环境
yarn add cross-env -S
https://www.npmjs.com/package/cross-env
"scripts": {
"dev": "cross-env NODE_ENV=development node ./app.js"
},
console.log("🍎🍎🍎🍎 ", process.env.NODE_ENV);
配置文件 config
// ./config/index.js
let config = {};
if (process.env.NODE_ENV == "development") {
const baseConfig = {
ip: "localhost",
host: 3000,
};
Object.assign(config, baseConfig);
}
module.exports = config;
// ./app.js
const Koa = require("koa");
const app = new Koa();
const config = require("./config/index");
require("./controllers")(app);
app.listen(config.host, () => {
console.log(
`服务已启动🚀🚀🚀🚀🚀 ===== http://${config.ip}:${config.host}`
);
});
热启动
node-supervisor
sudo yarn add supervisor -g
https://www.npmjs.com/package/supervisor
"scripts": {
"dev": "cross-env NODE_ENV=development node-supervisor ./app.js"
},
pm2
==预留==
🚗 模板引擎 (V)
koa-swig && ejs
koa-swig
yarn add koa-swig -S
koa-swig 性能突出,但是没人维护了
https://github.com/koa-modules/swig#readme
koa-swig 模板语言语法
https://www.jianshu.com/p/82cade205875
// ./app.js
const { join } = require("path");
const render = require("koa-swig");
const co = require("co");
app.context.render = co.wrap(
render({
// 查看根目录
root: join(config.viewDir),
// ???
autoescape: true,
// 缓存
cache: config.cacheMode,
// 默认视图外命名
ext: "html",
//
varControls: ["[[", "]]"],
// 默认(true)自动写入正文和响应
writeBody: false,
// 工具函数引入
filters: require("./utils/SwigFilters.js"),
})
);
// ./config/index.js
const { join } = require("path");
let config = {
viewDir: join(__dirname, "..", "views"),
};
if (process.env.NODE_ENV == "development") {
const baseConfig = {
cacheMode: false,
ip: "localhost",
host: 3000,
};
Object.assign(config, baseConfig);
}
module.exports = config;
// ./utils/SwigFilters.js
exports.text1 = (e) => {
return `${e}----text1`;
};
./views/web.html 主模板内容
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>
<title>{% block title %}{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
{% block content %}{% endblock %} {% block scripts %}{% endblock %}
</body>
</html>
./view/index/index.html 路由模板
{% extends '../web.html' %} {% block title %}🤔KOA2快速构架BFF应用🤔{% endblock
%} {% block head %} {% endblock %} {% block content %}
<header></header>
<main>
<h1>🤔KOA2快速构架BFF应用🤔</h1>
<h2>[[data]]</h2>
<h2>[[data | text1()]]</h2>
</main>
<footer></footer>
{% endblock %} {% block scripts %} {% endblock %}
controller 中输出
const html = await ctx.render("index/index", {
data: "IndexController",
});
ctx.body = html;
导入静态文件
yard add koa-static -S
https://www.npmjs.com/package/koa-static
// ./app.js
const serve = require("koa-static");
app.use(serve(".")); //待研究 指定某一目录
/* ./assets/css/index.css */
h1 {
color: salmon;
}
h2 {
color: yellowgreen;
}
<link rel="stylesheet" href="../../assets/css/index.css" />
🚗 数据模型 (M)
node-fetch
yarn add node-fetch@2 -S
https://www.npmjs.com/package/node-fetch
baseURL: 'https://devwww.laoyaoba.com/api',
// ./utils/SafeRequest.js
const fetch = require("node-fetch");
const config = require("../config");
class SafeRequest {
constructor(url) {
this.url = url;
this.baseURL = config.baseURL;
}
async fetch(options) {
let _fetch;
if (options.params) {
_fetch = fetch(this.baseURL + this.url, {
method: options.method,
body: options.params,
});
} else {
_fetch = fetch(this.baseURL + this.url);
}
return await new Promise((resolve, reject) => {
let result = {
message: "node-fetch:后端接口返回成功",
data: [],
};
_fetch
.then((res) => res.json())
.then((json) => {
if (json.errno == 0) {
result.data = json;
resolve(result);
} else {
result.data = json;
result.message = "node-fetch:后端返回数据异常";
result.api = this.baseURL + this.url;
result.params = options.params.toString();
reject(result);
}
})
.catch((error) => {
result.data = error;
result.message = "node-fetch:node-fetch和后端通讯异常";
result.api = this.baseURL + this.url;
result.params = options.params.toString();
reject(result);
});
});
}
}
module.exports = SafeRequest;
// ./models/IndexModel.js
const SafeRequest = require("../utils/SafeRequest.js");
class IndexModel {
constructor(app) {}
getFeedStream(options) {
const safeRequest = new SafeRequest("/news/feedstream");
return safeRequest.fetch({
method: "POST",
params: options.params,
});
}
}
module.exports = IndexModel;
// ./controllers/IndexController.js
const IndexModel = require("../models/IndexModel");
const indexModel = new IndexModel();
const { URLSearchParams } = require("url");
class IndexController {
constructor() {}
actionIndex() {
return async (ctx, next) => {
const result = await this.getData();
const html = await ctx.render("index/index", {
data: "IndexController",
list: result,
});
ctx.body = html;
};
}
async getData() {
try {
const params = await new URLSearchParams();
params.append("source", "pc");
const result = await indexModel.getFeedStream({
params,
});
return result.data.data;
} catch (e) {}
}
}
module.exports = IndexController;
{% for key, val in list %}
<h3>[[val.news_title]]</h3>
{% endfor %}