adamchainz / django-browser-reload Goto Github PK
View Code? Open in Web Editor NEWAutomatically reload your browser in development.
License: MIT License
Automatically reload your browser in development.
License: MIT License
3.9.18
4.2.7
No response
No response
When used with Django Components you have to restart the server every time you update the .py
file that registers the component.
If you disable Django Browser Reload then the component functionality works as expected.
I created a sample repo with a project demonstrating the issue. Directions are in the project readme.
https://github.com/ayoung-burnsmcd/components-browser-reload
By default, POSTs will be auto reloaded, and can mutate state depending on the url behaviour.
Often, a POST will redirect, so it's not a problem. But sometimes returning content directly from the POST response is valid. If a user leaves the page open, it will then be reloaded as a POST, which I don't think is desirable.
As an example, we had a POST view that generates a one-time password to use. We store the hashed version in the db, but display the plain text version to the user in the POST response body. When django-browser-reload reloads the page, it does a POST (which in our cases generates a new one-time password, invalidating the old one). We don't redirect as we don't want to store the plain text version of the password in a url (or in the session, ideally).
Would you support the idea of config option to disable reloading of anything except GETs? On by default, for b/w compat?
Can copy the pattern from django-htmx where the template tag is simple in jinja and then called by a Django template language wrapper.
Within a single browser, the SharedWorker
only refreshes the latest opened tab. That's a good feature, it prevents a thundering herd.
But if you open several browsers or use isolated sessions within one browser, several SharedWorkers
will run and connect to the events view. But unfortunately the threading event will mean only one of these running events views will actually pass the reload message to one of the browsers.
It would be good to use some kind of thread messaging construct to pass the event to all relevant running threads from event views. Thus, one might open a couple browsers to check between their incompatibilities, and see them all reload.
Folks thanks for maintaining this package. It recently stopped working for a project of mine and I bisected back to it starting to use the DjangoGZip middleware.
The symptom is that the reloads stop happening. Potential solution to #68 (comment).
I solved it by not using the GZip middleware at dev time, but perhaps this is a matter of ordering the middleware differently?
A suggestion for guarding against this, if you deem it useful: django-browser-reload
should inspect the middleware list and crash the development server on start with a helpful message if the gzip middleware is present (at the wrong place in the list?), unless ALLOW_BROKEN_GZIP_RELOAD=True
.
Cheers.
I am using the django-browser-reload in a project that I'm working on, and it works amazingly. But today I noticed a slight problem, and I don't know how to fix it.
It's only a small thing.
This is a Wagtail project, and I have a multilanguage site; therefore, I'm using Internationalization for the translations. I didn't want a prefix for the default language, so I added 'prefix_default_language=False' as described here in the Wagtail docs: https://docs.wagtail.org/en/stable/advanced_topics/i18n.html#bypass-language-prefix-for-the-default-language
From the moment I restarted my server, I got these errors repeatedly:
Not Found: /reload/events/
[08/Sep/2023 13:40:31] "GET /reload/events/ HTTP/1.1" 404 3712
Not Found: /reload/events/
[08/Sep/2023 13:40:32] "GET /reload/events/ HTTP/1.1" 404 3712
Sometimes it was a few seconds apart, and other times it was a few times every second.
For instance, I'd like to force a reload when I create or update a specific model instance in my app. Presumably, if django_browser_reload
is inactive (DEBUG
is False
, etc.) then this is a no-op.
Apologies if I simply missed it, but is there an explicitly supported method I can call (or signal I can raise) to achieve this?
3.12.2
4.2.11
1.12.1
Chrome 123
When django-browser-reload is enabled and we open a connection, it prevents uvicorn reload to trigger. The reload gets stuck on the following for infinite amount of time:
WARNING: WatchFiles detected changes in 'narcissus/components/meow.py'. Reloading...
INFO: Shutting down
INFO: Waiting for connections to close. (CTRL+C to force quit)
Adding --timeout-graceful-shutdown 2
makes the reload possible with the following message:
WARNING: WatchFiles detected changes in 'narcissus/components/meow.py'. Reloading...
INFO: Shutting down
INFO: Waiting for connections to close. (CTRL+C to force quit)
ERROR: Cancel 1 running task(s), timeout graceful shutdown exceeded <-- Indicates a running task that is not shutting down on uvicorn reload signal
INFO: Finished server process [1169]
INFO: Started server process [2964]
INFO: Waiting for application startup.
INFO: ASGI 'lifespan' protocol appears unsupported.
INFO: Application startup complete.
INFO: 172.18.0.1:51234 - "GET /__reload__/events/ HTTP/1.1" 200 OK
I think the following lines in src/django_browser_reload/views.py
might be the reason for this behaviour:
async def event_stream() -> AsyncGenerator[bytes, None]:
while True:
await asyncio.sleep(PING_DELAY)
yield message("ping", versionId=version_id)
if should_reload_event.is_set():
should_reload_event.clear()
yield message("reload")
I had an issue with reloads working when I had an NGINX proxy in front of DJANGO.
NOTE: web is the django service in my docker-compose file
upstream web {
server web:8000;
}
server {
...
location /__reload__ {
proxy_pass http://web;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header SSL_PROTOCOL https;
add_header X-DEBUG-RELOAD 1 always;
proxy_set_header Host $host;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_set_header Cache-Control 'no-cache';
chunked_transfer_encoding off;
}
location / {
proxy_pass http://web;
...
}
}
3.10.12
4.2.2
1.11.0
Latest Firefox, Latest Chromium
I did as described here, no luck. No JavaScript is injected into the page, no auto reloading of the browser tab happens, no trace back is shown. I also installed pywatchman, as recommened here, no results.
I also tried with this example repo. I followed these instructions. (I had to manually install the daphne package) Then ...
DEBUG=1 python manage.py runserver
logs to the linux console:
Application instance <Task pending name='Task-6' coro=<ASGIStaticFilesHandler.__call__() running at
/home/nils/Django/django-browser-reload-main/example/.venv/lib/python3.10/site-
packages/django/contrib/staticfiles/handlers.py:101> wait_for=<Future pending cb=[Task.task_wakeup()]>> for connection
<WebRequest at 0x7f12954b8670 method=GET uri=/__reload__/events/ clientproto=HTTP/1.1> took too long to shut down
and was killed.
... DEBUG=1 python manage.py runserver --noasgi
logs to the Javascript console in Chrome ...
Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'run-ad-auction'.
Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'join-ad-interest-group'.
Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'browsing-topics'.
127.0.0.1/:15 GET http://127.0.0.1:8000/static/django-browser-reload/reload-listener.js net::ERR_ABORTED 404 (Not
Found)
127.0.0.1/:8 GET http://127.0.0.1:8000/static/main.css net::ERR_ABORTED 404 (Not Found)
... and in Firefox:
Loading failed for the <script> with source “http://127.0.0.1:8000/static/django-browser-reload/reload-listener.js”.
127.0.0.1:8000:15:183
You could be more specific about "where" to place it in the MIDDLEWARE. A newcomer won't know about the default ordering, and the default Django project doesn't explicitly list GZipMiddleware.
Awesome project!
Hi Adam,
I'm trying to get django-browser-reload work with Tailwind CSS, and I'm almost there. However, I noticed a weird lag happening sporadically after I edit HTML code - the page reloads and shows the "No server response" and then reloads again and shows the working page. I guess that's because the reloader tries to fetch a page while the Django server is restarting. Please see the attached video. The behavior I'm describing happened in the second part.
So I was wondering if it's possible to implement a check that the development server is back before reloading a page?
PS: Thanks for the package!
No response
4.0.3
1.3.0
Chrome
When using asgi for django channels page requests do not respond - result is pending and then fail after stall. Have had to uninstall this module due to this error.
Are you aware of the problem?
3.9.5
4.0
main
Hey Adam,
Saw this on your blog (via the Django subreddit) and came here to see how you'd ended up doing things - mostly to see how you'd solved some of the thorny issues related to cancelling the SSE's WSGI request on client hang-up (because I have a similar package and I had to do some hacks!) ... and actually I don't know how in the world you've done it, but done it you have, kudos (I'd love to know which bit is solving it, if you're feeling generous at any point)
Anyway, trying to set it up to explore the hang-up situation, I encountered the following exception:
File "/path/.direnv/python-3.9.5/lib/python3.9/site-packages/django/utils/autoreload.py", line 644, in run_with_reloader
start_django(reloader, main_func, *args, **kwargs)
File "/path/.direnv/python-3.9.5/lib/python3.9/site-packages/django/utils/autoreload.py", line 629, in start_django
reloader.run(django_main_thread)
File "/path/.direnv/python-3.9.5/lib/python3.9/site-packages/django/utils/autoreload.py", line 334, in run
autoreload_started.send(sender=self)
File "/path/.direnv/python-3.9.5/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 170, in send
return [
File "/path/.direnv/python-3.9.5/lib/python3.9/site-packages/django/dispatch/dispatcher.py", line 171, in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
File "/path/.direnv/python-3.9.5/src/django-browser-reload/src/django_browser_reload/views.py", line 62, in on_autoreload_started
for directory in jinja_template_directories():
File "/path/.direnv/python-3.9.5/src/django-browser-reload/src/django_browser_reload/views.py", line 41, in jinja_template_directories
from django.template.backends.jinja2 import Jinja2
File "/path/.direnv/python-3.9.5/lib/python3.9/site-packages/django/template/backends/jinja2.py", line 3, in <module>
import jinja2
ModuleNotFoundError: No module named 'jinja2'
Naturally it's easy enough to resolve (installed jinja2), but thought you might want to know.
3.10.4
4.0
1.3.0
I carefully installed django-browser-reload and it has some unexpected behaviour with my project.
I decided to build your example project to find the issue, and the problem is the same within it.
Everything works as expected when I change and save a template file, I can see the changes occur in the browser.
But when I'm working with a view file, the server is actually reloaded when I save the file (which is something I expect):
/workspaces/dbr/example/core/views.py changed, reloading.
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
May 05, 2022 - 09:21:44
Django version 3.2.13, using settings 'example.settings'
Starting development server at http://127.0.0.1:8001/
Quit the server with CONTROL-C.
However, django-browser-reload seems to do nothing at this time, hence I see no change in my browser.
Plus, once the server restarted, the hot-reloading does not work on templates too.
I need to refresh my browser manually in that case to see the changes made in python files, and make the hot-reloading work again.
Using your example project, changing a thing in a view such as "title": "My Awesome Site"
and then saving, will do nothing.
Maybe a package upgrade broke something.
$ pip freeze
asgiref==3.4.1
Django==4.0.1
django-browser-reload==1.3.0
Jinja2==3.0.3
MarkupSafe==2.0.1
pywatchman==1.4.1
sqlparse==0.4.2
Thanks for your time.
3.10
4.1.2
1.6.0
Chrome
I use django as front service and my back-end service container in the same container stack.
I have to manage sub path based routing, so I decided to use nginx as a reverse proxy.
But when I change and save template code, The browser never received reload event from server. (and browser just reloaded when the worker long polling was timed out.)
here's my nginx.conf
worker_processes 4;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
location /api/web {
return 302 /api/web/;
}
location /api/web/ {
proxy_pass http://web:8000/;
}
location / {
proxy_pass http://front:80/;
}
}
}
Hope that I can get the solution. thank you! :)
3.10.8
4.1.3
No response
Chromium: Version 107.0.5304.87 (Official Build) Arch Linux (64-bit)
Hi Adam,
Thanks for this awesome and helpful tool.
A problem come when I use it with the runserver_plus
:
python manage.py runserver_plus localhost:8000 --cert-file certs/localhost.crt --key-file certs/localhost.key --nostatic --settings=config.settings.dev
It shows:
127.0.0.1 - - [03/Nov/2022 13:18:13] "GET /static/debug_toolbar/js/utils.js HTTP/1.1" 304 -
Error on request:
Traceback (most recent call last):
File "/home/me/.local/share/virtualenvs/django-starter-xnFyc4Yx/lib/python3.10/site-packages/werkzeug/serving.py", line 335, in run_wsgi
execute(self.server.app)
File "/home/me/.local/share/virtualenvs/django-starter-xnFyc4Yx/lib/python3.10/site-packages/werkzeug/serving.py", line 325, in execute
write(data)
File "/home/me/.local/share/virtualenvs/django-starter-xnFyc4Yx/lib/python3.10/site-packages/werkzeug/serving.py", line 298, in write
self.wfile.write(b"\r\n")
File "/usr/lib/python3.10/socketserver.py", line 826, in write
self._sock.sendall(b)
File "/usr/lib/python3.10/ssl.py", line 1237, in sendall
v = self.send(byte_view[count:])
File "/usr/lib/python3.10/ssl.py", line 1206, in send
return self._sslobj.write(data)
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:2396)
When I remove the django_browser_reload
from the INSTALLED_APPS, the problem disappear.
Django version: 4.1.3
Python version: 3.10.8 (main, Oct 13 2022, 21:13:48) [GCC 12.2.0] [x86_64-Linux-5.15.76-1-MANJARO]
My understanding is that django-browser-reload listens for four types of events: server reload, change to Django template, change to Jinja template, change to static asset.
I really enjoy django-browser-reload, but have started using Parcel to build static assets. Its watch
command provides hot module replacement. As you might guess, the issue is that if I use both django-browser-reload and parcel watch, the page reloads twice when a static asset changes. To avoid this, I can disable Parcel's reloading, but then I lose its superfast HMR (it can hot reload CSS stylesheets without requiring a full page reload).
Thus, it seems to me that it might be useful to have a way of telling django-browser-reload to ignore some types of events. In my specific case, I would simply disconnect it from static asset changes. Thanks!
Hi,
I'll start by saying this project is wonderful but if for some reason you accidentally run this in production you'll end up with a completely broken asgi event loop. The browser reload code seems to hog the event loop even after a request is closed. For synchronous servers it seems to be less of an issue but with the asgi
The logs will show the following
socket.send() raised exception
and then the worker will timeout after hanging for 10-15 seconds. It would be great to have either a warning if the browser middleware is running or maybe detect if we're using the none dev server and throw a warning that it may block the event loop
There may also be an additional problem where socket connections arent properly being closed after a page is refreshed?
@kezabelle's django-livereloadish does this by restoring these key pieces of state after reload. It serializes the values into sessionStorage
and restores them on page load.
I think this behaviour would be valuable to add here. Probably a good idea to add one at a time.
On my DB Buddy project I'm seeing many reloads for a single file changes. It looks like watchman is signalling the same file changing repeatedly.
Maybe something needs changing in this project, or we need to add debounce logic.
The browser will cache static assets so they may not update for users. There's no easy way aorund this in JS that I can see, but users can open devtools and disable caching.
location.reload()
can maybe do a hard reload on Firefox: https://twitter.com/AdamChainz/status/1471150134503346182
At least we could mention to open devtools.
This should be possible by telling the reloader to also watch static asset directories, with the autoreload_started
signal plus an extension of the file_changed
receiver.
Safari may be re-adding SharedWorker
support: https://bugs.webkit.org/show_bug.cgi?id=149850
Until then, we could possibly work with a plain Worker
(?) and ensure there's only one instance by communicating between tabs with a BroadcastChannel
.
3.9.10
4.0.2
1.3.0
Did an update on django-tailwind from 2.x to 3.1.1 and also changed from browser-sync to django-browser-reload. Followed the update instructions and compared all steps to a previously updated project without any problems.
But this time the browser just does not reload on changes. The script-Tag is in the source code of the page. Tailwind start does recognize the updated html or css. But the browser does not reload. No GET request to update the site is fired.
Do you have any idea where I can look for the problem?
Do you planning to safari support for this library?
3.12.0
4.2.6
1.12.0
No response
I have already described the behavior in the next issue: adamchainz/django-htmx#381
3.10
4.1
1.6.0
EDGE 103.0.1264.77 (Official build) (64-bit)
When I change .py files, the reload works as expected. But when I change html template files, inside the template folder of an app, or any other place, the reload is not triggered. Neither is the runserver reload, so it might have to do something with Django. But if there is a fix to make it work, every time we change HTML templates, it would be great. I am using jinja2 templates, and I made sure that the reload code is injected (but not that that could be the issue, because the reload is triggered, as I said, when .py files are changed). I tried several things inside DJANGO, but none of them worked.
Thanks a lot,
3.11.6
4.2.1
1.12.1
Firefox, Chrome
I have followed the Readme's installation. The script is inserted correctly, as I can see it in the Inspector. But I always get the following errors when I run python manage.py runserver
:
GET
http://127.0.0.1:8000/static/django-browser-reload/reload-listener.js [HTTP/1.1 404 Not Found 15ms]
Loading failed for the <script> with source “http://127.0.0.1:8000/static/django-browser-reload/reload-listener.js”.
I tried to run the example, it's working fine. The funny thing is that hot reloading on my own project works after running the example. So I guess there is a problem with creating the staticfiles. Maybe I overlooked something?
Since the view's request never finishes, there are no log messages to indicate connection. Add some, to help debug issues like #68 .
No response
No response
No response
Hi Adam,
I'm using the below with AutoHotKey to quickly refresh my browser via a hotkey. It's Windows specific though (although I bet there's alternatives for Mac and Linux).
I find it useful to refresh only at key moments, which this solution offers.
Happy to add a section to your docs if you want, on this solution. Or if you'd prefer, I could just flesh this solution out in a blog, and just reference that. No probs if you feel this is not a good idea :)
Cheers,
Andy.
F2::
; Save current window
WinActivate,ahk_class Chrome_WidgetWin_1
; ---------------------------------------
; Refresh Chrome
Process, Exist, chrome.exe
If(ErrorLevel) {
WinActivate, ahk_pid %ErrorLevel%
Send {F5}
}
; ---------------------------------------
The existing Django-specific logic, some of which is reused from DTL, can be somewhat duplicated for Jinja backends.
If the view crashes, the reloader can't reload on Django's error page.
This is because the script tag is not on the error page.
Perhaps we need to change to the same method django-debug-toolbar uses: a middleware that inserts itself before </body>
.
Hi,
I read in Django documentation that there's a way to mark a middleware as unused at startup. And it is completelly skipped by Django. I'm refering to [https://docs.djangoproject.com/en/4.0/topics/http/middleware/#marking-middleware-as-unused](this entry in the doc).
Maybe this would be useful here when DEBUG=False ?
Thanks for this project.
~=3.10.5
4.2.7
1.12.1
Chrome, Safari
Warning: StreamingHttpResponse must consume synchronous iterators in order to serve them asynchronously. Use an asynchronous iterator instead.
My application does not explicitly use StreamingHttpResponse or FileResponse in any of its views and I still keep getting this warning every time my application starts. The application is served under ASGI using Uvicorn. Any suggestions how do I get rid of this warning?
I have narrowed down that django-browser-reload is the one that might be potentially causing this warning for me. Any help is appreciated.
3.10.6
4.1.2
1.6.0
Chrome, Firefox, Safari
Dear Adam, it is me again (#68). Sorry to open this issue again, but I wanted to let you know that me problem is back.
When I startet a new project everything worked fine. Until now. I did not work on this project for a few weeks and when I now updated wagtail, django and django-tailwind I noticed that the reload stopped working again.
I spend serval hours debugging yesterday, but was not able to find the problem. But I figured out that the route "/reload/events/" seems to be the problem. Not exactly the route as the url and view are working and send a 200 http-code, but no pings are sent.
Broken project (same picture on url 127.0.0.1:8000):
Do you have any ideas what could prevent that the ping events are send? I can see them on views.py, but they do not arrive at the browser.
I totally understand if you close this straight away as we already spent time on this not finding an answer.
Thanks and beste Regards, Thomas
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.