Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Set node
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x

- name: Setup
run: npm i -g @antfu/ni
Expand All @@ -37,7 +37,10 @@ jobs:

strategy:
matrix:
node: [18, 20]
# 20 is the floor (matches h3's `engines`) and has no zstd in
# `node:zlib`; 22 and 24 do (added in 22.15 / 23.8), so both the zstd
# path and its fallback get exercised.
node: [20, 22, 24]
h3: [1, 2]
os: [ubuntu-latest, macos-latest]
fail-fast: false
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Set node
uses: actions/setup-node@v3
with:
node-version: 18.x
node-version: 20.x

- run: npx changelogithub
env:
Expand Down
47 changes: 40 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

## Features

✔️  **Zlib Compression:** You can use zlib compression (brotli, gzip and deflate)
✔️  **Zlib Compression:** You can use zlib compression (brotli, gzip, deflate and opt-in zstd)

✔️  **Stream Compression:** You can use stream compressions (gzip, deflate and opt-in brotli)
✔️  **Stream Compression:** You can use stream compressions (gzip, deflate and opt-in brotli / zstd)

✔️  **Compression Detection:** It uses the best compression which is accepted

Expand Down Expand Up @@ -116,6 +116,36 @@ await useBrotliCompressionStream(event, response)
> The brotli stream is flushed per chunk (`BROTLI_OPERATION_FLUSH`) so that streamed responses
> stay streamed. With zlib's defaults brotli buffers the whole body until the source closes.

## Zstd

Zstd is supported on both paths, and is opt-in for a different reason than brotli: `node:zlib`
only gained zstd in **Node 22.15.0** (and 23.8.0). Enabling it by default would make the
negotiated `Content-Encoding` depend on the Node version the app happens to run on, which is a
poor thing to discover in production. The package itself only requires Node >= 20.11.1, the same
floor as h3.

```ts
app.use(compression({ zstd: true })) // zstd, then brotli, then gzip, then deflate
app.use(compressionStream({ zstd: true, brotli: true })) // same order, streamed

await useCompression(event, response, { zstd: true })
```

Behaviour on a runtime without zstd:

- with the `zstd: true` **flag**, zstd is skipped during negotiation and the next accepted
encoding is used — no error, no special-casing needed in your code
- when **forced** (`compression('zstd')`, `useZstdCompression`), a `TypeError` naming the
required Node version is thrown, because silently sending something else would be worse

Branch on it yourself with the exported predicate:

```ts
import { isZstdSupported } from 'h3-compression'

app.use(compression({ zstd: isZstdSupported() }))
```

## Nuxt 3 & 4

If you want to use it in Nuxt you can define a nitro plugin.
Expand Down Expand Up @@ -175,21 +205,24 @@ H3-compression has a concept of composable utilities that accept `event` (from `
- `useGZipCompression(event, response)`
- `useDeflateCompression(event, response)`
- `useBrotliCompression(event, response)`
- `useCompression(event, response)`
- `useZstdCompression(event, response)`  – requires Node >= 22.15
- `useCompression(event, response, options?)`  – pass `{ zstd: true }` to include zstd

#### Stream Compression

- `useGZipCompressionStream(event, response)`
- `useDeflateCompressionStream(event, response)`
- `useBrotliCompressionStream(event, response)`
- `useCompressionStream(event, response, options?)`  – pass `{ brotli: true }` to include brotli
- `useZstdCompressionStream(event, response)`  – requires Node >= 22.15
- `useCompressionStream(event, response, options?)`  – pass `{ brotli: true }` / `{ zstd: true }`

#### Middleware (h3 v2)

- `compression(method?)`  – middleware using zlib (brotli, gzip, deflate)
- `compressionStream(method | options?)`  – stream middleware (gzip, deflate, opt-in brotli)
- `compressResponse(event, value, method?)`  – low-level helper returning a compressed `Response`
- `compression(method | options?)`  – middleware using zlib (brotli, gzip, deflate, opt-in zstd)
- `compressionStream(method | options?)`  – stream middleware (gzip, deflate, opt-in brotli / zstd)
- `compressResponse(event, value, method?, options?)`  – low-level helper returning a compressed `Response`
- `compressResponseStream(event, value, method?, options?)`  – low-level stream helper returning a compressed `Response`
- `isZstdSupported()`  – whether the runtime can compress with zstd

## Sponsors

Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"type": "module",
"version": "1.0.1",
"packageManager": "pnpm@8.7.0",
"description": "Adds compression to h3 request (brotli, gzip, deflate)",
"description": "Adds compression to h3 request (brotli, gzip, deflate, zstd)",
"author": {
"name": "Gregor Becker",
"email": "gregor@codedredd.de"
Expand All @@ -22,6 +22,7 @@
"gzip",
"brotli",
"deflate",
"zstd",
"compression"
],
"sideEffects": false,
Expand All @@ -48,6 +49,9 @@
"LICENSE",
"README.md"
],
"engines": {
"node": ">=20.11.1"
},
"scripts": {
"build": "unbuild",
"dev": "unbuild --stub",
Expand All @@ -66,7 +70,7 @@
"@antfu/eslint-config": "^0.41.0",
"@antfu/ni": "^0.21.6",
"@antfu/utils": "^0.7.6",
"@types/node": "^20.5.7",
"@types/node": "^22.20.1",
"@types/supertest": "^2.0.12",
"@vitest/coverage-v8": "^0.34.3",
"bumpp": "^9.2.0",
Expand Down
88 changes: 67 additions & 21 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading