Skip to content

fix: add @fastify/compress to reduce bundle transfer size on mobile#158

Open
eusip wants to merge 1 commit intohappier-dev:devfrom
eusip:fix/server-compression
Open

fix: add @fastify/compress to reduce bundle transfer size on mobile#158
eusip wants to merge 1 commit intohappier-dev:devfrom
eusip:fix/server-compression

Conversation

@eusip
Copy link
Copy Markdown

@eusip eusip commented Apr 23, 2026

Problem

The Happier server serves the web UI JS bundle (~19MB) without any compression. On mobile networks this causes the TCP connection to drop mid-transfer. The iOS app surfaces this as:

Server not supported — unexpected response

Fix

Register @fastify/compress globally in startApi() so all HTTP responses are compressed (gzip/zstd) before transmission. This reduces the ~19MB bundle to ~4–5MB on the wire.

app.register(import('@fastify/compress'), { global: true });

The plugin is registered alongside the existing @fastify/cors and @fastify/rate-limit plugins in apps/server/sources/app/api/api.ts, which is the single entry point for both full and light server flavors.

Impact

  • Fixes the iOS "Server not supported" connection drop on mobile networks
  • Benefits all self-hosted deployments — no proxy configuration required
  • No behavioral change on fast connections; compression is transparent

Verification

curl -sI --compressed https://<your-happier-instance> | grep content-encoding
# content-encoding: gzip

Summary by CodeRabbit

  • Improvements
    • API responses now benefit from automatic compression, delivering faster load times and reduced bandwidth consumption.

The server was serving the web UI JS bundle (~19MB) uncompressed. On
mobile networks this caused connections to drop mid-transfer, resulting
in the iOS app showing "Server not supported — unexpected response".

Registers @fastify/compress globally so all responses (including the
static JS bundle) are compressed with gzip/zstd. This fixes the issue
at the server layer for all self-hosted deployments, regardless of
whether they use Caddy, nginx, or any other proxy.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8d01e266-cc6d-4113-9683-94b1436803d5

📥 Commits

Reviewing files that changed from the base of the PR and between 4ee9219 and 287541b.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • apps/server/package.json
  • apps/server/sources/app/api/api.ts

Walkthrough

The changes add HTTP compression support to the Fastify server by introducing the @fastify/compress dependency and registering the compression middleware globally during API startup.

Changes

Cohort / File(s) Summary
Fastify Compression Setup
apps/server/package.json, apps/server/sources/app/api/api.ts
Added @fastify/compress dependency (v8.3.1) and registered compression middleware in global mode for HTTP response compression.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding @fastify/compress to reduce bundle transfer size on mobile networks, which directly matches the primary objective of the PR.
Description check ✅ Passed The PR description covers the problem statement, the fix implementation, impact analysis, and verification steps. While the template's 'How to test' section uses numbered steps, the description provides a verification command that accomplishes the same purpose. All critical information is present and well-structured.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 23, 2026

Greptile Summary

Registers @fastify/compress globally in startApi() to compress HTTP responses before transmission, reducing the ~19 MB JS bundle to ~4–5 MB on the wire and fixing the iOS "Server not supported" TCP drop on mobile. The plugin is correctly placed after cors / rate-limit and before route registration, so all Fastify-handled routes benefit without any per-route changes.

Confidence Score: 5/5

Safe to merge — the change is minimal, correct, and all remaining feedback is a non-blocking performance suggestion

Only a P2 observation about per-request re-compression overhead remains; no correctness, security, or reliability issues were found

No files require special attention

Important Files Changed

Filename Overview
apps/server/sources/app/api/api.ts Registers @fastify/compress globally after cors and rate-limit; plugin is correctly placed before route registration so all responses will be compressed
apps/server/package.json Adds @fastify/compress@8.3.1 (exact-pinned, consistent with @fastify/swagger and @sentry/node); also reorders @sentry/node and @socket.io/redis-streams-adapter alphabetically
yarn.lock Adds lock entries for @fastify/compress and its transitive deps (peek-stream, pumpify, duplexify, through2, stream-shift); lock changes look consistent with the declared dependency

Sequence Diagram

sequenceDiagram
    participant Client as iOS / Mobile Client
    participant Fastify as Fastify Server
    participant Compress as @fastify/compress
    participant StaticHandler as enableServeUi

    Client->>Fastify: GET / (Accept-Encoding: gzip)
    Fastify->>Compress: onSend hook (check Accept-Encoding)
    Fastify->>StaticHandler: route handler
    StaticHandler->>StaticHandler: readFile(index.html / bundle.js)
    StaticHandler-->>Fastify: reply.send(Buffer ~19MB)
    Fastify->>Compress: compress buffer (gzip)
    Compress-->>Fastify: compressed payload ~4-5MB
    Fastify-->>Client: 200 OK (Content-Encoding: gzip, ~4-5MB)

    Client->>Fastify: GET /v1/auth (Accept-Encoding: gzip)
    Fastify->>Compress: onSend hook
    Fastify-->>Client: 200 OK (Content-Encoding: gzip, small JSON)
Loading

Comments Outside Diff (1)

  1. apps/server/sources/app/api/utils/enableServeUi.ts, line 30-83 (link)

    P2 Per-request re-compression of large static assets

    readFile loads the entire file into a Buffer and then @fastify/compress compresses it in-process on every request. For the ~19 MB JS bundle this means ~19 MB allocated for the raw content plus another pass to produce the compressed output on every cold fetch — with no caching of the compressed result.

    This works correctly and solves the mobile drop, but it adds CPU pressure proportional to concurrent downloads. A lower-cost alternative is to pre-compress the bundle at build time (emitting .gz / .br siblings) and serve the pre-compressed file directly, or to cache the compressed Buffer keyed by file path after the first compression. Not required to merge, but worth a follow-up ticket if the server serves the bundle to many concurrent mobile clients.

Reviews (1): Last reviewed commit: "fix: add @fastify/compress to reduce bun..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant