import * as React from 'react'
import * as fs from 'fs'
import * as path from 'path'
import {renderToString} from 'react-dom/server'
import {match, RouterContext} from 'react-router'
import {Provider} from 'react-redux'
import ServerRequestHelper from '../server-request'
import {setServerRender} from '../fetch'
import configureStore from '../store'
import service from '../service'
interface YogInterface {
log:any
ralP:any
}
declare var yog:YogInterface
// 渲染整个页面
const renderFullPage = (htmlText:string, element:string, initialState:any, initialTitle:string)=> {
let content = htmlText
// 将内容塞到 #react-dom
content = content.replace(/
<\/div>/g, `
${element}
`)
// 设置 Redux 初始状态
content = content.replace(/__serverData\((\'|\")__INITIAL_STATE__(\'|\")\)/g, JSON.stringify(initialState))
// 设置 title
content = content.replace(/__serverData\((\'|\")__INITIAL_TITLE__(\'|\")\)/g, initialTitle)
return content
}
export interface Option {
req:any
res:any
routes:ReactRouter.RouteConfig
basename:string
rootReducer:any
htmlText:string
enableServerRender?:boolean
}
// 后端渲染
export default(option:Option)=> {
// 如果不启动后端渲染,直接返回未加工的模板
if (!option.enableServerRender) {
return option.res.status(200).send(renderFullPage(option.htmlText, '', {}, ''))
}
match({
routes: option.routes,
location: option.req.url,
basename: option.basename
}, (error:any, redirectLocation:any, renderProps:any) => {
if (error) {
option.res.status(500).send(error.message)
} else if (redirectLocation) {
option.res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
const serverRequestHelper = new ServerRequestHelper(service, option.req)
// 初始化 fetch
setServerRender(serverRequestHelper.Request as Function)
// 初始化 redux
const store = configureStore({}, option.rootReducer)
const InitialView = React.createElement(Provider, {store: store}, React.createElement(RouterContext, renderProps))
// 找到最深层组件的 title
const title = renderProps.components[renderProps.components.length-1].title
try {
// 初次渲染触发所有需要的网络请求
renderToString(InitialView)
// 拿到这些请求的action
const actions = serverRequestHelper.getActions()
Promise.all(actions.map((action:any)=> {
return store.dispatch(action)
})).then(()=> {
const componentHTML = renderToString(InitialView)
const initialState = store.getState()
// 将初始状态输出到 html
option.res.status(200).send(renderFullPage(option.htmlText, componentHTML, initialState, title))
})
} catch (err) {
option.res.status(200).send(renderFullPage(option.htmlText, `Server Render Error: ${err.toString()}`, {}, title))
}
} else {
option.res.status(404).send('Not Found')
}
})
}