2024-04-30 15:00:52 +08:00
|
|
|
|
import React from "react";
|
|
|
|
|
|
import {renderToString} from "react-dom/server";
|
2024-01-05 15:01:16 +08:00
|
|
|
|
import {StaticRouter, matchPath} from "react-router-dom";
|
2024-04-30 15:00:52 +08:00
|
|
|
|
import StyleContext from 'isomorphic-style-loader/StyleContext'
|
|
|
|
|
|
import {renderRoutes} from "react-router-config";
|
2024-04-17 17:12:30 +08:00
|
|
|
|
import Routes, { deepRoutes, specialRoute } from "../Routes";
|
2024-04-30 15:00:52 +08:00
|
|
|
|
import { Provider } from "react-redux";
|
|
|
|
|
|
import { serverStore } from "../src/redux/stores/configureStore";
|
|
|
|
|
|
import { setDefaultMeta } from '../src/common/UrlTool'
|
2024-04-23 14:31:31 +08:00
|
|
|
|
import Logger from "./log";
|
2024-04-16 09:21:49 +08:00
|
|
|
|
import { changeHead } from './setHead'
|
2024-01-05 15:01:16 +08:00
|
|
|
|
|
2024-05-08 09:59:48 +08:00
|
|
|
|
// 目前只用项目详情页的,不需要动态添加
|
2024-04-30 15:00:52 +08:00
|
|
|
|
const css = new Set() // 这个必须在路由函数里面,在外面的话,就会累加出现之前的css
|
|
|
|
|
|
const insertCss = (...styles) => styles.forEach(style => css.add(style._getCss()));
|
|
|
|
|
|
|
2024-01-05 15:01:16 +08:00
|
|
|
|
export const render = async (req,res)=>{
|
|
|
|
|
|
let _route = null,
|
|
|
|
|
|
_match = null;
|
2024-04-30 15:00:52 +08:00
|
|
|
|
Logger.info(`${req.url} UA:${req.headers['user-agent']}`)
|
2024-01-05 15:01:16 +08:00
|
|
|
|
|
2024-04-30 15:00:52 +08:00
|
|
|
|
let store = serverStore();
|
2023-12-26 13:49:10 +08:00
|
|
|
|
|
2024-01-05 15:01:16 +08:00
|
|
|
|
function matchSubRoutes(routes, url) {
|
|
|
|
|
|
for (const route of routes) {
|
|
|
|
|
|
// 检查当前路由是否匹配
|
2024-05-11 14:03:42 +08:00
|
|
|
|
let match = matchPath(url, { path: route.path, exact: true });
|
2024-01-05 15:01:16 +08:00
|
|
|
|
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,
|
2023-12-26 13:49:10 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2024-04-30 15:00:52 +08:00
|
|
|
|
|
|
|
|
|
|
if (_route && _route.component && _route.component.preFetch) {
|
2024-05-06 11:40:50 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置服务端请求cookie
|
2024-06-12 08:47:44 +08:00
|
|
|
|
if (req.headers.cookie) {
|
|
|
|
|
|
let cookies = req.headers.cookie.split(';')
|
|
|
|
|
|
for (let index = 0; index < cookies.length; index++) {
|
|
|
|
|
|
const element = cookies[index];
|
|
|
|
|
|
domObj.window.document.cookie = element
|
|
|
|
|
|
}
|
2024-05-06 11:40:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-04-30 15:00:52 +08:00
|
|
|
|
context = await _route.component.preFetch({
|
|
|
|
|
|
store,
|
|
|
|
|
|
match: _match,
|
|
|
|
|
|
query: req.path,
|
|
|
|
|
|
});
|
2024-05-07 10:20:07 +08:00
|
|
|
|
|
2024-05-11 10:25:13 +08:00
|
|
|
|
// 当前只做了项目详情页,没获取到数据使用原来的
|
2024-05-07 10:20:07 +08:00
|
|
|
|
if(!store.getState().projectReducer.projectBase.id) {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
2024-04-30 15:00:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-06 14:22:41 +08:00
|
|
|
|
let content = ''
|
2024-05-06 12:49:41 +08:00
|
|
|
|
|
2024-05-11 10:25:13 +08:00
|
|
|
|
// 匹配路由、并且不是特定一级路由、且不是只动态修改head的,在服务端渲染页面
|
2024-05-06 12:49:41 +08:00
|
|
|
|
if (_route && !specialRoute.includes(_match.url && _match.url.replace('/', '')) && !_route.onlyHead) {
|
|
|
|
|
|
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>
|
|
|
|
|
|
))
|
|
|
|
|
|
}
|
2024-04-30 15:00:52 +08:00
|
|
|
|
|
|
|
|
|
|
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()) }`
|
2024-05-11 10:25:13 +08:00
|
|
|
|
|
|
|
|
|
|
// 目前直接把详情页涉及到的css抽出来塞到返回的html里,没有使用insertCss
|
2024-04-30 15:00:52 +08:00
|
|
|
|
const styleNode = domObj.window.document.createElement('style')
|
|
|
|
|
|
styleNode.type = 'text/css'
|
2024-05-08 09:59:48 +08:00
|
|
|
|
// styleNode.innerHTML = `${ [...css].join('') }`
|
|
|
|
|
|
styleNode.innerHTML = detailCss
|
2024-04-30 15:00:52 +08:00
|
|
|
|
domObj.window.document.head.appendChild(script);
|
|
|
|
|
|
domObj.window.document.head.appendChild(styleNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-17 17:12:30 +08:00
|
|
|
|
if (_route && !specialRoute.includes(_match.url && _match.url.replace('/', ''))) {
|
2024-05-08 09:59:48 +08:00
|
|
|
|
// 匹配上的,并且只修改head的页面
|
|
|
|
|
|
if (_route.onlyHead) {
|
|
|
|
|
|
Logger.info(`matchRoot: ${ _match.url }`)
|
2024-05-14 11:40:38 +08:00
|
|
|
|
const result = await changeHead(_route, _match.params)
|
|
|
|
|
|
if (!result) return result
|
2024-05-08 09:59:48 +08:00
|
|
|
|
}
|
2024-04-17 10:10:27 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
return false
|
2024-04-16 09:21:49 +08:00
|
|
|
|
}
|
2024-01-05 15:01:16 +08:00
|
|
|
|
|
2024-01-12 10:11:16 +08:00
|
|
|
|
let html = domObj.serialize()
|
2023-12-26 13:49:10 +08:00
|
|
|
|
|
|
|
|
|
|
const prepHTML=(data,rootString)=>{
|
2024-04-30 15:00:52 +08:00
|
|
|
|
data=data.replace('<div id="root" class="page -layout-v -fit widthunit"></div>',`<div id="root" class="page -layout-v -fit widthunit">${rootString}</div>`);
|
2023-12-26 13:49:10 +08:00
|
|
|
|
return data;
|
|
|
|
|
|
}
|
2024-05-11 10:25:13 +08:00
|
|
|
|
|
2024-04-30 15:00:52 +08:00
|
|
|
|
res.send(prepHTML(html, content))
|
2024-01-12 10:11:16 +08:00
|
|
|
|
|
2024-04-30 15:00:52 +08:00
|
|
|
|
store = null
|
2023-12-26 13:49:10 +08:00
|
|
|
|
}
|