Jigar Jain Jigar Jain - 2 months ago 13
Javascript Question

Syntax Error: Unexpected token < while using renderToString(<RoutingContext {...renderProps} />

I am trying to use React & React-router for server side rendering. So far, it's just a copy paste code from various sources. But I am getting syntax error (Not run-time error) when I try to run the app using node. Below is the code

App.js

'use strict';
require('babel/register');

const express = require('express');
const http = require('http');
const handlebars = require('express-handlebars');
const renderToString = require('react-dom').server;
const match = require('react-router').match;
const RoutingContext = require('react-router').RoutingContext;
const Routes = require('./routes');
const app = express();
var server;

// JSX transpilation
require('node-jsx').install();

// Setting up handlebars
app.engine('.hbs', handlebars({
extname: '.hbs',
layoutsDir: 'views/server',
partialsDir: 'views/server/partials'
}));

app.set('view engine', '.hbs');

// Mount Routes
app.use('*', function (req, res) {
match({routes: routes, location: req.url}, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
console.log(renderProps);
var pageData = {
serverHtml: renderToString(<RoutingContext {...renderProps} />)
};
console.log(pageData);
res.render('base', pageData);
} else {
res.status(404).send('Not found')
}
});
});

server = http.createServer(app);

server.listen('3000', () => {
console.log('Express server listening on port ' + 3000);
});


The Error that I get while running
node --harmony app.js
is

serverHtml: renderToString(<RoutingContext {...renderProps} />)
^
SyntaxError: Unexpected token <
at exports.runInThisContext (vm.js:73:16)
at Module._compile (module.js:443:25)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3


Do I need to install/transform(babelify/jsx) my code for processing the JSX style tags? But I didn't found any such thing stated in any tutorials online.

Resources I followed


  1. React-router(Serverside Rendering)

  2. Server Side Rendering by React


Answer

Note - This method is deprecated. There are better alternative out there. As mentioned, require('node-jsx').install() is no longer maintained & using babel is the ideal way to go forward.

So I fixed the issue by making few changes to the above code

I removed the following line as it is not required

require('babel/register');

Then instead of transpiling app.js via babel, I just changed the JSX tag with React.createElement() as below:

//serverHtml: renderToString(<RoutingContext {...renderProps} />)
serverHtml: ReactDOM.renderToString(React.createElement(RoutingContext, renderProps))

The full updated code is as below:

'use strict';

const compression    = require('compression');
const express        = require('express');
const http           = require('http');
const handlebars     = require('express-handlebars');
const path           = require('path');
const React          = require('react');
const ReactDOM       = require('react-dom/server'); // Fixed this
const match          = require('react-router').match;
const RoutingContext = require('react-router').RoutingContext;
const app            = express();
var server;

require('node-jsx').install(); // Not required if you convert the below './routes' file from JSX into js
const Routes = require('./routes');

// Used for Gzipping all the resources
app.use(compression());

// Setting up handlebars
app.engine('.hbs', handlebars({
    extname: '.hbs',
    layoutsDir: 'views/server',
    partialsDir: 'views/server/partials'
}));

app.set('view engine', '.hbs');

// Set path to public assets
app.use(express.static(path.join(__dirname, 'public')));

// Mount Routes
app.use('*', function (req, res) {
    match({routes:Routes, location:req.url}, (error, redirectLocation, renderProps) => {
        if (error) {
          res.status(500).send(error.message)
        } else if (redirectLocation) {
          res.redirect(302, redirectLocation.pathname + redirectLocation.search)
        } else if (renderProps) {
            var pageData = {
                serverHtml: ReactDOM.renderToString(React.createElement(RoutingContext, renderProps))
            };

            res.render('base', pageData);
        } else {
          res.status(404).send('Not found')
        }
    });
});

server = http.createServer(app);

server.listen('3000', () => {
    console.log('Express server listening on port ' + 3000);
});

Thanks :)