Switch to offline compressed assets
This commit is contained in:
parent
3c64795f7a
commit
0fc99c2a0c
9 changed files with 117 additions and 24 deletions
37
articles/compressor.py
Normal file
37
articles/compressor.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
import itertools
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class DummyArticleWithCode:
|
||||
has_code = True
|
||||
|
||||
|
||||
class DummyArticleNoCode:
|
||||
has_code = False
|
||||
|
||||
|
||||
class DummyNonAuthenticatedUser:
|
||||
is_authenticated = False
|
||||
|
||||
|
||||
class DummyAuthenticatedUser:
|
||||
is_authenticated = True
|
||||
|
||||
|
||||
def offline_context():
|
||||
article_possibilities = [None, DummyArticleWithCode(), DummyArticleNoCode()]
|
||||
user_possibilities = [DummyAuthenticatedUser(), DummyNonAuthenticatedUser()]
|
||||
goatcounter_possibilities = [None, settings.GOATCOUNTER_DOMAIN]
|
||||
all_possibilities = [
|
||||
article_possibilities,
|
||||
user_possibilities,
|
||||
goatcounter_possibilities,
|
||||
]
|
||||
for _tuple in itertools.product(*all_possibilities):
|
||||
yield {
|
||||
"STATIC_URL": settings.STATIC_URL,
|
||||
"article": _tuple[0],
|
||||
"user": _tuple[1],
|
||||
"goatcounter_domain": _tuple[2],
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
import random
|
||||
import uuid
|
||||
from functools import cached_property, reduce
|
||||
from functools import cached_property
|
||||
|
||||
import rcssmin
|
||||
import readtime
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
@ -121,6 +122,10 @@ class Article(models.Model):
|
|||
filter(None, map(lambda k: k.strip().lower(), self.keywords.split(",")))
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def get_minified_custom_css(self):
|
||||
return rcssmin.cssmin(self.custom_css)
|
||||
|
||||
def get_admin_url(self):
|
||||
content_type = ContentType.objects.get_for_model(self.__class__)
|
||||
return reverse(
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{% extends 'articles/base.html' %}
|
||||
|
||||
{% block append_css %}
|
||||
<style>
|
||||
{{ article.custom_css }}
|
||||
</style>
|
||||
<style>{{ article.get_minified_custom_css }}</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ article.title }} | {% endblock %}
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
{% extends 'articles/base.html' %}
|
||||
|
||||
{% block append_css %}
|
||||
<style>
|
||||
{{ article.custom_css }}
|
||||
</style>
|
||||
<style>
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
<style>{{ article.get_minified_custom_css }}</style>
|
||||
<style>.pagination{display:flex;justify-content:space-between}</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% endblock %}
|
||||
|
|
|
@ -22,15 +22,10 @@
|
|||
{% if user.is_authenticated %}
|
||||
<link rel="stylesheet" href="{% static "authenticated.css" %}">
|
||||
{% endif %}
|
||||
{% block append_css %}
|
||||
{% endblock %}
|
||||
{% endcompress %}
|
||||
|
||||
{% compress js inline %}
|
||||
{% if user.is_authenticated %}
|
||||
<script src="{% static 'edit-keymap.js' %}" async></script>
|
||||
{% endif %}
|
||||
{% endcompress %}
|
||||
{% block append_css %}
|
||||
{% endblock %}
|
||||
|
||||
{% include "articles/snippets/favicon.html" %}
|
||||
</head>
|
||||
|
@ -60,7 +55,14 @@
|
|||
for ongoing builds <a href="{{ blog_pipelines_url }}">here</a>.
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
{% include "articles/snippets/analytics.html" %}
|
||||
{% compress js inline %}
|
||||
{% if user.is_authenticated %}
|
||||
<script src="{% static 'edit-keymap.js' %}" async defer></script>
|
||||
{% endif %}
|
||||
{% endcompress %}
|
||||
|
||||
</body>
|
||||
{% endspaceless %}
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import uuid
|
||||
|
||||
import pytest
|
||||
from django.core.management import call_command
|
||||
from django.utils import timezone
|
||||
|
||||
from articles.models import Article, User
|
||||
|
@ -43,3 +44,14 @@ def unpublished_article(author: User) -> Article:
|
|||
content="## some draft article markdown\n\n[a draft article link](https://article.com)",
|
||||
draft_key=uuid.uuid4(),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def enable_compressor(settings):
|
||||
settings.COMPRESS_ENABLED = True
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="session")
|
||||
def collect_static():
|
||||
call_command("collectstatic", "--no-input", "--clear")
|
||||
call_command("compress", "--force")
|
||||
|
|
|
@ -39,3 +39,41 @@ def test_save_article_doesnt_change_existing_slug(published_article: Article):
|
|||
published_article.title = "This is a brand new title"
|
||||
published_article.save()
|
||||
assert published_article.slug == original_slug
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_empty_custom_css_minified(published_article):
|
||||
published_article.custom_css = ""
|
||||
assert published_article.get_minified_custom_css == ""
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_simple_custom_css_minified(published_article):
|
||||
published_article.custom_css = ".cls {\n background-color: red;\n}"
|
||||
assert published_article.get_minified_custom_css == ".cls{background-color:red}"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_larger_custom_css_minified(published_article):
|
||||
published_article.custom_css = """\
|
||||
.profile {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.profile img {
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
max-height: 200px;
|
||||
min-height: 100px;
|
||||
border-radius: 10%;
|
||||
padding: 1rem;
|
||||
flex-shrink: 1;
|
||||
flex-grow: 0;
|
||||
padding: 0;
|
||||
}"""
|
||||
assert (
|
||||
published_article.get_minified_custom_css
|
||||
== ".profile{display:flex;justify-content:space-evenly;flex-wrap:wrap}.profile img{max-width:200px;min-width:100px;max-height:200px;min-height:100px;border-radius:10%;padding:1rem;flex-shrink:1;flex-grow:0;padding:0}"
|
||||
)
|
||||
|
|
|
@ -117,6 +117,13 @@ if MEMCACHED_LOCATION:
|
|||
"LOCATION": MEMCACHED_LOCATION,
|
||||
}
|
||||
}
|
||||
else:
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.db.DatabaseCache",
|
||||
"LOCATION": "cache",
|
||||
}
|
||||
}
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
|
@ -203,10 +210,7 @@ GOATCOUNTER_DOMAIN = os.getenv("GOATCOUNTER_DOMAIN")
|
|||
|
||||
LOGIN_URL = "admin:login"
|
||||
|
||||
# ASSETS_AUTO_BUILD = DEBUG
|
||||
# ASSETS_DEBUG = False
|
||||
|
||||
COMPRESS_ENABLED = True
|
||||
# COMPRESS_ENABLED = True # Enable this if you want to force compression during dev
|
||||
COMPRESS_FILTERS = {
|
||||
"css": [
|
||||
"compressor.filters.css_default.CssAbsoluteFilter",
|
||||
|
@ -218,3 +222,6 @@ COMPRESS_FILTERS = {
|
|||
}
|
||||
if DEBUG:
|
||||
COMPRESS_DEBUG_TOGGLE = "nocompress"
|
||||
|
||||
COMPRESS_OFFLINE = True
|
||||
COMPRESS_OFFLINE_CONTEXT = "articles.compressor.offline_context"
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
set -eux
|
||||
yes yes | python manage.py migrate
|
||||
python manage.py collectstatic --noinput --clear
|
||||
python manage.py compress
|
||||
gunicorn blog.wsgi -b 0.0.0.0:8000 --log-file -
|
||||
|
|
Reference in a new issue