添加服务端渲染到 create-react-app
Add Server Side Rendering to create-react-app
我正在研究create-react-app和SSR。
我在这个 repo 中添加了 redux 和 react-router => https://github.com/sarovin/StarteKit。
现在我想添加 SSR(服务器端渲染)而不对 create-react-app 进行任何修改。
我有一个 PR,我尝试实现它 => https://github.com/sarovin/StarteKit/pull/1
但是我有一些错误,因为函数 onClick()
在我的示例中不起作用:
// App.js
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { switcher } from './actions/switcher';
import logo from './logo.svg';
import './App.css';
const propTypes = {
switch: PropTypes.bool,
dispatch: PropTypes.func,
};
class App extends Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
console.log('onClick');
this.props.dispatch(switcher());
}
render() {
console.log('Switch', this.props.switch);
return (
<div className="App">
<div className="App-header">
{this.props.switch ? <img src={logo} className="App-logo" alt="logo" /> : null }
<h2>Welcome to React</h2>
</div>
<label className="switch" >
<input checked={this.props.switch} type="checkbox" onChange={this.onClick} />
<div className="slider round"></div>
</label>
</div>
);
}
}
function mapStateToProps(state) {
return {
switch: state.switcher.get('switch'),
};
}
App.propTypes = propTypes;
export default connect(mapStateToProps)(App);
//server.js
import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import hbs from 'express-hbs';
import cors from 'cors';
import React from 'react';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { renderToStaticMarkup } from 'react-dom/server';
import { RouterContext, match } from 'react-router';
import routes from './routes';
import * as reducers from './reducers';
console.log('info', 'Init App');
const app = express();
app.set("port", process.env.PORT || 8080);
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// Make index false, so that it is not resolved by default.
app.use(express.static(path.resolve('build'), {index: false}));
app.set("views", path.resolve('build'));
app.set("view engine", "html");
app.engine("html", hbs.express4());
app.use((req, res, next) => {
match({routes: routes, location: req.url}, (err, redirectLocation, renderProps) => {
if (err) {
return res.status(500).send(err.message);
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if(renderProps){
res.status(200);
console.log(renderProps);
const reducer = combineReducers(reducers);
const initialState = {};
let store = createStore(reducer, initialState);
let html = renderToStaticMarkup(
<Provider store={store}>
<RouterContext {...renderProps}/>
</Provider>
);
console.log('store', store.getState());
res.render('index.html', { content: html });
}
else res.status(404).send('Page not found');
});
});
app.listen(app.get("port"), () => {
console.log("Express server starting on port: " + app.get("port"));
});
有什么建议吗?
请尝试
https://github.com/antonybudianto/cra-universal
无需弹出,默认为零配置(v3.0.x)
如果您需要服务器端渲染,我建议 Next.js 而不是 create-react-app:
https://github.com/zeit/next.js/
我强烈推荐 razzle 用于您的项目。它将您的通用 JavaScript 应用程序所需的所有工具抽象为一个依赖项,这对于 SSR 来说是一个很大的收获。
我一直在想同样的事情。我结束了一个项目 https://github.com/haukurk/cra-ssr-ts-recipe。它是一个同构网络应用程序,允许您为 React 进行服务器渲染(支持 React Router 和 Redux)。如果您想执行任何 pre-fetching 数据,只需将 fetchData 函数添加到路由组件即可。
SSR 不是微不足道的东西,也不是内置于 React/CRA 中的东西,它总是会为您的网络应用程序包含一些额外的工作。
我也一直在研究 NextJS,因为人们似乎对它赞不绝口。我鼓励你看看那个。
我正在研究create-react-app和SSR。
我在这个 repo 中添加了 redux 和 react-router => https://github.com/sarovin/StarteKit。
现在我想添加 SSR(服务器端渲染)而不对 create-react-app 进行任何修改。
我有一个 PR,我尝试实现它 => https://github.com/sarovin/StarteKit/pull/1
但是我有一些错误,因为函数 onClick()
在我的示例中不起作用:
// App.js
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { switcher } from './actions/switcher';
import logo from './logo.svg';
import './App.css';
const propTypes = {
switch: PropTypes.bool,
dispatch: PropTypes.func,
};
class App extends Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
console.log('onClick');
this.props.dispatch(switcher());
}
render() {
console.log('Switch', this.props.switch);
return (
<div className="App">
<div className="App-header">
{this.props.switch ? <img src={logo} className="App-logo" alt="logo" /> : null }
<h2>Welcome to React</h2>
</div>
<label className="switch" >
<input checked={this.props.switch} type="checkbox" onChange={this.onClick} />
<div className="slider round"></div>
</label>
</div>
);
}
}
function mapStateToProps(state) {
return {
switch: state.switcher.get('switch'),
};
}
App.propTypes = propTypes;
export default connect(mapStateToProps)(App);
//server.js
import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import hbs from 'express-hbs';
import cors from 'cors';
import React from 'react';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { renderToStaticMarkup } from 'react-dom/server';
import { RouterContext, match } from 'react-router';
import routes from './routes';
import * as reducers from './reducers';
console.log('info', 'Init App');
const app = express();
app.set("port", process.env.PORT || 8080);
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// Make index false, so that it is not resolved by default.
app.use(express.static(path.resolve('build'), {index: false}));
app.set("views", path.resolve('build'));
app.set("view engine", "html");
app.engine("html", hbs.express4());
app.use((req, res, next) => {
match({routes: routes, location: req.url}, (err, redirectLocation, renderProps) => {
if (err) {
return res.status(500).send(err.message);
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if(renderProps){
res.status(200);
console.log(renderProps);
const reducer = combineReducers(reducers);
const initialState = {};
let store = createStore(reducer, initialState);
let html = renderToStaticMarkup(
<Provider store={store}>
<RouterContext {...renderProps}/>
</Provider>
);
console.log('store', store.getState());
res.render('index.html', { content: html });
}
else res.status(404).send('Page not found');
});
});
app.listen(app.get("port"), () => {
console.log("Express server starting on port: " + app.get("port"));
});
有什么建议吗?
请尝试
https://github.com/antonybudianto/cra-universal
无需弹出,默认为零配置(v3.0.x)
如果您需要服务器端渲染,我建议 Next.js 而不是 create-react-app: https://github.com/zeit/next.js/
我强烈推荐 razzle 用于您的项目。它将您的通用 JavaScript 应用程序所需的所有工具抽象为一个依赖项,这对于 SSR 来说是一个很大的收获。
我一直在想同样的事情。我结束了一个项目 https://github.com/haukurk/cra-ssr-ts-recipe。它是一个同构网络应用程序,允许您为 React 进行服务器渲染(支持 React Router 和 Redux)。如果您想执行任何 pre-fetching 数据,只需将 fetchData 函数添加到路由组件即可。
SSR 不是微不足道的东西,也不是内置于 React/CRA 中的东西,它总是会为您的网络应用程序包含一些额外的工作。
我也一直在研究 NextJS,因为人们似乎对它赞不绝口。我鼓励你看看那个。