node koa2 ssr项目搭建

685 阅读4分钟

这是我参与更文挑战的第1天,活动详情查看: 更文挑战

一、创键项目

  1. 创建目录 koa2

  2. npm init 创建 package.json,然后执行 npm install

  3. 通过 npm install koa 安装 koa 模块

  4. 通过 npm install supervisor 安装supervisor模块, 用于node热启动

  5. 在根目录下中新建 index.js 文件,作为入口文件, 内容如下:

    const Koa = require('koa'); // Koa 为一个class
    const app = new Koa();
    
    app.use(async (ctx, next) => {
      await next();
      ctx.response.body = 'Hello, koa2!';
    });
    
    app.listen(9527, () => {
      console.log('This server is running at http://localhost:' + 9527)
    })
    

6.配置package

{
  "name": "koa",
  "version": "1.0.0",
  "description": "",
  "main": "koa.js",
  "scripts": {
    "serve": "supervisor koa.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "koa": "^2.7.0",
    "supervisor": "^0.12.0"
  }
}

7 . 启动

npm run serve

二、路由配置

cnpm i koa-router


const router = new Router(); // 实例化路由

router.get('/', async (ctx, next) => {
  ctx.response.body = '<h5>好家伙</h5>';
});

app.use(router.routes());

   路由参数

//请求地址  www.*****/sss?from=1

router.get('/hello/:name', async (ctx, next) => {
  var name = ctx.params.name; // 获取请求参数    sss
  var from = ctx.query.from; // 1
  ctx.response.body = `<h5>好家伙, ${name}!</h5>`;
});

三、请求

      post

  const bodyParser = require('koa-bodyparser');
  app.use(bodyParser());


router.post('/login', async (ctx, next) => {
  let name = ctx.request.body.name;
  let password = ctx.request.body.password;
  console.log(name, password);
  ctx.response.body = `<h4>好家伙, ${name}!</h4>`;
});

       get

router.get('/', async (ctx, next) => {
  ctx.response.body = '<h4>好家伙</h4>'
});

四、html模板

1、好处

使用html模板,将html从js中分离出去,有助于项目开发和管理。而且,html模板在koa2中,必须通过中间件来实现。

2、koa-views + nunjucks实现html模板
    nunjucks.configure(resolve(__dirname, 'views'), { autoescape: true });

    app.use(views(__dirname + '/views', {
	map: { html: 'nunjucks' }
    }));

五、操作静态资源

1、静态资源在开发中的地位

静态资源环境在服务端是十分常用的一种服务,在后台开发中不仅有需要代码处理的业务逻辑请求,也会有很多的静态资源请求。比如请求js,css,jpg,png这些静态资源请求。也非常的多,有些时候还会访问静态资源路径。

2、koa-static-cache实现静态资源操作
app.use(
    staticCache(resolve("dist"), {
    	maxAge: 365 * 24 * 60 * 60
    })
)

六、进阶

1、结构

2、结合装饰器decorator写路由

   1.依赖安装

   2.配置.babelrc

{
  "presets": ['react', 'stage-0','env'],
  "plugins": [
    "transform-runtime",
    "transform-decorators-legacy",
    "transform-class-properties"
  ]
}

   3.decorator.js

const Router = require('koa-router')
const { resolve } = require('path')
const _ = require('lodash')
const glob = require('glob')
const R = require('ramda')

const symbolPrefix = Symbol('prefix')
const routerMap = new Map()

const isArray = c => _.isArray(c) ? c : [c]

export class Route {
  constructor (app, apiPath) {
    this.app = app
    this.apiPath = apiPath
    this.router = new Router()
  }

  init () {
    glob.sync(resolve(this.apiPath, './**/*.js')).forEach(require)
    for (let [conf, controller] of routerMap) {
      const controllers = isArray(controller)
      let prefixPath = conf.target[symbolPrefix]
      if (prefixPath) prefixPath = normalizePath(prefixPath)
      const routerPath = prefixPath + conf.path
      this.router[conf.method](routerPath, ...controllers)
    }

    this.app.use(this.router.routes())
    this.app.use(this.router.allowedMethods())
  }
}

const normalizePath = path => path.startsWith('/') ? path : `/${path}`

const router = conf => (target, key, descriptor) => {
  conf.path = normalizePath(conf.path)
  routerMap.set({
    target: target,
    ...conf
  }, target[key])
}

export const controller = path => target => (target.prototype[symbolPrefix] = path)

export const get = path => router({
  method: 'get',
  path: path
})

export const post = path => router({
  method: 'post',
  path: path
})

4.routes    view.js

const { controller, get } = require('../lib/decorator')
@controller('')
export class viewController {
	@get('/')
	async home(ctx, next) {	
		await ctx.render('index', {
			
		})
	}
	
	@get('/service')
	async enter(ctx, next) {
		await ctx.render('service', {
			title: '',
		})
	}
	
	@get('/404')
	async pageNUll(ctx, next) {
		await ctx.render('404', {
			title: ' ',
		})
	}
}
3、日志文件
cnpm i koa-log4


config/logs.jsvar path = require('path');

//日志根目录
var baseLogPath = path.resolve(__dirname, '../logs')

/*报错输出日志*/
//错误日志目录、文件名、输出完整路径
var errorPath = "/error";
var errorFileName = "error";
var errorLogPath = baseLogPath + errorPath + "/" + errorFileName;

/*请求数据得到响应时输出响应日志*/
//响应日志目录、文件名、输出完整路径
var responsePath = "/response";
var responseFileName = "response";
var responseLogPath = baseLogPath + responsePath + "/" + responseFileName;

/*操作数据库进行增删改等敏感操作记录日志*/
//操作日志目录、文件名、输出完整路径
var handlePath = "/handle";
var handleFileName = "handle";
var handleLogPath = baseLogPath + handlePath + "/" + handleFileName;

/*访问级别日志*/
var accessPath = "/access"
var accessFileName = "access";
var accessLogPath = baseLogPath + accessPath + "/" + accessFileName;

/*访问级别日志*/
var reqPath = "/req"
var reqFileName = "req";
var reqLogPath = baseLogPath + reqPath + "/" + reqFileName;

module.exports = {
    //日志格式等设置
    appenders:
        {
            "rule-console": {"type": "console"},
            "errorLogger": {
                "type": "dateFile",
                "filename": errorLogPath,
                "pattern": "-yyyy-MM-dd.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
                "path": errorPath
            },
            "resLogger": {
                "type": "dateFile",
                "filename": responseLogPath,
                "pattern": "-yyyy-MM-dd.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
//              "maxLogSize": 204800,
//              "numBackups": 3,
                "path": responsePath
            },
            "handleLogger": {
                "type": "dateFile",
                "filename": handleLogPath,//生成文件路径和文件名
                "pattern": "-yyyy-MM-dd.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
//              "maxLogSize": 204800,
//              "numBackups": 3,
                "path": handlePath
            },
            "accessLogger": {
                "type": "dateFile",
                "filename": accessLogPath,
                "pattern": "-yyyy-MM-dd.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
//              "maxLogSize": 204800,
//              "numBackups": 3,
                "path": accessPath
            },
            "reqLogger": {
                "type": "dateFile",
                "filename": reqLogPath,
                "pattern": "-yyyy-MM-dd.log",
                "alwaysIncludePattern": true,
                "encoding": "utf-8",
//              "maxLogSize": 204800,
//              "numBackups": 3,
                "path": reqPath
            },
        },
    //供外部调用的名称和对应设置定义
    categories: {
        "default": {"appenders": ["rule-console"], "level": "all"},
        "resLogger": {"appenders": ["resLogger"], "level": "info"},
        "errorLogger": {"appenders": ["errorLogger"], "level": "error"},
        "handleLogger": {"appenders": ["handleLogger"], "level": "all"},
        "accessLogger": {"appenders": ["accessLogger"], "level": "all"},
        "reqLogger": {"appenders": ["reqLogger"], "level": "error"}
    },
    "baseLogPath": baseLogPath
}


log.js

var log4js = require('koa-log4');
var logsConfig = require('../config/logs.js');
//加载配置文件
log4js.configure(logsConfig);
//调用预先定义的日志名称
var resLogger = log4js.getLogger("resLogger");
var errorLogger = log4js.getLogger("errorLogger");
var handleLogger = log4js.getLogger("handleLogger");
var reqLogger = log4js.getLogger("reqLogger");
var consoleLogger = log4js.getLogger();

exports.accessInfo = () => log4js.koaLogger(log4js.getLogger('accessLogger'));//访问日志
exports.logInfo = (data) => {consoleLogger.info(data)}
.............
.............
3、启动文件   start.js
require('babel-core/register')()
require('babel-polyfill')
require('./server/index.js')

cnpm  i

npm start

关于pm2自动部署   webpack打包  以及数据库后续有时间更新

欢迎干饭人一起推动优化

最后附上工具人地址:gitee.com/angry2bird/…