我正在尝试在我的反应应用程序中实现服务器端呈现(使用create-react-app环境)。我试图按照这里显示的示例,它仍然保持我的应用程序的结构。没有太大的不同,所以我认为在我自己的应用程序中遵循它不会是一个问题。 https://medium.com/@benlu/ssr-with-create-react-app-v2-1b8b520681d9
当我尝试构建应用时,我只是以下内容:Invariant Violation: Browser history needs a DOM
我随时随地都能找到,但似乎无法找到我做错的事。
客户端index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import Store from './store'
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(
<Provider store={Store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
&#13;
服务器端app.js
require('ignore-styles')
const bodyParser = require('body-parser')
const compression = require('compression')
const express = require('express')
const morgan = require('morgan')
const path = require('path')
const fs = require('fs')
require('babel-register')({
ignore: /\/(build|node_modules)\//,
presets: ['env', 'react-app']
})
// routes
const index = require('./routes/index')
// const api = require('./routes/api')
const universalLoader = require('./universal')
const app = express()
// Support Gzip
app.use(compression())
// Support post requests with body data (doesn't support multipart, use multer)
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: false }))
// Setup logger
app.use(morgan('combined'))
app.use('/', index)
// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')))
// app.use('/api', api)
// Always return the main index.html, so react-router render the route in the client
app.use('/', universalLoader)
module.exports = app
&#13;
服务器端universal.js
const path = require('path')
const fs = require('fs')
const React = require('react')
const {Provider} = require('react-redux')
const {renderToString} = require('react-dom/server')
const {StaticRouter} = require('react-router-dom')
const {default: configureStore} = require('../src/store')
const {default: App} = require('../src/App')
module.exports = function universalLoader(req, res) {
const filePath = path.resolve(__dirname, '..', 'build', 'index.html')
fs.readFile(filePath, 'utf8', (err, htmlData)=>{
if (err) {
console.error('read err', err)
return res.status(404).end()
}
const context = {}
const store = configureStore()
const markup = renderToString(
<Provider store={store}>
<StaticRouter
location={req.url}
context={context}
>
<App/>
</StaticRouter>
</Provider>
)
if (context.url) {
// Somewhere a `<Redirect>` was rendered
redirect(301, context.url)
} else {
// we're good, send the response
const RenderedApp = htmlData.replace('{{SSR}}', markup)
res.send(RenderedApp)
}
})
}
&#13;