# 正文
本节主要是补充一下以前没有提到的一些细节和一些问题以及解决思路,以便于我们可以更方便的应用本骨架进行业务开发,减少前期的一些时间准备成本。
本来打算将csr/ssr双模式渲染作为独立章节来说,但是具体的实现很简单,作为独立章节的话又确实没必要。
但是这个特性又非常重要,所以干脆将内容进行压缩一下,只说主要的部分,同时将本骨架的其他的一些细节合在一起介绍吧。
# ssr/csr 两种渲染模式支持
目前我们的骨架只是单纯的支持了ssr模式下的开发和运行,其实我们还可以做一个扩展,多加一个运行模式csr模式,这样整个应用就可以支持两种渲染模式。
我们可以根据需要来进行切换渲染模式,当应用的负载过大的时候我们也可以方便的切换为单页应用,这种临时处理方案可以迅速的降低服务器的压力。
# 实现说明
具体的实现很简单,我们在全局配置文件内增加一个配置,用于表示渲染模式。
我们目前是ssr模式,如果当前是csr 模式的话只需要返回一个空的html结构,然后向浏览器注入一个全局变量,表示当前的渲染模式。
其他的css/js资源正常按照ssr下的模式直出即可。
增加一个全局设置
// ./src/share/pro-config.js
//双端公用的配置文件
module.exports = {
__IS_SSR__:false,//是否为 ssr 模式
wdsPort:9002,//wds 服务的运行端口
nodeServerPort:9001,//node server 的监听端口
asyncComponentKey:'__IS_ASYNC_COMP_FLAG__'//标志组件是否是按需加载 turn | false
}
服务端模式判断
@前端进阶之旅: 代码已经复制到剪贴板
我们在ssr中间件对渲染模式进行判断,如果是csr则返回一个空的页面骨架。
let html="";//组件渲染结果
if (proConfig.__IS_SSR__){
//匹配路由
//数据预取
//组件渲染
}
//...
ctx.body = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>${tdk.title}</title>
<meta name="keywords" content="${tdk.keywords}" />
<meta name="description" content="${tdk.description}" />
${assetsMap.css.join('')}
</head>
<body>
<div id="root">
${html}
</div>
<textarea id="ssrTextInitData" style="display:none;">
${JSON.stringify(fetchResult)}
</textarea>
</body>
</html>
</body>
<script>
//注入全局渲染模式
window.__IS__SSR__=${proConfig.__IS_SSR__};
</script>
${assetsMap.js.join('')}
`;
高阶组件调整
@前端进阶之旅: 代码已经复制到剪贴板
我们的高阶组件PageContainer用来管理客户端页面在路由切换时是否进行异步获取数据,所以当前若是csr模式,则每次在componentDidMount内直接获取数据,也不需要监听popstate事件了。
// src/client/common/components/page-container/index.js
//...
async componentDidMount() {
_this = this; // 修正_this指向,保证_this指向当前渲染的页面组件
//只有当前是ssr模式才会注册事件,用于在页面切换时候触发
window.__IS__SSR && window.addEventListener('popstate', popStateCallback);
const canClientFetch = this.props.history && this.props.history.action === 'PUSH';//路由跳转的时候可以异步请求数据
if (canClientFetch || !window.__IS__SSR) {//如果是 csr 模式,每次都需要异步请求数据
await this.getInitialProps();
}
}
//...
@前端进阶之旅: 代码已经复制到剪贴板
