From 656e29c72b8bd478dfde1734b8686df727144ad2 Mon Sep 17 00:00:00 2001 From: David Larlet Date: Tue, 16 Jan 2024 17:41:38 -0500 Subject: [PATCH 1/3] Use custom storage instead of django-compressor --- .gitignore | 1 + pyproject.toml | 1 - umap/settings/base.py | 13 +-- umap/settings/local.py.sample | 3 - umap/templates/base.html | 8 +- umap/templates/umap/about_summary.html | 8 +- umap/templates/umap/content.html | 6 +- umap/templates/umap/css.html | 36 ++++---- umap/templates/umap/js.html | 111 +++++++++++-------------- umap/templates/umap/map_detail.html | 6 +- umap/tests/settings.py | 1 - umap/utils.py | 51 ++++++++++++ 12 files changed, 140 insertions(+), 105 deletions(-) diff --git a/.gitignore b/.gitignore index efb609d9..5e16b3ce 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ site/* node_modules umap.conf data +static ### Python ### # Byte-compiled / optimized / DLL files diff --git a/pyproject.toml b/pyproject.toml index c8c80e93..3fa6d9e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,6 @@ classifiers = [ dependencies = [ "Django==4.2", "django-agnocomplete==2.2.0", - "django-compressor==4.3.1", "django-environ==0.10.0", "django-probes==1.7.0", "Pillow==10.0.1", diff --git a/umap/settings/base.py b/umap/settings/base.py index 7437f416..b890d7fc 100644 --- a/umap/settings/base.py +++ b/umap/settings/base.py @@ -119,7 +119,6 @@ INSTALLED_APPS = ( "django.contrib.gis", "django_probes", "umap", - "compressor", "social_django", # See https://github.com/peopledoc/django-agnocomplete/commit/26eda2dfa4a2f8a805ca2ea19a0c504b9d773a1c # Django does not find the app config in the default place, so the app is not loaded @@ -163,9 +162,16 @@ MEDIA_ROOT = os.path.join("uploads") STATICFILES_FINDERS = [ "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder", - "compressor.finders.CompressorFinder", ] STATICFILES_DIRS = [] # May be extended when using UMAP_CUSTOM_STATICS +STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": "umap.utils.UmapManifestStaticFilesStorage", + }, +} # ============================================================================= # Templates @@ -262,9 +268,6 @@ LEAFLET_ZOOM = env.int("LEAFLET_ZOOM", default=6) # ============================================================================= # Third party app settings # ============================================================================= -COMPRESS_ENABLED = True -COMPRESS_OFFLINE = True - LOGIN_URL = "login" SOCIAL_AUTH_LOGIN_REDIRECT_URL = "/login/popup/end/" diff --git a/umap/settings/local.py.sample b/umap/settings/local.py.sample index 10e725ab..0fe412c8 100644 --- a/umap/settings/local.py.sample +++ b/umap/settings/local.py.sample @@ -29,9 +29,6 @@ DATABASES = { } } -COMPRESS_ENABLED = False -COMPRESS_OFFLINE = True - LANGUAGE_CODE = "en" # Set to False if login into django account should not be possible. You can diff --git a/umap/templates/base.html b/umap/templates/base.html index 97007244..50e83fac 100644 --- a/umap/templates/base.html +++ b/umap/templates/base.html @@ -1,4 +1,4 @@ -{% load compress umap_tags i18n %} +{% load umap_tags i18n static %} @@ -17,13 +17,13 @@ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> {# See https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs #} + href="{% static 'umap/favicons/apple-touch-icon.png' %}"> diff --git a/umap/templates/umap/about_summary.html b/umap/templates/umap/about_summary.html index 870047eb..b95bb3a3 100644 --- a/umap/templates/umap/about_summary.html +++ b/umap/templates/umap/about_summary.html @@ -1,9 +1,9 @@ -{% load i18n %} +{% load i18n static %}
@@ -13,7 +13,7 @@
@@ -29,7 +29,7 @@
diff --git a/umap/templates/umap/content.html b/umap/templates/umap/content.html index 1019bd6b..a9daf056 100644 --- a/umap/templates/umap/content.html +++ b/umap/templates/umap/content.html @@ -1,12 +1,10 @@ {% extends "base.html" %} -{% load umap_tags compress i18n %} +{% load umap_tags i18n %} {% block body_class %} content {% endblock body_class %} {% block extra_head %} - {% compress css %} - {% umap_css %} - {% endcompress css %} + {% umap_css %} {% umap_js %} {% endblock extra_head %} {% block header %} diff --git a/umap/templates/umap/css.html b/umap/templates/umap/css.html index 120ff967..5d91e589 100644 --- a/umap/templates/umap/css.html +++ b/umap/templates/umap/css.html @@ -1,28 +1,30 @@ +{% load static %} + + href="{% static 'umap/vendors/leaflet/leaflet.css' %}" /> + href="{% static 'umap/vendors/markercluster/MarkerCluster.css' %}" /> + href="{% static 'umap/vendors/markercluster/MarkerCluster.Default.css' %}" /> + href="{% static 'umap/vendors/editinosm/Leaflet.EditInOSM.css' %}" /> + href="{% static 'umap/vendors/minimap/Control.MiniMap.css' %}" /> + href="{% static 'umap/vendors/contextmenu/leaflet.contextmenu.css' %}" /> + href="{% static 'umap/vendors/toolbar/leaflet.toolbar.css' %}" /> + href="{% static 'umap/vendors/measurable/Leaflet.Measurable.css' %}" /> + href="{% static 'umap/vendors/fullscreen/leaflet.fullscreen.css' %}" /> + href="{% static 'umap/vendors/locatecontrol/L.Control.Locate.css' %}" /> - - - - - - + href="{% static 'umap/vendors/iconlayers/iconLayers.css' %}" /> + + + + + + diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html index 235f4a51..4a76c41b 100644 --- a/umap/templates/umap/js.html +++ b/umap/templates/umap/js.html @@ -1,62 +1,49 @@ -{% load compress %} -{% compress js %} - - - - - - - - - - - - - - - - - - - - - - - - - - - -{% endcompress %} -{% if locale %}{% endif %} -{% compress js %} - - - - - - - - - - - - - - - - - - - -{% endcompress %} +{% load static %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{% if locale %}{% endif %}{# TODO: handle dynamic locale! #} + + + + + + + + + + + + + + + + + + + diff --git a/umap/templates/umap/map_detail.html b/umap/templates/umap/map_detail.html index 25f927e7..42000f4a 100644 --- a/umap/templates/umap/map_detail.html +++ b/umap/templates/umap/map_detail.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load umap_tags compress i18n %} +{% load umap_tags i18n %} {% block head_title %} {{ map.name }} - {{ SITE_NAME }} {% endblock head_title %} @@ -7,9 +7,7 @@ map_detail {% endblock body_class %} {% block extra_head %} - {% compress css %} - {% umap_css %} - {% endcompress %} + {% umap_css %} {% umap_js locale=locale %} {% if object.share_status != object.PUBLIC %}{% endif %} {% endblock extra_head %} diff --git a/umap/tests/settings.py b/umap/tests/settings.py index 37a72c5f..e1105fa9 100644 --- a/umap/tests/settings.py +++ b/umap/tests/settings.py @@ -3,7 +3,6 @@ import os from umap.settings.base import * # pylint: disable=W0614,W0401 SECRET_KEY = "justfortests" -COMPRESS_ENABLED = False FROM_EMAIL = "test@test.org" EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" diff --git a/umap/utils.py b/umap/utils.py index 2a51fe4e..a18f567d 100644 --- a/umap/utils.py +++ b/umap/utils.py @@ -2,6 +2,7 @@ import gzip import os from django.conf import settings +from django.contrib.staticfiles.storage import ManifestStaticFilesStorage from django.urls import URLPattern, URLResolver, get_resolver @@ -162,3 +163,53 @@ def merge_features(reference: list, latest: list, incoming: list): merged.append(item) return merged + + +class UmapManifestStaticFilesStorage(ManifestStaticFilesStorage): + support_js_module_import_aggregation = True + + # We remove `;` at the end of all regexps to match our prettier config. + _js_module_import_aggregation_patterns = ( + "*.js", + ( + ( + ( + r"""(?Pimport(?s:(?P[\s\{].*?))""" + r"""\s*from\s*['"](?P[\.\/].*?)["']\s*)""" + ), + 'import%(import)s from "%(url)s"\n', + ), + ( + ( + r"""(?Pexport(?s:(?P[\s\{].*?))""" + r"""\s*from\s*["'](?P[\.\/].*?)["']\s*)""" + ), + 'export%(exports)s from "%(url)s"\n', + ), + ( + r"""(?Pimport\s*['"](?P[\.\/].*?)["']\s*)""", + 'import"%(url)s"\n', + ), + ( + r"""(?Pimport\(["'](?P.*?)["']\))""", + """import("%(url)s")""", + ), + ), + ) + + # https://github.com/django/django/blob/0fcee1676c7f14bb08e2cc662898dee56d9cf207↩ + # /django/contrib/staticfiles/storage.py#L78C5-L105C6 + patterns = ( + ( + "*.css", + ( + r"""(?Purl\(['"]{0,1}\s*(?P.*?)["']{0,1}\))""", + ( + r"""(?P@import\s*["']\s*(?P.*?)["'])""", + """@import url("%(url)s")""", + ), + # Remove CSS source map rewriting + ), + ), + # Remove JS source map rewriting + ) From 1b8e6164eda18bd46ddc217f8a9af111d9280228 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 17 Jan 2024 16:36:17 +0100 Subject: [PATCH 2/3] fix: use dynamic path for locale javascript --- umap/templates/umap/js.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html index 4a76c41b..5ef342ab 100644 --- a/umap/templates/umap/js.html +++ b/umap/templates/umap/js.html @@ -27,7 +27,11 @@ -{% if locale %}{% endif %}{# TODO: handle dynamic locale! #} +{% if locale %} + {% with 'umap/locale/'|add:locale|add:'.js' as path %} + + {% endwith %} +{% endif %} From 96ae7ddbc7638bd610aa1f79743248c7e0a79588 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Wed, 17 Jan 2024 18:42:46 +0100 Subject: [PATCH 3/3] chore: deactivate custom statics manager for test by default And add one file that run it and check all js files are loaded. --- umap/templates/umap/js.html | 2 +- umap/tests/integration/test_statics.py | 43 ++++++++++++++++++++++++++ umap/tests/settings.py | 3 ++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 umap/tests/integration/test_statics.py diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html index 5ef342ab..62df6bab 100644 --- a/umap/templates/umap/js.html +++ b/umap/templates/umap/js.html @@ -28,7 +28,7 @@ {% if locale %} - {% with 'umap/locale/'|add:locale|add:'.js' as path %} + {% with "umap/locale/"|add:locale|add:".js" as path %} {% endwith %} {% endif %} diff --git a/umap/tests/integration/test_statics.py b/umap/tests/integration/test_statics.py new file mode 100644 index 00000000..657609b1 --- /dev/null +++ b/umap/tests/integration/test_statics.py @@ -0,0 +1,43 @@ +import re +import shutil +import tempfile + +import pytest +from django.core.management import call_command +from django.utils.translation import override +from playwright.sync_api import expect + + +@pytest.fixture +def staticfiles(settings): + static_root = tempfile.mkdtemp(prefix="test_static") + settings.STATIC_ROOT = static_root + try: + call_command("collectstatic", "--noinput") + yield + finally: + shutil.rmtree(static_root) + + +def test_javascript_have_been_loaded( + map, live_server, datalayer, page, settings, staticfiles +): + settings.STORAGES["staticfiles"][ + "BACKEND" + ] = "umap.utils.UmapManifestStaticFilesStorage" + datalayer.settings["displayOnLoad"] = False + datalayer.save() + map.settings["properties"]["defaultView"] = "latest" + map.save() + with override("fr"): + url = f"{live_server.url}{map.get_absolute_url()}" + assert "/fr/" in url + page.goto(url) + # Hash is defined, so map is initialized + expect(page).to_have_url(re.compile(r".*#7/48\..+/13\..+")) + expect(page).to_have_url(re.compile(r".*/fr/")) + # Should be in French, so hashed locale file has been loaded correctly + button = page.get_by_text("Voir les calques") + expect(button).to_be_visible() + layers = page.locator(".umap-browse-datalayers li") + expect(layers).to_have_count(1) diff --git a/umap/tests/settings.py b/umap/tests/settings.py index e1105fa9..c79521f0 100644 --- a/umap/tests/settings.py +++ b/umap/tests/settings.py @@ -5,6 +5,9 @@ from umap.settings.base import * # pylint: disable=W0614,W0401 SECRET_KEY = "justfortests" FROM_EMAIL = "test@test.org" EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend" +STORAGES["staticfiles"][ + "BACKEND" +] = "django.contrib.staticfiles.storage.StaticFilesStorage" if os.environ.get("GITHUB_ACTIONS", False) == "true": DATABASES = {