gitlink ssr 动态head版本
This commit is contained in:
parent
7d5922ca49
commit
2c3615b628
14
Routes.js
14
Routes.js
|
|
@ -1,8 +1,8 @@
|
|||
import app from './src/App'
|
||||
import users from './src/forge/users/Index';
|
||||
import Detail from "./src/forge/Main/Detail";
|
||||
import Information from "./src/forge/Information/index"
|
||||
import NewsDetail from './src/forge/Information/Pages/newsDetail';
|
||||
// import users from './src/forge/users/Index';
|
||||
// import Detail from "./src/forge/Main/Detail";
|
||||
// import Information from "./src/forge/Information/index"
|
||||
// import NewsDetail from './src/forge/Information/Pages/newsDetail';
|
||||
|
||||
export default [
|
||||
{
|
||||
|
|
@ -26,16 +26,16 @@ export const deepRoutes = [
|
|||
{
|
||||
key: "zoneNews",
|
||||
path: "/zone/:deptId/newdetail/:id",
|
||||
component: NewsDetail
|
||||
// component: NewsDetail
|
||||
},
|
||||
{
|
||||
key: "zone",
|
||||
path: "/zone/:deptId",
|
||||
component: Information
|
||||
// component: Information
|
||||
},
|
||||
{
|
||||
key: "detail",
|
||||
path: "/:owner/:projectsId",
|
||||
component: Detail,
|
||||
// component: Detail,
|
||||
}
|
||||
]
|
||||
|
|
@ -17,6 +17,13 @@ const paths = require("./paths");
|
|||
const publicPath = "/";
|
||||
const env = getClientEnvironment("/","development");
|
||||
|
||||
const process = require('process');
|
||||
|
||||
process.on('uncaughtException', function (err) {
|
||||
// 开发时,websocket proxy 会因服务重新部署而报错中断本地 server,这里拦截一下
|
||||
console.log('拦截未处理异常:', err);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@
|
|||
},
|
||||
"@babel/helper-annotate-as-pure": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
|
||||
"integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.5"
|
||||
|
|
@ -243,7 +243,7 @@
|
|||
},
|
||||
"@babel/helper-builder-binary-assignment-operator-visitor": {
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz",
|
||||
"integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.15"
|
||||
|
|
@ -1456,7 +1456,7 @@
|
|||
},
|
||||
"core-js": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
||||
"dev": true
|
||||
},
|
||||
|
|
@ -1480,7 +1480,7 @@
|
|||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
|
||||
"dev": true
|
||||
}
|
||||
|
|
@ -1497,7 +1497,7 @@
|
|||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
||||
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz",
|
||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
|
||||
}
|
||||
}
|
||||
|
|
@ -21603,15 +21603,13 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
|
|
@ -21620,8 +21618,7 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.6.0",
|
||||
|
|
|
|||
|
|
@ -157,8 +157,8 @@
|
|||
"analyze": "npm run build -- --stats && webpack-bundle-analyzer build/bundle-stats.json",
|
||||
"analyz": "NODE_ENV=production npm_config_report=true npm run build",
|
||||
"dev": "npm-run-all --parallel dev:**",
|
||||
"dev:server": "cross-env NODE_ENV=production nodemon --exec babel-node \"./buildserver/bundle.js\" --watch config --watch server",
|
||||
"dev:build:server": "cross-env NODE_ENV=production webpack --config config/webpack.server.js",
|
||||
"dev:server": "cross-env NODE_ENV=dev nodemon --exec babel-node \"./buildserver/bundle.js\" --watch config --watch server",
|
||||
"dev:build:server": "cross-env NODE_ENV=dev webpack --config config/webpack.server.js",
|
||||
"pm2": "pm2 start pm2.json"
|
||||
},
|
||||
"jest": {
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@ 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'
|
||||
|
||||
export const render = async (req,res)=>{
|
||||
let _route = null,
|
||||
_match = null;
|
||||
Logger.info(`${req.url} UA:${req.headers['user-agent']}`)
|
||||
// Logger.info(`${req.url} UA:${req.headers['user-agent']}`)
|
||||
|
||||
let store = serverStore();
|
||||
|
||||
|
|
@ -57,39 +58,47 @@ export const render = async (req,res)=>{
|
|||
query: req.path,
|
||||
});
|
||||
}
|
||||
|
||||
const content = renderToString((
|
||||
<Provider store={store}>
|
||||
<StaticRouter location={req.path} context={context}>
|
||||
{renderRoutes(Routes)}
|
||||
{/* <Route path='/:owner/:projectsId' exact component={App}></Route> */}
|
||||
</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()) }`
|
||||
|
||||
domObj.window.document.head.appendChild(script);
|
||||
if (_route) {
|
||||
await changeHead(_route, _match.params)
|
||||
}
|
||||
|
||||
// 暂时不开放ssr,只修改head
|
||||
// const content = renderToString((
|
||||
// <Provider store={store}>
|
||||
// <StaticRouter location={req.path} context={context}>
|
||||
// {renderRoutes(Routes)}
|
||||
// {/* <Route path='/:owner/:projectsId' exact component={App}></Route> */}
|
||||
// </StaticRouter>
|
||||
// </Provider>
|
||||
// ))
|
||||
|
||||
// 暂时不开放ssr,只修改head
|
||||
// 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()) }`
|
||||
|
||||
// domObj.window.document.head.appendChild(script);
|
||||
// }
|
||||
|
||||
|
||||
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>`);
|
||||
// 暂时不开放ssr,只修改head
|
||||
// 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))
|
||||
// 暂时不开放ssr,只修改head
|
||||
// res.send(prepHTML(html, content))
|
||||
res.send(prepHTML(html, ''))
|
||||
|
||||
store = null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
// 兜底方案,先改head
|
||||
import { setDefaultMeta, setSeoMeta } from '../src/common/UrlTool'
|
||||
import { getProjectDetailFunc, getMainInfos, getNewsDetail } from '../src/services/project'
|
||||
|
||||
export const changeHead = async ({ key }, params) => {
|
||||
let res
|
||||
let data
|
||||
switch (key) {
|
||||
case 'detail':
|
||||
res = await getProjectDetailFunc(params.owner, params.projectsId);
|
||||
data = res.data
|
||||
if (data && data.status !== 404) {
|
||||
let keyWords=`${params.owner},${params.projectsId},${data.author && data.author.name}`;
|
||||
let title= `${params.owner}/${params.projectsId}${data.description?':'+data.description:''}`;
|
||||
setSeoMeta(keyWords,title,data.description || '',`/${params.owner}/${params.projectsId}`,params.owner,params.projectsId);
|
||||
}
|
||||
break;
|
||||
case 'zoneNews':
|
||||
res = await getNewsDetail(params.id)
|
||||
data = res.data.data
|
||||
if (data) {
|
||||
setSeoMeta(`${data.name}`, data.name, data.subTitle || '', `/zone/${params.deptId}/newdetail/${ params.id }`)
|
||||
}
|
||||
break;
|
||||
case 'zone':
|
||||
res = await getMainInfos(params.deptId);
|
||||
data = res.data.data
|
||||
if (data) {
|
||||
setSeoMeta(`${data.name}`, data.name, data.subTitle || '', `/zone/${params.deptId}`)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,14 +18,14 @@ function locationurl(list) {
|
|||
// TODO 开发期多个身份切换
|
||||
let debugType = ""
|
||||
if (isDev) {
|
||||
// const _search = window.location.search;
|
||||
// let parsed = {};
|
||||
// if (_search) {
|
||||
// parsed = queryString.parse(_search);
|
||||
// }
|
||||
// debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
||||
// window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
||||
// window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
|
||||
const _search = window.location.search;
|
||||
let parsed = {};
|
||||
if (_search) {
|
||||
parsed = queryString.parse(_search);
|
||||
}
|
||||
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
||||
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
||||
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
|
||||
}
|
||||
window._debugType = debugType;
|
||||
export function initAxiosInterceptors(props) {
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ export function setSeoMeta(keyWords, title, description, url, owner, projectId)
|
|||
document.querySelector(`meta[property='og:url']`).content = origin + url;
|
||||
document.querySelector(`meta[property='og:description']`).content = description + ' | GitLink';
|
||||
document.querySelector(`meta[property='og:image:alt']`).content = description + ' | GitLink';
|
||||
document.querySelector('meta[name="Keywords"]').content= `${ keyWords },${ keyWords ? '' : 'GitLink, git, 开源, 代码托管, 项目管理, 版本控制, 代码分享, 项目协作, 协同开发平台' }` ;
|
||||
document.querySelector('meta[name="Keywords"]').content= `${ keyWords }${ keyWords ? '' : 'GitLink, git, 开源, 代码托管, 项目管理, 版本控制, 代码分享, 项目协作, 协同开发平台' }` ;
|
||||
document.querySelector(`meta[name='description']`).content = description + ' | GitLink';
|
||||
document.querySelector(`meta[name='go-import']`).content = host + url + ' git ' + origin + url;
|
||||
document.querySelector(`meta[name='octolytics-dimension-user_login']`).content = owner;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { isPhone } from 'educoder';
|
|||
import { tempConfig } from '../tempInfo';
|
||||
import Acce from '../Component/mobile/accessory';
|
||||
import { addMeta, setSeoMeta } from 'educoder';
|
||||
// import CommentList from '../Component/comments/list'
|
||||
import CommentList from '../Component/comments/list'
|
||||
import { connect } from 'react-redux';
|
||||
import { withRouter } from "react-router";
|
||||
import { setZoneDetail, setNewsDetail } from '../../../redux/actions/server';
|
||||
|
|
@ -23,9 +23,6 @@ function NewsDetail(props){
|
|||
const [ commentReload, setCommentReload] = useState(undefined);
|
||||
const temp = props.temp;
|
||||
const zonedetail = props.zoneDetail || props.data;
|
||||
if (__SERVER__ && detail) {
|
||||
setMeta()
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
let initialContent = undefined;
|
||||
|
|
@ -50,7 +47,7 @@ function NewsDetail(props){
|
|||
}
|
||||
if (zonedetail) {
|
||||
document.title= zonedetail.mainTitle;
|
||||
setSeoMeta(`${zonedetail.name},`, zonedetail.name, zonedetail.subTitle, `/zone/${deptId}`)
|
||||
setSeoMeta(`${zonedetail.name},`, zonedetail.name, zonedetail.subTitle, `/zone/${deptId}/newdetail/${ id }`)
|
||||
}
|
||||
}
|
||||
},[zonedetail,detail])
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ function CoderDepot(props){
|
|||
|
||||
useEffect(()=>{
|
||||
// 设置网页标题
|
||||
if(projectDetail){
|
||||
if(projectDetail && projectDetail.project_identifier){
|
||||
const { author, name, description, default_branch} = projectDetail;
|
||||
if(branchName && branchName !== default_branch){
|
||||
// 处于某分支/标签
|
||||
|
|
|
|||
|
|
@ -310,7 +310,10 @@ class Detail extends Component {
|
|||
if (this.props.defaultDetail) {
|
||||
projectdata = this.props.defaultDetail
|
||||
} else {
|
||||
projectdata = await getProjectDetailFunc(owner, projectsId, !window.location.host).data;
|
||||
const res = await getProjectDetailFunc(owner, projectsId, !window.location.host);
|
||||
if (res.status === 200) {
|
||||
projectdata = res.data
|
||||
}
|
||||
}
|
||||
if (projectdata) {
|
||||
this.getDetail(projectdata)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
import axios from 'axios';
|
||||
import { url, zoneUrl } from '../ssrUrl';
|
||||
|
||||
const baseUrl = `${url}/api`
|
||||
const baseZoneUrl = `${zoneUrl}/api`
|
||||
let baseUrl = `${url}/api`
|
||||
let baseZoneUrl = `${zoneUrl}/api`
|
||||
|
||||
if (__CLIENT__) {
|
||||
let settings = localStorage.chromesetting&&JSON.parse(localStorage.chromesetting);
|
||||
baseUrl = settings && settings.common.main_site_url + '/api';
|
||||
baseZoneUrl = settings && settings.common.zone + '/api';
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
export async function getProjectFunc (owner, projectsId) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
export const url = process.env.NODE_ENV === 'production' ? 'https://www.gitlink.org.cn' : 'http://172.20.32.202:4000'
|
||||
export const zoneUrl = process.env.NODE_ENV === 'production' ? 'https://gateway.gitlink.org.cn' : 'http://172.20.32.202:4000'
|
||||
export const host = process.env.NODE_ENV === 'production' ? 'www.gitlink.org.cn' : '172.20.32.202:4000'
|
||||
export const url = process.env.NODE_ENV === 'production' ? 'https://www.gitlink.org.cn' : 'https://testforgeplus.trustie.net'
|
||||
export const zoneUrl = process.env.NODE_ENV === 'production' ? 'https://gateway.gitlink.org.cn' : 'https://testgetway.trustie.net'
|
||||
export const host = process.env.NODE_ENV === 'production' ? 'www.gitlink.org.cn' : 'testforgeplus.trustie.net'
|
||||
|
||||
// export const url = process.env.NODE_ENV === 'production' ? 'https://www.gitlink.org.cn' : ''
|
||||
// export const zoneUrl = process.env.NODE_ENV === 'production' ? 'https://gateway.gitlink.org.cn' : ''
|
||||
// export const host = process.env.NODE_ENV === 'production' ? 'www.gitlink.org.cn' : ''
|
||||
Loading…
Reference in New Issue