Next.js脚手架进阶系列
写在前面
作为一个前端,或者说普遍意义上的前端,应该是只做前端应该做的事,涉及到后端相关的知识可能接触不多,甚至,我们在使用服务端渲染框架的时候也只是把它当作优化首屏渲染速度和利于SEO的一种手段,本文就逆向思维的来扩展Next服务端渲染脚手架成一个全栈脚手架。
以前在没接触服务端渲染的时候就会总有这种思路,一般nodejs写项目大体都是nodejs框架(一般我选择express)+ 数据库(一般我选择MongoDB)+ 前端渲染模板,远古时期会使用ejs、jade之类的渲染模板,慢慢的前端框架写多了,就会尝试使用react和vue这种流行的前端框架。嗯,这应该也是很多人的思路,也是按照这个思路,我以前写了一篇Express + React + MongoDB实践 —— 很巧,也是我在掘金写的第一篇文章,思路是先搭建node端,然后渲染接入react前端框架~
然后慢慢随着知识掌握程度加深,逆向思考了一下,nodejs写伪全栈其实也就是几个要素,nodejs + 数据库 + 前端页面。其实服务端渲染框架已经具备了写大前端项目的一些要素。我们只需要在node端把路由api接入,然后在node 端连接上数据库,一个简单的全栈架构就完成了其实,剩下的就是按照我们以前的书写习惯与规范,进行业务开发,当然既然是全栈,在以往只写前端页面的基础上你需要设计数据库,书写API等更加庞大的工作。在这里我按照自己的理解粗略的画一个图吧,主要也是为了让大家能更简单明白我的意思~

文章写的越来越高级了😄,开始自己做图了。有时候我觉得写文章还真是巩固知识,梳理知识的一个很好的方式,推荐大家试一试,即使不写文章也可以写笔记。
这里我解释一下为什么我称之为伪全栈吧,全栈顾名思义,你确实一个人干了所有的工作,前端页面 + 后端API接口 + 数据库设计。但是你其实也只是使用了node的路由以及一些特性中间件,nodejs很多高级功能并没有使用以及后台和数据库相关的很多复杂逻辑也没有涉及(事物、锁等等乱七八糟的知识点)。作为一个伪全栈,这些我确实不是很明白,所以这里也不是探讨复杂逻辑的地方,我只是给大家提供一个简单的想法而已。
扩展过程
整体扩展过程其实就真的非常简单了,因为我们是直接通过SSR框架进行扩展,所以完全不需要考虑页面渲染部分,也就是只需要考虑Node + 数据库
即可。我们先来回顾一下项目整体的目录结构:
——————
| -- assets // ant-design global less var
| -- components // React UI component
| -- constants // constant directory
| -- ActionsTypes.js // save all action type
| -- ApiUrlForBE.js // save all apiUrl
| -- ...
| -- containers // React container component
| -- core // mehtod dirctory
| -- util.js // project method
| -- nextFetch.js // packing unfetch for easy use
| -- middlewares // middlewares
| -- client // client middlewares, deal redux action
| -- server // server middlewares, deal node event
| -- pages // Next.js routes
| -- redux
| -- actions // deal all projectaction
| -- reducers // deal all project reducer
| -- sagas // sace all project saga
| -- store.js
| -- static // save static source directory
| -- .babelrc
| -- .eslintrc
| -- .gitignore
| -- next.config.js // Next.js config file
| -- package.json
| -- server.js // server file
| -- pm2.config.js // pm2 deploy config file
| ... // other files
上面整体上是脚手架前端部分的架构,我们接下来就一步步进行扩展~
添加路由api
首先,我们新建/backend/routes
文件夹用来存放前后端的路由文件:
| -- backend // node backend
| -- routes // the backend routes
然后,我们约定俗成一下,前后端交互的api全部是http://${host}:${port}/api/${apiName}
的形式,然后我们在server.js注册api接口服务也就是添加路由中间件。
// server.js
const router = require('./backend/routes');
...
// 路由中间件
server.use('/api', router); // 添加router中间件
注册成功我们来尝试写一个前端调用node端的接口,就以获取用户列表为例:
// apiUrlForBE.js
const apiServer = `${process.env.API_HOST}:${process.env.PORT}/api`;
// const API url
export default {
/**
* 获取用户列表数据
* @method GET
*/
getUserList: `${apiServer}/user/list`
};
以开发环境为例,上面我们设置了
apiServer = http://localhost:3006/api
,也就是所有的前端请求都会走到我们的/api
路由然后返回数据。
// /backend/routes/user.js
const userData = [
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
...
]
// 获取用户列表
router.get('/list', (req, res) => {
const resData = {
data: userData
};
res.json(resData);
});
我们启动服务看一下:

/api
的服务端响应的数据,也就是说整个API接口请求的流程前后端通过了~
连接数据库
上面的接口成功了,但是我们响应的接口是mock的数据,也就是静态的,并不是从数据库中查到然后返回给前端的,所以可以进一步完善 —— 连接数据库。
我们在/backend
文件夹下新建/db
文件夹,用来链接我们的数据库以及数据库的相关配置操作。这里以mongoDB为例来进行相关配置:
| -- backend // node backend
| -- db // the directory of db
| -- config // db config directory
| -- models // mongoDB models
| -- shcemas // mongoDB schemas
| -- routes // the backend routes
// /config/config.js
// 数据库地址: 'mongodb://用户名:密码@ip地址:端口号/数据库';
// 一般如果没设置用户名和密码直接写IP地址就可以,数据库你可以新建一个
module.exports = {
mongodb : 'mongodb://127.0.0.1:27017/db-name'
};
// /config/mogoose.js
// 创建mogoose实例,链接数据库
const mongoose = require('mongoose');
const config = require('./config');
module.exports = () => {
mongoose.connect(config.mongodb, { useNewUrlParser: true });//连接mongodb数据库
// 实例化连接对象
var db = mongoose.connection;
db.on('error', console.error.bind(console, '连接错误:'));
db.once('open', () => {
console.log('MongoDB连接成功!!');
});
return db;
};
上面我们就把数据库扩展好了,剩下的环节就是连接数据库,进行增删改查操作等等了。感兴趣的小伙伴自己探索吧,如果想要更详细的就留言把,不把这些代码放到仓库的原因是那样就不像一个脚手架了,更像一个Demo了。
搭配apidoc实现自动化接口文档
上面的内容都完成之后,我们就可以开始全栈项目之旅了,作为大礼包的额外赠送,既然是全栈,那么肯定有庞大的API接口要去写,时间久了维护起来就比较麻烦,以前这些工作都是后端去做,现在全栈要一个人自己做,所以配套的再给大家介绍一个自动化API文档生成工具 -- apidoc
,它能通过我们在书写代码的时候进行简单的注释书写,最后帮我们生成可视化的api接口文档。最后的实现效果就如图所示:

更加详细的使用说明,可以见我的系列文章:边写边学系列(一) —— 使用apidoc,搞定自动化文档
总结
个人很喜欢Next.js,所以这个系列文章写的多一些,虽然使用的人很少,但是当作记录还是不错的,最近自己也想写点全栈的东西,正好打算使用这个扩展的脚手架来用,大家感兴趣的话可以多多提意见,不论是issue还是star我都很欢迎~以及交流共同进步才是最重要的。
【注】:这里只是抛砖引玉,任何SSR框架其实都是可以按照这个套路当全栈脚手架去用的,确实会比我们从头搭建要节省很多时间,而且采用自己最熟悉的前端框架做渲染模板肯定在效率上也会有提升的~
带后端的在
backend
分支,小伙伴不要找不到。