How to Bring Live-Reloading Back to a Django And React Project | Hacker Noon

Author profile picture

@ToruitasStuart

Creative coder @ Lollipop.ai and UAL:Creative Computing Institute

This article is a prequel of sorts to my earlier 110% Complete JWT Authentication with Django & React - 2020 article. That article covers how to get started with JWT authentication in a typical React and Django Rest Framework project, and it does that well enough. There’s just one major annoyance with it – I couldn’t figure out how to get live reloading working! So for every change made to the frontend, we had to shut down the dev server, rebuild the React bundle, and start it up again. Talk about tedious!

Recently I gave it another go as I developed a project which uses Celery and Django Channels for Websockets realtime interaction. That is a subject for another article.

Getting live reloading working is actually quite easy and straightforward, although it does require running both Django and Webpack dev servers simultaneously, so let’s run through the code with a barebones setup.

First, install Django and Django Rest Framework.

pipenv --python=3.8
pipenv shell
pipenv install django djangorestframework

Then create the project.

django-admin startproject djrhr

And the frontend app which will hold all the React code, and run all the standard migrations.

cd djrhr
python manage.py migrate
django-admin startapp frontend
cd ..

So now the structure of the project is like so:

djr-hotreload
--djrhr
----djrhr
----frontend
----manage.py
First thing we are going to do is prepare Django for serving the single

index.html

which will load the React script.

In

frontend/

, create a

templates/frontend

directory with an

index.html

and a

urls.py

, plus a related

style.css

like so:

frontend
--migrations
--templates
----frontend
------index.html
--static
----frontend
------style.css
--__init__.py
--admin.py
--apps.py
--models.py
--tests.py
--urls.py
--views.py
Let’s prepare

index.html

for loading React.

<!DOCTYPE html>
<html>
{% load static %}
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{% static 'frontend/style.css' %}">
    <title>Demo of Django and React hot-reloading</title>
</head>
<body>
    <div id="root" class="content">
        This will be the base template.
    </div>
<script type="text/javascript" src="{% static 'frontend/public/main.js' %}"></script>
</body>
</html>

We’ll add the extra stuff to the static folder in a bit.

First, create a view to serve our

index.html

. Standard Django view.

# views.py
from django.shortcuts import render

# Create your views here.
def index_view(request):
    return render(request,'frontend/index.html', context=None)
Add it to

urls.py
from django.urls import path
from django.conf.urls import url
from .views import index_view

urlpatterns = [
    path('', index_view),
    url(r'^.*/$', index_view)  # regex matches, then lets routing be handled by the frontend. Still needs a / at end.
]
And of course add the app in

settings.py

and URLs to the project

urls.py
# urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('frontend.urls'))
]
# settings.py

...

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'frontend'
]

...
Now run that server and navigate to

http://127.0.0.1:8000/

You should see a nice, boring template with the text
“This will be the base template.”

Cool.

That’s pretty much all we need to do on the Django side of things.

Now for React!

In the frontend directory, make a

src

directory which will hold the React code we write. Then in frontend’s

static

directory, make a

public

folder, which will hold the React code bundle for serving as represented by

main.js

in the tree below (you don’t need to make this file).

frontend
...
--src
--static
----frontend
------style.css
------public
--------main.js
...

We will use WebPack to handle our frontend development server, so first let’s install everything. Make sure you’re at the top level and then first initialize your npm project, then install what we need:

npm init
npm install --save react react-dom
npm install --save-dev webpack webpack-cli webpack-dev-server
Now you should have a new

package.json

and

package-lock.json

.

Django doesn’t pay much attention to the src folder we created, which will hold all the code we write fro our React project. So, any changes there are not seen and the Django dev server doesn’t reload to show the improvements. To get around that, we need to utilize the Webpack dev server, which will see the changes, rebuild the bundle, and put it in the static folder. Django will see it there and respond appropriately.

To use the Webpack development server, add this line to the scripts section of

package.json

.

"start:dev": "webpack-dev-server --config webpack.config.js",
Which can be used with the terminal command

npm run start:dev

.

Also in

package.json

change

"main"

to

"webpack.config.js"

Before we can do that, we have to actually configure Webpack.

Install the proper loaders for React.

npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader
Create this

webpack.config.js

file.

const path = require('path');

module.exports = {
    entry: [path.resolve(__dirname, 'djrhr/frontend/src/index.js')],
    // entry: {main: '/home/toruitas/Documents/GitHub/LollipopAI/django_backend/lollipopAI/frontend/src/index.js'},
    output: {
        // where compiled files go
        path: path.resolve(__dirname, "djrhr/frontend/static/frontend/public/"),

        // 127.0.0.1/static/frontend/public/ where files are served from
        publicPath: "/static/frontend/public/",
        filename: 'main.js',  // the same one we import in index.html
    },
    module: {
        // configuration regarding modules
        rules: [
            {
                // regex test for js and jsx files
                test: /.(js|jsx|mjs)?$/,
                // don't look in any node_modules/ or bower_components/ folders
                exclude:  /(node_modules|bower_components)/,
                // for matching files, use the babel-loader
                use: {
                    loader: "babel-loader",
                    options: {presets: ["@babel/env", "@babel/preset-react"]}
                },
            },
        ],
    },
    devServer: {
        writeToDisk: true,
    }
};

The key points to note are the output section, specifies where to put the emitted bundle code, and the devServer section. Make sure that

writeToDisk

is

true

, otherwise the devServer will simply hold the changes in memory and Django will never see them and never reload.

While the webpack devServer can do a LOT more than this – it is after all a complete dev server – we only need it for this one job. We don’t need it to serve any files, we don’t need it to perform any compression, we only need it to watch our code and recompile the files in real-time.

That’s really all there is to it, so let’s make write some super simple React code to test it out. Both App.js and index.js live in

frontend/src

.

// App.js

import React, { Component} from "react";


class App extends Component {

    constructor(){
        super();
    }

    render(){
        return(
            <div>
                This is the React index.
            </div>
        )
    }

}

export default App;
// index.js

import React from 'react'
import {render} from 'react-dom'
import App from './App';

render((
    <App  />
), document.getElementById('root'));
To test, in one terminal run

python djrhr/manage.py runserver

and in another run

npm run start:dev

. You should see a new

main.js

in

frontend/static/frontend/dist

, and if you didn’t you may need to make the directory. Opening up 127.0.0.1:8000 will show “This is the React index.”

Go to

App.js

and change the line “This is the React index” to whatever you want. Maybe something like… “How much wood would a woodchuck chuck if a woodchuck could chuck wood?”

If everything has gone alright, then you can look in both terminals and see the code recompile, and as the browser refreshes the code reloads.

Success!

You can find the final project on GitHub code here.
Author profile picture

Read my stories

Creative coder @ Lollipop.ai and UAL:Creative Computing Institute

Tags

The Noonification banner

Subscribe to get your daily round-up of top tech stories!

read original article here