0

So I've inherited a complete mess of a project that follows some unorthodox methods of server side rendering as outlined here: Client Routing (using react-router) and Server-Side Routing

Now I've been trying to upgrade it for the past week and probably wasted over 40 hours getting nowhere while I try to bring this mess to the proper and current state. It uses react 0.13.3 and I'd like to upgrade to at least 0.14.7 and react-router 2 but no matter how I try to approach this, the structure is so brittle that I continue to fail again and again. This is what I've got:

Client:

import React from "react";
import Router from "react-router";
import routes from "../shared/routes";

Router.run(routes, Router.HistoryLocation, (Handler, state) => {
  React.render(<Handler email =          {window.INITIAL_PROPS.email}
      urlData =        {window.INITIAL_PROPS.urlData}
      tagData =        {window.INITIAL_PROPS.tagData}
      talentData =     {window.INITIAL_PROPS.talentData}
      talentShowcase = {window.INITIAL_PROPS.talentShowcase}
      metrics =        {window.INITIAL_PROPS.metrics}
      loginData =      {window.INITIAL_PROPS.loginData}
      errorData =      {window.INITIAL_PROPS.errorData} />, document.getElementById('app'));
});

Server:

import express from "express";
var session = require("express-session");
var zip = require('express-zip');
var bodyParser = require("body-parser");
var multer = require("multer");

import React from "react";
import Router from "react-router";
import routes from "../shared/routes";

const app = express();

app.set('views', './views');
app.set('view engine', 'jade');

var constants = require('../constants');

// Server Modules
var Index = require('./serverModules/Index');
var Search = require('./serverModules/Search');
var Admin = require('./serverModules/Admin');
var User = require('./serverModules/User');

app.use(express.static(__dirname + '/../../public/'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(multer({dest: __dirname + '/../../public/' + 'assets/images/'}).single('Profile'));

app.use(session({
  secret: 'test session',
  resave: false,
  saveUninitialized: true
}));

Index(app, Router, routes, React);
Search(app, Router, routes, React);
Admin(app, Router, routes, React);
User(app, Router, routes, React);

// Redirect to Index Page on linking to a page which does not exist.
app.use(function (req, res, next) {

  res.redirect("/");
});

app.listen(process.env.PORT, function () {

  console.log('Server listening at port %s', process.env.PORT);
});

One of the serverModules(???) 'index':

var constants = require('../../constants');
var functions = require('../serverFunctions');

// Database & API Wrappers
var database = require('../database/databaseWrapper');
var smAPI = require('../socialMediaAPIs/socialMediaWrapper');

module.exports = function (app, Router, routes, React) {
  app.get('/', function (req, res) {
    var urlData = req.query;
    var session = req.session;
    var loginData = {};
    var email = undefined;
    // Check if the user is logged in.
    if (session.user === undefined) {
      res.redirect('/Login');
      return;
    } else {
      email = session.user.email;
      if (session.user.permissions !== undefined) {
        for (var i = 0; i < session.user.permissions.length; ++i) {
          loginData[session.user.permissions[i]] = true;
        }
      }
    }
    // Store the size of the talent list if it exists
    if (session.user.lists !== undefined) {
      urlData.lists = [];
      for (var i = 0; i < session.user.lists.length; ++i) {
        urlData.lists.push({name: session.user.lists[i].name, size: functions.getListSize(session.user.lists[i].talents)});
      }
    }
    Router.run(routes, req.url, Handler => {
      database.getIndexParams(function (tags, talents) {
        // Client-side variables.
        var props = {
          urlData: urlData,
          tagData: tags,
          loginData: loginData,
          email: email
        };
        let content = React.renderToString(
          <Handler
            urlData={urlData}
            tagData={tags}
            loginData={loginData}
            email={email}
          />
        );
        res.render('index', {
          scontent: content,
          props: JSON.stringify(props),
          title: "Project"
        });
      });
    });
  });
};

routes:

import { Route, DefaultRoute } from "react-router";
import React from "react";

import AppRouter from "./components/AppRouter";
import AppHandler from "./components/AppHandler";
import SearchHandler from "./components/SearchHandler";
import AdminHandler from "./components/AdminHandler";
import AddUserHandler from "./components/AddUserHandler";
import LoginHandler from "./components/LoginHandler";
import PasswordHandler from "./components/PasswordHandler";
import ForgotPasswordHandler from "./components/ForgotPasswordHandler";

export default (
    <Route name="root" handler={ AppRouter } path="/">
        <DefaultRoute handler={ AppHandler } />
        <Route name="Search" handler={ SearchHandler } path="Search" />
        <Route name="Admin" handler={ AdminHandler } path="Admin" />
        <Route name="AddUser" handler={ AddUserHandler } path="Admin/AddUser" />
        <Route name="Login" handler={ LoginHandler } path="Login" />
        <Route name="Password" handler={ PasswordHandler } path="ChangePassword" />
        <Route name="ForgotPassword" handler={ ForgotPasswordHandler } path="ForgotPassword" />
    </Route>
);

AppRouter:

import React from "react";
import { RouteHandler } from "react-router";

export default class AppHandler extends React.Component {
  render() {
    return (
      <RouteHandler
        email={this.props.email}
        urlData={this.props.urlData}
        tagData={this.props.tagData}
        talentData={this.props.talentData}
        talentShowcase={this.props.talentShowcase}
        metrics={this.props.metrics}
        loginData={this.props.loginData}
        errorData={this.props.errorData}
      />
    );
  }
}

AppHandler:

import React from "react";

var SearchHeader = require('./index/SearchHeader');
var User = require('./index/User');
var Footer = require('./Footer');

export default class AppHandler extends React.Component {
  render() {
    return (
      <div>
        <div id="backgroundWrapper">
          <div id="container">
            <SearchHeader
              urlData={this.props.urlData}
              tagData={this.props.tagData}
              loginData={this.props.loginData}
              email={this.props.email}
              tagLine={true}
              minHeight={640}
            />
            <User userData={this.props.talentShowcase}/>
          </div>
        </div>
        <Footer />
      </div>
    );
  }
}

and this is what the LoginHandler looks like:

import React from "react";

var Watermark = require('./Watermark');
var Login = require('./login/Login');
var Footer = require('./Footer');

export default class AppHandler extends React.Component {
  render() {
    return (
      <div id="content">
        <div id="backgroundWrapper" style={{ "height": "100%" }}>
          <div id="LoginWatermarkContainer">
            <Watermark black={true}/>
            <span id="LoginSubtitle">
              Login with your credentials below.
            </span>
            <div className="LoginWatermarkSeparator"></div>
          </div>
          <Login errorData={this.props.errorData}/>
        </div>
        <Footer positionStyle={{ "bottom": "0", "position": "fixed" }}/>
      </div>
    );
  }
}

How does one upgrade this, preferably to the most current version and if possible please show step by step solution because I feel quite stupid after failing to upgrade this for over a week. I have seen crazy and brittle setups before, but this by far takes the cake. I feel really frustrated, please help!

Community
  • 1
  • 1
Bartekus
  • 601
  • 1
  • 9
  • 15
  • Where are you having difficulty? Are you hitting specific issues. As it stands, this is too broad of a question. – lux Apr 13 '16 at 19:31
  • The question is quite simple, how do I upgrade this mess of an entanglement to react-router v2 & react/reactDOM 0.14.x however I'm afraid the answer is not since all my attempts at upgrading this, either part by part or all at once have failed. It seems so interwoven as basically be throw away and start from scratch kind of a deal... :( – Bartekus Apr 13 '16 at 23:56
  • Yes, the question itself is simple, but its loaded considering the sheer effort required to refactor this appropriately. Honestly, my first inclination was to say start with a fresh, clean Express server instance, and just try to render your `Index` route, and work down through any issues that arise. Open new questions if necessary, but basically try to localize the issue to a single route, then once you nail it, start adding others back in. That said, I agree, this _does_ look like a mess at first glance, so starting fresh, and correctly, might not be so bad in the end. – lux Apr 14 '16 at 00:04
  • That said, here's probably the most basic universal/iso react-router setup I've seen: https://github.com/DominicTobias/universal-react – lux Apr 14 '16 at 00:05
  • That's pretty good starter kit but I've been exposed and have experience with https://github.com/choonkending/react-webpack-node so I prefer that... So yeah, at the end of the day I guess what puzzles me the most is how react-router is tied to the express in this brittle setup: `Index(app, Router, routes, React);` Is it just me for being puzzled by doing it this way... – Bartekus Apr 14 '16 at 02:36
  • That's a nice repo, with mongo support to boot. And yeah the importing of the `Index` and the other "controllers" looks almost similar to someone who's maybe coded Java in the past; very servlet-esque. At any rate, I'm in agreement, I'm used to seeing folks utilizing `match()` as per the `react-router` docs for matching up the URL the route: https://github.com/reactjs/react-router/blob/master/docs/API.md#match-routes-location-history-options--cb – lux Apr 14 '16 at 02:43

0 Answers0