UNPKG

@yoot/yoot

Version:

The core library for yoot, providing a CDN-agnostic, chainable API for image URL transformations and adapter integration.

307 lines (213 loc) โ€ข 8.24 kB
<div align="center" style="display:grid;row-gap:0.5rem"> <h1>@yoot/yoot</h1> <p style="font-size:1.25rem;opacity:0.6"> <strong>One API. Any CDN. Full control.</strong> </p> <p style="margin-inline:auto"> A lightweight, flexible, CDN-agnostic image URL builder, <br/>designed with SSR and hydration in mind. </p> <div style="max-width:80ch;margin-inline:auto"> <a href="https://npmjs.com/package/@yoot/yoot"> <img src="https://img.shields.io/npm/v/@yoot/yoot?style=flat-square&logo=npm&logoColor=white" alt="NPM version for @yoot/yoot" /> </a> <a href="https://jsr.io/@yoot/yoot"> <img src="https://img.shields.io/jsr/v/@yoot/yoot?style=flat-square&logo=jsr&logoColor=white" alt="JSR version for @yoot/yoot" /> </a> <a href="https://bundlephobia.com/result?p=@yoot/yoot"> <img src="https://img.shields.io/bundlephobia/minzip/@yoot/yoot?style=flat-square&label=minzipped" alt="Bundle size" /> </a> <img src="https://img.shields.io/badge/TypeScript-%E2%9C%94-blue?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /> <img src="https://img.shields.io/npm/l/@yoot/yoot?style=flat-square" alt="License" /> </div> </div> --- > **TL;DR:** Define image transformations once and apply them across any CDN with a single shared API. --- &nbsp; ## Installation Install this core package along with the CDN [adapters](https://github.com/theisel/yoot#packages) you need: ```bash npm install @yoot/yoot @yoot/shopify @yoot/cloudinary ``` &nbsp; ## Table of contents - [Overview](#overview) - [Installation](#installation) - [Quick Start](#quick-start) - [Resources](#resources) - [Demo](#demo) - [Contributing](#contributing) - [License](#license) &nbsp; ## Overview Build predictable image URLs with a modular, chainable API โ€” designed for reusable, CDN-agnostic image transformations. ### Why `yoot`? - ๐Ÿง  Predictable API โ€” chainable, composable, no surprises. - ๐Ÿงต Presets โ€” define once, reuse everywhere. - ๐Ÿ”„ Portable โ€” safely serialize and hydrate in any SSR framework. - โš™๏ธ Lightweight โ€” zero runtime deps, framework-agnostic (Astro, SvelteKit, etc.). ### Design philosophy - ๐Ÿ’… Layout and delivery only โ€” leave visual effects to CSS. - ๐Ÿงฑ Small, modular adapters โ€” no global config or hidden logic. - ๐Ÿ”Œ Pluggable architecture โ€” choose an adapter or write your own. ### Adapters Adapters translate `yoot` directives into CDN-specific URLs โ€” handling each provider's syntax and features. โž• [See all available adapters](https://github.com/theisel/yoot#packages) &nbsp; ## Installation Install this core library, plus [CDN adapters](https://github.com/theisel/yoot/#available-packages) needed for your project: > Replace `<adapter-name>` with the specific adapter you want to use, e.g. `shopify`, `cloudinary`. ### Node / NPM ```bash npm install @yoot/yoot @yoot/<adapter-name> ``` ### Deno / JSR ```ts import {yoot} from 'jsr:@yoot/yoot'; import adapter from 'jsr:@yoot/<adapter-name>'; ``` ### Browser (importmap) ```html <script type="importmap"> { "imports": { "@yoot/yoot": "https://cdn.jsdelivr.net/npm/@yoot/yoot/+esm", "@yoot/<adapter-name>": "https://cdn.jsdelivr.net/npm/@yoot/<adapter-name>/+esm" } } </script> <script type="module"> import {yoot} from '@yoot/yoot'; import adapter from '@yoot/<adapter-name>'; </script> ``` &nbsp; ## Quick start ### Step 1. Register adapters Do this once per runtime (server/client). Use a bootstrap file: #### Explicit registration ```ts import {registerAdapters} from '@yoot/yoot'; import adapter1 from '@yoot/<adapter-name-1>'; import adapter2 from '@yoot/<adapter-name-2>'; registerAdapters(adapter1, adapter2); ``` #### Auto registration (via side-effect imports) ```ts import '@yoot/<adapter-name>/register'; ``` ### Step 2. Use the API #### Initializing The `yoot` function returns a chainable builder. You can optionally initialize it with an image URL or an object. ```ts import {yoot} from '@yoot/yoot'; // Without arguments const preset = yoot(); // With image URL const preset = yoot('https://...'); // With an object const preset = yoot({ src: 'https://...', alt: 'Alt text', width: 1024, // Optional: intrinsic width height: 1024, // Optional: intrinsic height }); ``` #### Single use ```ts const imgPreset = yoot('https://...').width(1024).aspectRatio(1).format('webp'); // Shortform: yoot('https://...').w(1024).ar(1).fm('webp'); const url = imgPreset.url; // Returns generated URL const attrs = getImgAttrs(imgPreset); // Attributes for `<img>` ``` #### Using presets ##### Create presets ```ts // yoot-presets.ts import {yoot} from '@yoot/yoot'; import {defineSrcSetBuilder, withImgAttrs, withSourceAttrs} from '@yoot/yoot/jsx'; // Or @yoot/yoot/html // Hero presets export const heroPreset = yoot() .width(1024) .aspectRatio(16 / 9) .fit('cover'); export const getHeroImgAttrs = withImgAttrs({loading: 'eager'}); export const getHeroSourceAttrs = withSourceAttrs({ srcSetBuilder: defineSrcSetBuilder({densities: [1, 2, 3]}), }); // Thumbnail presets export const thumbnailPreset = yoot().width(100).aspectRatio(1).fit('cover'); export const getThumbnailImgAttrs = withImgAttrs({loading: 'lazy'}); export const getThumbnailSourceAttrs = withSourceAttrs({ srcSetBuilder: defineSrcSetBuilder({widths: [100, 200, 300]}), }); ``` > See the [API docs](https://github.com/theisel/yoot/tree/main/docs) for all transformation options. ##### Use presets ```ts import {thumbnailPreset, getThumbnailImgAttrs, getThumbnailSourceAttrs} from './yoot-presets.ts'; // With a URL string const thumbnail = thumbnailPreset('https://cdn.example.com/image.jpg'); // Alternatively: thumbnailPreset.src('https://cdn.example.com/image.jpg'); // With an object const thumbnail = thumbnailPreset({ src: 'https://cdn.example.com/image.jpg', alt: 'Alt text', width: 2048, // Intrinsic width height: 2048, // Intrinsic height }); const thumbnailAttrs = getThumbnailImgAttrs(thumbnail); const webpSourceAttrs = getThumbnailSourceAttrs(thumbnail, { type: 'image/webp', // this helper modifies the format to webp }); const jpegSourceAttrs = getThumbnailSourceAttrs(thumbnail, { type: 'image/jpeg', // this helper modifies the format to jpeg }); ``` #### Output markup (JSX/HTML) > **Note:** Use environment-specific imports: > > - Use `@yoot/yoot/jsx` for React, Preact, Solid > - Use `@yoot/yoot/html` for Astro, Svelte, plain HTML ```tsx import {yoot} from '@yoot/yoot'; import {defineSrcSetBuilder, getImgAttrs, getSourceAttrs} from '@yoot/yoot/jsx'; // Or '@yoot/yoot/html' const imgPreset = yoot('https://...').format('png').width(800); const imgAttrs = getImgAttrs(imgPreset); // Example demonstrating that format can be overridden via `type` // and different `srcset` strategies can be used per <source>. const webpSourceAttrs = getSourceAttrs(imgPreset, { type: 'image/webp', // `type` overrides format 'png' media: '(min-width: 800px)', sizes: '(min-width: 800px) 800px, 100vw', srcSetBuilder: defineSrcSetBuilder({widths: [600, 800, 1200]}), }); const jpegSourceAttrs = getSourceAttrs(imgPreset, { type: 'image/jpeg', // `type` overrides format 'png' media: '(max-width: 799px)', sizes: '(max-width: 799px) 100vw', srcSetBuilder: defineSrcSetBuilder({densities: [1, 2, 3]}), }); return ( <picture> <source {...webpSourceAttrs} /> <source {...jpegSourceAttrs} /> <img {...imgAttrs} /> </picture> ); ``` &nbsp; ## Resources - ๐Ÿ“˜ [Read the docs](https://github.com/theisel/yoot/tree/main/docs) - ๐Ÿ” [View examples](https://github.com/theisel/yoot/tree/main/examples) &nbsp; ## Demo Try it live โ€” zero setup: [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/theisel/yoot/tree/main/demo) [![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/sandbox/github/theisel/yoot/tree/main/demo) &nbsp; ## Contributing Found a bug or wish to contribute? [Open an issue](https://github.com/theisel/yoot/issues) or [send a PR](https://github.com/theisel/yoot/blob/main/CONTRIBUTING.md). &nbsp; ## License Licensed under the ISC License.