masterkale / django-cra-helper Goto Github PK
View Code? Open in Web Editor NEWThe missing piece of the Django + React puzzle
License: MIT License
The missing piece of the Django + React puzzle
License: MIT License
CRA v2 uses code splitting, producing 3 assets by default when the live server is run:
bundle.js
Bootstrapping/liveserver code presumably.
main.chunk.js
Main application code.
0.chunk.js
Vendor code.
Currently django-cra-helper
only supports returning the bundle path in generate_manifest
.
Unfortunately this is complicated by a lack of a coherent asset manifest in CRA2.
I had my "homepage": "/frontend" in package.json, and when doing "collectstatic --no-input", I got the following error:
$ python manage.py collectstatic --no-input
{'frontend/static/css/main.6e3fab79.chunk.css': 'main_css', 'frontend/static/js/main.7f0b0954.chunk.js': 'main_js', 'frontend/static/js/main.7f0b0954.chunk.js.map'
: 'main_js_map', 'frontend/static/js/runtime-main.e2bed40b.js': 'runtime_main_js', 'frontend/static/js/runtime-main.e2bed40b.js.map': 'runtime_main_js_map', 'front
end/static/css/2.11a187e6.chunk.css': 'static_css_2_11a187e6_chunk_css', 'frontend/static/js/2.ec811320.chunk.js': 'static_js_2_ec811320_chunk_js', 'frontend/stati
c/js/2.ec811320.chunk.js.map': 'static_js_2_ec811320_chunk_js_map', 'frontend/index.html': 'index_html', 'frontend/precache-manifest.faa980a089f14cfd9dcd994ddf3709
db.js': 'precache_manifest_faa980a089f14cfd9dcd994ddf3709db_js', 'frontend/service-worker.js': 'service_worker_js', 'frontend/static/css/2.11a187e6.chunk.css.map':
'static_css_2_11a187e6_chunk_css_map', 'frontend/static/css/main.6e3fab79.chunk.css.map': 'static_css_main_6e3fab79_chunk_css_map', 'frontend/static/js/2.ec811320
.chunk.js.LICENSE.txt': 'static_js_2_ec811320_chunk_js_LICENSE_txt'}
Traceback (most recent call last):
File "manage.py", line 21, in <module>
main()
File "manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "C:\Users\known\Documents\code\manager\venv\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
utility.execute()
File "C:\Users\known\Documents\code\manager\venv\lib\site-packages\django\core\management\__init__.py", line 377, in execute
django.setup()
File "C:\Users\known\Documents\code\manager\venv\lib\site-packages\django\__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "C:\Users\known\Documents\code\manager\venv\lib\site-packages\django\apps\registry.py", line 91, in populate
app_config = AppConfig.create(entry)
File "C:\Users\known\Documents\code\manager\venv\lib\site-packages\django\apps\config.py", line 90, in create
module = import_module(entry)
File "C:\Python38\lib\importlib\__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 783, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "C:\Users\known\Documents\code\manager\venv\lib\site-packages\cra_helper\__init__.py", line 33, in <module>
STATIC_ASSET_MANIFEST = generate_manifest(CRA_URL, CRA_FS_APP_DIR)
File "C:\Users\known\Documents\code\manager\venv\lib\site-packages\cra_helper\asset_manifest.py", line 114, in generate_manifest
rel_static_path = manifest[mapped_manifest_items[path]]
KeyError: 'static/js/runtime-main.e2bed40b.js'
(I modified your package to print out the "mapped_manifest_items" after line 112 in asset_manifest.py, which results in the dict in the beginning)
Not only does collectstatic not work, django itself seems to be broken, since I can't even run "check".
Then I removed the "homepage" setting from package.json, I got (the second time, actually, so no new files were copied, but it was successful)
$ python manage.py collectstatic --no-input
{'static/css/main.6e3fab79.chunk.css': 'main_css', 'static/js/main.c67dbaad.chunk.js': 'main_js', 'static/js/main.c67dbaad.chunk.js.map': 'main_js_map', 'static/js
/runtime-main.1f1f19a3.js': 'runtime_main_js', 'static/js/runtime-main.1f1f19a3.js.map': 'runtime_main_js_map', 'static/css/2.11a187e6.chunk.css': 'static_css_2_11
a187e6_chunk_css', 'static/js/2.9d1ff8ae.chunk.js': 'static_js_2_9d1ff8ae_chunk_js', 'static/js/2.9d1ff8ae.chunk.js.map': 'static_js_2_9d1ff8ae_chunk_js_map', 'ind
ex.html': 'index_html', 'precache-manifest.ccfb517866d1102d0142a5fc91597f11.js': 'precache_manifest_ccfb517866d1102d0142a5fc91597f11_js', 'service-worker.js': 'ser
vice_worker_js', 'static/css/2.11a187e6.chunk.css.map': 'static_css_2_11a187e6_chunk_css_map', 'static/css/main.6e3fab79.chunk.css.map': 'static_css_main_6e3fab79_
chunk_css_map', 'static/js/2.9d1ff8ae.chunk.js.LICENSE.txt': 'static_js_2_9d1ff8ae_chunk_js_LICENSE_txt'}
0 static files copied to 'C:\Users\known\Documents\code\manager\staticfiles', 143 unmodified, 325 post-processed.
It appears there is no support provided for Service Workers, am I correct? If so, this necessary to properly support create-react-app.
I would expect it to work similarly to the Manifest solution provided, I guess.
If I'm wrong about this, can you point me towards how to support Service Workers in my app.
Hey,
What's the correct way of accessing images in public/ folder inside your cra app?
I am trying to access the image in a react component.
I tried the It didn't work.
@MasterKale
If the CRA liveserver is not running, django-cra-helper makes its assets findable to collectstatic
by putting them into STATICFILES_DIRS
:
STATICFILES_DIRS
is used by "django.contrib.staticfiles.finders.FileSystemFinder"
, so this only works if this finder is in STATICFILES_FINDERS
. While the default settings.py
generated for new Django projects includes it, it's also not unheard of to remove it - for example, when you turn your project into an app itself.
It would therefore be great if there were a short note in the README specifying that this is required (and not just a django default).
Line 73 in e65ff34
Would have saved me a dive into the source code of the project just now.
So my application works fine on chrome but on both safari and Chrome I get the following errors:
I have enabled the javascript.options.shared_memory: True in about:config
Not sure if we are loading the js files in wrong order maybe?
@MasterKale
Hi,
Thanks so much for the library, it's exactly what I was looking for :) However, I am having an issue with hot reloading.
Following the recommended instructions and adding re_path(r'^sockjs-node/(?P<path>.*)$', proxy_cra_requests),
is giving me an error in the console followed by "The development server has disconnected:
WebSocket connection to 'ws://localhost:8000/sockjs-node' failed: Error during WebSocket handshake: Unexpected response code: 301
I've thought this may be due to the slash, so I varied it by making the slash optional in the regex, and now I get:
webpackHotDevClient.js:60 WebSocket connection to 'ws://localhost:8000/sockjs-node' failed: Error during WebSocket handshake: 'Upgrade' header is missing
Am wondering if this is a me issue, a docs issue, or a version incompatibility issue, if anyone's using this library and come across this?
Thanks
When live reloading is happening, the bundle will request HMR manifest, JS and sourcemap files. I had to add the following paths to proxy_urls
proxy_urls = [
re_path(r'^__webpack_dev_server__/(?P<path>.*)$', proxy_cra_requests),
re_path(r'^(?P<path>.+\.hot-update\.(js|json|js\.map))$', proxy_cra_requests),
]
@MasterKale
This project is awesome. Thanks for putting this together. I am using React-router:
const App = () => (
<BrowserRouter>
<Provider store={store}>
<Fragment>
<div className="App">
<Switch>
<Route exact path={"/login"} component={Login} />
<Route exact path={"/home"} component={MainPage} />
<Route path={"/"} component={Login} />
</Switch>
</div>
</Fragment>
</Provider>
</BrowserRouter>
);
export default App;
Any time I try to visit these paths the app defaults to DJANGO paths. How do I enable react routes with this integration?
print(BASE_DIR)
print(BASE_DIR)
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASEDIR, 'static')
print(STATIC_ROOT)
I have defined the static folder but I can't run production. npm run build works fine but if I do collectstatic this happens. If I keep running the npm start then it works but then in production it tries to get bundles from localhost:3000
module = import_module(entry)
File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
File "<frozen importlib._bootstrap>", line 991, in _find_and_load
File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 783, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/home/security_portal/Envir/py3.8_env/lib/python3.8/site-packages/cra_helper/__init__.py", line 33, in <module>
STATIC_ASSET_MANIFEST = generate_manifest(CRA_URL, CRA_FS_APP_DIR)
File "/home/security_portal/Envir/py3.8_env/lib/python3.8/site-packages/cra_helper/asset_manifest.py", line 57, in generate_manifest
settings.STATICFILES_DIRS += [static_dir]
TypeError: can only concatenate tuple (not "list") to tuple
(py3.8_env) security_portal@security:~/SecurityPortal/backend
@MasterKale any ideas?
EDIT: It seems like it is working now, I'm not exactly sure what happened or why. The files are appearing in my staticfiles
directory now however it seems like the site doesn't require them to be in staticfiles
. It seems to work as long as the cra_project/build
folder has been generated. I'm going to close this until i can more accurately reproduce/describe this error. Cheers!
Hey there,
Great work on this project, I was pretty easily able to get it up and running for development with minimal hitches. I have run into a wall when trying to get the production setup going with the static files and such.
Here's my current settings.py
:
settings.py
"""
Django settings for djangoreactapp project.
Generated by 'django-admin startproject' using Django 3.0.6.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
import django_on_heroku
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'hk7rah&ktc=j)^o!qiq4cua_eay0(=5(4xy=o7(1&((n3jmu(='
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'cra_helper', # must be placed above django.contrib.staticfiles
'django.contrib.staticfiles',
'rest_framework',
'posts',
'frontend_app'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'djangoreactapp.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'cra_helper.context_processors.static'
],
},
},
]
WSGI_APPLICATION = 'djangoreactapp.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
# https://github.com/MasterKale/django-cra-helper#configuration
STATICFILES_FINDERS = [
# Django defaults
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# A finder to pull in asset-manifest.json
'cra_helper.finders.CRAManifestFinder',
]
CRA_APP_NAME = 'frontend'
django_on_heroku.settings(locals())
And when I run python manage.py collectstatic --no-input
, here's the tree of my staticfiles
folder.
├── staticfiles
│ ├── admin
│ │ ├── css
│ │ ├── fonts
│ │ ├── img
│ │ └── js
│ ├── asset-manifest.f40398444816.json
│ ├── asset-manifest.f40398444816.json.gz
│ ├── asset-manifest.json
│ ├── asset-manifest.json.gz
│ ├── rest_framework
│ │ ├── css
│ │ ├── docs
│ │ ├── fonts
│ │ ├── img
│ │ └── js
│ └── staticfiles.json
So it definitely seems like the asset-manifest.json (as well as a couple other asset-manifest.* files i'm not sure of) gets copied over. I can confirm this by commenting out all the django-cra-helper things in settings.py
and re-running python manage.py collectstatic --no-input
. When doing this, the staticfiles
folder looks like this:
├── staticfiles
│ ├── admin
│ │ ├── css
│ │ ├── fonts
│ │ ├── img
│ │ └── js
│ ├── rest_framework
│ │ ├── css
│ │ ├── docs
│ │ ├── fonts
│ │ ├── img
│ │ └── js
│ └── staticfiles.json
Any thoughts on why the files from the build folder aren't getting copied over?
asset_manifest.py fails when CRA liveserver is not found.
File "/usr/local/lib/python3.7/site-packages/cra_helper/asset_manifest.py", line 50, in generate_manifest
_manifest[asset_key] = os.path.relpath(path, 'static/')
File "/usr/local/lib/python3.7/posixpath.py", line 459, in relpath
path = os.fspath(path)
TypeError: expected str, bytes or os.PathLike object, not dict
I've pinpointed the cause here:
The filemappings are under files
key. Changing line 46 to:
for filename, path in data.get('files').items():
seems to fix the issue. I am guessing this is the desired functionability?
Hey,
I am trying to build the CRA over a dev instance. I am using an external interface.
So for example my Django is bound to port 0.0.0.0:443 and my cra is bound to port 0.0.0.0 3000
But I am accessing the website with: example.test.com externally. But the scripts for cra are not loading in dev from example.test.com:3000. As I am running in DEBUG instance. How can I make a non localhost setup work?
Sorry this is a bit confusing but happy to provide more context and any questions you have.
Hi,
Thanks for this module. It really helps a lot.
We are currently having an issue in production where we need to lower the size of our production app. Is it possible for cra_helper
to not require reactjs/build/
in production? If I understand it correctly, it is there needed only until we call the collectstatic
. After that, we should be able to delete it. Is that a right assumption?
Since Django v2.1 there's been a built-in way of safely converting a Python dict to a valid Javascript object in the json_script
template tag:
https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#json-script
I think it's worth looking into getting rid of this package's json
template tag as I'd much rather lean on built-in functionality than continue to maintain something now seemingly redundant.
Using [email protected], the instructions for getting Django to work with React's liveserver don't seem to work. The filenames in the bundle_js
template variable aren't the same as the script filenames the liveserver loads.
Here's a comparison:
React Liveserver | Django | |
---|---|---|
Loaded scripts | ||
Result | (blank screen) |
Specifically, django-cra-helper
is loading 0.chunk.js
, while the React liveserver is loading vendors~main.chunk.js
instead.
Here's my template file that Django is loading:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<title>django-cra-helper liveserver bug</title>
{% if entrypoints %}
{% for file in entrypoints.css %}
<link href="{% static file %}" rel="stylesheet" />
{% endfor %}
{% elif main_css %}
<link href="{% static main_css %}" rel="stylesheet" />
{% endif %}
</head>
<body>
<div id="root">{# React frontend gets rendered here #}</div>
{% if bundle_js %}
{% for file in bundle_js %}
<script type="text/javascript" src="{{ file }}"></script>
{% endfor %}
{# django-cra-helper liveserver integration does not work without this script #}
<!-- <script
type="text/javascript"
src="http://localhost:3000/static/js/vendors~main.chunk.js"
></script> -->
{% elif entrypoints %}
{% for file in entrypoints.js %}
<script type="text/javascript" src="{% static file %}"></script>
{% endfor %}
{% endif %}
</body>
</html>
If I manually load the vendors~main.chunk.js
script (commented out in that snippet 👆), then everything works as I'd expect; the app loads correctly, and changes to files are detected properly.
Here's a reproduction repo if it helps.
I think the solution involves the lines of code below. Fixing the issue may simply involve adding to/modifying what django-cra-helper
puts in the bundle_js
array.
django-cra-helper/cra_helper/asset_manifest.py
Lines 39 to 46 in e65ff34
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.