Add Server Side Rendering to create-react-app

2020-03-30 06:08发布

问题:

i am studying create-react-app and SSR.

I have add redux and react-router in this repo => https://github.com/sarovin/StarteKit.

Now i want add SSR ( server side rendering ) without any modification to create-react-app.

I have a PR where i try to implement it => https://github.com/sarovin/StarteKit/pull/1

But i have some error because the function onClick() not work in my example:

// 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"));
});

Have any suggestion?

回答1:

If you need server side rendering, I would suggest Next.js instead of create-react-app: https://github.com/zeit/next.js/



回答2:

I'll strongly recommend razzle for your project. it abstracts all the required tooling for your universal JavaScript application into a single dependency which is a great gain doing SSR.



回答3:

I've been thinking about the same thing. I ended up with a project https://github.com/haukurk/cra-ssr-ts-recipe. It's an isomorphic web app that allows you to do server rendering for React (with support for React Router and Redux). You simply add fetchData function to your route component if you want to do any pre-fetching of data.

SSR is not something that is trivial nor built into React/CRA and will always include some extra work for your web app.

I've also been looking into NextJS, as people seem to be praising it a lot. I encourage you to look at that.



回答4:

Please try

https://github.com/antonybudianto/cra-universal

No need to eject and it's zero config by default (v3.0.x)