v6.7.3: faster loading, and pages search engines can read
The bundles carried all thirteen translations at once and a page fetched them a third time as raw source; each page now loads only its own language. Alongside that: JavaScript is minified, the eight stylesheets are served as one file, the QR scanner is fetched after the app is up instead of on every visit, Inter ships once rather than five copies of the same file, and Font Awesome is subset to the 82 icons this app draws instead of all 2468. 1.85 MB across 43 requests becomes under 700 KB across 33. On mobile the page starts drawing in 1.6 s instead of 6.3 s and is usable in 4.5 s instead of 11 s. Pages also carry their text in the HTML now. Everything was drawn by JavaScript into an empty div, so crawlers saw correct metadata around nothing, and twelve of the thirteen language pages had never been shown to anyone. The documentation is published under /docs/ with a new FAQ, and unknown addresses return a real 404. Separately: the localized shells were served with the year-long immutable cache header meant for static assets, which pinned anyone who opened /de/ or /ru/ to that build. The header is fixed and the service worker refreshes what it cached. Claude-Session: https://claude.ai/code/session_014KjzTXxrhzYoDDWChYQ4u2
This commit is contained in:
+25
-31
@@ -1,7 +1,7 @@
|
||||
# nginx config for serving SecureBit.chat (static PWA) on Fly.io.
|
||||
# Mirrors the behavior of the Apache .htaccess: correct JS MIME for ES modules
|
||||
# (.jsx/.mjs), no-cache for the app shell / service worker / versioning files,
|
||||
# long-immutable cache for hashed/static assets, security headers, SPA fallback.
|
||||
# long-immutable cache for hashed/static assets, security headers, honest 404s.
|
||||
|
||||
worker_processes auto;
|
||||
events { worker_connections 1024; }
|
||||
@@ -40,10 +40,16 @@ http {
|
||||
# one level avoids nginx's header-inheritance reset between blocks.
|
||||
map $uri $sb_cache {
|
||||
default "public, max-age=31536000, immutable";
|
||||
~^/index\.html$ "no-cache, no-store, must-revalidate";
|
||||
~^/$ "no-cache, no-store, must-revalidate";
|
||||
# Quoted because nginx reads a bare { as the start of a block: an unquoted
|
||||
# regex with a repetition count fails the config at boot, not at request time.
|
||||
# Both anchors matter. These patterns used to be ~^/index\.html$ and ~^/$,
|
||||
# which match the English shell and nothing else — so /de/, /ru/index.html and
|
||||
# every other localized page fell through to the one-year immutable default
|
||||
# below. A visitor who opened a localized page kept that exact HTML, and the
|
||||
# ?v= stamps inside it, for a year: no release could reach them.
|
||||
"~^/([a-z]{2}/)?(index\.html)?$" "no-cache, no-store, must-revalidate";
|
||||
"~^/([a-z]{2}/)?manifest\.json$" "no-cache, no-store, must-revalidate";
|
||||
~^/sw\.js$ "no-cache, no-store, must-revalidate";
|
||||
~^/manifest\.json$ "no-cache, no-store, must-revalidate";
|
||||
~^/meta\.json$ "no-cache, no-store, must-revalidate";
|
||||
# Operator ICE/TURN config: must never be cached long, or the browser
|
||||
# locks onto a stale server list (default was max-age=1y immutable).
|
||||
@@ -65,28 +71,6 @@ http {
|
||||
~^/sitemap\.xml$ "public, max-age=3600";
|
||||
}
|
||||
|
||||
# Which app shell an unmatched navigation falls back to. A request under /de/ must
|
||||
# land on /de/index.html, not the English one — otherwise every deep link into a
|
||||
# localized page silently switches language. The entries between the markers are
|
||||
# rewritten by scripts/build-i18n.js from locales/site.json.
|
||||
map $uri $sb_shell {
|
||||
default /index.html;
|
||||
# BEGIN generated locale shells
|
||||
~^/de/ /de/index.html;
|
||||
~^/fr/ /fr/index.html;
|
||||
~^/es/ /es/index.html;
|
||||
~^/uk/ /uk/index.html;
|
||||
~^/ru/ /ru/index.html;
|
||||
~^/zh/ /zh/index.html;
|
||||
~^/ko/ /ko/index.html;
|
||||
~^/hi/ /hi/index.html;
|
||||
~^/ar/ /ar/index.html;
|
||||
~^/he/ /he/index.html;
|
||||
~^/fa/ /fa/index.html;
|
||||
~^/ur/ /ur/index.html;
|
||||
# END generated locale shells
|
||||
}
|
||||
|
||||
# CDN-Cache-Control is read by Cloudflare (and other CDNs) *independently* of the
|
||||
# browser Cache-Control above, and takes precedence at the edge. We force "no-store"
|
||||
# for the app shell, service worker and version files so a CDN can never serve a
|
||||
@@ -95,10 +79,11 @@ http {
|
||||
# so immutable hashed assets keep being edge-cached normally for performance.
|
||||
map $uri $sb_cdn_cache {
|
||||
default "";
|
||||
~^/index\.html$ "no-store";
|
||||
~^/$ "no-store";
|
||||
# Same anchoring fix as above: Cloudflare was edge-caching the localized
|
||||
# shells for a year too.
|
||||
"~^/([a-z]{2}/)?(index\.html)?$" "no-store";
|
||||
"~^/([a-z]{2}/)?manifest\.json$" "no-store";
|
||||
~^/sw\.js$ "no-store";
|
||||
~^/manifest\.json$ "no-store";
|
||||
~^/meta\.json$ "no-store";
|
||||
~^/config/ice-servers\.js$ "no-store";
|
||||
~^/dist/ "no-store";
|
||||
@@ -135,10 +120,19 @@ http {
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# SPA-style fallback so unknown navigation routes still load the app shell.
|
||||
# The app has no client-side routes: every real address is either a file, the
|
||||
# root, or a locale directory, and $uri/ resolves /de/ through the index
|
||||
# directive. So an unknown path is a typo or a scanner probe, not a route.
|
||||
# Answering those with the app shell under 200 OK made every one of them an
|
||||
# indexable "page" — an infinite URL space that Search Console reports as soft
|
||||
# 404s and duplicates, spending crawl budget on addresses that do not exist.
|
||||
location / {
|
||||
try_files $uri $uri/ $sb_shell;
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# A real page for a real 404, rather than nginx's own. Served from the root, so
|
||||
# the block above resolves it as an ordinary file; the 404 status is preserved.
|
||||
error_page 404 /404.html;
|
||||
}
|
||||
|
||||
# One canonical hostname. www.securebit.chat has its own Fly certificate (so
|
||||
|
||||
Reference in New Issue
Block a user