Skip to content
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

Dynamic SCRIPT_NAME and compressed assets #1197

Open
bcail opened this issue Jul 13, 2023 · 8 comments
Open

Dynamic SCRIPT_NAME and compressed assets #1197

bcail opened this issue Jul 13, 2023 · 8 comments

Comments

@bcail
Copy link
Contributor

bcail commented Jul 13, 2023

This is using Django 4.2.3, django-compressor 4.4, and gunicorn 20.1.0. I'm trying out the dynamic SCRIPT_NAME feature (PR #876), but I'm having trouble getting it working.

I have a gunicorn app running on localhost:8000, and it's proxied through nginx at /app. Here's the nginx config:

location /app {
       proxy_pass              http://localhost:8000;
       proxy_set_header SCRIPT_NAME /app;
}

I ran the compress command.

When I hit a view on my app, I can see that SCRIPT_NAME is correctly coming through as /app, but the URL to the compressed static file is still just /static/..., without the /app prefix. Shouldn't the URL to the compressed static file be updated with the SCRIPT_NAME prefix?

From my settings file:

STATIC_URL = 'static/'
COMPRESS_ENABLED = True
COMPRESS_OFFLINE = True
COMPRESS_OUTPUT_DIR = ''
@bcail
Copy link
Contributor Author

bcail commented Jul 13, 2023

From PR #876, it looks like I'm supposed to add my own class that dynamically adds the SCRIPT_NAME prefix to the STATIC_URL (and COMPRESS_URL) (or am I supposed to use the LazyScriptNamePrefixedUrl class from the test code)? Should this feature be documented?

@carltongibson
Copy link
Contributor

This looks like you're hitting this issue in Django...

https://code.djangoproject.com/ticket/34028

The long and short is that script name doesn't really work outside of the request-response cycle, so not with compress.

You might need to adjust your static url when running the command (or else find a way of making it work)

@bcail
Copy link
Contributor Author

bcail commented Jul 13, 2023

Thanks, @carltongibson. I actually don't have any static url in the compressed asset itself - this is just an issue with linking to the compressed asset when the response is generated.

I tried adding the LazyScriptNamePrefixedUrl class to my settings.py, and used that for COMPRESS_URL, and now it looks like the URL to the compressed asset does correctly contain the SCRIPT_NAME value.

So it looks like the feature does work, if the user adds a str subclass and uses that in their settings. Should this be added to the documentation?

@carltongibson
Copy link
Contributor

...this is just an issue with linking to the compressed asset when the response is generated.

Following the discussion on the linked Django issue, in this circumstance SRIPT_NAME should be working no? 🤔

Maybe it's an issue with Django, maybe it's a configuration issue, but a minimal reproduce on a fresh project, and a report to Django is likely the way to go.

I don't think it's a compressor issue per se? 🤔 (Using the utility from compressor's test suite looks like patching over any issue, rather than addressing it 😬)

@carltongibson
Copy link
Contributor

carltongibson commented Jul 14, 2023

Reviewing the docs for FORCE_SCRIPT_NAME, SCRIPT_NAME is part of the WSGI environment, rather than an HTTP header, so I think you'd need to set it in your wsgi.py, or gunicorn config, rather than setting it as an HTTP header in Nginx.

https://docs.djangoproject.com/en/4.2/ref/settings/#force-script-name

Update: Although the gunicorn FAQ seems to imply either would be good: https://docs.gunicorn.org/en/stable/faq.html — you'll need to experiment to pin down exactly the behaviour.

@bcail
Copy link
Contributor Author

bcail commented Jul 14, 2023

@carltongibson thanks again for your comments.

Here's a question: if I want to mount my app at different prefixes (eg. /foo and /bar) at the same time (with offline compression and compressed assets served from /foo/static and /bar/static), does compressor support that? If so, how should I configure it (especially the COMPRESS_URL)?

What I'm seeing locally is that if I set COMPRESS_URL to a regular value like /static, the SCRIPT_NAME doesn't get added to the links on the page to the compressed assets. If I make the COMPRESS_URL a dynamic value where I add the SCRIPT_NAME on each call (ie. using the class from the compressor tests), then it works. (This seems to fit with what I see in the PR #876 where the feature was added.)

@carltongibson
Copy link
Contributor

Grr. I'd have to play. (And there's not enough info, or a quick reproduce here, so that I can do that.) I'd reckon per-deploy settings with slight tweaks would do it. (I saw you commented about the offline context on another issue...)

@bcail
Copy link
Contributor Author

bcail commented Jul 14, 2023

Here's a playground project: https://github.com/bcail/dj_playground. I'm running it with: DJANGO_SETTINGS_MODULE=playground.settings gunicorn playground.wsgi:application

Here's my nginx config:

        location /foo/static {
                alias /var/www/playground_static;
        }

        location /bar/static {
                alias /var/www/playground_static;
        }

        location /foo {
                proxy_pass              http://localhost:8000;
                proxy_set_header SCRIPT_NAME /foo;
        }

        location /bar {
                proxy_pass              http://localhost:8000;
                proxy_set_header SCRIPT_NAME /bar;
        }

playground/settings.py has two options for COMPRESS_URL, one commented out. If I use the normal /static value, the compressed asset doesn't work. If I change it to the LazyScriptNamePrefixedUrl value, then the compressed asset works on both /foo/polls and /bar/polls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants