Server side Express.js - request '/ json / version /

I have an express server that pre-renders my app-app. I have a routes file that matches the HomeContainer on the base route /, and all other routes correspond to a page not found.

import HomeContainer from 'containers/home-container/home-container';
import PageNotFound from 'components/page-not-found/page-not-found';

const routes = [
  {
    path: '/',
    exact: true,
    component: HomeContainer
  },
  {
    path: '*',
    component: PageNotFound
  }
];

export default routes;

The problem I am facing is that when I run the application on the server, the page that the route did not find receives a visualization before quickly switching to the HomeContainer route.

I found that this is because my express server makes a request /json/versionbefore it sends a request to /, this route does not match one in the routes file, and therefore the page is not found the component is rendered.

, page not found, . node, , , emit _http_server.js

URL-, .

Debugger screenshot

- .

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { StaticRouter, matchPath } from 'react-router-dom';
import serialize from 'serialize-javascript';
import expressStaticGzip from 'express-static-gzip';
import sourceMapSupport from 'source-map-support';

import routes from 'routes';
import configureStore from 'store';
import AppContainer from 'containers/app-container/app-container';

if (process.env.NODE_ENV === 'development') {
  sourceMapSupport.install();
}

const app = express();

app.use(expressStaticGzip('./static/assets'));

app.get('*', (req, res, next) => {
  const store = configureStore();

  /**
   * Load initial data into state
   * match requested URL path to the component in routes
   * check for 'fireInitialActions' method (found in the container components)
   * and dispatch if it exists
   */
  const routeComponentPromises = routes.reduce((accumulator, route) => {
    if (matchPath(req.url, route) && route.component && route.component.fireInitialActions) {
      accumulator.push(Promise.resolve(store.dispatch(route.component.fireInitialActions())));
    }

    return accumulator;
  }, []);

  Promise.all(routeComponentPromises)
    .then(() => {
      const context = {};
      const markup = renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={context}>
            <AppContainer />
          </StaticRouter>
        </Provider>
      );

      const initialData = store.getState();
      res.send(`
        <!DOCTYPE html>
        <html>
          <head>
            <title>Test</title>
            <script src='vendor.js' defer></script>
            <script src='app.js' defer></script>
            <script>window.__initialData__ = ${serialize(initialData)}</script>
          </head>
          <body>
            <div id="root">${markup}</div>
          </body>
        </html>
      `);
    })
    .catch(next);
});

app.listen(process.env.PORT || 3000, () => {
  console.log('Server is listening');
});

- , ?

: , - https://d26dzxoao6i3hh.cloudfront.net/items/2z3y3f1x3N1D2e422W42/Screen%20Recording%202017-10-23%20at%2012.24%20pm.mov

+6
1

100% , , .

, ,

  • EJS
  • indexFromEmptyFile false gzip

2 , , index.html, index.ejs, , , index.html .

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import { StaticRouter, matchPath } from 'react-router-dom';
import serialize from 'serialize-javascript';
import sourceMapSupport from 'source-map-support';
import expressStaticGzip from 'express-static-gzip';

import routes from 'routes';
import configureStore from 'store';
import AppContainer from 'containers/app-container/app-container';

if (process.env.NODE_ENV === 'development') {
  sourceMapSupport.install();
}

const app = express();

app.set('views', './static/');
app.set('view engine', 'ejs');
app.use(expressStaticGzip('static/assets', { indexFromEmptyFile: false }));

app.get('*', (req, res, next) => {
  const store = configureStore();

  /**
   * Load initial data into state
   * match requested URL path to the component in routes
   * check for 'fireInitialActions' method (found in the container components)
   * and dispatch if it exists
   * return as promises so we can chain
   */
  const routeComponentPromises = routes.reduce((accumulator, route) => {
    if (matchPath(req.url, route) && route.component && route.component.fireInitialActions) {
      accumulator.push(Promise.resolve(store.dispatch(route.component.fireInitialActions())));
    }

    return accumulator;
  }, []);

  Promise.all(routeComponentPromises)
    .then(() => {
      const context = {};
      const markup = renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={context}>
            <AppContainer />
          </StaticRouter>
        </Provider>
      );

      const initialData = serialize(store.getState());

      res.render('index.ejs', {initialData, markup});
    })
    .catch(next);
});

app.listen(process.env.PORT || 3000, () => {
  console.log('Server is listening');
});`
0

All Articles