What a page needs to show a photograph at every screen's size, from a
preset of variants with a ladder of widths (Storehouse.Variants): its
src, its srcset, its size, its placeholder. As data, for a JSON API,
or as an <img> (Storehouse.Components.img/1).
Storehouse.Responsive.resolve(file, :photo, sizes: "(min-width: 60rem) 60rem, 100vw")
#=> %Storehouse.Responsive{
# src: "/variants/…/photo-2560-e04b77d1",
# srcset: "/variants/…/photo-640-… 640w, …, /variants/…/photo-2560-… 2400w",
# sizes: "(min-width: 60rem) 60rem, 100vw",
# width: 2400, height: 1600,
# placeholder: "data:image/webp;base64,…", color: "#9a7b76", …}The srcset has the ladder's widths below the original's, then the
original's own (up to the widest step): never a size larger than the
photograph. Each is asked for at its step of the ladder, or the next one
up, so every photograph's sizes are the ladder's, and a CDN keeps few
of them; a step past the original's width gives the original's. Its
width and height are those of the largest, for the page to keep the
room before the image arrives.
It reads no store: the original's width and height are the file's
(Storehouse.store/2 keeps them), its placeholder and colour its
analysis's (Storehouse.Analyzer.Placeholder, ThumbHash, BlurHash).
It encodes as JSON (JSON.Encoder, Jason.Encoder).
Warming
A variant is made the first time it is asked for, and a large original
takes seconds: warm/3 asks for each size once, before the first
visitor does, and warm_later/3 does it out of the request, on the app's
runner. Off unless the app turns it on, in production:
config :storehouse, Storehouse.Responsive, warm: true
Summary
Functions
Whether warming is on: :enabled, else the configured :warm, false
by default, so that development and tests ask no image service.
The src, srcset, size and placeholder of file with preset.
Every URL resolve/3 gives for file with preset, once each: the
sizes to warm.
Makes file's sizes with each of presets before a visitor asks for
them: {:ok, count}, or {:error, {:not_warmed, failed}} with what was
not made and why.
warm/3 out of the request, as a job of the app's runner, when warming
is on (enabled?/1), and nothing when it is off. The original is not
read: the file's width is all it needs. A file's job waiting is not
queued again.
The widths of file's srcset with preset, each with the step of
the ladder it is asked for at: [{width, step}], narrowest first.
Types
@type t() :: %Storehouse.Responsive{ blurhash: String.t() | nil, color: String.t() | nil, height: pos_integer() | nil, placeholder: String.t() | nil, sizes: String.t() | nil, src: String.t(), srcset: String.t(), thumbhash: String.t() | nil, width: pos_integer() | nil }
Functions
Whether warming is on: :enabled, else the configured :warm, false
by default, so that development and tests ask no image service.
@spec resolve(Storehouse.File.t(), atom(), keyword()) :: t()
The src, srcset, size and placeholder of file with preset.
Options
:src- the width ofsrc, for a browser that takes nosrcset(the step of the ladder as wide, or the next one up). The default is the largest.:sizes- thesizesattribute, as given: what the layout's slot for the photograph is, at each screen's width. See the Variants guide.Storehouse.Variants.url/3's, for each URL.
@spec urls(Storehouse.File.t(), atom(), keyword()) :: [String.t()]
Every URL resolve/3 gives for file with preset, once each: the
sizes to warm.
Options
:up_to- the widest step: larger ones are left to be made when asked for (a lightbox's, zoomed in). The default is every one.:src, andStorehouse.Variants.url/3's, as forresolve/3.
@spec warm(Storehouse.File.t(), atom() | [atom()], keyword()) :: {:ok, non_neg_integer()} | {:error, {:not_warmed, [{term(), term()}]}}
Makes file's sizes with each of presets before a visitor asks for
them: {:ok, count}, or {:error, {:not_warmed, failed}} with what was
not made and why.
With a renderer that renders in the app (Storehouse.Renderer.Vix),
each is made with Storehouse.variant/3, in the format a browser of
today is given. With one of URLs (Storehouse.Renderer.Imgproxy), each
URL is asked for, as a browser of today asks: the service renders it and
the CDN in front keeps it. One at a time, so the app's visitors never
wait behind a batch.
It warms when it is called, turned on or not.
Options
:up_toand:src- as forurls/2.:through-:renderor:http. The default is the renderer's::httpasks a variant's URL, through the plug or a CDN, for a renderer in the app that is behind one.:accept- theAcceptheader. The default is a browser's that takes AVIF and WebP.:base_url- put before a URL that is a path, to ask it over HTTP:"https://example.com".:timeout- for each, in milliseconds. The default is 90 seconds.:adapter, andStorehouse.Variants's configuration.
@spec warm_later(Storehouse.File.t(), atom() | [atom()], keyword()) :: :ok | {:error, term()}
warm/3 out of the request, as a job of the app's runner, when warming
is on (enabled?/1), and nothing when it is off. The original is not
read: the file's width is all it needs. A file's job waiting is not
queued again.
On a queue of its own, so that the app's other work never waits behind it, with Oban:
Storehouse.Responsive.warm_later(file, [:photo],
up_to: 3840,
runner: {Storehouse.Runner.Oban, queue: :warm}
)Options
:runner- the runner, in place of the app's (Storehouse.Runner).:enabled- in place of the configured:warm.warm/3's.
@spec widths(Storehouse.File.t(), atom(), keyword()) :: [ {pos_integer(), pos_integer()} ]
The widths of file's srcset with preset, each with the step of
the ladder it is asked for at: [{width, step}], narrowest first.
# A photograph 1500 wide, a ladder of 640, 1280 and 1920:
Storehouse.Responsive.widths(file, :photo)
#=> [{640, 640}, {1280, 1280}, {1500, 1920}]For a file whose width is not known, the ladder's.