前言
这篇文章讲述如何整合koa,react,nunjacks,koa-router实现一个服务端渲染的工程
koa搭建服务器
// index.js
const Koa = require('koa')
const app = new Koa()
app.use(async(ctx, next) => {
ctx.body = 'hello world!'
next()
})
app.listen(3000)
复制代码
这里说个基础问题
为什么要执行next?
这是因为koa会安装很多的中间件,next()通知执行下一个中间件的操作
可以看到访问localhost:3000,就可以看到hello world了执行node index.js
接入路由功能
试想,koa如何做路由管理?
可以看下当我们请求localhost:3000/home时,koa可以拿到些什么信息
可以看到ctx.request.url,其实就是路由,那么是否可以对当前代码中的中间件做个改造const Koa = require('koa')
const app = new Koa()
app.use(async(ctx, next) => {
switch(ctx.request.url){
case '/home':
ctx.body = 'home';
break;
case '/list':
ctx.body = 'list';
break;
default:
ctx.body = 'default';
}
next();
})
app.listen(3000)
复制代码
这是访问localhost:3000/home,或者localhost:3000/list,可以看到已经成功了
到这里一个简单的koa路由就完成了,可是如何接入react和koa-router呢
接入koa-router
koa-router的接入很简单
<!--router.js-->
<!--step 1. 定义router文件,这里我从文件夹去读取文件来定义router-->
const Router = require('koa-router')
const router = new Router()
const glob = require('glob')
glob.async('**/*.js', {
cwd: './src/page'
}).forEach(fpath => {
fpath = fpath.replace('/\/index.js/g', '');
router.all('/' + fpath, (ctx, next) => {
ctx.body = +new Date
next()
})
})
复制代码
<!--step 2. koa-router接入koa-->
const router = require('./router')
app.use(router.routes())
复制代码
koa接入React服务端渲染
接入渲染的话主要是从router.all这里接入,可以思考两个问题
- react component需要转成string
- 需要一个后端渲染模版
针对这两个问题,搜索下解决方案:
- React通过react-dom/server的renderToString把VNode转成string
- koa可以使用koa-nunjucks-2模版引擎
了解koa-nunjucks-2的使用
这里因为我把模版放在了【项目根目录/nunjucks/tmpl下面的index.html】
const koaNunjucks = require('koa-nunjucks-2')
app.use(koaNunjucks({
ext: 'html',
path: path.join(__dirname, '../nunjucks', 'tmpl'),
nunjucksConfig: {
trimBlocks: true
}
}));
复制代码
<!--index.html模版-->
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="utf-8">
<title>{{ pageTitle }}</title>
</head>
<body>
<div id="root">{{ content }}</div>
</body>
</html>
复制代码
改造router.all
<!--这里render的第一个参数index的意思是:nunjucks/tmpl/index.html 即nunjucks模版-->
router.all('/'+fpath, (ctx, next) => {
ctx.render('index', {
pageTitle: '测试nunjucks',
content: '123'
})
})
复制代码
运行下,可以发现nunjucks运行成功!
react renderToString接入nunjucks
在ctx.render时把content替换成react的string
const React = require('react')
const ReactDomServer = require('react-dom/server')
let comppath = path.join(__dirname, 'src/page', fpath, 'index')
let comp = require(comppath).default
let compVNode = React.createElement(comp)
let content = ReactDomServer.renderToString(compVNode)
ctx.render('index', {
pageTitle: fpath,
content: content
})
复制代码
到这里差不多就实现了react接入nunjucks,至于react的component,可以随便定义两个,如下:
<!--/page/home/react.js-->
import React from 'react'
export default () => {
return <h1>
homePage
</h1>
}
复制代码
<!--/page/list/react.js-->
import React from 'react'
export default () => {
return <h1>
listPage
</h1>
}
复制代码
这里需要注意一个问题:
require导入,不支持es6的语法,以及无法就解析JSX,所以先用babel对两个js编译下
<!--step 1. 安装es2015 react preset-->
npm install babel-preset-es2015
npm install babel-preset-react
复制代码
<!--step 2. 设置.babelrc-->
{
"presets": ["es2015", "react"]
}
复制代码
<!--step 3. 编译js-->
babel src/page/home/react.js -o src/page/home/index.js
babel src/page/home/react.js -o src/page/home/index.js
复制代码
ok,到这就完全实现了KOA-REACT-SSR,效果图如下: