Compress our own responses (#288)
* 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.
This commit is contained in:
+11
-6
@@ -6,17 +6,22 @@ server {
|
||||
|
||||
client_max_body_size 60m;
|
||||
|
||||
# ihasmail serves its bundle uncompressed and leaves this to the proxy, so
|
||||
# without these directives the browser downloads about 915 KB where 307 KB
|
||||
# would do. text/event-stream is deliberately absent from gzip_types: the
|
||||
# push stream must not be compressed or buffered.
|
||||
# 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;
|
||||
# ihasmail serves scripts as text/javascript, so listing only
|
||||
# application/javascript silently leaves the largest asset uncompressed.
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user