Reputation: 1180
I am embedding a react project inside my django app. I am serving the index.html file created by npm run build
from django as opposed to just using django as a third party api. I like this approach as it leverages django user authentication/ csrf tokens/ etc.
After npm run build
I am extracting the head and the scripts on index.html and putting them in my base.html
of django, this way, the react scripts will be available wherever I need them and I can use my django templates for my navbar, footer etc.
The problem I am having is I have to copy and paste the headers and scripts on every build, so my question is if there is a way to make npm run build
build the files with the same name every time, or perhaps another solution, so when I rebuild the react project I don't have to recopy and paste to base.html
?
Here is a code snippet sample
base.html
<html>
<head>
<!-- Copy and pasted header files from react build-->
</head>
<body>
<navbar></navbar>
{% block content %}
{% endblock %}
<script> //copy and pasted scripts from react build - different script names on every build </script>
</body>
</html>
And then a file served by django
homepage.html
{% extend 'base.html' %}
<div class="other-django-stuff"></div>
{% block content %}
<div id="root"></div> // where my react project is anchored
{% endblock %}
Upvotes: 1
Views: 642
Reputation: 1180
Thanks to Emanuele's guidance Here is the following solution using python. This assumes the react static build folder is added to STATIC_DIRS in settings.py:
base.html
<html>
<head>
{% include 'react_head.html' %}
</head>
<body>
<navbar></navbar>
{% block content %}
{% endblock %}
{% include 'react_scripts.html' %}
<script src='django-scripts.js'></script>
</body>
</html>
build_base.py
from bs4 import BeautifulSoup
index = open( "build/index.html" )
soup = BeautifulSoup( index, features="html.parser" )
links = soup.findAll( "link" )
scripts = soup.findAll( "script" )
with open( "./../templates/react_head.html", "w" ) as html:
html.write( r"{% load static %}" + "\n" )
for link in links:
url = link["href"]
if "favicon" in url: continue
fname = "/".join( url.split("/static/")[1:] )
link["href"] = '{% static ' + f"'{fname}' " + r"%}"
html.write( link.prettify() )
with open( "./../templates/react_scripts.html", "w" ) as html:
html.write( r"{% load static %}" + "\n" )
for script in scripts:
if 'src' in script:
url = script["src"]
fname = "/".join( url.split("/static/")[1:] )
script["src"] = '{% static ' + f"'{fname}' " + r"%}"
html.write( script.prettify() )
package.json
"scripts": {
...
"build": "react-scripts build && python ./build_base.py",
...
},
Upvotes: 1
Reputation: 4489
Well, so what is needed in this case is a post build script that allows you to edit the file called base.html
to have the right names and scripts produced by the build. I will describe here some conceptual steps on how to achieve this result.
Step n. 1: Change the package.json
file to allow the execution of a script after the build
In this case I am using a JavaScript script file that will be run using nodejs, but you can use also other languages or shell scripts
"scripts": {
...
"build": "react-scripts build && node ./postbuild.js",
...
},
Note that, since the &&
operator is used, the postbuild.js
file will executed only if the build will have success.
Step n. 2: Create the post build script that will write your base.html
file
With the script you will be able to write the base.html
file dynamically.
Note: Since you can create the script in different languages, the script itself it is not included in the answer.
Upvotes: 1