How to build and deploy a flexible React/Django hybrid application

by Kensuke Numakura and Patrick Sneep

at DjangoCongress JP 2019

Kensuke Numakura

CTO & Co-Founder

Patrick Sneep

Fullstack Engineer

Who we are

  • Awakens Inc. - A Genomics Startup Based in Tokyo (JP) and Berkeley (USA)
  • Building Genomelink - A cloud based consumer genomics platform (genomelink.io)

Server Side Rendering

Django Engineer's trouble in 2019

Single Page Application

vs

  • templated views
  • jQuery for AJAX
  • UI rendered client side
  • backend just an API

Server Side Rendering

 

Old but still very powerful

.... like a dinosaur?

Single Page Application

Promises magical powers but maybe just a dream

... like a unicorn?

Our Goal: Hybrid

Utilize the best of both!

We want to build a "dinocorn"!

Our App: Genomelink

Hybrid Architecture

Pages using React

(one entrypoint per page)

  • complex UI
  • pages with asynchronous processing
  • often iterating
  • can use common components

Hybrid Architecture

Pages without React

(Just Django Templates)

  • leveraging thirdparty libraries (allauth etc)
  • simple pages without user interaction or just one form
  • SEO relevant pages (landingpage)
  • admin console

Show me the code!

React & Django Integration

GET /dashboard

React & Django Integration

def dashboard_index(request):
    genome = get_owner_genome(request.user)
    cards = get_cards(genome)

    props = {
        "cards": cards,
        "header": get_global_header_context(request, genome),
    }

    return render(
        request,
        "dashboard/index.html",
        {"react_props": json.dumps(props)},
    )

Dashboard Django view

React & Django Integration

<html>
    ...

    <script src="{% react_url 'dashboard' %}"></script>

    <div id="react-entry" />
    
    <script>
        const props = {{ react_props | safe }};
        renderApp(props);
    </script>

    ...
</html>

Dashboard template "dashboard/index.html"

React & Django Integration

React App entry (inside dashboard bundle)

import React from 'react';
import ReactDOM from 'react-dom';
import DashboardApp from '../dashboard/App';

window.renderApp = props => {
    const AppElement = React.createElement(DashboardApp, props);
    const entry = document.getElementById('react-entry');
    ReactDOM.render(
        AppElement,
        entry,
    );
};

React & Django Integration

React app rendered without additional API call

Styling

Challenges

React and non-React pages have duplicated CSS code! 😞

Boilerplate

Lot of duplicated code to call React code from Django template 😞

Static file handling

Difficult to integrate webpack with Django 🤔

Directory structure

/frontend

  package.json

  /src

  /node_modules

  ...

/webapp

  requirements.txt

  /app

  /config/settings.py

  /static/{js,css,img}

             /js/react/dashboard.js

             /js/react/plans.js

1. $ yarn build

2. $ manage.py collectstatic

3. $ aws s3 sync

AWS S3 🚀

CI, staging and production

local

$ yarn start

CI

staging/production

React

localhost:3000

$ yarn start &

Django

$ manage.py runserver

localhost:8000

$ pytest

Hot reloading 😎

S3 + CloudFront

https://static.genomelink.io/{js,css,img}

https://static.genomelink.io/js/react/*.js

EC2

https://genomelink.io

from django.contrib.staticfiles.templatetags.staticfiles import static

@register.simple_tag
def react_url(app_name):
    if settings.DJANGO_ENV == 'local':
        url = 'http://localhost:3000/react/{}.js'.format(app_name)
    else:
        url = static('js/react/{}.js'.format(app_name))
    return url
<script src="{% react_url 'dashboard' %}"></script>

custom template tag

CI, staging and production

$ yarn start

React

localhost:3000

Hot reloading 😎

S3 + CloudFront

 

https://static.genomelink.io/js/react/*.js

Django

Build and Deploy

  • CircleCI
  • AWS Elastick Beanstalk (EC2 w/ Apache, ELB)
name: Setup Django webapp
command: |
  cd webapp && python3 -m venv venv && . venv/bin/activate
  pip install --upgrade -r requirements/ci.txt
name: Setup React
command: |
  cd frontend
  yarn install

+ cache /venv

+ cache /node_modules

name: Build React and static files
command: |
  cd frontend
  yarn build

  cd ../webapp
  python manage.py collectstatic --noinput --link  # STATIC_ROOT = 'tmp/static'
name: Deploy webapp and static files
command: |
  cd webapp
  aws s3 sync tmp/static s3://static.genomelink.io/static/
  eb deploy --timeout 30

Takeaway

  • You can get many of the advantages of client side rendering without much of the complexity using a hybrid approach!
     
  • Shared React components between pages helps for rapid development
     
  • Use gradual adoption! Try it out for your own application.

We're hiring!

Questions?

Demo

Made with Slides.com