Skip to content

Instantly share code, notes, and snippets.

@amol-
Last active January 23, 2017 00:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amol-/4563c7dc27c94d8ea58fabacb4cd71c6 to your computer and use it in GitHub Desktop.
Save amol-/4563c7dc27c94d8ea58fabacb4cd71c6 to your computer and use it in GitHub Desktop.
Isomorphic React applications in Python
export class HelloWorld extends React.Component {
render() {
return (
<div className="helloworld">
Hello {this.props.name}
</div>
);
}
}

Make sure you pip install TurboGears2, dukpy, tgext.webassets and kajiki before trying this.

react.js, react-dom.js and react-dom-server.js can be downloaded from https://cdnjs.com/libraries/react/15.3.2

Make sure you put react.js, react-dom.js, react-dom-server.js and HelloWorld.jsx into a statics/js directory.

import json
import os
import tg
from tg import AppConfig
from tg import TGController
from tg import expose
import kajiki
from markupsafe import Markup
page = kajiki.XMLTemplate(u'''<html>
<head>
</head>
<body>
<div id="isomor">${render_react('HelloWorld.HelloWorld', name='World')}</div>
<script py:for="m in g.webassets['bundle.js'].urls()" src="$m"></script>
<script>
ReactDOM.render(React.createElement(HelloWorld.HelloWorld, { name: "World" }), document.getElementById('isomor'));
</script>
</body>
</html>
''', mode='html5')
class RootController(TGController):
@expose()
def index(self):
return page(dict(
render_react=tg.config['react_renderer'].render,
g=tg.app_globals
)).render()
from dukpy import JSInterpreter, jsx_compile
class ReactRenderer(object):
def __init__(self, jspath):
self.jspath = jspath
self.jsi = JSInterpreter()
self.jsi.loader.register_path(self.jspath)
self.components = {}
self.initialized = False
def _init(self):
if self.initialized:
return
self.jsi.evaljs(
[f.data() for f in tg.app_globals.webassets['bundle.js'].build()] +
["var ReactDOM = require('react-dom-server');"]
)
self.initialized = True
def render(self, component, **kwargs):
self._init()
code = "ReactDOM.renderToString(React.createElement({component}, {args}), null);".format(
component=component, args=json.dumps(kwargs)
)
return Markup(self.jsi.evaljs(code))
config = AppConfig(minimal=True, root_controller=RootController())
config.renderers = ['kajiki']
config.serve_static = True
config.paths['static_files'] = 'statics'
config.react_renderer = ReactRenderer(os.path.join(os.path.dirname(__file__), 'statics', 'js'))
from webassets.filter import register_filter
from dukpy.webassets import BabelJSX
register_filter(BabelJSX)
import tgext.webassets as wa
wa.plugme(
config,
options={
'babel_modules_loader': 'umd'
},
bundles={
'bundle.js': wa.Bundle(
'js/react.js',
'js/react-dom.js',
wa.Bundle(
'js/HelloWorld.jsx',
filters='babeljsx',
),
output='assets/bundle.js'
)
}
)
application = config.make_wsgi_app()
from wsgiref.simple_server import make_server
print("Serving on port 8080...")
httpd = make_server('', 8080, application)
httpd.serve_forever()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment