前言
看了很多写服务端渲染(next.js)的文章,但发现搜索的服务端渲染的案例都是一些比较简单,或者不太系统的例子,如果做一个演示或者demo还是可以的,但是在实际应用上不利于分工协作,部署上线。明明可以做大型项目却不知怎么去应用,所以带着这些痛点和疑惑,决定自己做一套next + koa + mongodb 可以应用到应用级项目的项目框架(此项目还在更新中),项目还在不断优化中,希望大家可以多多指点。
话不多说,上图先开始介绍下项目的规划和想法
项目介绍
这个是项目的首页,应该大家都能看出来了,是一个模仿掘金的的个人博客项目。包含了基本的登录,注册,写文章,展示文章。。。后续还会继续添加新的功能。目标是发布上线,不断迭代,最终做一个成熟且完整的项目。
项目结构
跟传统的ssr项目一样,分为View层,和sever层,不熟悉的next.js,和koa.js的可以先去脑补一下next文档&&koa文档,view层后面会简单说下,咱们重点说一下server层的构建,sever层主要分为apps.js(入口文件 app.js已废弃),controller(接口定义,渲染的页面配置),middleware(中间件),router(路由),token(登录注册时token定义)- 入口文件apps.js
const Koa = require('koa')
const next = require('next')
const koaRoute = require('./router')
const bodyParser = require('koa-bodyparser');
const middleware = require('./middleware')
const cors = require('koa2-cors');
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = new Koa()
//注入中间件
middleware(server)
server.use(bodyParser())
//注入路由
koaRoute(server,app,handle)
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`)
})
})
1.middleware
apps.js入口文件比较简单,因为主要逻辑封装到组件中,先从middleware说起
const bodyParser = require('koa-bodyparser');
const logger = () => {
return async (ctx, next) => {
const start = Date.now()
bodyParser()
await next()
const responseTime = (Date.now() - start)
console.log(`响应时间为: ${responseTime / 1000}s`)
}
}
module.exports = (app) => {
app.use(logger())
}
如果看过koa文档会发现,不管使用路由和插件,都需要new Koa()以后再用use去调用,这里只用到一个响应时间方法,以后可能会用到更多中间间,如果引入一个就要在入口引入一次会比较繁琐,所以封装通用方法,可以继续添加,只需在入口引入一次就可以了。
2. controller
controller里面主要是koa里的路由管理,分为接口管理(api)和视图路由管理(view)以及数据库管理(db.js),以及入口文件(index.js)。api里的getListInfor.js:
const DB = require('../db')
const loginInfor = (app) =>{
return async (ctx, next) => {
await DB.insert(ctx.request.body).then(res =>{
ctx.response.body = {
infor:'ok'
}
})
}
}
module.exports = loginInfor
view里的home.js
const home = (app) =>{
return async (ctx, next) => {
await app.render(ctx.req, ctx.res, '/home', ctx.query)
ctx.respond = false
}
}
module.exports = home
api.js
const Monk = require('monk')
const url = 'mongodb://localhost:27017/home'; // Connection URL
const db = Monk(url)
const dbName = 'col'
const collection = db.get(dbName)
module.exports = collection
//本地用mongdb搭建的数据库,调用方法用的monk插件,不了解的可以去github搜索
index.js:
//VIEW
const index = require('./view/index')
const home = require('./view/home')
const editText = require('./view/editText')
const essay = require('./view/essay')
const myself = require('./view/myself')
//API
const getListInfor = require('./api/getListInfor')
const loginInfor = require('./api/loginInfor')
const POST = 'post'
const GET = 'get'
module.exports = {
view:{// 不需要请求方式
index,
home,
editText,
essay,
myself,
},
api:{
getListInfor:{
method:GET,
getListInfor
},
loginInfor:{
method:POST,
loginInfor
}
}
}
3.router
const router = require('./node_modules/koa-router')()
const Controller = require('../controller')
const koaRoute = (app,handle) =>{ //把view层和api层挂载到router
// view
const {view,api} = Controller
for(item in view){
let _name = null;
let _moudle = null
if(item == 'index'){
_name = '/';
_moudle = view['index']
}else{
_name = '/' + item;
_moudle = view[item]
}
router.get(_name,_moudle(app))
}
//api
for(item in api){
let _method = api[item].method
let _name = '/' + item;
let _moudle = api[item][item]
router[_method](_name,_moudle(app))
}
router.get('*', async ctx => {
await handle(ctx.req, ctx.res)
ctx.respond = false
})
return router.routes() //启动路由
}
module.exports = (server,app,handle) =>{
server.use(koaRoute(app,handle))
}
这时候可以再看一下apps.js是怎么引入的:
const app = next({ dev })
const handle = app.getRequestHandler()
const koaRoute = require('./router')
app.prepare()
.then(() => {
const server = new Koa()
//注入路由
koaRoute(server,app,handle) // 相当于koa里面app.use(router.routes()) 启动路由......
未完待续。。。