Skip to content

Commit

Permalink
Merge branch '3.4.2-SNAPSHOT' of github.com:vert-x3/vertx-examples in…
Browse files Browse the repository at this point in the history
…to 3.4.2-SNAPSHOT
  • Loading branch information
cescoffier committed Jun 13, 2017
2 parents 510f5a3 + 5a803f9 commit 77c68c7
Show file tree
Hide file tree
Showing 10 changed files with 441 additions and 0 deletions.
13 changes: 13 additions & 0 deletions reactjs-server-side-rendering/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
### Vert.x + React.js SSR

This projects aims at showing [Vert.x](http://vertx.io) and [react.js]https://facebook.github.io/react/) server side rendering capabilities.

To run the project, simply run `npm install && npm start` from the project's root directory, then point your browser at [http://localhost:8080](http://localhost:8080) to get started.

The example shows how to reuse `react.js` code in your server and use it to prerender the start HTML page.

It also shows how to use `webpack` and `babel` in order to overcome the limitations of Nashorn with respect to javascript language level.

The client code (Browser) lives under `src/client` and the server code under `src/server`. All code under `src/shared` is shared by both client and server (typically your react application logic).

For a more productive development workflow, the `package.json` file also has a `watch` script using `vert.x`, if run, it will start your application and on file save it will reload the application for you.
44 changes: 44 additions & 0 deletions reactjs-server-side-rendering/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "vertx-reactjs-server-side-rendering",
"version": "1.0.0",
"description": "Example showing how to mix react.js and vert.x and server side rendering",

"mainVerticle": "server.js",

"scripts": {
"clean": "rm -Rf .vertx",

"install": "node ./webpack.config.js",
"postinstall": "mvn -f .vertx/pom.xml package",

"build": "./node_modules/.bin/webpack",
"build:release": "npm run clean && ./node_modules/.bin/webpack -p && npm run clean",

"prestart": "npm run build:release",
"start": "java -jar run.jar",

"watch": "npm run start -- --redeploy=\"src/**\" --on-redeploy=\"npm run watch\""
},

"author": "Paulo Lopes",
"license": "MIT",

"dependencies": {
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-router": "^3.0.2"
},

"devDependencies": {
"babel-core": "^6.22.1",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"webpack": "^2.2.0"
},

"javaDependencies": {
"io.vertx:vertx-lang-js": "3.4.1",
"io.vertx:vertx-web": "3.4.1"
}
}
9 changes: 9 additions & 0 deletions reactjs-server-side-rendering/src/client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import { render } from 'react-dom';
import { Router, browserHistory } from 'react-router';
import routes from '../shared/components/routes';

render (
<Router routes={routes} history={browserHistory} />,
document.getElementById('app')
);
77 changes: 77 additions & 0 deletions reactjs-server-side-rendering/src/server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const Router = require("vertx-web-js/router")
const StaticHandler = require("vertx-web-js/static_handler")
const posts = require('../shared/posts')

import React from 'react';
import {renderToString} from 'react-dom/server'
import {match, RouterContext} from 'react-router'
import routes from '../shared/components/routes'

const app = Router.router(vertx);

app.get('/api/post').handler((ctx) => {
ctx.response()
.putHeader("content-type", "application/json")
.end(JSON.stringify(posts));
});

app.get('/api/post/:id/*').handler((ctx) => {
const id = ctx.request().getParam('id')

const post = posts.filter(p => p.id == id)

if (post) {
ctx.response()
.putHeader("content-type", "application/json")
.end(JSON.stringify(post[0]))
} else {
ctx.fail(404);
}
});

app.get().handler((ctx) => {
match({routes: routes, location: ctx.request().uri()}, (err, redirect, props) => {

if (err) {
ctx.fail(err.message);
} else if (redirect) {
ctx.response()
.putHeader("Location", redirect.pathname + redirect.search)
.setStatusCode(302)
.end();
} else if (props) {
const routerContextWithData = (
<RouterContext
{...props}
createElement={(Component, props) => {
return <Component posts={posts} {...props} />
}}
/>
);
const appHtml = renderToString(routerContextWithData)

ctx.response()
.putHeader("content-type", "text/html")
.end(`<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://unpkg.com/wingcss" />
<meta charset="UTF-8">
<title>Universal Blog</title>
</head>
<body>
<div id="app">${appHtml}</div>
<script src="/bundle.js"></script>
</body>
</html>`)
} else {
ctx.next()
}
});
});

app.get().handler(StaticHandler.create().handle)

vertx.createHttpServer().requestHandler(app.accept).listen(8080)

console.log('Server listening: http://127.0.0.1:8080/')
70 changes: 70 additions & 0 deletions reactjs-server-side-rendering/src/shared/components/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react'
import Post from './Post'
import {Link, IndexLink} from 'react-router'

const allPostsUrl = '/api/post';

class App extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: props.posts || []
}
}

componentDidMount() {
const request = new XMLHttpRequest();
request.open('GET', allPostsUrl, true);
request.setRequestHeader('Content-type', 'application/json');

request.onload = () => {
if (request.status === 200) {
this.setState({
posts: JSON.parse(request.response)
});
}
};

request.send()
}

render() {
const posts = this.state.posts.map((post) => {
const linkTo = `/${post.id}/${post.slug}`;

return (
<li key={post.id}>
<Link to={linkTo}>{post.title}</Link>
</li>
)
});

const {postId, postName} = this.props.params;
let postTitle, postContent;
if (postId && postName) {
const post = this.state.posts.filter(p => p.id == postId)[0];
if (post) {
postTitle = post.title;
postContent = post.content;
}
}

return (
<div>
<IndexLink to="/">Home</IndexLink>
<h3>Posts</h3>
<ul>
{posts}
</ul>

{postTitle && postContent ? (
<Post title={postTitle} content={postContent}/>
) : (
this.props.children
)}
</div>
)
}
}

export default App
7 changes: 7 additions & 0 deletions reactjs-server-side-rendering/src/shared/components/Home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

const Home = () => ( <div> <h1>Welcome to the Universal Blog!</h1> <p>Check out the latest posts!</p> </div>);


export default Home;

5 changes: 5 additions & 0 deletions reactjs-server-side-rendering/src/shared/components/Post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';

const Post = ({title, content}) => ( <div> <h3>{title}</h3> <p>{content}</p> </div>);

export default Post;
11 changes: 11 additions & 0 deletions reactjs-server-side-rendering/src/shared/components/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './App';
import Home from './Home';

module.exports = (
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/:postId/:postName" />
</Route>
);
32 changes: 32 additions & 0 deletions reactjs-server-side-rendering/src/shared/posts.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 77c68c7

Please sign in to comment.