zah*_*uzi 5 reactjs redux server-side-rendering react-ssr loadable-component
我的 ssr 网页在启动客户端时闪烁,这意味着页面渲染服务器端渲染的 html,然后变为空白,然后开始重新加载所有内容。
我正在开发一个反应项目,我们决定将其从在客户端渲染更改为在服务器渲染。该项目包括react-router-dom,redux和react-redux,material-ui它附带react-jss, loadable/component,还通过 来处理头元素react-helmet-async,并且在 ssr 中它使用express.js这似乎是必须的。
react-router-dom我做了文档上的所有内容。BrowserRouter在客户端和StaticRouterssr 中使用并向context其传递一个对象。redux,react-redux我保存preloaded_state在窗口中的变量中,并在客户端获取它,然后将其传递给存储。还获取了一些外部数据以获取页面源上的内容。所以我在 ssr 中有一些请求和数据获取。material-ui我创建了一个new serverSideStyleSheet并收集了整个项目的所有样式。react-helmet-async我Helmet为每个页面设置了不同的标签,收集不同的标题、描述和...个人。还有一个helmetProvidercsr 和 ssr 的包装器。react-helmet但它与 .i 不兼容。renderToNodeStream我没有更改react-helmet-async,尽管我没有使用 renderToNodeStream 但renderToNodeStream希望将其迁移到有一天。express.js我按照文档所说使用它,但是在我添加之后,loadable/component我无法通过仅添加来获得成功的服务器端渲染 app.get('*' , ServerSideRender)。所以我必须添加我想要在服务器中渲染的每个网址app.get(url ,ServerSideRender)。发生此问题是因为我在Router.js. 因此,当我以正常方式导入组件时,不会出现任何闪烁,一切都很好,但未使用的 js 会降低我页面的性能分数。我需要可加载组件停止使页面闪烁。
index.html :仅在客户端中呈现
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta name="robots" content="noindex, nofollow" />
<meta data-rh="true" name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no" />
<link href="%PUBLIC_URL%/fonts.css" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
<script src="%PUBLIC_URL%/main.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
index.js :仅在客户端中呈现
import React from 'react'
import ReactDOM from 'react-dom'
import {loadableReady} from '@loadable/component'
import App from './App'
import {BrowserRouter} from 'react-router-dom'
import {HelmetProvider} from 'react-helmet-async'
import { Provider } from 'react-redux'
loadableReady(() => {
const preloadedState = window.__PRELOADED_STATE__
delete window.__PRELOADED_STATE__
ReactDOM.hydrate(
<BrowserRouter>
<HelmetProvider>
<Provider store={store(preloadedState)}>
<App />
</Provider>{" "}
</HelmetProvider>
</BrowserRouter>,
document.getElementById("root")
);
})
Run Code Online (Sandbox Code Playgroud)
ssrIndex.js
require('ignore-styles')
require('@babel/register')({
ignore: [/(node_modules)/],
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
'babel-plugin-dynamic-import-node',
'@babel/plugin-transform-modules-commonjs',
'@loadable/babel-plugin',
],
})
// Import the rest of our application.
require('./SSR.js')
Run Code Online (Sandbox Code Playgroud)
SSR.js
import React from 'react'
import express from 'express'
import ReactDOMServer from 'react-dom/server'
import {StaticRouter} from 'react-router-dom'
import {Provider} from 'react-redux'
import ServerStyleSheets from '@material-ui/styles/ServerStyleSheets'
import {HelmetProvider} from 'react-helmet-async'
import {ChunkExtractor, ChunkExtractorManager} from '@loadable/server'
import path from 'path'
import App from './App'
import store from './redux/store'
import template from './utils/template'
const PORT = 8080
const app = express()
const renderPage = (req, res, preload) => {
const staticRouterContext = {}
const helmetContext = {}
const statsFile = path.resolve(__dirname, '../build', 'loadable-component.json')
const extractor = new ChunkExtractor({statsFile})
const sheets = new ServerStyleSheets()
const html = ReactDOMServer.renderToString(
sheets.collect(
<ChunkExtractorManager extractor={extractor}>
<HelmetProvider context={helmetContext}>
<StaticRouter location={req.url} context={staticRouterContext}>
<Provider store={store(preload)}>
<App />
</Provider>
</StaticRouter>
</HelmetProvider>
</ChunkExtractorManager>,
),
)
const {helmet} = helmetContext
const wholeData = template('scripts', {
chunks: html,
helmet,
extractor,
sheets,
preload,
})
res.send(wholeData)
}
const serverRenderer = (req, res, next) => {
fetchSomeExternalData()
.then(response => {
// response.data is used as preloaded data and passed to the store of redux
// also stored in a variable called __PRELOADED_STATE__ in window to use in client side
// to populate store of redux
renderPage(req, response, response.data)
})
.catch(err => {
// start server side rendering without preloaded data
renderPage(req, res)
})
}
// each url that i want to render on the server side i should add here individually
// which is not so convenient
app.get('/', serverRenderer)
app.get('/my-url-1/', serverRenderer)
app.get('/my-url-2/', serverRenderer)
app.use(express.static(path.join(__dirname, '/../build/')))
// the * doesnt seem to work
app.get('*', serverRenderer)
app.listen(PORT, () => {
if (process.send) {
process.send('ready')
}
})
Run Code Online (Sandbox Code Playgroud)
应用程序.js
<div>
<Header/>
<Router/>
<Footer/>
</div>
Run Code Online (Sandbox Code Playgroud)
我很高兴听到任何建议或解决方案。感谢您的时间。
| 归档时间: |
|
| 查看次数: |
1611 次 |
| 最近记录: |