Proposal: FileSystemFinder and AppDirectoriesFinder shall serve unminimized assets in DEBUG mode

67 vues
Accéder directement au premier message non lu

Jacob Rief

non lue,
23 avr. 2020, 05:09:1323/04/2020
à Django developers (Contributions to Django itself)
When specifying paths to assets like JavaScript files, but also CSS, the Django documentation states: 
Any links to the file in the codebase should point to the compressed version.

This statement however does not properly reflect Django's internal handling of such assets, for instance in
we see, that Django only serves the minimized version of the file, when not in DEBUG mode.

This inconsistent handling of assets can cause other problems for third party apps, if they follow the documentation as show in the first link.
If in their Media definition they refer to the minimized version of a Django asset, say 'admin/js/vendor/jquery/jquery.min.js', then
the automatic sorting does not work anymore in DEBUG mode. If on the other side they refer to 'admin/js/vendor/jquery/jquery.js',
then automatic sorting fails in production. 

There are two solutions to this problem.

Either

The documentation explicitly states that when a Media definition refers to internal Django assets, one must distinguish between the
minimized and unminimized version, just as Django's internal Media definitions do (see code examples above).
This however can easily be forgotten and errors therefore become visible only after deployment.

Or

We rewrite the FileSystemFinder and AppDirectoriesFinder so that in DEBUG mode, Django looks if an unminimized version
of the same asset exists, and if so it then serves that. Doing that automatically is easy, because the general convention is, that the .min
infix is always placed immediately before the .js- or .css file extension.

In many of my projects I therefore use these two alternative finders, which do exactly that:

import os
from django.conf import settings
from django.contrib.staticfiles.finders import (FileSystemFinder as FileSystemFinderBase, AppDirectoriesFinder as AppDirectoriesFinderBase)


class FileSystemFinder(FileSystemFinderBase):
"""
In debug mode, serve /static/any/asset.min.ext as /static/any/asset.ext
"""
locations = []
serve_unminimized = getattr(settings, 'DEBUG', False)

def find_location(self, root, path, prefix=None):
if self.serve_unminimized:
# search for the unminimized version, and if it exists, return it
base, ext = os.path.splitext(path)
base, minext = os.path.splitext(base)
if minext == '.min':
unminimized_path = super().find_location(root, base + ext, prefix)
if unminimized_path:
return unminimized_path
# otherwise proceed with the given one
path = super().find_location(root, path, prefix)
return path


class AppDirectoriesFinder(AppDirectoriesFinderBase):
serve_unminimized = getattr(settings, 'DEBUG', False)

def find_in_app(self, app, path):
matched_path = super().find_in_app(app, path)
if matched_path and self.serve_unminimized:
base, ext = os.path.splitext(matched_path)
base, minext = os.path.splitext(base)
if minext == '.min':
storage = self.storages.get(app, None)
path = base + ext
if storage.exists(path):
path = storage.path(path)
if path:
return path
return matched_path

In my opinion this approach makes Django's internal and 3rd party package code more readable, because it removes the clutter of
case distinction between DEBUG and production mode for each referred JavaScript and CSS asset. It also might be less error prone.


Adam Johnson

non lue,
23 avr. 2020, 15:37:3023/04/2020
à django-d...@googlegroups.com
Maybe we can move to always serving minimized assets with corresponding source maps? I was under the impression this is the "best practice" these days.

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/dd904eeb-a877-48d3-81fa-e72fe71a6735%40googlegroups.com.


--
Adam

Carlton Gibson

non lue,
24 avr. 2020, 01:21:2424/04/2020
à django-d...@googlegroups.com
It seems this thread ties in with the current discussion about static assets. For instance if we were to include a compression step, you’d always just reference the raw assets, these being processed, with source maps if we had that, for production. 

Jacob Rief

non lue,
25 avr. 2020, 15:59:3925/04/2020
à Django developers (Contributions to Django itself)
On Friday, April 24, 2020 at 7:21:24 AM UTC+2, Carlton Gibson wrote:
For instance if we were to include a compression step, you’d always just reference the raw assets, these being processed, with source maps if we had that, for production. 

It certainly is the proper approach to refer to the canonical representation of a file, rather than a transformed one. However in case of JavaScript and CSS assets, tools written in JavaScript (from my point of view) are much more sophisticated, rather than their Python equivalents. Therefore this step usually is performed outside of Django, usually within an npm run ... command. So unless Django embraces npm in order to execute the compile/compress/concatenate/uglify-steps, I don't see a lot of possibilities other than referring to the processed, aka *.min.xyz file.

Carlton Gibson

non lue,
26 avr. 2020, 01:16:1126/04/2020
à Django developers (Contributions to Django itself)

On 25 Apr 2020, at 21:59, Jacob Rief <jacob...@gmail.com> wrote:

So unless Django embraces npm in order to execute the compile/compress/concatenate/uglify-steps, I don't see a lot of possibilities other than referring to the processed, aka *.min.xyz file.

Well, see the other thread but, this kind of thing is exactly what you do with compressor’s COMPRESS_PRECOMPILERS, as I talked about there. 

IF Django is going to incorporate this sort of thing then that kind of flexibility would be necessary. 
Répondre à tous
Répondre à l'auteur
Transférer
0 nouveau message