When you hear Django and React you might think of having a microservice approach with two separate services hosted separately, which communicate through an HTTP-based API. Frontend and backend are separate apps running as independent services. The two apps have nothing to do with each other, other than the shared API. You can pretty much replace either of them and replace them with different technologies and everything will be fine as long as the API is respected.
We love that approach, there is nothing wrong with it and this is not a hit piece going after it.
So why talk about a different approach? Django already provides a lot of features like security and user management. We do not want to redo this already established work in React.
This requires another more integrated approach, which allows us to use Django features while having the interactivity and sheer awesomeness of React.
The base Idea is not that weird, it’s not even new. We are just extending a Django template with javascript to give it interactivity.
That’s it.
It’s basically the same as having a script tag in your template that shows an alert on load saying “hello world”, only instead of “hello worlding”, it loads a full-blown single-page app. It’s the same thing Django devs have been doing since Django started. The only difference is we are now using Webpack to simplify (complicate?) our deployment into Django.
When creating the production build, Webpack will use the Javascript App Entrypoint template and the JavaScript App source to generate a Django template and handle the loading of assets.
The entry point template and assets are stored where Django can collect them and are deployed along with the Django application. This means when Django serves the page, it will now run the JavaScript application on the browser.
One thing to note about the JavaScript App Template is that it is also a Django template. You can add Django-specific code in it as well as those for Webpack. Webpack will ignore the Django stuff and by the time Django gets its hand on it, the Webpack stuff will already be processed.
During development, the process simplifies slightly since we are no longer generating and deploying assets. Instead, we use the Webpack Dev server to serve them from memory. The only thing that still needs to be saved to the file system is the Django template.
This allows us to still have the functionality of the Webpack dev server such as hot reloading while running our Javascript application from Django.
We just need a simple app with a template that extends the entry point template, as we will be loading our React app via this Django template.
Webpack is our special sauce that makes everything work. Webpack is a frontend bundler that combines all dependencies and provides a deployable bundle. So while using it, we can build our front end up with a great deal of complexity and Webpack will make sure everything works when we deploy. Webpack will make sure that all our dependencies are correctly loaded and injected.
The first task is to set the Webpack output directory for static files. This is the folder Webpack will save all those dependencies. For our current project, this has to be somewhere that Django can collect. So since our frontend folder is on the same level as the Django app, we can name it static
, and call it a day.
Every application needs an entry point, where you get started. Webpack allows us to set this entry point to whatever we want. In our case we want that entry point to be a Django template.
Webpack dev server is a tool that provides us fast in-memory access to assets and live reloading. It’s responsible for injecting all required stuff when we are running a development build. In our case, since we changed our entry point and our development is running in Django we have to also update how the dev server is configured.
Normally everything is kept in memory but for this scenario, we want the entry point to be saved so that Django can access it.
For both production and development entry points we can use HtmlWebpackPlugin
.
HtmlWebpackPlugin creates the entry point for our SPA app. In a pure node-based setup this would generate the HTML file served together with the static assets by a web server to the client. We changed the output of the entry point HTML file to a Django template folder.
HtmlWebpackPlugin comes with its own Html template, which we’ll call the Input template to avoid confusion with the Output template or Django template (that we are going to build). The Input template can be defined anywhere but if you bootstrapped the project for example with Create React App (CRA) It’s located in the <javascript app root>/public/index.html
.
React, like most frontend frameworks, is built upon a bunch of node packages, which are managed via a package manager, these days typically npm or yarn. You can create the React folder anywhere but we chose to create it as a subdirectory of the Django application.
If you’ve created a React Application recently, odds are you’ve used Create React App (CRA). CRA gives you a set of sane defaults that under most circumstances will work just fine. This is great for normal projects because you do not have to worry about that additional config and every time CRA updates those settings are updated also.
However, the cost of this simplification is customizability. CRA doesn’t give you access to Webpack, and as explained above, Webpack configuration is central to what we are trying to achieve. So if you are building with React you have a few options that will give you access to Webpack con.
There are plugins that will extend CRA and give access to Webpack config. But at the time of writing most didn’t support the latest version of CRA.
The React Devs suggest that if you want to make changes to Webpack config in CRA you fork the CRA project and update your changes there. You can then use that forked CRA to create your application. This feels like overkill for a simple application.
If you are making multiple applications that all need the same changes I would advise you to fork CRA.
As mentioned before CRA gives you sane defaults and hides a lot of the complexity of React.
Ejecting is unhiding everything. When you eject a React App you are telling it that you will now take over everything, all configurations, all package management everything! This gives you access to all config files but you are now responsible for updates, and any problems with config everything. Ejecting can not be reversed.
But if you want you can nope out of CRA altogether.
You can create React apps from scratch, I’m talking empty directory, yarn init, yarn add React. It’s a bit more work, but it has the benefit of only having the config you want. This is a fun exercise but one I don’t recommend if you have a deadline.
So now we can run a React app using the webpack generated Django template, but what if our application needs to support multiple pages?
To differentiate which page you are on you have several solutions:
Both using React router and passing page data are pretty simple to implement, so either approach is acceptable. Using multiple Django templates on the other hand is more powerful but also more complicated and is probably overkill for small projects.
Once everything is set up you will have a tightly integrated application with Django and React. The front-end developer tools will work as expected and deployment should give you your Django application which loads React when it renders.
That’s pretty much it. We have a repo with the code which you can have a look at and feel free to fork it and play around with it.