* Compress our own responses The bundle went out uncompressed unless a proxy in front did the work: 933 KB on the wire where 311 KB does, on every first load. Both example proxy configs compress, but that only helps deployments that copied them, and the default should not depend on reading the examples. Hono's middleware, with the proxy routes held back. `/api/blob`, `/api/image`, `/api/ics` and `/api/upload` forward somebody else's bytes under a content-length copied from upstream, and issue #76 was a silent truncation caused by exactly that header disagreeing with its body. Re-encoding them would be safe in principle -- the length is dropped and the response goes out chunked -- but they carry attachments and images that are already compressed, so there is nothing to win and a scar to respect. `/api/events` is listed with them even though Hono already skips text/event-stream by content type, so that changing the push route's type cannot quietly start buffering the stream. `/api/health` is excluded for the opposite reason: at 47 bytes gzip made it 73. Hono's size threshold cannot catch that on its own, because it only applies when a response carries a content-length and `c.json()` does not set one. The other JSON routes stay compressed -- a JMAP response has just as unknown a length and can run to hundreds of kilobytes. Verified against the built image: assets come back gzipped with Vary set, 662 KB to 209 KB; /api/events still returns text/event-stream with no content-encoding and delivered a StateChange while mail was being written; health is 47 bytes either way. No user-visible strings, so no catalogue work. * Word the comment for either side compressing The app compresses its own responses as of the follow-on change, so a note saying the bundle ships uncompressed would be wrong as soon as that lands. nginx passes through what the upstream already encoded rather than re-encoding it -- verified single-encoded with both layers active -- so the directives are correct either way and the comment now says so without asserting which side does the work. * Test compression against a fixture, not the web build The compression tests asked for `/` and asserted a gzipped 200. That passes locally, where `web/dist` is lying around from an earlier build, and fails in CI, which runs `npm test` before `npm run build`: with no bundle the shell route serves the "web build not found" fallback, which is short, plain text and correctly uncompressed. The failure read as compression being broken when the tests were simply depending on a build step that had not run. They now build their own static root in a temp directory and point STATIC_DIR at it, in a separate file so the environment is set before the app module is imported. Checked by moving web/dist aside and running the suite the way CI does.
45 lines
1.5 KiB
Plaintext
45 lines
1.5 KiB
Plaintext
# Example nginx location block for ihasmail behind TLS termination.
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name mail.example.com;
|
|
# ssl_certificate ...; ssl_certificate_key ...;
|
|
|
|
client_max_body_size 60m;
|
|
|
|
# Compression. The bundle is the bulk of first load -- about 933 KB
|
|
# uncompressed against 311 KB gzipped -- and nginx passes through anything
|
|
# the upstream already encoded rather than re-encoding it, so this is
|
|
# correct whether or not ihasmail compresses on its own.
|
|
#
|
|
# text/event-stream is deliberately absent from gzip_types: the push stream
|
|
# must not be compressed or buffered, which is also why proxy_buffering is
|
|
# off below.
|
|
gzip on;
|
|
gzip_vary on;
|
|
gzip_proxied any;
|
|
gzip_comp_level 5;
|
|
gzip_min_length 1024;
|
|
# text/javascript is listed explicitly: ihasmail serves scripts with that
|
|
# type rather than application/javascript, so a conventional gzip_types
|
|
# list compresses the stylesheet and leaves the largest asset alone.
|
|
gzip_types
|
|
application/javascript
|
|
application/json
|
|
application/manifest+json
|
|
image/svg+xml
|
|
text/css
|
|
text/javascript
|
|
text/plain;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:8080;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
# Server-Sent Events (push notifications)
|
|
proxy_buffering off;
|
|
proxy_read_timeout 3600s;
|
|
}
|
|
}
|