diff --git a/.babelrc b/.babelrc index 51a8ae4..f0d8043 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,4 @@ { - "presets": ["es2015", "stage-2"], - "plugins": ["transform-runtime"] + 'presets': ['es2015', 'stage-2'], + 'plugins': ['transform-runtime'] } diff --git a/.eslintrc.js b/.eslintrc.js index 934f7f2..ab1a81f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -7,14 +7,14 @@ module.exports = { extends: 'standard', plugins: [ 'html', - "promise" + 'promise' ], env: { - "node": true + 'node': true }, rules: { // add your custom rules here // allow console - "no-console": 0, + 'no-console': 0, // allow paren-less arrow functions 'arrow-parens': 0, // allow async-await diff --git a/README.md b/README.md index 930fc78..73d94fd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ 此脚手架只安装了一些和Koa2不冲突的搭建RESTful API Server的必要插件,附带每一个插件的说明。采用ESlint进行语法检查。 -因此脚手架主要提供RESTful API,故暂时不考虑前端静态资源处理。基本目录结构与vue-cli保持一致,可配合React、AngularJS、Vue.js等前端框架使用。在Cordova/PhoneGap中使用时需要开启跨域功能。 +因此脚手架主要提供RESTful API,故暂时不考虑前端静态资源处理,只提供静态资源访问的基本方法便于访问用户上传到服务器的图片等资源。基本目录结构与vue-cli保持一致,可配合React、AngularJS、Vue.js等前端框架使用。在Cordova/PhoneGap中使用时需要开启跨域功能。 **免责声明:** 此脚手架仅为方便开发提供基础环境,任何人或组织均可随意克隆使用,使用引入的框架需遵循原作者规定的相关协议(框架列表及来源地址在下方)。采用此脚手架产生的任何后果请自行承担,本人不对此脚手架负任何法律责任,使用即代表同意此条。 @@ -22,7 +22,7 @@ $ git clone https://github.com/yi-ge/koa2-API-scaffold.git $ cd mv koa2-API-scaffold $ npm install -$ npm run dev #可执行npm start跳过ESlint检查。 +$ npm run dev # 可执行npm start跳过ESlint检查。 ``` 访问: http://127.0.0.1:3000/ @@ -37,7 +37,7 @@ $ rm -rf .git $ git init $ git remote add origin `您的git仓库地址` $ npm install -$ npm run dev #可执行npm start跳过ESlint检查。 +$ npm run dev # 可执行npm start跳过ESlint检查。 ``` ## 调试说明 @@ -79,14 +79,10 @@ http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/ ### Docker部署说明 ``` $ docker pull node -$ docker run -itd --name RESTfulAPI -v "$PWD":/usr/src/app -w /usr/src/app node node ./dist/app.js +$ docker run -itd --name RESTfulAPI -v '$PWD':/usr/src/app -w /usr/src/app node node ./dist/app.js ``` -通过 -``` -$ docker ps -``` -查看是否运行成功及运行状态 +通过'docker ps'查看是否运行成功及运行状态 ### Linux/Mac 直接后台运行生产环境代码 有时候为了简单,我们也这样做: @@ -94,7 +90,7 @@ $ docker ps $ nohup node ./dist/app.js > logs/out.log & ``` -查看运行状态(如果有"node app.js"出现则说明正在后台运行): +查看运行状态(如果有'node app.js'出现则说明正在后台运行): ``` $ ps aux|grep app.js ``` @@ -110,7 +106,7 @@ $ tail -f logs/out.log ``` ### 配合Vue-cli部署说明 -Vue-cli(Vue2)运行"npm run build"后会在"dist"目录中生成所有静态资源文件。推荐使用Nginx处理静态资源以达最佳利用效果,然后通过上述任意一种方法部署RESTful API服务器。前后端是完全分离的,请注意Koa2 RESTful API Server项目中config/main.json里面的跨域配置。 +Vue-cli(Vue2)运行'npm run build'后会在'dist'目录中生成所有静态资源文件。推荐使用Nginx处理静态资源以达最佳利用效果,然后通过上述任意一种方法部署RESTful API服务器。前后端是完全分离的,请注意Koa2 RESTful API Server项目中config/main.json里面的跨域配置。 推荐的Nginx配置文件: ``` @@ -150,23 +146,37 @@ $ docker run -itd -p 80:80 -p 443:443 -v `pwd`/nginx_config:/etc/nginx/conf.d ng > 引入插件的版本将会持续更新 引入的插件: -`` koa nodemon babel-cli babel-register babel-plugin-transform-runtime babel-preset-es2015 babel-preset-stage-2 gulp gulp-eslint eslint eslint-config-standard eslint-friendly-formatter eslint-plugin-html eslint-plugin-promise `` +`` koa@2 koa-bodyparser@next koa-router@next koa-session2 koa-static2 koa-compose require-directory babel-cli babel-register babel-plugin-transform-runtime babel-preset-es2015 babel-preset-stage-2 gulp gulp-eslint eslint eslint-config-standard eslint-friendly-formatter eslint-plugin-html eslint-plugin-promise nodemailer promise-mysql `` -"koa-bodyparser": "^3.2.0", -"koa-compose": "^3.1.0", -"koa-convert": "^1.2.0", -"koa-favicon": "^2.0.0", -"koa-json": "^1.1.3", -"koa-logger": "^1.3.0", -"koa-multer": "^1.0.0", -"koa-router": "^7.0.1", -"koa-session": "^3.3.1", -"koa-static2": "^0.1.8", -"koa-onerror": "^3.0.1", +koa-multer': '^1.0.0', -**koa**: HTTP框架 +**koa2**: HTTP框架  Synopsis: HTTP framework. - From: https://github.com/koajs/koa + From: https://github.com/koajs/koa v2 + +**koa-bodyparser**: body解析器 + Synopsis: A body parser for koa, base on co-body. support json, form and text type body. + From: https://github.com/koajs/logger + +**koa-router**: Koa路由 + Synopsis: Router middleware for koa. + From: https://github.com/alexmingoia/koa-router/tree/master/ + +**koa-session2**: Session中间件 + Synopsis: Middleware for Koa2 to get/set session. + From: https://github.com/Secbone/koa-session2 + +**koa-static2**: 静态资源中间件 + Synopsis: Middleware for Koa2 to serve a folder under a name declared by user. + From: https://github.com/Secbone/koa-static2 + +**koa-compose**: 多个中间件组合成一个 + Synopsis: Compose several middleware into one. + From: https://github.com/koajs/compose + +**require-directory**: 递归遍历指定目录 + Synopsis: Recursively iterates over specified directory. + From: https://github.com/troygoode/node-require-directory **babel-cli**: Babel编译ES6代码为ES5代码  Synopsis: Babel is a JavaScript compiler, ES6 to ES5. @@ -201,7 +211,7 @@ $ docker run -itd -p 80:80 -p 443:443 -v `pwd`/nginx_config:/etc/nginx/conf.d ng  From: https://github.com/feross/eslint-config-standard **eslint-friendly-formatter**: 使得ESlint提示在Sublime Text或iterm2中更友好,Atom也有对应的ESlint插件。 - Synopsis: A simple formatter/reporter for ESLint that's friendly with Sublime Text and iterm2 "click to open file" functionality + Synopsis: A simple formatter/reporter for ESLint that's friendly with Sublime Text and iterm2 'click to open file' functionality  From: https://github.com/royriojas/eslint-friendly-formatter **eslint-plugin-html**: 检查HTML文件中的JS代码规范 @@ -214,13 +224,36 @@ $ docker run -itd -p 80:80 -p 443:443 -v `pwd`/nginx_config:/etc/nginx/conf.d ng **eslint-plugin-promise**: ESlint依赖项  Synopsis: ESlint Rules for the Standard Linter. - From: https://github.com/xjamundx/eslint-plugin-standard + From: https://github.com/xjamundx/eslint-plugin-standard + +**nodemailer**: 发送邮件 + Synopsis: Send e-mails with Node.JS. + From: https://github.com/nodemailer/nodemailer + +**promise-mysql**: 操作MySQL数据库依赖 + Synopsis: Promise Mysql. + From: https://github.com/lukeb-uk/node-promise-mysql 支持Koa2的中间件列表:https://github.com/koajs/koa/wiki -其它经常配合Koa2的插件: +**其它经常配合Koa2的插件:** + **koa-nunjucks-2**: -一个好用的模版引擎,可用于前后端,nunjucks。https://github.com/mozilla/nunjucks +一个好用的模版引擎,可用于前后端,nunjucks:https://github.com/mozilla/nunjucks + +**koa-favicon**: +Koa的favicon中间件:https://github.com/koajs/favicon + +**koa-server-push**: +HTTP2推送中间件:https://github.com/silenceisgolden/koa-server-push + +**koa-convert**: 转换旧的中间件支持Koa2 + Synopsis: Convert koa generator-based middleware to promise-based middleware. + From: https://github.com/koajs/convert + +**koa-logger**: 请求日志输出,需要配合上面的插件使用 + Synopsis: Development style logger middleware for Koa. + From: https://github.com/koajs/logger ## 目录结构说明 @@ -240,13 +273,18 @@ $ docker run -itd -p 80:80 -p 443:443 -v `pwd`/nginx_config:/etc/nginx/conf.d ng ├── config │   └── main.js # 主配置文件(*谨防泄密!) ├── src # 源代码目录,编译后目标源代码位于 dist 目录 -│   ├── app.js # koa 配置 -│   ├── config # 配置目录 +│   ├── app.js # 入口文件 +│   ├── plugin # 插件目录 +│   └── smtp_sendemail # 示例插件 - 发邮件 +│   ├── tool # 工具目录 +│   ├── PluginLoader.js # 插件引入工具 +│   └── Common.js # 示例插件 - 发邮件 +│   ├── lib # 库目录 │   ├── controllers # 控制器 -│   ├── index.js # 入口文件 │   ├── models # 模型 │   ├── routes # 路由 -│   └── services # service +│   └── services # 服务 +├── assets # 静态资源目录 └── logs # 日志目录 ``` @@ -255,15 +293,15 @@ $ docker run -itd -p 80:80 -p 443:443 -v `pwd`/nginx_config:/etc/nginx/conf.d ng ### AngularJS (Ionic同) ``` $http({ - method: "post", - url: "http://localhost:3000/xxx", - data: {para1:"para1",para2:"para2"}, + method: 'post', + url: 'http://localhost:3000/xxx', + data: {para1:'para1',para2:'para2'}, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (data) { }).error(function (data) { - }); + }) ``` ### jQuery @@ -271,27 +309,27 @@ $http({ $.ajax({ cache: false, type: 'POST', - url: "http://localhost:3000/xxx", + url: 'http://localhost:3000/xxx', data: { para1: para1 }, async: false, - dataType: "json", + dataType: 'json', success: function (result) { }, error: function (err) { - console.log(err); + console.log(err) } -}); +}) // 上传文件 //创建FormData对象 -var data = new FormData(); +var data = new FormData() //为FormData对象添加数据 // $.each($('#inputfile')[0].files, function (i, file) { - data.append('upload_file', file); -}); + data.append('upload_file', file) +}) $.ajax({ url: 'http://127.0.0.1:3000/api/upload_oss_img_demo', type: 'POST', @@ -300,38 +338,38 @@ $.ajax({ contentType: false, //不可缺 processData: false, //不可缺 success: function (data) { - console.log(data); - if (data.result == "ok") { - $("#zzzz").attr("src", data.img_url); + console.log(data) + if (data.result == 'ok') { + $('#zzzz').attr('src', data.img_url) } } -}); +}) ``` ### MUI ``` -mui.ajax({ url: "http://localhost:3000/xxx", dataType: "json", +mui.ajax({ url: 'http://localhost:3000/xxx', dataType: 'json', success: function(data){ }, error: function(data){ - console.log("error!"); + console.log('error!') } -}); +}) ``` ### JavaScript ``` var xhr = new XMLHttpRequest() - xhr.open("POST", "http://localhost:3000/xxx", true) //POST或GET,true(异步)或 false(同步) - xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded") + xhr.open('POST', 'http://localhost:3000/xxx', true) //POST或GET,true(异步)或 false(同步) + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded') xhr.withCredentials = true xhr.onreadystatechange = function () { if (obj.readyState == 4 && obj.status == 200 || obj.status == 304) { var gotServices = JSON.parse(xhr.responseText) }else{ - console.log("ajax失败了") + console.log('ajax失败了') } } xhr.send({para1: para1}) @@ -342,8 +380,8 @@ https://github.com/pagekit/vue-resource ``` // global Vue object Vue.http.post('/someUrl', [body], { - headers: {"Content-type", "application/x-www-form-urlencoded"} -}).then(successCallback, errorCallback); + headers: {'Content-type', 'application/x-www-form-urlencoded'} +}).then(successCallback, errorCallback) ``` ### fetch @@ -365,7 +403,7 @@ fetch('/users', { }) // 文件上传 -var input = document.querySelector('input[type="file"]') +var input = document.querySelector('input[type='file']') var data = new FormData() data.append('file', input.files[0]) @@ -382,7 +420,7 @@ https://github.com/visionmedia/superagent ``` request.post('/user') .set('Content-Type', 'application/json') - .send('{"name":"tj","pet":"tobi"}') + .send('{'name':'tj','pet':'tobi'}') .end(callback) ``` @@ -391,6 +429,6 @@ request.post('/user') ## 彻底移除ESlint方法 删除package.json的devDependencies中所有eslint开头的插件,根目录下的“.eslintignore、.eslintrc.js”文件,并且修改package.json的dev为: ``` -"dev": "gulp start" +'dev': 'gulp start' ``` 删除gulpfile.js中的lint、eslint_start两个任务,并且把default改为“gulp.task('default', ['start']”。 diff --git a/assets/update/.gitkeep b/assets/update/.gitkeep new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/assets/update/.gitkeep @@ -0,0 +1 @@ +1 diff --git a/build/dev-server.js b/build/dev-server.js index 085b34e..2e119ef 100644 --- a/build/dev-server.js +++ b/build/dev-server.js @@ -1,2 +1,2 @@ -require("babel-register") -require("../src/app") +require('babel-register') +require('../src/app') diff --git a/config/main.js b/config/main.js index e69de29..403e748 100644 --- a/config/main.js +++ b/config/main.js @@ -0,0 +1,15 @@ +import path from 'path' + +export let SystemConfig = { + HTTP_server_type: 'http://', // HTTP服务器地址,包含"http://"或"https://" + HTTP_server_host: 'localhost',// HTTP服务器地址,请勿添加"http://" + HTTP_server_port: '3000',// HTTP服务器端口号 + System_country: 'zh-cn', // 所在国家的国家代码 + System_plugin_path: path.join(__dirname, "plugins/"), // 插件路径 + mysql_host: 'localhost', // MySQL服务器地址 + mysql_user: 'root', // 数据库用户名 + mysql_password: 'root', // 数据库密码 + mysql_database: 'test', // 数据库名称 + mysql_port: 3306, // 数据库端口号 + mysql_prefix: 'api_' // 默认"api_" +} diff --git a/package.json b/package.json index aa693c6..52e3008 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,14 @@ "production": "node dist/app.js" }, "dependencies": { - "koa": "^1.2.4" + "koa": "^2.0.0", + "koa-bodyparser": "^3.2.0", + "koa-compose": "^2.5.1", + "koa-router": "^7.0.1", + "koa-session2": "^1.0.8", + "nodemailer": "^2.7.2", + "promise-mysql": "^3.0.0", + "require-directory": "^2.1.1" }, "devDependencies": { "babel-cli": "^6.22.2", @@ -26,7 +33,8 @@ "eslint-plugin-standard": "^2.0.1", "gulp": "^3.9.1", "gulp-eslint": "^3.0.1", - "gulp-nodemon": "^2.2.1" + "gulp-nodemon": "^2.2.1", + "koa-logger": "^1.3.1" }, "engines": { "node": ">= 6.9.4", diff --git a/src/app.js b/src/app.js index 4ce04d0..4767ff4 100644 --- a/src/app.js +++ b/src/app.js @@ -1,3 +1,57 @@ +import Koa2 from 'koa' +import KoaBodyParser from 'koa-bodyparser' +import KoaSession from 'koa-session2' +import KoaStatic from 'koa-static2' +import { SystemConfig } from '../config/main.js' +import path from 'path' -console.log('ok') -console.log('aaa') +import MainRoutes from './routes/main-routes' +import ErrorRoutes from './routes/error-routes' +import PluginLoader from './tool/PluginLoader' + +const app = new Koa2() +const BodyParser = new KoaBodyParser() +const env = process.env.NODE_ENV || 'development' // Current mode + +app.use(BodyParser({ + detectJSON: function (ctx) { + return /\.json$/i.test(ctx.path) + }, + extendTypes: { + json: ['application/x-javascript'] // will parse application/x-javascript type body as a JSON string + }, + onerror: function (err, ctx) { + ctx.throw('body parse error:' + err, 422) + } +})) // Processing request +.use(KoaStatic('assets', path.resolve(__dirname, '../assets'))) // Static resource +.use(KoaSession({key: 'RESTfulAPI'})) // Set Session 生产环境务必随机设置一个值 +.use(PluginLoader(SystemConfig.System_plugin_path)) +.use((ctx, next) => { + if (ctx.request.header.host.split(':')[0] === 'api.XXX.com' || ctx.request.header.host.split(':')[0] === '127.0.0.1') { + ctx.set('Access-Control-Allow-Origin', '*') + ctx.set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept') + ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS') + ctx.set('Access-Control-Allow-Credentials', true) // 允许带上 cookie + } + return next() +}) +.use(MainRoutes.routes()) +.use(MainRoutes.allowedMethods()) +.use(ErrorRoutes()) + +if (env === 'development') { // logger + app.use((ctx, next) => { + const start = new Date() + return next().then(() => { + const ms = new Date() - start + console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) + }) + }) +} + +app.listen(SystemConfig.HTTP_server_port) + +console.log('Now start HTTP server on port ' + SystemConfig.HTTP_server_port + '...') + +export default app diff --git a/src/controllers/api.js b/src/controllers/api.js new file mode 100644 index 0000000..e69de29 diff --git a/src/controllers/index.js b/src/controllers/index.js new file mode 100644 index 0000000..f805626 --- /dev/null +++ b/src/controllers/index.js @@ -0,0 +1,2 @@ +let requireDirectory = require('require-directory') +module.exports = requireDirectory(module) diff --git a/src/lib/mysql.js b/src/lib/mysql.js new file mode 100644 index 0000000..9df134d --- /dev/null +++ b/src/lib/mysql.js @@ -0,0 +1,52 @@ +import mysql from 'promise-mysql' +import { SystemConfig } from '../config.js' +import { SqlFormat } from '../tool/common_tool.js' + +let pool = mysql.createPool({ + // connectionLimit: 4, // 连接池最多可以创建的连接数 + host: SystemConfig.mysql_host, + user: SystemConfig.mysql_user, + password: SystemConfig.mysql_password, + database: SystemConfig.mysql_database, + port: SystemConfig.mysql_port, + insecureAuth: true +}) + +// 执行一行SQL语句并返回结果 +export let query = (sql) => { + return pool.query(SqlFormat(sql)) +} + +// 执行多行SQL语句并返回结果 +export let querys = (sqls) => { + let keys = Object.keys(sqls) + let list = Object.values(sqls) + let promises = list.map(function (sql) { + return query(sql) + }) + + return Promise.all(promises).then(data => { + let result = {} + for (let index in data) { + result[keys[index]] = data[index] + } + return result + }) +} + +// 返回连接 +export let getSqlConnection = () => { + return pool.getConnection().disposer(function (connection) { + pool.releaseConnection(connection) + }) +} + +// 连接使用方法 +// var Promise = require("bluebird") +// Promise.using(getSqlConnection(), function(connection) { +// return connection.query('select `name` from hobbits').then(function(row) { +// return process(rows) +// }).catch(function(error) { +// console.log(error) +// }) +// }) diff --git a/src/models/index.js b/src/models/index.js new file mode 100644 index 0000000..f805626 --- /dev/null +++ b/src/models/index.js @@ -0,0 +1,2 @@ +let requireDirectory = require('require-directory') +module.exports = requireDirectory(module) diff --git a/src/plugin/smtp_sendemail/index.js b/src/plugin/smtp_sendemail/index.js new file mode 100644 index 0000000..65b6026 --- /dev/null +++ b/src/plugin/smtp_sendemail/index.js @@ -0,0 +1,38 @@ +import nodemailer from 'nodemailer' + +// 发送Email(目前使用的是阿里云SMTP发送邮件) +// receivers 目标邮箱,可以用英文逗号分隔多个。(我没试过) +// subject 邮件标题 +// text 文本版本的邮件内容 +// html HTML版本的邮件内容 +// 返回 +// result 200是成功,500是失败 +// info 是返回的消息,可能是结果的文本,也可能是对象。(这个错误不要暴露给用户) +export let sendemail = (receivers, subject, text, html) => { + return new Promise(function (resolve) { + let transporter = nodemailer.createTransport('smtp://postmaster%40abcd.com:password@smtp.abcd.com') + + // setup e-mail data with unicode symbols + let mailOptions = { + from: '"XX平台 👥" ', // sender address + to: receivers, + subject: subject, + text: text || 'Hello world 🐴', // plaintext body + html: html || 'Hello world 🐴' // html body + } + + transporter.sendMail(mailOptions, function (error, info) { + if (error) { + resolve({ + result: 500, + info: error + }) + } else { + resolve({ + result: 200, + info: info.response + }) + } + }) + }) +} diff --git a/src/routes/error-routes.js b/src/routes/error-routes.js new file mode 100644 index 0000000..3559405 --- /dev/null +++ b/src/routes/error-routes.js @@ -0,0 +1,10 @@ +module.exports = function () { + return function (ctx, next) { + switch (ctx.status) { + case 404: + ctx.body = '没有找到内容 - 404' + break + } + return next() + } +} diff --git a/src/routes/main-routes.js b/src/routes/main-routes.js new file mode 100644 index 0000000..f69ce0d --- /dev/null +++ b/src/routes/main-routes.js @@ -0,0 +1,15 @@ +import KoaRouter from 'koa-router' +// import controllers from '../controllers/index.js' + +const router = new KoaRouter() + +router + .get('/', function (ctx, next) { + ctx.body = '禁止访问!' + }) // HOME 路由 + // .get('/api/:api_type/:name', controllers.api.api_get) + // .put('/api/:api_type/:name', controllers.api_put.api_put + // .post('/api/:api_type/:name', controllers.api.default) + // .delect('/api/:api_type/:name', controllers.api.default) + +module.exports = router diff --git a/src/services/.gitkeep b/src/services/.gitkeep new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/src/services/.gitkeep @@ -0,0 +1 @@ +1 diff --git a/src/tool/Common.js b/src/tool/Common.js new file mode 100644 index 0000000..be9b000 --- /dev/null +++ b/src/tool/Common.js @@ -0,0 +1,63 @@ +import { + SystemConfig +} from '../config/main.js' + +// 截取字符串,多余的部分用...代替 +export let setString = (str, len) => { + let StrLen = 0 + let s = '' + for (let i = 0; i < str.length; i++) { + if (str.charCodeAt(i) > 128) { + StrLen += 2 + } else { + StrLen++ + } + s += str.charAt(i) + if (StrLen >= len) { + return s + '...' + } + } + return s +} + +// 格式化设置 +export let OptionFormat = (GetOptions) => { + let options = '{' + for (let n = 0; n < GetOptions.length; n++) { + options = options + '\'' + GetOptions[n].option_name + '\':\'' + GetOptions[n].option_value + '\'' + if (n < GetOptions.length - 1) { + options = options + ',' + } + } + return JSON.parse(options + '}') +} + +// 替换SQL字符串中的前缀 +export let SqlFormat = (str) => { + if (SystemConfig.mysql_prefix !== 'bm_') { + str = str.replace(/bm_/g, SystemConfig.mysql_prefix) + } + return str +} + +// 数组去重 +export let HovercUnique = (arr) => { + let n = {} + let r = [] + for (var i = 0; i < arr.length; i++) { + if (!n[arr[i]]) { + n[arr[i]] = true + r.push(arr[i]) + } + } + return r +} + +// 获取json长度 +export let getJsonLength = (jsonData) => { + var arr = [] + for (var item in jsonData) { + arr.push(jsonData[item]) + } + return arr.length +} diff --git a/src/tool/PluginLoader.js b/src/tool/PluginLoader.js new file mode 100644 index 0000000..138bfd4 --- /dev/null +++ b/src/tool/PluginLoader.js @@ -0,0 +1,34 @@ +import fs from 'fs' +import path from 'path' +import compose from 'koa-compose' + +function getDirs (srcpath) { + return fs.readdirSync(srcpath).filter(file => { + return fs.statSync(path.join(srcpath, file)).isDirectory() + }) +} + +module.exports = (srcpath, filename = 'index.js') => { + let plugins = {} + + let dirs = getDirs(srcpath) + let list = [] + + for (let name of dirs) { + let fn = require(path.join(srcpath, name, filename)) + + if (typeof fn !== 'function' && typeof fn.default === 'function') { + fn = fn.default + } else { + throw (new Error('plugin must be a function!')) + } + + plugins[name] = fn + + list.push(function (ctx, next) { + return fn(ctx, next) || next() + }) + } + + return compose(list) +}