KOA-REACT-SSR的实现

马宜民
2023-12-01

前言

这篇文章讲述如何整合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()通知执行下一个中间件的操作

执行node index.js

可以看到访问localhost:3000,就可以看到hello world了

接入路由功能

试想,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,效果图如下:

转载于:https://juejin.im/post/5d5bd474f265da03e275ee14

 类似资料: