New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document best practices for serving frontend app with frontend routing #372
Comments
Honestly, the best practice there would be to not have django serve static files. |
Another option is to expose a My impression, though, is that you wanted Whitenoise to be used as middleware only and not appear anywhere in an app except for |
@merwok thank you for the response! Did I misinterpret the Whitenoise documentation? It seemed to me to imply "sometimes Whitenoise is actually better than setting up Nginx yourself, unless you are an expert". Based on the SO posts I linked to, there are many people who
(Note that all of those describe me.) |
Can this be achieved by directly using Whitenoise with a Django wsgi application instead of as middleware, as in this SO answer?
The |
That is what the doc says! And I (just a user of whitenoise note, not a maintainer) do agree with it for django static files. |
I think I came up with a decent solution, leveraging the way WhiteNoise middleware manages its own configuration. views.py:
urls.py:
settings.py
Please comment on whether this is reasonable for production! Thank you. |
When I say "reasonable in production", please know that I understand you ideally don't want a Python Really hoping a Whitenoise developer can comment. Thank you. |
If anyone comes across this, you can create a custom middleware that directs to your SPA's routes in your app that extends WhiteNoise as so:
Then, in your
With this middleware, you don't have to add ANYTHING to your
The obvious drawback to this: if your frontend refers to a I suppose you could prevent Django from serving your |
If you want to use the idea in my last comment, use this:
This excludes routes like |
Honestly I think this functionality makes a great case for Whitenoise as a project. I would much rather implement this in Python than figure out the Nginx config mini-language. I know Nginx is used all over the world and it's probably very easy to figure this out from documentation, but I don't see why we should have to. |
If you want to serve the same HTML file at multiple URL's, or even a catch-all URL, use plain Django to do that. I think it's out of scope for Whitenoise, whose focus is on serving static files which have single URL's. For example, you can write catch-all-paths routing like so: from django.urls import path
from example.core.views import frontend_index
urlpatterns = [
path("", frontend_index),
path("<path:path>", frontend_index),
] And then write a view that serves a pre-built from django.conf import settings
from django.http import FileResponse
from django.views.decorators.http import require_GET
@require_GET
def frontend_index(request, path=""):
index_file = (settings.BASE_DIR / "frontend" / "index.html").open("rb")
return FileResponse(index_file) There's no need to invoke Whitenoise to serve a file within Django, nor for whitenoise to provide a "serve" function. It's probably better to use a Django template for For more examples on serving a few arbitrary files with vanilla Django see my favicons post. |
Python Version
3.9.5
Django Version
4.0.2
Package Version
6.0.0
Description
There are many SO posts in which folks ask "How do I configure Django to serve my
index.html
when I visit routes handled by a frontend router?" (such asreact-router
,react-router-dom
, or Angular's router). For example, when I visitmyDjangoURL.com/app/frontendRoute
, how do I serve a file inapp/build/index.html
that loads a React/Angular app with a browser-based router that handles the/frontendRoute
route?This, this, this, and this all have answers that suggest configuring Django wildcard URLs/paths and returning something like
django.shortcuts.render(request,'index.html')
ordjango.views.generic.TemplateView
. Of coursedjango.contrib.staticfiles.views.serve
is not available in production (whendjango.conf.settings.DEBUG
isFalse
), but everyone asking this question really wants a function likeserve
, and not a function likerender
(maybe the implementation of these functions is similar enough that it doesn't matter, but the function names suggest something is wrong). "Serving" one single static file as a rendered template is probably okay performance-wise if Whitenoise is managing and serving all the built dependencies linked to inindex.html
.I think it creates a few problems, though:
django.conf.settings.TEMPLATES
, where it doesn't belong, possibly causing template name conflicts (because this build folder may not be managed in the same way as a Python app)render
might cause weird behavior considering Javascript frameworks might use some of the same syntax as Django's/Jinja's templating language (e.g.{{variablename}}
might cause a templating/rendering error).index.html
file would not be a version-hashed copy in the static folder, which could fail to update in caches somewhere downstream, defeating the purpose of Whitenoise's versioning efforts for this one file.Whitenoise already supports some "interface sugar" by serving an "index" file (
WHITENOISE_INDEX_FILE = True
in Django) when the static file root is served. Considering the proliferation of frontend routing (evidenced by the StackOverflow posts I linked to above), I think you should expose a frontend routing interface to be used in Django's settings. I think this interface could look something like the following:that automatically adds a catchall route that serves
index.html
for any route starting with'/app/
or
The interface would probably need some way to both include and exclude certain routes/filepaths, and Whitenoise might want to add a quick check to ensure none of these routes conflict with existing static content routes (and if so, maybe it automatically changes file and directory names in the
STATIC_ROOT
folder so that static content can still be served without this issue).I don't 100% understand how Whitenoise does its thing, but it makes the case for replacing Nginx unless you know how to configure everything according the best practices. This reverse-proxying configuration seems like a very easy concern compared to everything else Whitenoise does, and I think it seems wrong for users (like me) to set up Nginx for the sole purpose of it having config options to allow frontend routing.
If this is already possible in a first-class supported way using Django/Whitenoise, please close the issue but please explain what I'm missing (and what the others on the SO posts are missing). Please note that if this is supported, I don't think it's clear from the documentation.
The text was updated successfully, but these errors were encountered: