perf: self-host Poppins font — eliminate render-blocking Google Fonts

Replace external Google Fonts CSS request (780ms render-blocking) with
self-hosted woff2 files served from /static/fonts/ with 30-day cache.

- 8 woff2 files: Poppins 400/500/600/700 × latin/latin-ext (53KB total)
- Inline @font-face declarations in <style> tag (no external request)
- font-display: swap preserved (no FOIT)
- CSP updated: removed fonts.googleapis.com and fonts.gstatic.com

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-04-07 18:14:55 +02:00
parent 7f56de7974
commit 085eafe503
10 changed files with 22 additions and 9 deletions

8
app.py
View File

@ -793,9 +793,7 @@ def set_security_headers(response):
response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin' response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
response.headers['Permissions-Policy'] = 'camera=(), microphone=(), geolocation=(self)' response.headers['Permissions-Policy'] = 'camera=(), microphone=(), geolocation=(self)'
# Cache static assets (CSS, JS, images, fonts) # Note: static file caching is handled by Nginx (30d), not Flask
if request.path.startswith('/static/'):
response.headers['Cache-Control'] = 'public, max-age=2592000' # 30 days
# Freshness signal for SEO crawlers # Freshness signal for SEO crawlers
if response.content_type and 'text/html' in response.content_type and 'Last-Modified' not in response.headers: if response.content_type and 'text/html' in response.content_type and 'Last-Modified' not in response.headers:
@ -807,9 +805,9 @@ def set_security_headers(response):
csp = ( csp = (
"default-src 'self'; " "default-src 'self'; "
"script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; " "script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; "
"style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com; " "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; "
"img-src 'self' data: https:; " "img-src 'self' data: https:; "
"font-src 'self' https://cdn.jsdelivr.net https://fonts.gstatic.com; " "font-src 'self' https://cdn.jsdelivr.net; "
"frame-src https://www.google.com/maps/; " "frame-src https://www.google.com/maps/; "
"connect-src 'self'" "connect-src 'self'"
) )

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -34,10 +34,25 @@
<!-- Preload critical resources for LCP optimization --> <!-- Preload critical resources for LCP optimization -->
<link rel="preload" href="{{ url_for('static', filename='img/favicon-512.png') }}" as="image"> <link rel="preload" href="{{ url_for('static', filename='img/favicon-512.png') }}" as="image">
<!-- Fonts - Poppins (norda-biznes.info style) --> <!-- Fonts - Poppins (self-hosted, no render-blocking external request) -->
<link rel="preconnect" href="https://fonts.googleapis.com"> <style>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> @font-face { font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap;
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet"> src: url('/static/fonts/poppins-400-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap;
src: url('/static/fonts/poppins-400-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 500; font-display: swap;
src: url('/static/fonts/poppins-500-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 500; font-display: swap;
src: url('/static/fonts/poppins-500-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 600; font-display: swap;
src: url('/static/fonts/poppins-600-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 600; font-display: swap;
src: url('/static/fonts/poppins-600-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 700; font-display: swap;
src: url('/static/fonts/poppins-700-latin-ext.woff2') format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Poppins'; font-style: normal; font-weight: 700; font-display: swap;
src: url('/static/fonts/poppins-700-latin.woff2') format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
</style>
<!-- Styles --> <!-- Styles -->
<style> <style>