浏览器历史记录需要 DOM
Browser history needs a DOM
已经有关于此主题的问题,解决方案指向服务器上的 memoryHistory。但是,我这样做了,问题仍然存在于客户端文件夹内的 store.js 上。虽然我没有使用这个 client/store.js,但它仍然给我与主题相同的错误。
所以我猜测我在服务器端或客户端包装组件的方式有问题。
我正在处理已经加载的项目堆栈 - redux、react-redux、react-router-redux、redux-thunk、history 等...老实说,这些让我望而生畏,无法为SSR - 服务器端渲染(我的基本动机)
我将分享我在这个练习中涉及的结构和重要文件!
先欢迎服务器
server/bootstrap.js
require('ignore-styles');
require('babel-register')({
ignore: [ /(node_modules)/ ],
presets: ['es2015', 'react-app']
});
require('./index');
server/index.js
import express from 'express';
import serverRenderer from './middleware/renderer';
const PORT = 3000;
const path = require('path');
const app = express();
const router = express.Router();
// root (/) should always serve our server rendered page
router.use('^/$', serverRenderer);
// other static resources should just be served as they are
router.use(express.static(
path.resolve(__dirname, '..', 'build'),
{ maxAge: '30d' },
));
router.use('*', serverRenderer);
// tell the app to use the above rules
app.use(router);
// start the app
app.listen(PORT, (error) => {
if (error) {
return console.log('something bad happened', error);
}
console.log("listening on " + PORT + "...");
});
server/middleware/renderer.js
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import store from '../../src/store';
import {createMemoryHistory } from 'history';
import { StaticRouter } from 'react-router'
// import our main App component
import App from '../../src/index';
const path = require("path");
const fs = require("fs");
const history = createMemoryHistory({
initialEntries: ['/', '/next', '/last'],
initialIndex: 0
})
export default (req, res, next) => {
const filePath = path.resolve(__dirname, '..', '..', 'build', 'index.html');
fs.readFile(filePath, 'utf8', (err, htmlData) => {
if (err) {
console.error('err', err);
return res.status(404).end()
}
const html = ReactDOMServer.renderToString(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>
);
return res.send(
htmlData.replace(
'<div id="root"></div>',
`<div id="root">${html}</div>`
)
);
});
}
我的 src 文件夹结构将是
- 组件
- 容器
- 应用
- index.js
- styles.js
- index.js
- store.js
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import { StaticRouter } from 'react-router'
import './index.css';
import store, { history } from './store';
import App from './containers/app';
const target = document.querySelector('#root');
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>,
target
);
难以理解
src/store.js
import { createStore, applyMiddleware, compose } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import thunk from 'redux-thunk';
import createHistory from 'history/createBrowserHistory';
import rootReducer from './reducers';
export const history = createHistory();
const initialState = {};
const enhancers = [];
const middleware = [thunk, routerMiddleware(history)];
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension;
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension());
}
}
const composedEnhancers = compose(applyMiddleware(...middleware), ...enhancers);
const store = createStore(rootReducer, initialState, composedEnhancers);
export default store;
在 运行 节点 server/bootstrap.js 上,它给我一个错误
Invariant Violation: Browser history needs a DOM
并且此错误在 store.js
中生成
如果有人可以通过共享代码让我知道我当前的 SSR create-react-app 哪里做错了什么!
我加载了应用程序两次。一次在客户端,一次在服务器。
我使用相同的设置(提供程序和连接的路由器)单独在服务器中呈现,重要的是将 createBrowserHistory 更改为 createMemoryHistory
并且它有效。
已经有关于此主题的问题,解决方案指向服务器上的 memoryHistory。但是,我这样做了,问题仍然存在于客户端文件夹内的 store.js 上。虽然我没有使用这个 client/store.js,但它仍然给我与主题相同的错误。
所以我猜测我在服务器端或客户端包装组件的方式有问题。
我正在处理已经加载的项目堆栈 - redux、react-redux、react-router-redux、redux-thunk、history 等...老实说,这些让我望而生畏,无法为SSR - 服务器端渲染(我的基本动机) 我将分享我在这个练习中涉及的结构和重要文件!
先欢迎服务器
server/bootstrap.js
require('ignore-styles');
require('babel-register')({
ignore: [ /(node_modules)/ ],
presets: ['es2015', 'react-app']
});
require('./index');
server/index.js
import express from 'express';
import serverRenderer from './middleware/renderer';
const PORT = 3000;
const path = require('path');
const app = express();
const router = express.Router();
// root (/) should always serve our server rendered page
router.use('^/$', serverRenderer);
// other static resources should just be served as they are
router.use(express.static(
path.resolve(__dirname, '..', 'build'),
{ maxAge: '30d' },
));
router.use('*', serverRenderer);
// tell the app to use the above rules
app.use(router);
// start the app
app.listen(PORT, (error) => {
if (error) {
return console.log('something bad happened', error);
}
console.log("listening on " + PORT + "...");
});
server/middleware/renderer.js
import React from 'react'
import ReactDOMServer from 'react-dom/server';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import store from '../../src/store';
import {createMemoryHistory } from 'history';
import { StaticRouter } from 'react-router'
// import our main App component
import App from '../../src/index';
const path = require("path");
const fs = require("fs");
const history = createMemoryHistory({
initialEntries: ['/', '/next', '/last'],
initialIndex: 0
})
export default (req, res, next) => {
const filePath = path.resolve(__dirname, '..', '..', 'build', 'index.html');
fs.readFile(filePath, 'utf8', (err, htmlData) => {
if (err) {
console.error('err', err);
return res.status(404).end()
}
const html = ReactDOMServer.renderToString(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>
);
return res.send(
htmlData.replace(
'<div id="root"></div>',
`<div id="root">${html}</div>`
)
);
});
}
我的 src 文件夹结构将是
- 组件
- 容器
- 应用
- index.js
- styles.js
- 应用
- index.js
- store.js
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import { StaticRouter } from 'react-router'
import './index.css';
import store, { history } from './store';
import App from './containers/app';
const target = document.querySelector('#root');
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>,
target
);
难以理解
src/store.js
import { createStore, applyMiddleware, compose } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import thunk from 'redux-thunk';
import createHistory from 'history/createBrowserHistory';
import rootReducer from './reducers';
export const history = createHistory();
const initialState = {};
const enhancers = [];
const middleware = [thunk, routerMiddleware(history)];
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension;
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension());
}
}
const composedEnhancers = compose(applyMiddleware(...middleware), ...enhancers);
const store = createStore(rootReducer, initialState, composedEnhancers);
export default store;
在 运行 节点 server/bootstrap.js 上,它给我一个错误
Invariant Violation: Browser history needs a DOM
并且此错误在 store.js
如果有人可以通过共享代码让我知道我当前的 SSR create-react-app 哪里做错了什么!
我加载了应用程序两次。一次在客户端,一次在服务器。
我使用相同的设置(提供程序和连接的路由器)单独在服务器中呈现,重要的是将 createBrowserHistory 更改为 createMemoryHistory
并且它有效。