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.
Related
I am writing mt first cli app with node and I am facing some issues using babel to transpile my code.
Basically, the app should start an express server which does ssr for react (similar to what next does).
Somewhere in the process I use jsx syntax to render react component, so I need to transpile my code with babel.
I am familiar on how to do this with babel cli or with webpack,
howevere, I`m still facing issues implementing it for cli app.
In my package.json file I have:
"bin": {
"ssr": "./cli/ssr.js"
},
and my ssr.js file:
#!/usr/bin/env node
const server = require('../server');
const routes = require('../../routes.js');
const createStore = require('redux').createStore;
const port = process.env.PORT || 3000;
const args = process.argv;
const defReducer = function(state={}, action){
return state;
}
const configureStore = createStore(defReducer);
const instance = server(routes, configureStore, {}, {});
instance.listen(port, ()=>{
console.log(`ssr server runs on localhost://${port}`);
});
and my server.js file is just a regular express server:
const express = require('express');
const cors = require('cors');
const renderer = require('./renderer');
module.exports = (Routes, createStore=()=>null, renderOpts={}, routerContext={})=>{
const app = express();
app.use(express.static('public'));
app.use(cors());
const port = process.env.PORT || 3000;
app.get('*.js', (req, res, next) => {
req.url = req.url + '.gz';
res.set('Content-Encoding', 'gzip');
next();
});
app.all('*', (req, res) => {
const store = createStore();
const promises = matchRoutes(Routes, req.path).map(( { route } ) => {
if (typeof route.path === 'undefined') { return null; }
let ctx = {store, module:route.module, req, res}
return route.loadData ? route.loadData(ctx) : null;
});
Promise.all(promises).then(() => {
const content = renderer(Routes, req, store, renderOpts, routerContext);
if (context.url) {
return res.redirect(301, context.url);
}
if (context.notFound) {
res.status(404);
}
res.send(content);
});
});
return app;
}
inside server.js file I call renderer which does:
const content = renderToString(
<Provider store={store}>
<StaticRouter location={req.url} context={routerContext} basename= {opts.baseName || ''}>
<div>{renderRoutes(Routes)}</div>
</StaticRouter>
</Provider>
);
and this is where I get my syntax errors...
I also tried to precompile my server.js file using webpack and babel
and than link the bin command to the bundle.js output but it didn`t work
I get this error popping on the screen:
What is the correct way of using babel with cli app?
I followed a few steps here which you can find by going here https://babeljs.io/setup and clicking "CLI". I was able to transpile your server.js JSX following those steps, plus a couple extra in a fresh new folder. In order to transpile your code, here's what I did:
Created a package.json by running (used all default values)
npm init
Created src\server.js file with your small <Provider> excerpt above
Ran the following commands to install babel and the react libraries:
npm install --save-dev #babel/core #babel/cli
npm install --save-dev #babel/preset-env
npm install --save-dev #babel/preset-react
Created a .babelrc file with this single line:
{ "presets": ["#babel/preset-env", "#babel/preset-react"] }
Created build script in package.json
scripts: { "build": "babel src -d lib" }
Ran the build:
npm run-script build
And it successfully ran and transpiled the js into a new file within the lib folder. Try it out in a brand new folder and let me know how goes works for you
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'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
I am completely new to server side javascript so any help would really be appreciated.
I recently followed this tutorial https://www.youtube.com/watch?v=p-x6WdwaJco to build a simple RESTful API with node.js mongodb and express. The tutorial also uses a library called node-restful https://github.com/baugarten/node-restful.
First of all I built a server.js in the root directory:
// Dependencies
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
// Mongo DB
mongoose.connect('mongodb://localhost/rest_test');
// Express
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
// Routes
app.use('/api', require('./routes/api'));
var test = require('./routes/api');
// Start Server
app.listen(3000);
console.log('API is running on port 3000')
Then I created api.js in root/routes
// Dependencies
var express = require('express');
var router = express.Router();
// Models
var Product = require('../models/product');
// Routes
Product.methods(['get', 'put', 'post', 'delete']);
Product.register(router, '/products');
// Return router
module.exports = router;
Finally I created a file called product.js within root/models:
// Dependencies
var express = require('express');
var restful = require('node-restful');
var mongoose = restful.mongoose;
// Schema
var productSchema = new mongoose.Schema({
name: String,
sku: String,
price: Number,
});
// Return model
module.exports = restful.model('Products', productSchema);
This is where my issue is(i think) - the server runs fine until I attempt to use .methods() and .register() on mongoose.Schema() from api.js. It keeps telling me that .methods is undefined in Product.
I have been through the tutorial over and over and can see nothing wrong with my code. All libraries seemed to have installed correctly. Mongo is running...
I have a feeling that mongoose.Schema is not registering properly but have no idea why as everything seems to be as it is in the tutorial - there are no similar complaints on the tutorial - so I can only assume this is "my problem" but I just can't see where I've gone wrong....
Thanks in advance....
I copied your code exactly and then was able to run it without any issues. So this most likely means there's some issue in your local environment. Most likely an old/outdated package.
In your root directory, create a file called package.json with the following contents:
{
"name": "stackoverflow-30492214",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node server.js"
},
"dependencies": {
"body-parser": "^1.12.4",
"express": "^4.12.4",
"mongoose": "^3.9.7",
"node-restful": "^0.1.18"
},
"devDependencies": {}
}
And then, in the same directory, in your terminal run npm clean && npm install. This should download/install/build dependencies as defined by the package.json. Once done, try running the server again node server.js. You might get a warning about the mongoose package being an unstable version, but you shouldn't see any .method() or .register() undefined errors.