egg.js踩坑记录(一)开始篇

1,859 阅读3分钟

吴文周 签名

需求背景

  • 中间层与注册中心以及api网关诉求

决策依据

语言决策

  • 选型有三个大类(JAVA,GO,nodejs)
  • JAVA社区完善场景支撑丰富,劣势前端团队语言瓶颈
  • GO性能优势,跨平台先天优势,劣势团队适配性不足(本来应该是最佳选择)
  • nodejs团队语言切合度高,劣势性能差,安全性低,环境依赖(依然选择)

框架选择

  • 框架选型express(50k+star)和egg.js(10k+star)
  • express社区和解决方案优势明细,劣势代码规范,以及企业化的场景支撑都需要从头维护,本人自己在没看egg之前也实现过一个类似的epress模板。有些场景还是有所缺失。
  • egg.js优势规范化程度高,场景覆盖比个人想象要全,劣势社区和解决方案支持不太友好,问题都比较难以解决与定位,并不是严格意义上的开箱即用,扩展能力不强。
  • 从时间成本和团队规范的角度选择了egg.js

项目细节

场景支撑

  • 日志,进程守护,目录规划,配置方案基本不用做了,egg这方面是开箱即用的

规范

  • 代码规范
  • git规范
{
    "lint-staged:js": "npm run lint -- --fix && npm run lint:style",   
    "lint:prettier": "prettier --check \"**/*\" --end-of-line auto",  
    "lint:style": "",    "prettier": "prettier -c --write \"**/*\""  
}, 
 "husky": {   
   "hooks": {      
     "pre-commit": "npm run lint-staged",      
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"    
    }  
},  
"lint-staged": {    
   "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",    
   "**/*.{js,jsx,tsx,ts,md,json}":
     [      "prettier --write"    ]  
}
  • 使用husky和lint-staged解决规范的问题注意事项@commitlint/cli的9.1.2版本存在bug 会出现提交不了的报错,可以选择该版本以下。commitlint配置信息如下
  module.exports = {  extends: ['@commitlint/config-conventional'],};

中间件加载顺序(应该官方内置的中间件顺序会导致部分功能bug)

  • 反向代理中间件需要在bodyParser之前
  • graphql中间件又需要bodyParser之后
  • 需要自定义启动项的app.js
/* 
 * @Description: 自定义启动项
 * @Author: 吴文周 
 * @Github: http://gitlab.yzf.net/wuwenzhou 
 * @Date: 2020-06-28 13:38:19 
 * @LastEditors: 吴文周 
 * @LastEditTime: 2020-08-24 22:08:00 
 */
 'use strict';
  const Consul = require('./app/utils/consul');
  class AppBootHook {  
    constructor(app) {    
      this.app = app;  
   }  
   configWillLoad() {    
   // 此时 config 文件已经被读取并合并,但是还并未生效    
   // 这是应用层修改配置的最后时机    
   // 将方向代理服务加载在bodyParser之前    
     const statusIdx = this.app.config.coreMiddleware.indexOf('bodyParser');    
     this.app.config.coreMiddleware.splice(statusIdx, 0, 'proxy');    
     this.app.config.coreMiddleware.splice(statusIdx + 2, 0, 'graphql');  
   }  
   async didLoad() {    
   // 所有的配置已经加载完毕    
   // 可以用来加载应用自定义的文件,启动自定义的服务    
   // 例如:创建自定义应用的示例  
   }  
   async willReady() {    
     // 所有的插件都已启动完毕,但是应用整体还未 ready   
     // 可以做一些数据初始化等操作,这些操作成功才会启动应用    
     // 例如:从数据库加载数据到内存缓存  
   }  
   async didReady() {    
     // 应用已经启动完毕  
   }
}
module.exports = AppBootHook;

Docker容器化

  • docker已经不仅仅是运维考虑的问题,在开发阶段就应该考虑全流程的闭环,环境问题真的很重要在跨团队合作过程中。当然好处不仅仅如此。
  • 第一步安装docker(忽略)
  • 第二步在项目中添加Dockerfile
# 设置基础镜像,如果本地没有该镜像,会从Docker.io服务器pull镜像
FROM node:alpine
# 设置时区
ENV TZ=Asia/ShanghaiRUN 
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 创建app目录
RUN mkdir -p /usr/src/node-app/server
# 设置工作目录
WORKDIR /usr/src/node-app/server
# 拷贝package.json文件到工作目录(被注释的流程会导致依赖无发下载)
# !!重要:package.json需要单独添加。
# Docker在构建镜像的时候,是一层一层构建的,仅当这一层有变化时,重新构建对应的层。
# 如果package.json和源代码一起添加到镜像,则每次修改源码都需要重新安装npm模块,
#这样木有必要。
# 所以,正确的顺序是: 添加package.json;安装npm模块;添加源代码。
# COPY package.json /usr/src/node-app/server/package.json
# 安装npm依赖# 如果使用的境外服务器,即改为`RUN npm i`。
# RUN npm i 
# 拷贝所有源代码到工作目录
COPY . /usr/src/node-app/server
# 如果使用的境外服务器,无需使用私有的镜像源,私有仓库下载快,即改为`RUN npm i`RUN npm i --registry=xxx
# 暴露容器端口
EXPOSE 7001
# 启动node应用该命令单独配置
CMD npm run docker
  • 第三步添加.dockerignore(注意前面有点的)
# Logs
logs
npm-debug.log*
# Coverage directory used by tools like istanbul
coverage
# Dependency directories
node_modules
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
.idea
.node_modules
.vscode
run
typings
  • 第四步配置package.json添加执行命令去掉--daemon --title(随意)
"docker": "egg-scripts start",
  • 第五步开始docker流程
docker build -t egg .#注意有个.
#启动容器 第一个端口是绑定的本机端口,:后面的端口是egg内部端口对外暴露
docker run -d --name egg  -p 9002:7001 egg 
  • 先查看是否执行成功
docker ps # 是否存在刚才生成的容器
  • 如果不存在说明启动失败查看启动日志
docker logs 容器id
  • 本机ip+9002即可访问egg的docker服务了
  • 其他关键命令
docker images # 查看所有镜像
docker rmi 镜像id或者名称 # 删除镜像
docker rm 容器id或者名称 # 删除容器

完结

撒花