简体   繁体   中英

NodeJS Server Side working Locally but not on Heroku

I was wondering if anyone else has had the problem where they have created a Server side rendering NodeJS app which works perfectly locally but then doesn't load server side once deployed to heroku.

I have created an app using Jared Palmer's awesome RazzleJS in combination with Redux, React Router and React Router Config.

The way it works is that in my server.js file I check the component that is loading for a static function called fetchData , if the function exists then the function is run which is a promise based request to an API using axios in a thunk.

In my server.js file another function then runs that checks all promises have completed before finally rendering the HTML for the page.

Locally this works perfectly and even with Javascript disabled the page is loading complete with the data fetched.

Having deployed this to heroku (single dyno - hobby plan) however if I disable javascript the page is loading with the data missing, suggesting that page is being rendered before the promises resolve. The data is then being loaded correctly using the equivalent ComponentDidMount dispatch for the data.

I currently have the following code:

Server.js

function handleRender(req, res) {
  const sheet = new ServerStyleSheet();

  const store = createStore(rootReducer, compose(applyMiddleware(thunk)));

  const branch = matchRoutes(Routes, req.url);
  const promises = branch.map(({ route }) => {
    let fetchData = route.component.fetchData;

    return fetchData instanceof Function
      ? fetchData(store, req.url)
      : Promise.resolve(null);
  });

  return Promise.all(promises).then(() => {      
    const context = {};
    const html = renderToString(
      sheet.collectStyles(
        <Provider store={store}>
          <StaticRouter context={context} location={req.url}>
            {renderRoutes(Routes)}
          </StaticRouter>
        </Provider>
      )
    );

    const helmet = Helmet.renderStatic();
    const styleTags = sheet.getStyleTags();
    const preloadedState = store.getState();

    if (context.url) {      
      res.redirect(context.url);
    } else {      
      res
        .status(200)
        .send(renderFullPage(html, preloadedState, styleTags, helmet));
    }
  });
}

Example React Component

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchProductData } from '../thunks/product-data';

class Test extends Component {
  static fetchData(store, url) {
    store.dispatch(fetchProductData());
  }

  componentDidMount() {
    if(this.props.productData.length === 0 ) {
      this.props.fetchProductData() // Successfully fetches the data
    }
  }

  render() {
    return (
      <div>
        { this.props.productData && this.props.productData.map( (product, i)  => {
          return <div key={i}>{product.title}</div>
        })}
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    productData: state.productData
  }
};

const mapDispatchToProps = dispatch => {
  return {
    fetchProductData(){
      dispatch(fetchProductData());
    }
  }
};

export const TestContainer = connect(mapStateToProps, mapDispatchToProps)(Test);

This is just an example of the component layout as the ones I actually have are quite complex but in this instance productData would be set to [] in defaultState.

Also all reducers and actions are working correctly locally it is only when deployed to Heroku on a hobby plan that the server side rendering seems to no longer work?

So after a morning of research the reason that it wasn't working in my live environment was because I have a HOC wrapping component for the purposes of tracking analytics.

React-router-config however can't handle the fact that the fetchData function is another level deeper in the hierarchy and so all my promises were resolved with null.

Now that I have removed the HOC component again, server side rendering is once again working properly :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM