@major-tanya/itty-compression
v0.2.13
Published
A compression middleware for use with itty-router
Downloads
163
Maintainers
Readme
itty-compression
A work-in-progress, proof-of-concept compression middleware to provide Response Compression for use in itty-router projects.
Probably compatible with a variety of other routers.
Not recommended for production use.
Features
Your choice of algorithm
itty-compression includes:
| Middleware | Algorithm(s) |
|-------------------------|----------------------------|
| brotliCompression | brotli (br) only |
| deflateCompression | deflate only |
| gzipCompression | gzip only |
| negotiatedCompression | brotli (br), gzip, deflate |
What is negotiatedCompression?
negotiatedCompression compares the client's Accept-Encoding header against the list of supported encodings (see
table) and uses the first algorithm both the client and itty-compression can agree on. The priority is as follows:
- brotli (br)
- gzip
- deflate
- no compression
If the client doesn't accept any supported algorithm, the middleware will add the Vary header with the
value Accept-Encoding (or append the value if the header already exists) to inform the client of this capability.
As with the other middlewares, the original request object is needed to read the client's Accept-Encoding header. If
the request is not provided, the Accept-Encoding header isn't set, or no mutually supported algorithm could be
determined, this middleware will function as a no-op instead, returning the input with only the Vary: Accept-Encoding
header added.
No duplicate compression of Responses.
itty-compression won't attempt to compress already compressed
Responses again, be it from other routing steps/middleware or from accidentally duplicating it in the route handling.
Rather small middlewares
While not in the same ballpark as itty-router itself, the middlewares are kept as small as possible, with further
optimisations always on the table.
Current sizes are:
| middleware | size |
|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| brotliCompression | |
|
deflateCompression | |
|
gzipCompression | |
|
negotiatedCompression | |
Typed
itty-compression is entirely written in TypeScript, so it comes with types automatically.
Currently supported compression algorithms:
- brotli (br)
- gzip
- deflate
Vary Header setting
itty-compression will always set the Vary header to include Accept-Encoding, even if the response was not
compressed.
How to use
itty-compression directly depends on Node's zlib via importing node:zlib.
Install with npm install @major-tanya/itty-compression (or your favoured alternative to npm).
Once installed, pick your compression algorithm, or use the flexible negotiatedCompression middleware
(Your Choice of Algorithm).
itty-router v5 with AutoRouter or Router
The freshly released v5 of itty-router includes some more batteries-included routers that allow for some more concise
syntax when using itty-compression. Example based on the
v5 AutoRouter documentation.
Example: negotiatedCompression (replace with your middleware of choice)
import { negotiatedCompression } from 'itty-compression';
import { AutoRouter } from 'itty-router';
const router = AutoRouter({ // using batteries-included AutoRouter
finally: [negotiatedCompression],
});
// const router = Router({ // using the medium Router
// // do not forget to add the json handler for the medium Router before the compression middleware
// finally: [json, negotiatedCompression],
// });
// AutoRouter's integrated json formatter handles this automatically
router.get('/dogs/toto', (request) => ({
name: 'Toto',
breed: 'Cairn Terrier',
color: 'black',
}));
export default router;itty-router v5 with IttyRouter (also itty-router v4)
Example: negotiatedCompression (replace with your middleware of choice)
import { negotiatedCompression } from 'itty-compression';
import { error, IttyRouter, json } from 'itty-router';
// const router = Router(); // only itty-router v4
const router = IttyRouter(); // only itty-router v5
// downstream json middleware handles stringifying
router.get('/dogs/toto', (request) => ({
name: 'Toto',
breed: 'Cairn Terrier',
color: 'black',
}));
export default {
fetch: (request, ...args) => router
// .handle(...args) // only itty-router v4
.fetch(...args) // only itty-router v5
.then(json) // <-- do not forget an appropriate handler here or you may encounter problems with itty-compression
.then((response) => negotiatedCompression(response, request)) // <-- add the compression handler downstream
.catch(error),
};Note: It's important to add the original request in order for itty-compression to be able to respect the
client's Accept-Encoding header. If the request (or the header) is not provided, the compression middleware will
function as a no-op, returning the input with only the Vary header added.
Compatibility & Testing
Known compatible with
Theoretically compatible with any framework/library/router that allows for access to the client request and the in-progress response before it is sent to the client and also supports async middleware.
Goals
- Provide compression for
itty-routersimilar to the middleware provided by compression for Express
TODO
- [ ] More library/framework compatibility data?
- [ ] Code golfing
- [ ] More robust approach to suboptimal inputs
Thanks
- kwhitley for the creation of the ittiest router I've ever seen.
