-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Labels
Description
面临的问题及解决方案
服务器渲染遇到了以下几个问题。
- 判断运行环境,差异化加载资源
- 解决路由共享问题
- 解决initial data 问题
- 服务器 render方法
- 服务器运行es6
解决方案
1.判断运行环境
因为部分依赖的js不是渲染用,可是其他逻辑。比如以下jssdk。是对接客户端app端方法。在服务器渲染时,不需要依赖加载。所以判断环境是否是window
// 浏览器加载
if ( 'undefined' !== typeof window ) {
require('../utils/dtSdk');
}
2.共享路由
routes.js
import { Route } from "react-router";
import React from "react";
export default (
<Route name="app" path="/" component={App}>
<Route path="a" component={a} />
<Route path="*" component={error404}/>
</Route>
);
server.js 见 代码一
获取请求的url,react-router提供的match方法可以捕获此url。进入router。之后进入请求逻辑,获取数据。
app.get('/*', function (req, res) {
//请求
const location = createLocation(req.url);
//匹配路由
match({ routes, location }, (err, redirectLocation, renderProps) => {
//获取数据
// 数据填充store
// render
})
});
client.js
React.render(
<Provider store={store}>
{() =>
<ReduxRouter>
<Router children={routes} history={history} />
</ReduxRouter>
}
</Provider>,
document.getElementById('root')
);
3.初始化数据
html是react+data的dom,initialState是在页面的store
const renderFullPage = (html, initialState) => {
return `
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="/static/app.css">
</head>
<body>
<div id="root">${html}</div>
<script>
window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};
</script>
<script src="/static/bundle.js"></script>
</body>
</html>
`;
}
4.服务器 render方法, 见代码一
react 有renderToString的api
const InitialView = (
<Provider store={store}>{() =>
<RoutingContext {...renderProps}/>
}
</Provider>
);
const componentHTML = React.renderToString(InitialView);
5.服务器运行es6
使用babel-core/register
require('babel-core/register');
require('./server');
服务器代码示例,代码一
app.get('/*', function (req, res) {
const location = createLocation(req.url);
fetchInventoryByIds(user => {
if(!user) {
return res.status(401).end('Not Authorised');
}
match({ routes, location }, (err, redirectLocation, renderProps) => {
if(err) {
console.error(err);
return res.status(500).end('Internal server error');
}
if(!renderProps)
return res.status(404).end('Not found');
const store = configureStore({
user : user,
version : packagejson.version,
NewSingleGoodsData: user.NewSingleGoodsData
});
const InitialView = (
<Provider store={store}>
{() =>
<RoutingContext {...renderProps} />
}
</Provider>
);
fetchComponentDataBeforeRender(store.dispatch, renderProps.components, renderProps.params)
.then(html => {
const componentHTML = React.renderToString(InitialView);
const initialState = store.getState();
res.status(200).end(renderFullPage(componentHTML,initialState))
})
.catch(err => {
console.log(err)
res.end(renderFullPage("",{}))
});
});
}
)
});
项目结构
保证主业务逻辑服务器端和客户端皆可用
+-- client
| +-- index.js(客户端的app.js入口)
+-- common
| +-- containers
| +-- compenents
| +-- actions
| +-- reducers
| +-- router
| +--(react+redux+react-router业务逻辑)
+-- server
| +-- server
结果
渲染前后的差别的差别。不做服务器渲染,dom内容是通过客户端js渲染完成。传输的html只是一个空模版。服务器渲染后会把内容填满后提供完整的html
渲染前的html
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/static/app.css">
</head>
<div id="root"></div>
<body>
<script src="/static/bundle.js"></script>
</body>
</html>
服务器渲染后的html
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/static/app.css">
</head>
<body>
<div id="root">
<section data-reactid=".29kxietvhmo" data-react-checksum="861612904"><section data-reactid=".29kxietvhmo.0"><ul data-reactid=".29kxietvhmo.0.0"><li class="cp-nsgoods-item" data-reactid=".29kxietvhmo.0.0.$0"><div class="pg-new-single-goods" data-reactid=".29kxietvhmo.0.0.$0.0"><div class="pg-new-single-goods-time" data-reactid=".29kxietvhmo.0.0.$0.0.0"><span data-reactid=".29kxietvhmo.0.0.$0.0.0.0">2016</span><span data-reactid=".29kxietvhmo.0.0.$0.0.0.1">年</span><span data-reactid=".29kxietvhmo.0.0.$0.0.0.2">4</span><span data-reactid=".29kxietvhmo.0.0.$0.0.0.3">月</span><span data-reactid=".29kxietvhmo.0.0.$0.0.0.4">26</span><span data-reactid=".29kxietvhmo.0.0.$0.0.0.5">日 </span><span data-reactid=".29kxietvhmo.0.0.$0.0.0.6">星期二</span></div><section class="swiper-banners" data-reactid=".29kxietvhmo.0.0.$0.0.1"><div class="swiper-container0 swiper-container" data-reactid=".29kxietvhmo.0.0.$0.0.1.0"><div class="swiper-wrapper" data-reactid=".29kxietvhmo.0.0.$0.0.1.0.0"><a href="http://www.duitang.com/guide2/buy_group_purchase/2016042601/?__urlopentype=pageweb" data-background="http://img4q.duitang.com/uploads/people/201604/25/20160425142354_tFnhU.thumb.800_0.jpeg" class="swiper-lazy swiper-slide" data-reactid=".29kxietvhmo.0.0.$0.0.1.0.0.$0">
</div>
<script src="/static/bundle.js"></script>
</body>
</html>