相信技术,持续学习,在掘金输出,2021年上半年年中总结之 项目复盘一
一、Vue3 + TS 学习
使用 Typescript + Vue3 从零到一测试到上线 高仿知乎专栏
知会 created by Vue3+TS 致敬知乎!!
还是学习了慕课的教程
学习项目介绍
-
Vue3+Typescript全网首发,最火技术双剑合璧,Vue3 配合Typescript,使用新版Vuex和Vue-Router全家桶完成前后端分离复杂项目 -
组件库为脉络 实现一系列由易到难的通用组件开发,可谓学会一个基本的组件库的开发。
-
提供真实后端
API告别mock数据,并提供swagger在线调试查询。
项目地址
学习过程已一步一步提交到 github, 每个提交都一一对应, 可以按 commit 进行分解学习。
自己写的代码完全开源,大家可以任意研究学习,二次开发。当然还是欢迎大家点个 Star⭐⭐⭐ 【👉👉 项目仓库地址】(github) 【👉👉 源码链接】(gitee)
安装依赖
npm install
yarn
运行本地开发环境
npm run serve
二、Koa 学习
koa-app koa 实战总结
1. 初始化项目 启动服务
mkdir koa-app
npm init -y
git init
yarn add koa -S
yarn add nodemon -D
mkdir app
cd app
touch index.js
vi index.js
cd.. to folder koa-app
vi package.json
add "scripts": "start": "nodemon app/index.js",
# 启动项目
yarn start ==> server on localhost:9000
2. 提交
2.1 提交规范 commitizen
yarn add commitizen -D
add "scripts": "commit": "git add . && git-cz"
add "config": { "commitizen": { "path": "node_modules/cz-conventional-changelog" }}
2.2 提交到 github & gitee
前提是:两个账户已分别绑定 git 权限
git remote add github git@github.com:xn213/koa-app.git
git remote add gitee git@gitee.com:xn213/koa-app.git
yarn commit
# 分别提交
git push github
git push gitee
升级省事: 同时提交到 github 和 gitee
修改 .git/config
[remote "origin"]
url = git@github.com:xn213/koa-app.git
url = git@gitee.com:xn213/koa-app.git
fetch = +refs/heads/*:refs/remotes/origin/*
这时第一次提交到 gitee, alias: gp == git push 会提示如下图,
由于上面分别提交到 github 和 gitee, 设置了 git remote gitee..., 要使用如下命令提交
git push --set-upstream origin master
此命令会在 .git/config 中添加如下字段
[branch "master"]
remote = origin
merge = refs/heads/master
3. 改造路由
3.1 抽离路由模块
yarn add koa-router -S
cd app
mkdir router
touch index.js
touch routes.js
4. 参数解析,抽离中间件
4.1 koa-compose 简化中间件引用
yarn add koa-compose koa-bodyparser -S
# 插件 koa-compose 简化引用中间件的写法。
# 插件 koa-bodyparser 处理 post 请求体中的参数
// app/index.js
const compose = require('koa-compose')
const MD = require('./middlewares/')
const app = new Koa()
app.use(compose(MD))
// controllers/test.js
ctx.body = ctx.request.body
这里 post 请求 拿不到 body 的参数,找轮子>插件
4.2 koa-bodyparser 处理 post 请求参数
// >app
mkdir middlewares
touch index.js
# 注意: koa-bodyparser 处理需放在路由前面
4.3 formidable 处理 上传文件
koa-bodyparser 插件只能解析 4 种数据 [ 'json', 'form', 'text', 'xml' ],当上传文件的时候,是获取不到文件的.
这里借助插件 formidable 文档
yarn add formidable -S
// middlewares/formidable.js
const Formidable = require('formidable')
const { tempFilePath } = require('../config')
module.exports = () => {
return async function (ctx, next) {
const form = new Formidable({
multiples: true,
// 上传的临时文件保存路径 抽离到 config/base 一些配置
// uploadDir: `${process.cwd()}/${tempFilePath}`
uploadDir: tempFilePath,
})
await new Promise((reslove, reject) => {
form.parse(ctx.req, (err, fields, files) => {
if (err) {
reject(err)
} else {
// 暂未设置请求头 忽略 请求中添加 二进制 content-type
ctx.request.body = fields
ctx.request.files = files
reslove()
}
})
})
await next()
}
}
// middlewares/index.js 中引入 注册 暴露出去
const formidable = require('./formidable')
const mdFormidable = formidable()
module.exports = [mdFormidable, mdKoaBody, mdRoute, mdRouterAllowed]
另: 抽离配置文件,添加配置文件目录: app/config
// config/index.js
const base = require('./base')
const dev = require('./dev')
const pre = require('./pre')
const pro = require('./pro')
const env = process.env.NODE_ENV || 'dev'
const configMap = {
dev,
pre,
pro,
}
module.exports = Object.assign(base, configMap[env])
5. 工具函数和常量配置抽离 挂载到上下文
编写工具函数 app/utils/index.js & test.js
cd app
mkdir utils
cd utils
touch index.js
vi index.js i 编辑输入: :wq 保存退出
// utils/index.js
const testUtils = require('./test')
module.exports = {
testUtils,
}
touch test.js
vi test.js i编辑输入
// utils/test.js
const test = 'test utils string'
module.exports = testUtils = () => {
return test
}
挂载到 App context 上下文
// app/index.js
...
const config = require('./config')
const utils = require('./utils')
app.context.utils = config
app.context.utils = utils
...
6. 统一返回格式 & 错误处理
6.1 统一 成功 or 失败 返回格式
- 成功
// app/middlewares/response.js
const response = () => {
return async (ctx, next) => {
ctx.res.fail = ({ code, data, msg }) => {
ctx.body = {
code,
data,
msg,
}
}
ctx.res.success = (msg) => {
ctx.body = {
code: 0,
data,
msg: msg || 'success',
}
}
await next()
}
}
module.exports = response
- 失败
// app/middlewares/error.js
const error = () => {
return async (ctx, next) => {
try {
await next()
if (ctx.status === 200) {
ctx.res.success()
}
} catch (err) {
if (err.code) {
ctx.res.fail({ code: err.code, msg: err.message })
} else {
// 程序运行时错误
ctx.app.emit('error', err, ctx)
}
}
}
}
module.exports = error
- 在
middlewares/index.js中引入
const response = require('./response')
const error = require('./error')
const mdResHandler = response()
const mdErrHandler = error()
module.exports = [mdFormidable, mdKoaBody, mdResHandler, mdErrHandler, mdRoute, mdRouterAllowed]
6.2 错误处理
- 程序运行时错误使用
koa的错误处理事件,需要在app/index.js配置
所有的返回值是在 middlewares/error.js 里拦截了一下,如果状态码是 200,用成功的工具函数包装返回,如果不是则又分为两种情况:一种是我们自己抛出的,包含业务错误码的情况(这种情况我们用失败的工具函数包装返回);另一种是程序运行时报的错,这个往往是我们代码写的有问题(这种情况我们触发 koa 的错误处理事件去处理),针对失败的第二种情况,我们还需要修改启动文件 app/index.js,添加如下代码:
// 程序本身错误
app.on('error' (err, ctx) => {
if(ctx) {
ctx.body = {
code: 9000,
msg: `程序运行时错误: ${err.message}`
}
}
})
- 测试一下: 在
controllers/test.js添加如下代码:
2.1. 成功
// controllers/test.js
const getList = async () => {
ctx.body = '返回结果'
}
请求接口, 返回值如下,我们定义的 controller 成功返回
2.2. 业务抛出错误
// controllers/test.js
const getList = async (ctx) => {
const data = ''
// 业务中抛出失败
ctx.utils.assert(data, ctx.utils.throwError(10001, '验证码失效'))
ctx.body = '返回结果'
}
2.3. 程序本身报错
这时添加一行 a = b, 这里 b 未定义,则为程序本身错误, 触发 koa error 事件
const getList = async (ctx) => {
const a = b
ctx.body = '返回结果'
}
7. 跨域处理 @koa/cors
直接用插件 @koa/cors npm/@koa/cors
app/middlewares/index.js 中引入,实例化,导出
// middlewares/index.js 跨域处理
const cors = require('@koa/cors')
const mdCors = cors({
origin: '*',
credentials: true,
allowMethods: ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'],
})
module.exports = [
mdFormidable,
mdKoaBody,
mdCors,
mdResHandler,
mdErrorHandler,
mdRoute,
mdRouterAllowed,
]
8. 添加日志 log4js
插件:log4js
// middlewares/log.js
const log4js = require('log4js')
const { flag, level, outDir } = require('../config').logConfig
log4js.configure({
appenders: {
cheese: {
type: 'file',
filename: `${outDir}/receive.log`,
},
},
categories: {
default: {
appenders: ['cheese'],
level: 'info',
},
},
pm2: true,
})
const logger = log4js.getLogger()
logger.level = level
module.exports = () => {
return async (ctx, next) => {
const { method, path, origin, query, body, headers, ip } = ctx.request
const data = {
method,
path,
origin,
query,
body,
ip,
headers,
}
await next()
if (flag) {
const { status, params } = ctx
data.status = status
data.params = params
data.result = ctx.body || 'no content'
if (ctx.body.code !== 0) {
logger.error(JSON.stringify(data))
} else {
logger.info(JSON.stringify(data))
}
}
}
}
app/middlewares/index.js 引入/注册/配置
const log = require('./log')
const mdLogger = log()
module.exports = [
mdFormidable,
mdKoaBody,
mdCors,
mdLogger,
mdResHandler,
mdErrHandler,
mdRoute,
mdRouterAllowed
]