refactor(fes-cli): 精简和优化mock代码

n
This commit is contained in:
harrywan 2020-10-27 16:28:59 +08:00
parent a2da5d9821
commit d521575515
10 changed files with 214 additions and 327 deletions

View File

@ -6,7 +6,7 @@ const opn = require('opn');
const path = require('path');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpackDevMiddleware = require('webpack-dev-middleware');
const initMock = require('../mock/init.js');
const createMock = require('./createMock');
module.exports = function createDevServer(port, defaultConfig) {
@ -18,7 +18,7 @@ module.exports = function createDevServer(port, defaultConfig) {
const app = express();
// 初始化Mock数据
initMock(app);
createMock(app);
const compiler = webpack(defaultConfig);

View File

@ -0,0 +1,202 @@
/* eslint-disable import/no-dynamic-require */
const Mock = require('mockjs');
const faker = require('faker');
const path = require('path');
const fs = require('fs');
const express = require('express');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const logger = require('morgan');
const httpProxy = require('http-proxy');
const url = require('url');
const log = require('./log');
const util = require('./util');
const router = express.Router();
const proxy = httpProxy.createProxyServer();
proxy.on('open', (proxySocket) => {
proxySocket.on('data', (chunk) => {
log.message(chunk.toString());
});
});
proxy.on('proxyRes', (proxyRes) => {
log.message(
'RAW Response from the target',
JSON.stringify(proxyRes.headers, true, 2)
);
const cookie = proxyRes.headers['set-cookie'];
if (cookie && cookie.length > 0) {
for (let i = 0; i < cookie.length; i++) {
cookie[i] = cookie[i].replace('Secure', '');
}
}
});
proxy.on('error', (e) => {
log.error(e);
});
// 根据参数个数获取配置
function getOption(arg) {
const len = arg.length;
// 默认配置
const option = {
headers: {
'Cache-Control': 'no-cache'
},
statusCode: 200,
cookies: [],
timeout: 0
};
if (len === 0) {
return option;
}
if (len === 1) {
const newOption = arg[0];
if (util.isObject(newOption)) {
util.each(newOption, (value, key) => {
if (key === 'headers') {
util.each(newOption.headers, (headervalue, headerkey) => {
option.headers[headerkey] = newOption.headers[headerkey];
});
} else {
option[key] = newOption[key];
}
});
}
} else {
option.url = arg[0];
option.result = arg[1];
}
return option;
}
// 把基于 cgiMockfile 的相对绝对转成绝对路径
function parsePath(value) {
const PROJECT_DIR = process.env.PWD || process.cwd();
return path.resolve(PROJECT_DIR, value);
}
const createMock = function () {
const cgiMock = function (...arg) {
const option = getOption(arg);
if (!option.url || !option.result) {
return;
}
// option.method is one of ['get','post','delete','put'...]
const method = option.method || 'use';
router[method.toLowerCase()](option.url, (req, res) => {
setTimeout(() => {
// set header
res.set(option.headers);
// set Content-Type
option.type && res.type(option.type);
// set status code
res.status(option.statusCode);
// set cookie
util.each(option.cookies, (item) => {
const name = item.name;
const value = item.value;
delete item.name;
delete item.value;
res.cookie(name, value, item);
});
// do result
if (util.isFunction(option.result)) {
option.result(req, res);
} else if (
util.isArray(option.result)
|| util.isObject(option.result)
) {
!option.type && res.type('json');
res.json(option.result);
} else {
!option.type && res.type('text');
res.send(option.result.toString());
}
}, option.timeout);
});
};
cgiMock.prefix = '/';
// 读取文件内容
cgiMock.file = function (file) {
return fs.readFileSync(parsePath(file));
};
cgiMock.proxy = function (host) {
process.nextTick(() => {
router.use((req, res) => {
proxy.web(req, res, {
target: host,
secure: false
});
});
});
proxy.on('proxyReq', (proxyReq) => {
proxyReq.setHeader('Host', url.parse(host).host);
});
};
return cgiMock;
};
let cachePrefix = '';
const loadMock = function (app, cgiMockFile, cgiMock) {
router.stack = [];
util.cleanCache(cgiMockFile);
const projectMock = require(cgiMockFile);
if (!util.isFunction(projectMock)) {
log.error('mock.js 应该导出Function !');
return false;
}
projectMock(cgiMock, Mock, faker);
cachePrefix = cgiMock.prefix;
app.use(cachePrefix, (req, res, next) => {
router(req, res, next);
});
return true;
};
const loadCustomRoute = function (app) {
const PROJECT_DIR = process.env.PWD || process.cwd();
const cgiMockFile = path.resolve(PROJECT_DIR, './mock.js');
const cgiMock = createMock(app);
if (!fs.existsSync(cgiMockFile)) {
log.error('mock.js不存在请检查!');
} else {
try {
if (loadMock(app, cgiMockFile, cgiMock)) {
log.message('mock.js 加载成功');
}
util.watchFile(cgiMockFile, () => {
log.message('mock.js 发生变化重新加载Mock');
loadMock(app, cgiMockFile, cgiMock);
});
} catch (e) {
log.error('mock.js 加载失败,请检查:');
log.error(JSON.stringify(e));
}
}
};
module.exports = function (app) {
app.use(logger('dev'));
app.use(
bodyParser.urlencoded({
extended: false
})
);
app.use(cookieParser());
loadCustomRoute(app);
};

View File

@ -1,142 +0,0 @@
const express = require('express');
const fs = require('fs');
const path = require('path');
const httpProxy = require('http-proxy');
const url = require('url');
const util = require('./util');
const proxy = httpProxy.createProxyServer();
global.router = express.Router();
/**
* 数据模拟函数
*/
function cgiMock() {
// eslint-disable-next-line
const option = getOption(arguments);
if (!option.url || !option.result) {
return;
}
// option.method is one of ['get','post','delete','put'...]
const method = option.method || 'use';
global.router[method.toLowerCase()](option.url, (req, res) => {
setTimeout(() => {
// set header
res.set(option.headers);
// set Content-Type
option.type && res.type(option.type);
// set status code
res.status(option.statusCode);
// set cookie
util.each(option.cookies, (item) => {
const name = item.name;
const value = item.value;
delete item.name;
delete item.value;
res.cookie(name, value, item);
});
// do result
if (util.isFunction(option.result)) {
option.result(req, res);
} else if (util.isArray(option.result) || util.isObject(option.result)) {
!option.type && res.type('json');
res.json(option.result);
} else {
!option.type && res.type('text');
res.send(option.result.toString());
}
}, option.timeout);
});
}
// 根据参数个数获取配置
function getOption(arg) {
const len = arg.length;
// 默认配置
const option = {
headers: {
'Cache-Control': 'no-cache'
},
statusCode: 200,
cookies: [],
timeout: 0
};
if (len === 0) {
return cgiMock;
} if (len === 1) {
const newOption = arg[0];
if (util.isObject(newOption)) {
util.each(newOption, (value, key) => {
if (key === 'headers') {
util.each(newOption.headers, (headervalue, headerkey) => {
option.headers[headerkey] = newOption.headers[headerkey];
});
} else {
option[key] = newOption[key];
}
});
}
} else {
option.url = arg[0];
option.result = arg[1];
}
return option;
}
// 把基于 cgiMockfile 的相对绝对转成绝对路径
function parsePath(value) {
return path.join(global.cgiMockFilePath, value);
}
// log proxy data
proxy.on('open', (proxySocket) => {
proxySocket.on('data', (chunk) => {
console.log(chunk.toString());
});
});
proxy.on('proxyRes', (proxyRes) => {
console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
const cookie = proxyRes.headers['set-cookie'];
if (cookie && cookie.length > 0) {
for (let i = 0; i < cookie.length; i++) {
cookie[i] = cookie[i].replace('Secure', '');
}
}
});
proxy.on('error', (e) => {
console.log(e);
});
// 规则之外的请求转发
cgiMock.proxy = function (host) {
process.nextTick(() => {
global.router.use((req, res) => {
proxy.web(req, res, {
target: host,
secure: false
});
});
});
proxy.on('proxyReq', (proxyReq) => {
proxyReq.setHeader('Host', url.parse(host).host);
});
};
// 读取文件内容
cgiMock.file = function (file) {
return fs.readFileSync(parsePath(file));
};
cgiMock.prefix = '/';
module.exports = cgiMock;

View File

@ -1,97 +0,0 @@
const Mock = require('mockjs');
const faker = require('faker');
const path = require('path');
const fs = require('fs');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const onFinished = require('on-finished');
const util = require('./util');
const cgiMock = require('./cgiMock');
const log = require('../helpers/log');
const main = {
init(app, argv, cwd) {
this.app = app;
this.argv = argv;
this.cwd = cwd;
app.use(logger('dev'));
app.use(
bodyParser.urlencoded({
extended: false
})
);
app.use(cookieParser());
this.customRoute();
},
customRoute() {
const argv = this.argv;
const defaultCgiMockFile = path.join(process.cwd(), 'mock.js');
const home = process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'];
let cgiMockFile;
if (argv) {
if (argv.f) {
if (process.platform === 'win32') {
cgiMockFile = path.resolve(this.cwd, this.argv.f);
} else if (argv.f[0] === '~') {
cgiMockFile = path.resolve(
home,
argv.f.replace(/^~\//, '')
);
} else {
cgiMockFile = path.resolve(this.cwd, this.argv.f);
}
} else {
cgiMockFile = defaultCgiMockFile;
}
} else {
cgiMockFile = defaultCgiMockFile;
}
global.cgiMockFilePath = path.resolve(cgiMockFile, '..');
const loadRouteConfig = function () {
util.cleanCache(cgiMockFile);
try {
if (!fs.existsSync(cgiMockFile)) {
log.error('mock.js文件不存在请检查!');
} else {
// eslint-disable-next-line
const projectMock = require(cgiMockFile);
if (util.isFunction(projectMock)) {
global.router.stack = [];
projectMock(cgiMock, Mock, faker);
log.message('mock.js 加载成功');
} else {
log.error(
'mock.js 应该导出Function !'
);
}
}
} catch (e) {
log.error('mock.js 加载失败,请检查:');
log.error(JSON.stringify(e));
}
};
loadRouteConfig();
this.app.use(cgiMock.prefix, (req, res, next) => {
onFinished(res, () => {
loadRouteConfig();
});
global.router(req, res, next);
});
util.watchFile(cgiMockFile, () => {
log.message('mock.js 发生变化重新加载Mock');
loadRouteConfig();
});
}
};
module.exports = main.init.bind(main);

View File

@ -1,17 +0,0 @@
const express = require('express');
const argv = require('yargs').argv;
const port = argv.p || 8888;
const cwd = process.cwd();
const app = express();
const init = require('../init');
init(app, argv, cwd);
app.set('port', port);
app.listen(port, () => {
console.log(`cgiMock server listening on ${port}`);
});

View File

@ -1,64 +0,0 @@
module.exports = function mock(cgiMock, Mock) {
const Random = Mock.Random;
// 前缀,全局(可选)
cgiMock.prefix = '/prefix';
// 返回一个数字
cgiMock('/number', 123);
// 返回一个json
cgiMock({
url: '/json',
result: {
code: '400101', msg: "不合法的请求:Missing cookie 'wb_app_id' for method parameter of type String", transactionTime: '20170309171146', success: false
}
});
// 利用mock.js 产生随机文本
cgiMock('/text', Random.cparagraph());
// 返回一个字符串 利用mock.js 产生随机字符
cgiMock('/string', Mock.mock({
'string|1-10': '★'
}));
// 正则匹配url, 返回一个字符串
cgiMock(/\/abc|\/xyz/, 'regexp test!');
// option.result 参数如果是一个函数, 可以实现自定义返回内容, 接收的参数是是经过 express 封装的 req 和 res 对象.
cgiMock(/\/function$/, (req, res) => {
res.send('function test');
});
// 返回文本 fs.readFileSync
cgiMock('/file', cgiMock.file('./test.json'));
// 更复杂的规则配置
cgiMock({
url: /\/who/,
method: 'GET',
result(req, res) {
if (req.query.name === 'kwan') {
res.json({ kwan: '孤独患者' });
} else {
res.send('Nooooooooooo');
}
},
headers: {
'Content-Type': 'text/plain',
'Content-Length': '123',
ETag: '12345'
},
cookies: [
{
name: 'myname', value: 'kwan', maxAge: 900000, httpOnly: true
}
],
// 接口随机延迟
timeout: Mock.mock({
'number|1000-5000': 1000
}).number
});
};

View File

@ -1 +0,0 @@
file test

View File

@ -25,12 +25,12 @@ module.exports = (cgiMock, Mock) => {
// 正则匹配url, 返回一个字符串
// cgiMock(/\/abc|\/xyz/, 'regexp test!');
cgiMock(/\/abc|\/xyz/, 'regexp test!');
// option.result 参数如果是一个函数, 可以实现自定义返回内容, 接收的参数是是经过 express 封装的 req 和 res 对象.
// cgiMock(/\/function$/, function (req, res) {
// res.send('function test');
// });
cgiMock(/\/function$/, (req, res) => {
res.send('function test');
});
// 返回文本 fs.readFileSync
// cgiMock('/file', cgiMock.file('./test.json'));

View File

@ -76,6 +76,12 @@ export default {
if (this.FesStorage.get('userLogin') === true) {
this.getRole();
}
this.FesApi.fetch('/login', {
}).then((res) => {
console.log(res);
});
},
methods: {
login() {