基于 dva 的服务器端渲染库。
特性:
- 无需添加额外的服务器端数据获取代码
- 最小化客户端与服务器端渲染的差异
[email protected]
[email protected]
[email protected]
$ npm install express-dva-ssr --save
配置服务器端渲染参数
import ssr from 'express-dva-ssr';
ssr.config({
timeout: 6 * 1000, // 等待异步操作的超时时间
/**
* 异步操作超时后,是否终止渲染,并抛出异常
*
* true:忽略超时,停止等待异步操作,直接返回渲染结果
* false:终止渲染,并抛出异常,渲染失败
*/
ignoreTimeout: true,
verbose: true, // console 输出日志
staticMarkup: false, // 是否创建额外的DOM属性
});
服务器端渲染核心函数
import ssr from 'express-dva-ssr';
ssr.render({
url: 'https://www.example.com/users/alexyan', // 需要渲染的路由
/**
* 服务器端环境数据。
* 在服务器端会在 namespace 为 ssr 的 model 中注入
* 可以传入 http 请求中的 useragent 等请求相关信息,方便对渲染进行控制
*
* 注意!!!: 出于安全考虑,请不要传入服务器敏感信息
*/
env: { platform: 'mobile' },
/**
* 配置初始化 state
*/
initialState: {
},
/**
* 初始化 dva app, 注册 model, 返回 dva 实例
*
* 如果指定 createApp, models 将不生效
*/
createApp: function(opts) {
const app = dva(opts);
app.model(require('./models/app'));
app.model(require('./models/user'));
return app;
},
/**
* 配置 Routes, 参数详见 react-router
*/
routes: [<Route path="/" render={() => <div>/</div>} />,
<Route path="/user" render={() => <div>/tech</div>} />
],
/**
* 配置 models, 详见 dva model
*/
models: [
Model
],
/**
* 生成完整网页
*
* html: 服务器端渲染片段
* state: 渲染后的 state
* context: 服务器端渲染上下文
*/
renderFullPage: async ({html, state, context}) => {
const ssrHtml = `
<div id="root">
${html}
</div>
<script>
window.__INITIAL_STATE__ = ${JSON.stringify(state)};
</script>
`;
return indexHtml.replace(`<div id="root"></div>`, ssrHtml);
}
/**
* 完成最终渲染页面后调用,可以在这个阶段进行结果缓存等操作
*
* html: 服务器端渲结果
* url: 渲染路由
* state: 渲染后的 state
* env: 服务器端环境数据
*/
onRenderSuccess: async (html, url, env, state) => {
}
}).then((RenderResult) => {
console.log(RenderResult);
})
服务器端渲染结果类型描述
{
/**
* 渲染结果状态码
*
* 200: 渲染成功
* 404: 渲染失败,url 无法找到匹配的 route
* 500: 渲染失败
*/
code: 200,
url: 'https://www.example.com/users/alexyan', // 渲染的路由
env: {}, // 服务器端环境数据
html: '<html></html>', // 服务器端渲染最终页面
error: new Error('error') // 渲染异常,当 code 为 500 时存在
}
返回 Express
中间件
参数介绍见 render() 函数
const exporesMiddleware = ssr.runtimeSSRMiddle({
routes,
models,
createApp,
renderFullPage,
onRenderSuccess,
initialState
});
const app = express();
app.use(exporesMiddleware);
设置 sync 强制跳过异步操作,直接进行渲染
<Route path="/" sync component={Index} />
function runtimeSSRMiddle({
routes, renderFullPage, createApp, initialState, onRenderSuccess
}) {
return async (req, res, next) => {
const result = await render({
url: req.url,
env: { ua: req.headers['user-agent'] },
routes,
renderFullPage,
createApp,
initialState,
onRenderSuccess
});
switch (result.code) {
case 200:
return res.end(result.html);
case 302:
return res.redirect(302, result.redirect);
case 404:
next();
break;
case 500:
next(result.error);
break;
default:
next();
break;
}
};
}