Skip to content

+server: precompress client assets at build time and serve the variants #3451

Description

@nitedani

Request

Could the default self-hosted +server build gain end-to-end precompression support?

For a Node self-hosted build, the useful outcome is:

  1. vike build emits Brotli (and optionally gzip) variants for eligible files in dist/client/.
  2. The generated production server prefers those variants instead of dynamically encoding the same asset on every request.

This likely needs coordination with Universal Deploy rather than being only a Vike build hook, but Vike is where the user-facing contract should live: Vike creates the client artifact and selects/configures the default production adapter.

This is production-motivated

We reached this while investigating real high-CPU fallout in a Vike production deployment. A fresh current Vike self-hosted install resolves @universal-deploy/node@0.1.9 with srvx@0.11.22, whose default static path dynamically runs Brotli quality 11 for every eligible response. The immediate dependency fix is tracked in universal-deploy#34.

Upgrading to srvx 0.12 is an important safety fix because it moves request-time Brotli to quality 4. But q4 on every cache miss is still repeated work, and quality 4 also produces a larger representation than a build can afford to create once.

On Node 24.14.0, for a representative 126,324-byte minified JavaScript asset:

Brotli quality encode time output size
4 2.7 ms 45,117 bytes
11 157.6 ms 39,489 bytes

The point is not to run q11 on a request. It is to run it once at build time, then serve those 39,489 bytes with no compression CPU on the production request path and with a known Content-Length.

Current end-to-end gap

This means merely installing a Vite compression plugin is not an end-to-end workaround: it can create the files, but the default Vike/Universal Deploy server doesn't probe or select them. Conversely, enabling encodings: true in the server would add a missing stat on every request until the build actually ships variants.

Suggested shape

The exact configuration boundary is open, but the implementation should ideally:

  • Target the client output only (dist/client/), not the server bundle.
  • Precompress compressible text assets above a sensible threshold; skip already-compressed formats and omit a variant when it doesn't reduce size.
  • Use maximum-quality Brotli at build time, with bounded concurrency so a large build doesn't create its own CPU/memory spike. Gzip can be emitted as a compatibility fallback.
  • Enable srvx's precompressed-variant lookup for the generated Node server and prefer disk variants over on-the-fly compression.
  • Decide explicitly whether q4 remains a fallback for files without variants or whether a fully precompressed build uses compress: false.
  • Preserve correct Vary, coding-specific validators, Content-Length, conditional request, and range behavior.
  • Be target-aware: managed platforms/CDNs often handle compression themselves, so this may be a self-hosted Node default or an opt-in rather than an unconditional cost for every deployment target.
  • Cover public-directory files as well as Vite-emitted hashed assets, while keeping configuration available for very large/unusual assets.

An integration test could build a fresh +server app, request a hashed JS asset with Accept-Encoding: br, and assert that the adjacent .br file is served with the correct headers and without creating a request-time Brotli stream.

Related runtime fallbacks

Build-time precompression is the preferred path for Vike-owned static assets. It doesn't replace runtime fallbacks for files that weren't part of the build or for stable dynamic responses:

  • srvx#289 tracks a bounded encoded-representation cache for the static server's on-the-fly fallback.
  • universal-middleware#353 tracks an opt-in representation cache for responses using @universal-middleware/compress.

Those paths are complementary, but precompression is the only one that moves both fast and maximum-quality encoding completely out of production requests for Vike's immutable build assets.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions