forgeplus-react/server/render.js

122 lines
3.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react";
import {renderToString} from "react-dom/server";
import {StaticRouter, matchPath} from "react-router-dom";
import StyleContext from 'isomorphic-style-loader/StyleContext'
import {renderRoutes} from "react-router-config";
import Routes, { deepRoutes, specialRoute } from "../Routes";
import { Provider } from "react-redux";
import { serverStore } from "../src/redux/stores/configureStore";
// import App from "../src/App";
// import { Route } from 'react-router-dom';
import { setDefaultMeta } from '../src/common/UrlTool'
import Logger from "./log";
import { changeHead } from './setHead'
const css = new Set() // 这个必须在路由函数里面在外面的话就会累加出现之前的css
const insertCss = (...styles) => styles.forEach(style => css.add(style._getCss()));
export const render = async (req,res)=>{
let _route = null,
_match = null;
Logger.info(`${req.url} UA:${req.headers['user-agent']}`)
let store = serverStore();
function matchSubRoutes(routes, url) {
for (const route of routes) {
// 检查当前路由是否匹配
let match = matchPath(url, route.path);
if (match) {
// 如果当前路由匹配,并且它有子路由,递归检查子路由
if (route.routes) {
// 递归调用匹配子路由
const subMatch = matchSubRoutes(route.routes, url);
if (subMatch) {
_route = route;
_match = subMatch;
return true;
}
}
// 如果没有子路由,或者子路由不匹配,但当前路由匹配,返回当前路由
_route = route;
_match = match;
return true;
}
}
// 如果没有找到匹配的路由返回false
return false;
}
matchSubRoutes(deepRoutes, req.url.split("?")[0])
let context = {
code: 200,
};
if (_route && _route.component && _route.component.preFetch) {
// 设置服务端请求cookie
let cookies = req.headers.cookie.split(';')
for (let index = 0; index < cookies.length; index++) {
const element = cookies[index];
domObj.window.document.cookie = element
}
context = await _route.component.preFetch({
store,
match: _match,
query: req.path,
});
}
const content = renderToString((
<Provider store={store}>
<StaticRouter location={req.path} context={context}>
<StyleContext.Provider value={{insertCss}}>
{renderRoutes(Routes)}
{/* <Route path='/:owner/:projectsId' exact component={App}></Route> */}
</StyleContext.Provider>
</StaticRouter>
</Provider>
))
if (!content) {
// 未匹配到详情页恢复默认header
setDefaultMeta()
} else {
// 匹配到服务端渲染页面注入state
let script = domObj.window.document.getElementById('initState')
if (!script) {
script = domObj.window.document.createElement('script')
script.setAttribute('id', 'initState')
}
script.textContent = `window.__initState__ = ${ JSON.stringify(store.getState()) }`
const styleNode = domObj.window.document.createElement('style')
styleNode.type = 'text/css'
styleNode.innerHTML = `${ [...css].join('') }`
domObj.window.document.head.appendChild(script);
domObj.window.document.head.appendChild(styleNode);
}
if (_route && !specialRoute.includes(_match.url && _match.url.replace('/', ''))) {
Logger.info(`matchRoot: ${ _match.url }`)
await changeHead(_route, _match.params)
} else {
return false
}
let html = domObj.serialize()
const prepHTML=(data,rootString)=>{
data=data.replace('<div id="root" class="page -layout-v -fit widthunit"></div>',`<div id="root" class="page -layout-v -fit widthunit">${rootString}</div>`);
return data;
}
res.send(prepHTML(html, content))
store = null
}