Skip to content

Commit fba3899

Browse files
authored
Merge pull request #27 from MasterKale/feat/react-scripts-4.0.0-support
feat/react-scripts-4.0.0-support
2 parents 4681329 + dc27b2e commit fba3899

13 files changed

+163
-131
lines changed

.editorconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# EditorConfig is awesome: https://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
[*]
7+
indent_style = space
8+
indent_size = 2
9+
end_of_line = lf
10+
charset = utf-8
11+
trim_trailing_whitespace = true
12+
insert_final_newline = true
13+
14+
[*.py]
15+
indent_size = 4

Pipfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ verify_ssl = true
77
django = "*"
88

99
[packages]
10-
bleach = "*"
1110
six = "*"
1211
webencodings = "*"
1312
django-proxy = "*"

Pipfile.lock

Lines changed: 31 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -185,25 +185,23 @@ React assets will be included with the other static assets in the `settings.STAT
185185

186186
Similar to the `bundle_js` template variable mentioned earlier, **django-cra-helper** includes numerous other template variables when the CRA liveserver is _not_ running:
187187

188-
<details>
189-
<summary>For older projects using <strong>react-scripts@&lt;=2.1.8</strong></summary>
188+
<details open>
189+
<summary>For projects using <strong>react-scripts@&gt;=3.2.0</strong></summary>
190190

191-
The two most important variables are `main_js` and `main_css`. These can be injected into the page via a typical call to `{% static %}` in the template:
191+
Starting with `[email protected]`, a new `entrypoints` property can be found in **asset-manifest.json**. This contains an array of files that **django-cra-helper** makes available in templates to more easily inject these files via new `entrypoints.css` and `entrypoints.js` arrays:
192192

193193
```html
194-
{% if main_css %}
195-
<link href="{% static main_css %}" rel="stylesheet">
196-
{% endif %}
194+
{% for file in entrypoints.css %}
195+
<link href="{% static file %}" rel="stylesheet">
196+
{% endfor %}
197197
```
198198
```html
199-
{% if main_js %}
200-
<script type="text/javascript" src="{% static main_js %}"></script>
201-
{% endif %}
199+
{% for file in entrypoints.js %}
200+
<script type="text/javascript" src="{% static file %}"></script>
201+
{% endfor %}
202202
```
203203

204-
> NOTE: Recent attempts at building a fresh CRA project with `[email protected]` were unsuccessful in recreating SPAs that allowed for just a single `main_js`. `npm run build`-produced artifacts functioned almost identically to artifacts generated the same as `[email protected]`, detailed below.
205-
>
206-
> There may be child dependencies of `react-scripts` that make it no longer possible to start apps that will function with the above instructions. In these cases, please try the instructions in the next section.
204+
> NOTE: These JavaScript and CSS files should be arranged in an order required for the site to load; the ultimate order is derived from the order present in **asset-manifest.json**.
207205
</details>
208206
209207
<details>
@@ -223,22 +221,24 @@ Similar to the `bundle_js` template variable mentioned earlier, **django-cra-hel
223221
</details>
224222

225223
<details>
226-
<summary>For projects using <strong>react-scripts@&gt;=3.2.0</strong></summary>
224+
<summary>For older projects using <strong>react-scripts@&lt;=2.1.8</strong></summary>
227225

228-
Starting with `[email protected]`, a new `entrypoints` property can be found in **asset-manifest.json**. This contains an array of files that **django-cra-helper** makes available in templates to more easily inject these files via new `entrypoints.css` and `entrypoints.js` arrays. These **replace** the `main_css` and `main_js` values used above:
226+
The two most important variables are `main_js` and `main_css`. These can be injected into the page via a typical call to `{% static %}` in the template:
229227

230228
```html
231-
{% for file in entrypoints.css %}
232-
<link href="{% static file %}" rel="stylesheet">
233-
{% endfor %}
229+
{% if main_css %}
230+
<link href="{% static main_css %}" rel="stylesheet">
231+
{% endif %}
234232
```
235233
```html
236-
{% for file in entrypoints.js %}
237-
<script type="text/javascript" src="{% static file %}"></script>
238-
{% endfor %}
234+
{% if main_js %}
235+
<script type="text/javascript" src="{% static main_js %}"></script>
236+
{% endif %}
239237
```
240238

241-
> NOTE: These JavaScript and CSS files should be arranged in an order required for the site to load; the ultimate order is derived from the order present in **asset-manifest.json**.
239+
> NOTE: Recent attempts at building a fresh CRA project with `[email protected]` were unsuccessful in recreating SPAs that allowed for just a single `main_js`. `npm run build`-produced artifacts functioned almost identically to artifacts generated the same as `[email protected]`, detailed below.
240+
>
241+
> There may be child dependencies of `react-scripts` that make it no longer possible to start apps that will function with the above instructions. In these cases, please try the instructions in the next section.
242242
</details>
243243
244244
### Supporting CRA's relative paths
@@ -261,12 +261,15 @@ Before: /static/js/main.319f1c51.chunk.js
261261
After: /frontend/static/js/main.319f1c51.chunk.js
262262
```
263263

264-
**To make sure the React imports/assets/etc... can be found even when hosted through Django, you'll also need to update `STATIC_URL` in Django's settings.py to include the path prefix:**
264+
To make sure the React imports/assets/etc... can be found even when hosted through Django, you'll also need to update `STATIC_URL` in Django's settings.py to include the path prefix:
265265

266266
```py
267267
STATIC_URL = '/frontend/static/'
268+
CRA_PACKAGE_JSON_HOMEPAGE = '/frontend'
268269
```
269270

271+
The value set to `CRA_PACKAGE_JSON_HOMEPAGE` above should match the value of `"homepage"` in **package.json** so that **django-cra-helper** can find the CRA liveserver and redirect appropriately:
272+
270273
Once these changes are made then the React app should be able to find everything it needs to function.
271274

272275
## React in Django templates
@@ -332,7 +335,6 @@ Below is the Django app view's **index.html** template that can render across mu
332335

333336
```html
334337
{% load static %}
335-
{% load cra_helper_tags %}
336338
<!DOCTYPE html>
337339
<html lang="en">
338340

@@ -353,9 +355,13 @@ Below is the Django app view's **index.html** template that can render across mu
353355
<body>
354356
<div id="react">Loading...</div>
355357

358+
{{ props | json_script:"react-props" }}
359+
356360
<script>
357361
window.component = '{{ component }}';
358-
window.props = {{ props | json }};
362+
window.props = JSON.parse(
363+
document.getElementById('react-props').textContent
364+
);
359365
window.reactRoot = document.getElementById('react');
360366
</script>
361367
{% if bundle_js %}
@@ -378,12 +384,8 @@ Below is the Django app view's **index.html** template that can render across mu
378384
```
379385
The context's `component` and `props` are bound to `window.component` and `window.props` respectively.
380386

381-
Note the use of the `json` filter when setting `windows.props`! `{% load cra_helper_tags %}` provides this filter as a way to easily sanitize and convert a Python `dict` to a Javascript `Object`. The View context prepared above thus renders to the following typical Javascript Object:
387+
Note the use of the `json_script` filter when setting `windows.props`. [Django provides this filter](https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#json-script) as a way to easily sanitize and convert a Python `dict` to a Javascript `Object`. The contents of the injected `<script>` tag can be run through `JSON.parse()` to safely assign it to a variable.
382388

383-
```js
384-
// This is what is returned in the rendered HTML
385-
window.props = {"env": "Django"};
386-
```
387389
Finally, `window.reactRoot` specifies the container element that the React component should be rendered into. Setting a value for this is only required if the container's `id` is *not* **"root"** (the same ID assigned to the container `<div>` in the CRA project's `index.html`.)
388390

389391
### Combining Django and React routes

cra_helper/__init__.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,23 @@
2626
else:
2727
CRA_APP_NAME = 'react'
2828

29+
# Be mindful of CRA's relative paths when bootstraping from the CRA liveserver
30+
_cra_liveserver_url = CRA_URL
31+
if hasattr(settings, 'CRA_PACKAGE_JSON_HOMEPAGE'):
32+
relative_path = str(settings.CRA_PACKAGE_JSON_HOMEPAGE)
33+
# Normalize homepage path if it starts with / or ends with /
34+
if relative_path.startswith('/'):
35+
# Strip leading /
36+
relative_path = relative_path[1:]
37+
if relative_path.endswith('/'):
38+
# Strip trailing /
39+
relative_path = relative_path[0:-1]
40+
41+
# Should result in something like 'http://localhost:3000/frontend'
42+
_cra_liveserver_url = '{}/{}'.format(_cra_liveserver_url, relative_path)
43+
2944
# The path to the CRA project directory, relative to the Django project's base directory
3045
CRA_FS_APP_DIR = os.path.join(settings.BASE_DIR, CRA_APP_NAME)
3146

3247
# A list of entries in CRA's build bundle's
33-
STATIC_ASSET_MANIFEST = generate_manifest(CRA_URL, CRA_FS_APP_DIR)
48+
STATIC_ASSET_MANIFEST = generate_manifest(_cra_liveserver_url, CRA_FS_APP_DIR)

cra_helper/asset_manifest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def generate_manifest(cra_url: str, app_dir: str) -> dict:
4141
# These two files will alternate being loaded into the page
4242
'{}/static/js/0.chunk.js'.format(cra_url),
4343
'{}/static/js/1.chunk.js'.format(cra_url),
44+
45+
'{}/static/js/vendors~main.chunk.js'.format(cra_url),
4446
# This bundle seems to contain some vendor files
4547
'{}/static/js/main.chunk.js'.format(cra_url)
4648
]

cra_helper/templatetags/__init__.py

Whitespace-only changes.

cra_helper/templatetags/cra_helper_tags.py

Lines changed: 0 additions & 21 deletions
This file was deleted.

cra_helper/tests/test_asset_manifest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def test_returns_bundle_url_if_cra_is_running(self, mock_hosted_check):
117117
'http://foo.bar:9999/static/js/bundle.js',
118118
'http://foo.bar:9999/static/js/0.chunk.js',
119119
'http://foo.bar:9999/static/js/1.chunk.js',
120+
'http://foo.bar:9999/static/js/vendors~main.chunk.js',
120121
'http://foo.bar:9999/static/js/main.chunk.js'
121122
]
122123
})

cra_helper/tests/test_cra_helper_tags.py

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)