服务器端呈现时,浏览器历史记录需要DOM

时间:2017-09-01 20:38:15

标签: javascript reactjs redux serverside-rendering

我正在尝试在我的反应应用程序中实现服务器端呈现(使用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;
&#13;
&#13;

服务器端app.js

&#13;
&#13;
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;
&#13;
&#13;

服务器端universal.js

&#13;
&#13;
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;
&#13;
&#13;

0 个答案:

没有答案