Skip to content

Instantly share code, notes, and snippets.

@koistya
Last active September 15, 2023 07:32
Show Gist options
  • Star 90 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save koistya/24715d295fbf710d1e24 to your computer and use it in GitHub Desktop.
Save koistya/24715d295fbf710d1e24 to your computer and use it in GitHub Desktop.
Server-side Rendering (SSR) for ReactJS / Flux Applications. Setting document.title

Files

The basic structure of a React+Flux application (see other examples)

 - /src/actions/AppActions.js     - Action creators (Flux)
 - /src/components/Application.js - The top-level React component
 - /src/constants/ActionTypes.js  - Action types (Flux)
 - /src/core/Dispatcher.js        - Dispatcher (Flux)
 - /src/stores/AppStore.js        - The main store (Flux)
 - /src/app.js                    - Client-side startup script
 - /src/server.js                 - Server-side startup script

The Top-level React Component

// src/components/Application.js

var React = require('react');

var Application = React.createClass({

  propTypes: {
    path: React.PropTypes.string.isRequired,
    onSetTitle: React.PropTypes.func.isRequired
  },

  render() {
    var page = AppStore.getPage(this.props.path);
    this.props.onSetTitle(page.title);
    
    return (
      <div className="container">
        <h1>{page.title}</h1>
        <div>{page.content}</div>
      </div>
    );
  }
});

module.exports = Application;

Client-side Startup Script (aka Bootstrap)

// src/app.js

var React = require('react');
var Dispatcher = require('./core/Dispatcher');
var Application = require('./components/Application');

var app = React.createElement(Application, {
  path: window.location.pathname,
  onSetTitle: (title) => document.title = title
}));

app = React.render(app, document.body);

Dispatcher.register((payload) => {
  if (payload.action.actionType === ActionTypes.CHANGE_LOCATION) {
    app.setProps({path: payload.action.path});
  }
});

Server-side Startup Script (Node.js/Express)

// src/server.js

var _ = require('lodash');
var express = require('express');
var React = require('react');

// The top-level React component + HTML template for it
var Application = React.createFactory(require('./components/Application'));
var template = fs.readFileSync(path.join(__dirname, 'index.html'), 'utf8');

var server = express();

server.set('port', (process.env.PORT || 5000));

// Server-side rendering (SSR)
server.get('*', function(req, res) {
  var data = {};
  var component = Application({
    path: req.path,
    onSetTitle: (title) => data.title = title,
    onPageNotFound: () => res.status(404)
  });
  data.body = React.renderToString(component);
  var html = _.template(template, data);
  res.send(html);
});

server.listen(server.get('port'), function() {
  console.log('HTTP server is running at http://localhost:' + server.get('port'));
});

HTML Template for Server-side Rendering

// src/index.html

<!doctype html>
<html class="no-js" lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title><%- title %></title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="css/app.css">
  </head>
  <body>
    <!--[if lt IE 8]>
      <p class="browsehappy">
        You are using an <strong>outdated</strong> browser.
        Please <a href="http://browsehappy.com/">upgrade your browser</a>
        to improve your experience.
      </p>
    <![endif]-->
    <%= body %>
    <script src="app.js"></script>
  </body>
</html>

Example

@penakamaayo
Copy link

@nyablo
Copy link

nyablo commented Feb 4, 2016

@michaelost
Copy link

@sergeydevhub
Copy link

I have question, sure you will never guess...

@RusinovAnton
Copy link

I had guessed @buscando question and so have same one.

@MualiMual
Copy link

Copy link

ghost commented Feb 17, 2016

@landed1
Copy link

landed1 commented Feb 19, 2016

who is batman ?

@lakshmantgld
Copy link

is this some git bot ?

@sirajulm
Copy link

@landed1 Batman is @Waterloo. But I really dont know where he is now

@aight8
Copy link

aight8 commented May 9, 2016

@maxpain
Copy link

maxpain commented May 26, 2016

@yookore
Copy link

yookore commented May 28, 2016

So who is answering the question?

@philipgiuliani
Copy link

philipgiuliani commented Jun 17, 2016

Same question as @cameronroe, @jeremyeast, @MelkorNemesis, @aayler, @bigdestroyer, @Laskos, @perpaer, @Kaveckas, @evidanary, @dkoleary88 @louwers @komocode @wzup @boyney123 @penakamaayo @NazarYablonskiy @michaelost, @abaoaqus, @buscando, @RusinovAnton @NobleGestures, @lubbertdas, @aight8, @Maxpain177

@NEX1S
Copy link

NEX1S commented Jun 17, 2016

Same question as @philipgiuliani, @cameronroe, @jeremyeast, @MelkorNemesis, @aayler, @bigdestroyer, @Laskos, @perpaer, @Kaveckas, @evidanary, @dkoleary88 @louwers @komocode @wzup @boyney123 @penakamaayo @NazarYablonskiy @michaelost, @abaoaqus, @buscando, @RusinovAnton @NobleGestures, @lubbertdas, @aight8, @Maxpain177

@rcolepeterson
Copy link

Same question as @philipgiuliani, @cameronroe, @jeremyeast, @MelkorNemesis, @aayler, @bigdestroyer, @Laskos, @perpaer, @Kaveckas, @evidanary, @dkoleary88 @louwers @komocode @wzup @boyney123 @penakamaayo @NazarYablonskiy @michaelost, @abaoaqus, @buscando, @RusinovAnton @NobleGestures, @lubbertdas, @aight8, @Maxpain177

@FlorianWendelborn
Copy link

Just let the server insert an INITIAL_STATE variable into the HTML, then read that variable in the client script and execute a hydrate action. If you have further questions, you can easily reach me on Gitter.

@maxbook
Copy link

maxbook commented Nov 1, 2016

Same question as @philipgiuliani, @cameronroe, @jeremyeast, @MelkorNemesis, @aayler, @bigdestroyer, @Laskos, @perpaer, @Kaveckas, @evidanary, @dkoleary88 @louwers @komocode @wzup @boyney123 @penakamaayo @NazarYablonskiy @michaelost, @abaoaqus, @buscando, @RusinovAnton @NobleGestures, @lubbertdas, @aight8, @Maxpain177, @rcolepeterson

@o-shabashov
Copy link

Same question as @philipgiuliani, @cameronroe, @jeremyeast, @MelkorNemesis, @aayler, @bigdestroyer, @Laskos, @perpaer, @Kaveckas, @evidanary, @dkoleary88 @louwers @komocode @wzup @boyney123 @penakamaayo @NazarYablonskiy @michaelost, @abaoaqus, @buscando, @RusinovAnton @NobleGestures, @lubbertdas, @aight8, @Maxpain177, @rcolepeterson, @maxbook

@igorgolovanov
Copy link

igorgolovanov commented Nov 17, 2016

@frank-dspeed
Copy link

@philipgiuliani, @cameronroe, @jeremyeast, @MelkorNemesis, @aayler, @bigdestroyer, @Laskos, @perpaer (@imrvelj), @Kaveckas, @evidanary, @dkoleary88 @louwers @komocode @wzup @boyney123 @penakamaayo @NazarYablonskiy @michaelost, @abaoaqus, @buscando, @RusinovAnton @NobleGestures, @lubbertdas, @aight8, @Maxpain177, @rcolepeterson, @maxbook, @o-shabashov, @golovanov

I want to Answer that Question There is More than one DOM in Reality.
Shadow DOM, browser DOM, Other Virtual DOM's,

So first of all the ServerSide Renders and throws that HTML after that the frontend will render also but in a Virtual DOM and it will Only render Objects that are not in the browser DOM and will take Parts from the Browser DOM and will sync both

Keywords for that are Shadow binding, DOM Syncing, and so on bind and attach of DOM Elements.

You can think about a DOM like a normal JAVASCRIPT Object :) so we can easy loop over them.

Hope that makes sense and helped you all to understand.

@xuezhma
Copy link

xuezhma commented Aug 29, 2017

@quentinbt
Copy link

@digitalashes
Copy link

@Mach12
Copy link

Mach12 commented Mar 5, 2018

@rohail-kalyar-pakwheels
Copy link

All,
Hopefully, this approach can help you.

https://fluxible.io/blog/2014-11-06-bringing-flux-to-the-server.html

@ondrek
Copy link

ondrek commented Jan 28, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment