I'm trying to render an extremely simple component on the server before passing to the client, transforming using gulp and babelify like so:
gulp.task("react-assessment", function(){
return browserify("./app/assessment/react/components/app.react.js")
.transform(babelify)
.bundle()
.pipe(source("reactBundle.js"))
.pipe(gulp.dest("./browser"))
});
The component works fine on the client:
var React = require("react");
var ReactDOM = require("react-dom");
var Title = React.createClass({
render: function(){
return <h1>Hello World</h1>
}
});
module.exports = ReactDOM.render(
<Title/>,
document.getElementById("react-assessment")
);
However when I require the file in Node.js with Express, the server crashes with unexpected token
return <h1>Hello World</h1>
^
SyntaxError: Unexpected token <
When I've used the old methodology of using /** #jsx React.DOM */ at the top of the component file, there were no problems.
Route:
var express = require('express'),
router = express.Router(),
ReactDOMServer = require("react-dom/server");
JSX = require('node-jsx').install({
extension: '.jsx'
}),
AssessmentComponent = require("../react/components/app.react.jsx");
Where am I going wrong?
Solved by using babel/register. No need for React.DOM
Related
I am very new to reactJs and just started to learn the features of reactJS. I am trying to figure out a way to pass the value from nodeJS to reactJS via server side rendering concept.
In the below example, I was able to define a react component and add it in server and render it in UI but I am not sure how to pass the data to the component that can be used inside the component render function.
client.js
var React=require('react');
var ReactDOM=require('react-dom');
var Component=require('./Component.jsx');
ReactDOM.render(
React.createElement(Component),document
);
Component.jsx
var React=require('react'),
Request=require('superagent')
module.exports = React.createClass({
getInitialState: function () {
return {
};
},
componentWillMount: function () {
},
componentDidMount: function() {
clearInterval(this.intervalID)
},
_handleClick: function () {
alert('You clicked!')
},
render:function(){
return(
<html>
<head>
<title> ReactJS - demo </title>
<link rel='stylesheet' href='/style.css'/>
</head>
<body>
<div>
<h1>react js testing</h1>
<p>This is so cool</p>
<button onClick={this._handleClick}>Click Me!</button>
</div>
<script src='/bundle.js'/>
</body>
</html>
);
}
});
Server.js
require('babel-register')({
presets:['react']
});
var express = require('express');
var app=express();
var React=require('react');
var ReactDOMServer=require('react-dom/server');
var Component=require('./Component.jsx');
app.use(express.static('public'));
app.get('/',function(request,response){
var html=ReactDOMServer.renderToString(
React.createElement(Component)
)
response.send(html)
});
var PORT=4444;
app.listen(PORT,function(){
console.log("Node js listening in port:"+ PORT);
})
Update 1:
I am now able to pass the value to the server side rendered component as below
React.createElement(Component,{object:...})
Now the server side setup works fine.
I need to make this {object:...} available in my client.js also for client side functionality to work. Any idea how to get this value in client.js?
React.createElement
ReactElement createElement(
string/ReactClass type,
[object props],
[children ...]
)
Create and return a new ReactElement of the given type. The type argument can be either an html tag name string (eg. 'div', 'span', etc), or a ReactClass (created via React.createClass).
In the your version in the
React.createElement(Component)
u need use something like
React.createElement(Component, {obj: obj, ...: ...})
I'm trying to serve a front end with Koa (v2). Eventually, I want to use React. But for now, I'm simply trying to serve a simple html file.
app/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
server.js
import 'babel-polyfill';
import koa from 'koa';
import koaRouter from 'koa-router';
import serve from 'koa-static';
import mount from 'koa-mount';
const app = new koa();
const router = new router({ prefix: '/koa' });
// This route works
router.get('/', async (ctx) => {
ctx.body = 'Hello from Koa!';
});
app.use(router.routes());
const front = new koa();
// This route doesn't work.
front.use(serve(__dirname + '/app'));
// However, this will work, so then, I'm not using koa-serve correctly?
// front.use(async (ctx) => {
// ctx.body = "Mount this.";
// });
app.use(mount('/', front));
app.listen(3000);
So how do I serve the front-end?
I've used a similar code and it worked for me, strange, almost like your example, just that I'm not using async
const koa = require('koa');
const koaRouter = require('koa-router');
const mount = require('koa-mount');
const serve = require('koa-static');
const app = new koa();
const router = new koaRouter({ prefix: '/koa' });
router.get('/', function *() {
this.body = 'Hello from Koa!';
});
app.use(router.routes());
const front = new koa();
front.use(serve(__dirname + '/app'));
app.use(mount('/', front));
app.listen(3000);
Try using koa-sendfile, just to test it out. I've got other example below
Note that I'm using koa-route, not koa-router like in your example
And also, there's a folder called "app" that contains the "index.html"
'use strict';
const koa = require('koa');
const router = require('koa-route');
const mount = require('koa-mount');
const sendfile = require('koa-sendfile');
const serve = require('koa-static');
const app = koa();
const ui = koa();
const api = koa();
// API Mount
function *apiCall() {
this.body='response from api';
}
api.use(router.get('/', apiCall));
// UI Mount
// you have 2 ways:
// // 1. Using koa-sendfile
// function *serveIndex() {
// this.body='response from ui';
// yield sendfile(this, __dirname + '/app/index.html');
// if (!this.status) this.throw(404);
// }
// ui.use(serveIndex);
// 2. Using koa-static
ui.use(serve('app'));
app.use(mount('/api', api));
app.use(mount('/', ui));
app.listen(3000);
I have followed the tutorial found here:
https://blog.frankdejonge.nl/rendering-reactjs-templates-server-side/
In my server.js:
'use strict';
require("babel/register");
var React = require('react');
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use('/', function(req, res) {
try {
var view = path.resolve('public/src/' + req.query.module);
var component = require(view);
var props = req.body || null;
res.status(200).send(
React.renderToString(
React.createElement(component, props)
)
);
} catch (err) {
res.status(500).send(err.message);
}
});
app.listen(3000);
console.log('Listening carefully...')
But when I run it I get Cannot find module 'babel/register'
If I comment that out, it works, but I get the following in the browser:
Unexpected token import
I'm guessing this is due to the error.
How can I fix this?
I changed it to this:
require('babel-register')({
presets: ['es2015', 'react']
});
...
Which got it a bit further, but now in my browser I am getting:
React.renderToString is not a function
My component:
import React from 'react';
class HelloComponent extends React.Component {
render () {
return (
<h1>Hello, {this.props.name}!</h1>
);
}
}
HelloComponent.defaultProps = { name: 'World' };
export default HelloComponent;
Looks like this code is using BabelJS version 5 - so when you will install babel#5 - it should work.
But maybe it would be better if you replace require("babel/register"); with require("babel-register"); and use babel#6. Also, you will need to add .babelrc file with configuration for babeljs (https://babeljs.io/docs/usage/babelrc/).
If you are looking to ready to use configuration for server-side rendering for react components - take a look at this project: https://github.com/zxbodya/reactive-widgets (I am an author).
It is a bit more than just server side rendering - it is a complete solution that will allow you to build isomorphic js components for your PHP application.
The proper syntax for babel register seems different now: use require("babel-register"); after having installed babel.
see require('babel/register') doesn't work : it is a similar issue
All:
I am pretty new to React, right now I am trying how to do server side rendering, I use Express.js as my server, so the code is like:
//server.js
var express = require("express");
var ReactDOMServer = require("react-dom/server");
var MyCom = require("./components");
var domstring = ReactDOMServer.renderToString(MyCom);
var app = express();
app.get("/", function(req, res){
res.json({
name: "new com",
dom: domstring
});
});
And
// components.js
var React = require("react");
var MyCom = React.createClass({
render: function(){
return (<h1>Hello, server side react</h1>);
}
});
module.exports = MyCom;
I use babel to transpile the JSX, but when I start server, I do not know why I keep getting error like:
Invariant Violation: renderToString(): You must pass a valid
ReactElement.
Could anyone give some clue why this not work?
Thanks
Your module exports a ReactComponent, and renderToString accepts a ReactElement (i.e. an instantiated ReactComponent).
In order to render it, you want to instantiate it like so:
ReactDOMServer.renderToString(<MyCom />);
Using a factory allows you to have all your components in separate files and instantiate them without using jsx syntax in your server. Very useful for the main wrapper component.
require('babel-core/register')({
presets: ['react']
});
var express = require('express');
var reactDOM = require('react-dom/server');
var react = require('react');
var app = express();
app.get('/', function (req, res) {
var mainFile = require('./app.jsx');
var output = reactDOM.renderToString(react.createFactory(mainFile)({
data: yourInitialData
}));
res.send(output);
});
I have included two questions here, the two questions will be at the end of this post.
=================>>> Background <<<=================
I'm trying to test out react isomorphic way, and I setup a server.js and I install the following node modules
my node version node: '0.12.0'
"babel": "^4.7.16",
"babel-core": "^4.7.16",
"babel-loader": "^4.2.0",
"babel-runtime": "^4.7.16",
"node-jsx": "^0.12.4",
The following is my server.js ( partial )
require("babel/register")({experimental: true});
require('node-jsx').install({extension:'.jsx'});
var express = require('express');
var server = express();
var port = process.env.PORT || 3000;
var React = require('react');
var EntryPointComponent = React.createFactory(require('./router.jsx'));
server.use(function(req, res, next) {
var component = EntryPointComponent();
var html = React.renderToString(component);
res.send(html);
});
server.listen(port);
And below is example routes.jsx ( partial, it will be include in router.jsx )
var React = require('react'),
Router = require('react-router'),
{Route, NotFoundRoute} = Router,
App = require('./app'),
DefaultHandler = require('./pages/test');
module.exports = (
<Route handler={App}>
<Route name="test" handler={DefaultHandler} path="/test" addHandlerKey={true} />
<NotFoundRoute handler={DefaultHandler} />
</Route>
)
The following is router.jsx
var React = require('react'),
Router = require('react-router'),
routes = require('./routes');
Router.run(routes, function(Handler) {
React.render(<Handler/>, document.getElementById("content"));
});
=================>>> Problem <<<=================
when I try to run the following command
node server.js --harmony
It will throw me Unexpected token issue
/blah/blah/blah/routes.jsx:3
{Route, NotFoundRoute} = Router,
^
SyntaxError: Unexpected token {
=================>>> Questions <<<=================
Looks like the Node didn't recognize the ES6 syntax, and I try to include "babel", am I use it correctly?? Or how to make Node understand ES6 syntax ??
Is the above a correct way to setup isomorphic react app ?? Or what would be the correct / recommended way to setup the react app in isomorphic way ??
Any advice is appreciated, thanks.
You are 'overriding' babel loader by using 'node-jsx'. Docs.
//"there can be only one!" :)
require("babel/register")({experimental: true});
//to be removed
//require('node-jsx').install({extension:'.jsx'});
Both Node.js and io.js doesn't support ES6 destructuring assignment yet.