react首屏SSR,nodejs同构解决方案

网上看了N篇文章,有几篇比较高级的我看不太懂,其他基本全是吹逼复制不讲实质性东西的,我结合了一些自己的见解,写下了这篇可直接复制可用的,虽然还有基于流的解决方案,但是资料不多,时间也有限,就采用这个吧暂时。

1.create-react-app

2.src同级目录下新建server文件夹,新建index.js和entry.js

3.第一个问题:让koa支持import

//index.js 写koa
import Koa from 'koa';
const app = new Koa();
app.listen(8889, () => {
    console.log('ssr starting');
})

//entry.js 作为入口文件处理koa使用import
require('babel-register')({
    presets:["env","react"]
});
require('babel-polyfill');
module.exports = require('./index');

//依赖
"devDependencies": {
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "babel-register": "^6.26.0"
}

4.第二个问题:我之前使用的是react提供的lazy和Suspense来处理code splitting,做SSR的时候发现不行,改为react-loadable,

抽离组件,新建util>loadable>index.js

import React from 'react';
import Loadable from 'react-loadable';

const loadingComponent = () => {
    return (
        <div>我正在加载哦哦哦哦哦哦哦哦!</div>
    )
}

export default ((loader,loading = loadingComponent) => {
    return Loadable({
        loader,
        loading
    })
})

使用react-loadable

//App.js
import React from 'react';
import './App.css';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
import loadable from './util/loadable';

import Home from './pages/home';
import ReactTransitionGroup from './pages/react-transition-group';

const About = loadable(() => import('./pages/about'));

function App() {

  return (
    <div className="App">
      <h1>react-example</h1>
        <Router>
          <Route path='/' exact component={Home}></Route>
          <Route path='/about' exact component={About}></Route>
          <Route path='/reactTransitionGroup' component={ReactTransitionGroup}></Route>
        </Router>
    </div>
  );
}

export default App;

5.接下来就是服务端(大家都懂的,前面试了N+1次)

server/index.js

// 关于react
import React from 'react';
import Router from 'koa-router';
import { StaticRouter } from 'react-router-dom';//react的路由换成这个
import { renderToString } from 'react-dom/server';//这个是渲染react组件的
import Home from '../src/pages/home';//这个是首页,需要渲染的页面
// //关于koa
import Koa from 'koa';
import KoaStatic from 'koa-static';
// // 关于node
import fs from 'fs';
import path from 'path';


const app = new Koa();

const router = new Router();

router.get('/', async (ctx) => {
    //我也不知道这个context是干什么用的
    const context = {};
    //把你react App组件内的东西放到这里来!你可以尝试直接返回出结果,就是root内容
    const reactAppString = await renderToString(
        (
            <div className="App">
                <h1>react-example</h1>
                <StaticRouter
                location={ctx.url}
                context={context}
                >
                    <Home />
                </StaticRouter>
            </div>
        )
    );
    //indexFile先把文件读取出来
    const indexFile = await path.resolve(__dirname + 'build/index.html').replace('server','');
    const data = await fs.readFileSync(indexFile,'utf8',function(err,data){
        return data;
    });
    //替换root内容为之前的reactAppString
    let dataReplaced = await data.replace('<div id="root"></div>',`<div id="root">${reactAppString}</div>`);
    console.log(dataReplaced)
    //最后返回出去
    ctx.body = dataReplaced;
});

app.use(router.routes());
app.use(router.allowedMethods());

//static记得一定要写在这里,不然首页会默认导到build/index.html,root内没有内容
app.use(KoaStatic(
  path.resolve(__dirname + 'build').replace('server', '')
));


app.listen(8889, () => {
    console.log('ssr starting');
})

渲染结果:

最后总结一下:首屏SSR就是用户访问服务器,服务器返回出带有内容的root,然后再交由客户端,我这里的话基本能够满足我的需求,但是还有数据获取的问题没有解决,因为涉及的问题会有点多,我感觉新人真的不太合适做SSR,我自己接下来也打算往umi+ts+antd+dva这里去探探,看看有没有方便一些的解决办法。

github:https://github.com/Tcbun/react-example

猜你喜欢

转载自blog.csdn.net/weixin_42450794/article/details/102974119
今日推荐