npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@uxf/resizer

v14.0.0

Published

UXF Resizer

Readme

@uxf/resizer

npm

On-the-fly image resizing that serves the /generated/... URLs produced by resizerImageUrl (@uxf/core). It ships Next.js App Router route handlers for local development and a standalone HTTP server (uxf-resizer, built on Hono) for self-hosting. Resizing is done with sharp.

When to use

This package serves and generates resized images. It does not build image URLs — that is done client-side by resizerImageUrl from @uxf/core/utils/resizer, which encodes the resize parameters into a /generated/... path.

  • Production — a shared/global resizer service handles the /generated/... requests; you typically do not run this package there.
  • Local development — mount ProxyGET / StaticGET as Next.js route handlers so /generated/... URLs resolve during next dev.
  • Self-hosting — run the uxf-resizer CLI (Hono server on Node) driven by a config file.

Both entry points read the same URL segments (width, height, fit, position, background, trim, quality, target format) and pipe the source image through sharp. Generated files are cached on disk and re-served on subsequent requests.

Installation

yarn add @uxf/resizer --dev

The only runtime dependency is sharp. The standalone server additionally needs hono, @hono/node-server, and yargs — they are not installed transitively, so add them yourself when you use the CLI:

yarn add @uxf/resizer hono @hono/node-server yargs --dev

Node >= 24 is required (route matching uses the built-in URLPattern).

Quick start

Next.js App Router route handlers for local development. Two handlers are exported:

  • ProxyGET — proxies uploaded images from the API and resizes them.
  • StaticGET — resizes static assets (public/ files and Next.js _next/static/media imports).

Folder structure:

src/
    app/
        generated/
            [...path]/
                route.ts    # ProxyGET  → uploaded images
            static/
                [...path]/
                    route.ts    # StaticGET → static images
// src/app/generated/[...path]/route.ts
import { ProxyGET as GET } from "@uxf/resizer";

export { GET };
// src/app/generated/static/[...path]/route.ts
import { StaticGET as GET } from "@uxf/resizer";

export { GET };

Both handlers read their upstream location from environment variables:

# .env.local
NEXT_PUBLIC_FRONTEND_URL=http://127.0.0.1:3000   # StaticGET source (Next.js static media)
NEXT_PUBLIC_API_URL=https://uxf.cz               # ProxyGET source (fetches <API_URL>/upload/...)

API

Exported from the package root (@uxf/resizer):

| Export | Signature | Description | | ----------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ProxyGET | (request: Request) => Promise<Response> | Next.js route handler. Matches /generated/:namespace/:p1/:p2/:filename_..._:extension.:toFormat, fetches the source from ${NEXT_PUBLIC_API_URL}/upload/:namespace/:p1/:p2/:filename.:extension, resizes, caches under the process CWD, and returns the image. | | StaticGET | (request: Request) => Promise<Response> | Next.js route handler. Matches /generated/static/..._:quality/:version/:filename.:extension.:toFormat. Reads local public/:filename.:extension; for _next/static/media/* imports it fetches from ${NEXT_PUBLIC_FRONTEND_URL}. |

Command-line server:

uxf-resizer

Starts a Hono server (via @hono/node-server) on port 3000 that applies the routes from the configuration (see below). Requires the extra dependencies listed under Installation. Responses carry Content-Type, Content-Length and Last-Modified; the server does not emit ETag and does not handle Range or conditional requests — put a cache/CDN in front of it if you need those.

Route parameters

The URL segments understood by every route. They are produced by resizerImageUrl (@uxf/core) and mapped onto sharp options.

| Parameter | Values | Default (falls back to sharp) | | ---------- | ---------------------------------------- | ------------------------------------ | | width | number or x (auto) | undefined (auto) | | height | number or x (auto) | undefined (auto) | | fit | fit code (see below) | cover | | position | position code (see below) | sharp default (centre) | | background | hex (e.g. FFFFFF) or t (transparent) | t when the route has no segment | | trim | number (threshold) or nt (no trim) | no trim | | quality | number (1–100) or x (auto) | sharp default (avif: 50, others: 80) | | toFormat | webp, png, avif, jpg, svg | jpg |

svg is a passthrough — the source file is copied unchanged, without resizing. A route does not have to capture every parameter: a missing fit, position, background, trim or quality falls back to the default in the table.

Fit codes

  • cv: cover
  • f: fill
  • cn: contain
  • in: inside
  • out: outside

Position codes

  • a: attention
  • b: bottom
  • c: centre
  • e: entropy
  • l: left
  • lb: left bottom
  • lt: left top
  • r: right
  • rb: right bottom
  • rt: right top
  • t: top

Server configuration

The uxf-resizer CLI reads its config from .resizer-config.json in the working directory, or from the UXF_RESIZER_CONFIG environment variable (an inline JSON string, which takes precedence). Generated files are written to UXF_RESIZER_GENERATE_PATH (defaults to the process CWD).

The config is an array of { route, source } objects.

  • route is a URLPattern pathname pattern (Node's built-in implementation; the syntax is path-to-regexp v6 compatible): :name, :name(regexp), several parameters per segment (:width(\d+)_:height(\d+)), :name(.*) to capture across slashes. Matching is case-insensitive and captured values are percent-decoded. The first matching route wins.
  • source is the original file location (a local path or an http(s) URL, which is fetched). Every :name is replaced by the captured value; a +, * or ? suffix is accepted and ignored (:filename+ and :filename are equivalent). The domain may itself be a parameter (https://:url/...); a port such as localhost:3000 is left alone.

The legacy Express form :filename(*) is still accepted and rewritten to :filename(.*) with a startup warning — update your configs.

[
    {
        "route": "/generated/static/:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)/:version/:filename(.*).:extension.:toFormat",
        "source": "https://static.example.dev/:filename+.:extension"
    },
    {
        "route": "/generated/:namespace/:p1/:p2/:filename([a-f0-9\\-]+)_:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)_:extension.:toFormat",
        "source": "https://s3.example.dev/:namespace/:p1/:p2/:filename.:extension"
    }
]

resizerGetDefaultConfig(generatedFilesUrl, staticFilesUrl) from @uxf/core/utils/resizer returns exactly this two-route shape.

UXF Basic configuration (deprecated)

Deprecated — use the global resizer for all projects instead.

[
    {
        "route": "/generated/static/:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)/:version/:filename(.*).:extension.:toFormat",
        "source": "https://uxf-base.uxf.dev/:filename+.:extension"
    },
    {
        "route": "/generated/:namespace/:p1/:p2/:filename([a-f0-9\\-]+)_:width(\\d+|x)_:height(\\d+|x)_:fit([a-z]+)_:position([a-z]+)_:background([a-z]+)_:trim([a-z]+)_:quality(\\d+|x)_:extension.:toFormat",
        "source": "https://s3.uxf.dev/${APP_NAME}-${APP_ENV}/:namespace/:p1/:p2/:filename.:extension"
    }
]

Gotchas

  • URLs are built elsewhere. Encode the parameters with resizerImageUrl from @uxf/core/utils/resizer; this package only serves the resulting paths.
  • CLI dependencies are not transitive. hono, @hono/node-server, and yargs are dev dependencies of this package, so a consumer running uxf-resizer must install them explicitly.
  • Parameters are validated only by the route regexps. A value that passes the route but is not a known code (an unknown fit, a non-numeric width) falls back to sharp defaults or makes sharp throw, which is answered with 404.
  • Generated files are cached on disk. Once a variant exists under the output path it is served as-is; delete the cached file to force regeneration.
  • The server listens on a fixed port 3000 and an empty or invalid configuration (including a route URLPattern cannot parse) throws on startup. SIGINT/SIGTERM close the server.
  • quality defaults to sharp's own defaults when set to x (avif ≈ 50, others ≈ 80). Values are expected in the 1–100 range.

Links