博客
关于我
使用typescript改造koa开发框架
阅读量:420 次
发布时间:2019-03-06

本文共 5829 字,大约阅读时间需要 19 分钟。

原文地址:

强类型的 TypeScript 开发体验和维护项目上相比 JavaScript 有着明显的优势,那么对常用的脚手架进行改造也就势在必行了。

接下来开始对基于 koa 框架的 node 后端脚手架进行改造:

  1. 项目开发环境 和 typescript 编译环境的搭建;
  2. nodekoa、koa中间件和使用到的库 添加类型化支持;
  3. 基于 typesript 的特性改造项目。

项目开发环境搭建

基于 gulp 搭建开发编译环境,gulp-typescript 插件用于编译 typescript 文件, gulp-nodemon 则可以监控文件内容的变更,自动编译和重启node服务,提升开发效率。

npm install -D gulp gulp-nodemon gulp-typescript ts-node typescript

gulp 的配置

gulpfile.js 的设置

const { src, dest, watch, series, task } = require('gulp');const del = require('del');const ts = require('gulp-typescript');const nodemon = require('gulp-nodemon');const tsProject = ts.createProject('tsconfig.json');function clean(cb) {  return del(['dist'], cb);}// 输出 js 到 dist目录function toJs() {  return src('src/**/*.ts')    .pipe(tsProject())    .pipe(dest('dist'));}// nodemon 监控 ts 文件function runNodemon() {  nodemon({    inspect: true,    script: 'src/app.ts',    watch: ['src'],    ext: 'ts',    env: { NODE_ENV: 'development' },    // tasks: ['build'],  }).on('crash', () => {    console.error('Application has crashed!\n');  });}const build = series(clean, toJs);task('build', build);exports.build = build;exports.default = runNodemon;

typescript 的配置

tsconfig.json 的设置

{  "compilerOptions": {    "baseUrl": ".", // import的相对起始路径    "outDir": "./dist", // 构建输出目录    "module": "commonjs",    "target": "esnext",// node 环境支持 esnext    "allowSyntheticDefaultImports": true,    "importHelpers": true,    "strict": false,    "moduleResolution": "node",    "esModuleInterop": true,    "forceConsistentCasingInFileNames": true,    "noImplicitAny": true,    "suppressImplicitAnyIndexErrors": true,    "noUnusedParameters": true,    "noUnusedLocals": true,    "noImplicitReturns": true,    "experimentalDecorators": true, // 开启装饰器的使用    "emitDecoratorMetadata": true,    "allowJs": true,    "sourceMap": true,    "paths": {      "@/*": [ "src/*" ]    }  },  "include": [    "src/**/*"  ],  "exclude": [    "node_modules",    "dist"  ]}

eslint 的配置

当然 eslint 也要添加对 typescript 对支持

npm install -D @typescript-eslint/eslint-plugin @typescript-eslint/parser

.eslintrc.json 的设置

{  "env": {    "es6": true,    "node": true  },  "extends": [    "eslint:recommended",    "plugin:@typescript-eslint/eslint-recommended"  ],  "globals": {    "Atomics": "readonly",    "SharedArrayBuffer": "readonly"  },  "parser": "@typescript-eslint/parser",  "parserOptions": {    "ecmaVersion": 2018,    "sourceType": "module"  },  "plugins": [    "@typescript-eslint"  ],  "rules": {    "indent": [ "warn", 2 ],    "no-unused-vars": 0  }}

package.json 运行配置

最后就是设置 package.json 的 scripts

"scripts": {    "start": "gulp",// dev    "build": "gulp build", // output    "eslint": "eslint --fix --ext .js,.ts src/",    "server": "export NODE_ENV=production && node dist/app" // production server  },

添加类型化支持

项目主要使用到了以下的组件

  • jsonwebtoken
  • koa
  • koa-body
  • koa-compress
  • koa-favicon
  • koa-logger
  • koa-router
  • koa-static
  • koa2-cors
  • log4js

那么就要安装对应的 type 文件,当然别忘了 @types/node

npm install -D @types/jsonwebtoken @types/koa @types/koa-compress @types/koa-favicon @types/koa-logger @types/koa-router @types/koa-static @types/koa2-cors @types/log4js @types/node

使用 typescript 装饰器 改造项目

.net mvc 框架有个很便利的地方就是 使用装饰器对控制器进行配置,现在通过 typescript 的装饰器也可以实现相同的功能。这里需要使用到反射相关的库 reflect-metadata,用过 JavaC# 的小伙伴,对反射的原理一定不陌生。

定义http请求的装饰器

我们再也不需要在路由配置和控制器方法之间来回查找和匹配了

import 'reflect-metadata'import { ROUTER_MAP } from '../constant'/** * @desc 生成 http method 装饰器 * @param {string} method - http method,如 get、post、head * @return Decorator - 装饰器 */function createMethodDecorator(method: string) {  // 装饰器接收路由 path 作为参数  return function httpMethodDecorator(path: string) {    return (proto: any, name: string) => {      const target = proto.constructor;      const routeMap = Reflect.getMetadata(ROUTER_MAP, target, 'method') || [];      routeMap.push({ name, method, path });      Reflect.defineMetadata(ROUTER_MAP, routeMap, target, 'method');    };  };}// 导出 http method 装饰器export const post = createMethodDecorator('post');export const get = createMethodDecorator('get');export const del = createMethodDecorator('del');export const put = createMethodDecorator('put');export const patch = createMethodDecorator('patch');export const options = createMethodDecorator('options');export const head = createMethodDecorator('head');export const all = createMethodDecorator('all');

装饰控制器的方法

export default class Sign {      @post('/login')  async login (ctx: Context) {    const { email, password } = ctx.request.body;    const users = await userDao.getUser({ email });    // ...    return ctx.body = {      code: 0,      message: '登录成功',      data    };  }  @post('/register')  async register (ctx: Context) {    const { email, password } = ctx.request.body;    const salt = makeSalt();    // ...    return ctx.body = {      code: 0,      message: '注册成功!',      data    }  }  }

收集元数据和添加路由

我们已经把装饰器添加到对应控制器的方法上了,那么怎么把元数据收集起来呢?这就需要用到 node 提供的 fs 文件模块,node服务第一次启动的时候,扫描一遍controller文件夹,收集到所有控制器模块,结合装饰器收集到的metadata,就可以把对应的方法添加到 koa-router

import 'reflect-metadata'import fs from 'fs'import path from 'path'import { ROUTER_MAP } from './constant'import { RouteMeta } from './type'import Router from 'koa-router'const addRouter = (router: Router) => {  const ctrPath = path.join(__dirname, 'controller');  const modules: ObjectConstructor[] = [];  // 扫描controller文件夹,收集所有controller  fs.readdirSync(ctrPath).forEach(name => {    if (/^[^.]+?\.(t|j)s$/.test(name)) {      modules.push(require(path.join(ctrPath, name)).default)    }  });  // 结合meta数据添加路由  modules.forEach(m => {    const routerMap: RouteMeta[] = Reflect.getMetadata(ROUTER_MAP, m, 'method') || [];    if (routerMap.length) {      const ctr = new m();      routerMap.forEach(route => {        const { name, method, path } = route;        router[method](path, ctr[name]);      })    }  })}export default addRouter

最后

这样对koa项目脚手架的改造基本完成,源码请查看

转载地址:http://icduz.baihongyu.com/

你可能感兴趣的文章
MTD技术介绍
查看>>
MySQL
查看>>
MySQL
查看>>
mysql
查看>>
MTK Android 如何获取系统权限
查看>>
MySQL - 4种基本索引、聚簇索引和非聚索引、索引失效情况、SQL 优化
查看>>
MySQL - ERROR 1406
查看>>
mysql - 视图
查看>>
MySQL - 解读MySQL事务与锁机制
查看>>
MTTR、MTBF、MTTF的大白话理解
查看>>
mt_rand
查看>>
mysql -存储过程
查看>>
mysql /*! 50100 ... */ 条件编译
查看>>
mudbox卸载/完美解决安装失败/如何彻底卸载清除干净mudbox各种残留注册表和文件的方法...
查看>>
mysql 1264_关于mysql 出现 1264 Out of range value for column 错误的解决办法
查看>>
mysql 1593_Linux高可用(HA)之MySQL主从复制中出现1593错误码的低级错误
查看>>
mysql 5.6 修改端口_mysql5.6.24怎么修改端口号
查看>>
MySQL 8.0 恢复孤立文件每表ibd文件
查看>>
MySQL 8.0开始Group by不再排序
查看>>
mysql ansi nulls_SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON 什么意思
查看>>