changeset 776540959eac in www.tryton.org:default
details: https://hg.tryton.org/www.tryton.org?cmd=changeset&node=776540959eac
description:
Include critical CSS to landing pages and load CSS asynchronously
issue11469
review413111003
diffstat:
app.py | 41 +++++++++++++++++++++++++++++++++++++++--
critical-css/Dockerfile | 21 +++++++++++++++++++++
critical-css/critical.sh | 33 +++++++++++++++++++++++++++++++++
docker-compose.yml | 14 ++++++++++++++
templates/layout.html | 9 ++++++++-
5 files changed, 115 insertions(+), 3 deletions(-)
diffs (196 lines):
diff -r db7156b455ed -r 776540959eac app.py
--- a/app.py Sat May 07 18:37:47 2022 +0200
+++ b/app.py Sat May 14 10:01:44 2022 +0200
@@ -13,7 +13,7 @@
from http import HTTPStatus
from logging.handlers import SMTPHandler
from operator import attrgetter
-from random import sample, shuffle
+from random import choice, sample, shuffle
from urllib.parse import urljoin, urlparse
import requests
@@ -61,6 +61,8 @@
('SISalp', [(45.903956, 6.099937), (43.132028, 5.935532)]),
('Virtual Things', [(48.13585, 11.577415), (50.775116, 6.083565)]),
]
+CRITICAL_CSS_DIR = os.environ.get('CRITICAL_CSS')
+CRITICAL_CSS_COOKIE = 'critical-css'
cache = Cache(config={'CACHE_TYPE': 'simple'})
if os.environ.get('MEMCACHED'):
@@ -121,7 +123,11 @@
def cache_key_prefix_view():
scheme = 'https' if request.is_secure else 'http'
- return 'view/%s/%s' % (scheme, request.path)
+ if not request.cookies.get('critical-css'):
+ return 'view/%s/%s/%s' % (
+ scheme, request.path, critical_css(timestamp=True))
+ else:
+ return 'view/%s/%s' % (scheme, request.path)
LinkHeader = namedtuple(
@@ -216,6 +222,32 @@
return dict(url_for_canonical=url_for_canonical)
+def critical_css(timestamp=False):
+ if (CRITICAL_CSS_DIR
+ and request.endpoint
+ and not request.cookies.get(CRITICAL_CSS_COOKIE)):
+ file = os.path.join(CRITICAL_CSS_DIR, request.endpoint + '.css')
+ if os.path.exists(file):
+ if timestamp:
+ return int(os.path.getmtime(file))
+ else:
+ return open(file, 'r').read()
+
+
[email protected]_request
+def add_critical_css_cookie(response):
+ if (CRITICAL_CSS_DIR
+ and response.mimetype == 'text/html'
+ and not request.cookies.get(CRITICAL_CSS_COOKIE)):
+ response.set_cookie(CRITICAL_CSS_COOKIE, '1')
+ return response
+
+
[email protected]_processor
+def inject_critical_css():
+ return dict(critical_css=critical_css)
+
+
@cache.memoize(timeout=365 * 24 * 60 * 60)
def dominant_color(path):
if app.debug:
@@ -523,6 +555,8 @@
@cache.cached(key_prefix=cache_key_prefix_view)
@add_links(PRECONNECT_HEADERS + JS_LINK_HEADERS + CSS_LINK_HEADERS)
def success_story(story):
+ if story == '_':
+ story = choice(CASES).name
cases = [c for c in CASES if c.story or c.name == story]
try:
next_case = cases[(cases.index(story) + 1) % len(cases)]
@@ -578,6 +612,9 @@
@cache.cached(key_prefix=cache_key_prefix_view)
@add_links(PRECONNECT_HEADERS + JS_LINK_HEADERS + CSS_LINK_HEADERS)
def event(event):
+ if event == '_':
+ event = 'layout'
+
class Day:
def __init__(self, date, *events, location=None, full=False):
if not isinstance(date, datetime.date):
diff -r db7156b455ed -r 776540959eac critical-css/Dockerfile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/critical-css/Dockerfile Sat May 14 10:01:44 2022 +0200
@@ -0,0 +1,21 @@
+from node:15
+LABEL maintainer="Tryton <[email protected]>" \
+ org.label-schema.name="Tryton" \
+ org.label-schema.url="http://www.tryton.org/" \
+ org.label-schema.vendor="Tryton"
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ libasound2 \
+ libatk-bridge2.0 \
+ libgtk-3-0 \
+ libnss3 \
+ libx11-xcb1 \
+ libxss1 \
+ libxtst6 \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN npm install -g critical
+
+COPY critical.sh /
+CMD ["/critical.sh"]
diff -r db7156b455ed -r 776540959eac critical-css/critical.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/critical-css/critical.sh Sat May 14 10:01:44 2022 +0200
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+: ${OUTPUT:='/tmp'}
+: ${SITE:='localhost'}
+
+for page in \
+ "/ index" \
+ "/success-stories success_stories" \
+ "/success_stories/_ success_story" \
+ "/download download" \
+ "/forum forum" \
+ "/presentations presentations" \
+ "/events/_ event" \
+ "/contribute contribute" \
+ "/develop develop" \
+ "/develop/guidelines/code guidelines_code" \
+ "/develop/guidelines/documentation guidelines_documentation" \
+ "/develop/guidelines/help-text guidelines_documentation_help" \
+ "/develop/guidelines/howto guidelines_documentation_howto" \
+ "/foundation foundation" \
+ "/supporters supporters" \
+ "/donate donate" \
+ "/service-providers service_providers" \
+ "/service-providers/start service_providers_start" \
+ "/not_found not_found"
+do
+ set -- ${page}
+ critical http://${SITE}${1} > "${OUTPUT}/${2}.css"
+done
+
+tail -f /dev/null
diff -r db7156b455ed -r 776540959eac docker-compose.yml
--- a/docker-compose.yml Sat May 07 18:37:47 2022 +0200
+++ b/docker-compose.yml Sat May 14 10:01:44 2022 +0200
@@ -7,6 +7,9 @@
- website.env
environment:
- MEMCACHED=memcached
+ - CRITICAL_CSS=/critical-css
+ volumes:
+ - critical-css:/critical-css
ports:
- "127.0.0.1:5000:5000"
restart: unless-stopped
@@ -18,3 +21,14 @@
ports:
- "127.0.0.1:11211:11211"
restart: unless-stopped
+ critical-css:
+ build: critical-css
+ environment:
+ - OUTPUT=/critical-css
+ - SITE=website:5000
+ volumes:
+ - critical-css:/critical-css
+ depends_on:
+ - website
+volumes:
+ critical-css:
diff -r db7156b455ed -r 776540959eac templates/layout.html
--- a/templates/layout.html Sat May 07 18:37:47 2022 +0200
+++ b/templates/layout.html Sat May 14 10:01:44 2022 +0200
@@ -36,8 +36,15 @@
{% endif %}
{% block style %}
- <link rel="stylesheet" href="{{ url_for('static',
filename='css/main.css') }}"/>
+ {% set css = critical_css() %}
+ {% if css %}
+ <style type="text/css">
+ {{ css|safe }}
+ </style>
+ {% endif %}
+ <link rel="preload" href="{{ url_for('static',
filename='css/main.css') }}" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript>
+ <link rel="stylesheet" href="{{ url_for('static',
filename='css/main.css') }}"/>
<link rel="stylesheet" href="{{ url_for('static',
filename='css/noscript.css') }}"/>
</noscript>
{% endblock style %}