Skip to content

Commit

Permalink
Add cache warming docs; iterate colours
Browse files Browse the repository at this point in the history
  • Loading branch information
colepeters committed Mar 7, 2024
1 parent 9c1f003 commit 985205a
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 34 deletions.
126 changes: 106 additions & 20 deletions app/docs/md/enhance-ui/image.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: '@enhance/image'

<doc-callout mark="🧑‍🔬">

Enhance Image is currently in beta! We expect to introduce some minor changes to the [configuration options](#configuration) before launching the stable version of this component.
**Enhance Image is currently in beta!** We anticipate introducing some minor changes to the [configuration options](#configuration) and [cache warming](#cache-warming) before launching the stable version of this component.

</doc-callout>

Expand Down Expand Up @@ -61,18 +61,30 @@ The above configuration will tell the image transformation service that, for eve

In more detail:

#### `widths` (optional)
<dl>

<dt><code>widths</code> (optional)</dt>
<dd>

The `widths` option takes an array of pixel widths, specified as unitless integers. A variant of your source image will be generated for every width specified, with a height corresponding to the source image's intrinsic aspect ratio. The default widths are 2400, 1200, and 800.

#### `format` (optional)
</dd>

<dt><code>format</code> (optional)</dt>
<dd>

The format option takes one of the following format strings: `webp`, `avif`, `jxl`, `jpeg`, `png`, or `gif`. Generated images will be returned in the given format. `webp` is recommended for compatibility and performance, and is the default option. [Read more about image formats on the web here.](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types)

#### `quality` (optional)
</dd>

<dt><code>quality</code> (optional)</dt>
<dd>

The quality setting takes a number between 0–100. Generated images will be returned at the quality level specified. It's best to choose a quality level that results in the smallest possible file size without significant degradation in image quality — this can vary based on the content of the images being processed, and you may need to experiment a bit to find the best setting based on your content. The quality option defaults to 80.

</dd>
</dl>

### Single File Component

To use the SFC, first import it from the package, and then re-export it to make it available to your app:
Expand All @@ -92,15 +104,24 @@ You can then use the SFC in your pages and other elements, for example:

The SFC accepts the following attributes, which are proxies for [the same named attributes of the Image element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes):

#### `src`
<dl>

<dt><code>src</code></dt>
<dd>

The path to the source image in your project.

#### `alt`
</dd>

<dt><code>alt</code></dt>
<dd>

A description of the image. For images that are purely decorative, this can be an empty string.

#### `sizes` (optional)
</dd>

<dt><code>sizes</code> (optional)</dt>
<dd>

A comma separated list of source size descriptors, plus a fallback value.

Expand All @@ -119,18 +140,89 @@ There are a few important caveats to keep in mind when using the `sizes` attribu

The `sizes` attribute has a default value of `100vw`.

#### `width` and `height` (optional)
</dd>

<dt><code>width</code> and <code>height</code> (optional)</dt>
<dd>

Each of these attributes takes a unitless length which describes the intrinsic (not the rendered) width and height of your source image. The browser will use this to compute the aspect ratio of your image, which will help to avoid [Cumulative Layout Shift](https://web.dev/cls/). These properties can also be set via CSS; note that if they are specified as HTML attributes, any CSS styles targeting your images’ width and height will override those attributes.

#### `loading` (optional)
</dd>

<dt><code>loading</code> (optional)</dt>
<dd>

A string of either `'eager'` or `'lazy'`. Using the `'lazy'` value will instruct the browser to defer loading the image until it determines it will be needed. The default value, as per the HTML image element spec, is `'eager'` (which will instruct the browser to load the image source as soon as the image element is processed). [Read further on MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/loading).

#### `fetchpriority` (optional)
</dd>

<dt><code>fetchpriority</code> (optional)</dt>
<dd>

A string of either `'high'`, `'low'`, or `'auto`. Provides a hint to the browser as to the relative priority of fetching an image’s source, relative to other images. The default is `'auto'`.

</dd>
</dl>

## Cache warming

The transformation service that powers Enhance Image creates variants of your images on demand — that is, when they are requested by the browser of an end user visiting your site. These images are cached for performance once created. However, the initial network request for each image variant (before it’s cached) can take longer to return than may be ideal, especially for larger or complex images.

For this reason, Enhance Image includes a script for ‘warming’ your image caches, which ensures that each image is cached (and will thus be loaded as quickly as possible) before an end user ever requests it.

This script is available to run via [`npx`](https://docs.npmjs.com/cli/v10/commands/npx), as follows:

```shell
npx @enhance/image warm --directory /public/images --domain https://example.org
```

The script takes two arguments:

<dl>

<dt><code>--directory</code></dt>
<dd class="mbe0">

The path to the directory in your project containing the images you’ll be using with Enhance Image, for which you’d like variants (and caches) generated, e.g. `/public/images`. This path **must start with `/public`**. The directory will be scanned recursively, so only the top most directory needs to be provided.

</dd>

<dt><code>--domain</code></dt>
<dd>

The URL of your application’s deployment, e.g. `https://example.org` or `https://image-4ab.begin.app`.

</dd>

</dl>

Note: The warming script may take some time to complete its initial run. On subsequent runs, images that have already had their caches warmed in previous runs will be skipped, making subsequent runs much faster.

### Integrating with GitHub Actions

We recommend integrating the cache warming script with [GitHub Actions](https://docs.github.com/en/actions) in order to automate this functionality. (The script can be run from your terminal, however this can be easily forgotten on subsequent deployments.)

A GitHub Action workflow for running this script could look (in part) like this:

```yaml
name: CI

on: [push]

jobs:
deploy:
name: Deploy (production)
#

steps:
#

- name: Warm image caches
run: npx @enhance/image warm --directory /public/images --domain https://example.org
```
This will ensure that your image caches are warmed each time a production deploy is made.
## Examples
### Basic usage
Expand Down Expand Up @@ -205,17 +297,15 @@ export default async function Preflight ({ req }) {

## Usage notes

### `sizes` attribute

The `sizes` attribute used by Enhance Image is simply a proxy for [`HTMLImageElement.sizes`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes). This `sizes` attribute, as specified by [the HTML living standard](https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-sizes), can be tough to wrap your head around in certain cases. However, we believe it’s beneficial to remain close to the web platform, as it avoids the need to learn brittle abstractions and thus keeps knowledge reusable. As such, when you learn how to work with Enhance Image’s `sizes` attribute, you’re actually learning how to work with the Image element’s `sizes` attribute — warts and all.

Below are several considerations to keep in mind when using `sizes`.

#### Order of media conditions
### Order of media conditions

When multiple media conditions are listed, the first media condition that matches the viewport will be used, and all others will be ignored. Therefore, if using `min-width` media queries, these should be written in descending order, e.g. `(min-width: 72em) 25vw, (min-width: 48em) 50vw`. Conversely, `max-width` media queries should be written in ascending order.

#### Using absolute lengths
### Using absolute lengths

When deciding which of your generated images to use for a given media condition in `sizes`, the browser evaluates multiple factors — not just the viewport width, but also the current display’s pixel density, and potentially other factors as determined by the particular browser.

Expand All @@ -227,14 +317,10 @@ For this reason, it’s often advantageous (and makes for a clearer implementati

For further details, see [MDN’s documentation on the `sizes` attribute](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes), or their [documentation of the `img` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img).

### Performance

You may notice a delay in loading a transformed image the first time it’s requested by your browser. This delay should only occur with the first request; subsequent requests should be cached and thus load much faster. We’re actively working on improving performance for image loading — see the roadmap below.

## Roadmap

The following updates are either planned or currently in active development:

- Update the image transformation service to pregenerate image transformations ahead of runtime to improve performance
- Private S3 bucket support
- Support for handling image assets via private S3 buckets
- Streamline image cache warming

48 changes: 36 additions & 12 deletions app/elements/doc/content.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,28 @@ export default function DocContent({ html }) {
}
:host > ::slotted([slot]) > * {
margin-bottom: 1.5rem;
margin-block-end: 1.5rem;
}
:host > ::slotted([slot]) > h1,
:host > ::slotted([slot]) > h2,
:host > ::slotted([slot]) > h3,
:host > ::slotted([slot]) > h4 {
margin-bottom: 0.75rem;
margin-block-end: 0.75rem;
}
:host > ::slotted([slot]) > h1 {
font-weight: 700;
}
:host > ::slotted([slot]) > h2,
:host > ::slotted([slot]) > h3,
:host > ::slotted([slot]) > h4 {
margin-bottom: 0.75rem;
font-weight: 600;
}
h1 {
font-size: 1.953rem;
}
h2 {
margin-block-start: 1.5em;
font-size: 1.563rem;
}
h3 {
Expand Down Expand Up @@ -62,41 +62,64 @@ export default function DocContent({ html }) {
list-style-position: outside;
}
dt {
font-weight: 600;
margin-block-end: 0.25rem;
}
dd + dt {
margin-block-start: 1.5rem;
}
dd {
border: 2px solid var(--cloud-ateneo);
border-radius: 0.25rem;
font-size: 0.875em;
padding: 0.875rem 1rem;
}
dd > *:not(:last-child) {
margin-block-end: 1rem;
}
table {
width: 100%;
border: 1px solid var(--smoke-indigo);
border: 1px solid var(--cloud-ateneo);
}
table thead th,
table tfoot th {
color: var(--inky-lily);
background: var(--smoke-indigo);
background: var(--cloud-ateneo);
}
table caption {
padding: 0.5rem;
}
table th,
table td {
padding: 0.5rem;
border: 1px solid var(--smoke-indigo);
border: 1px solid var(--cloud-ateneo);
}
blockquote {
padding: 0.8rem 0.6rem 0.6rem;
background-color: var(--smoke-indigo);
background-color: var(--cloud-ateneo);
box-shadow: rgba(0, 0, 0, 0.3) 0px 0px 1px 0px;
border-radius: 0.333rem;
border-radius: 0.25rem;
}
:not(pre) > code {
padding: 0.1rem 0.2rem;
line-height: 1rem;
overflow-wrap: break-word;
background-color: var(--smoke-indigo);
background-color: var(--cloud-ateneo);
font-family: Menlo, Monaco, Consolas, monospace;
font-size: 0.9375em; /* Fixed width fonts tend to have larger x height */
border-radius: 0.25rem;
}
:not(pre, dt) > code {
font-size: 0.9375em; /* Fixed width fonts tend to have larger x height */
}
blockquote :not(pre) > code {
background-color: var(--smoke-denim);
}
Expand All @@ -108,7 +131,8 @@ export default function DocContent({ html }) {
padding: 0.7rem 0.9rem;
font-family: 'Roboto Mono', monospace;
color: var(--hl-color);
background-color: var(--hl-bg);
background-color: var(--cloud-ateneo);
border-radius: 0.25rem;
white-space: pre;
tab-size: 2;
-webkit-overflow-scrolling: touch;
Expand Down Expand Up @@ -137,7 +161,7 @@ export default function DocContent({ html }) {
}
hr {
border-color: var(--smoke-indigo);
border-color: var(--cloud-ateneo);
}
</style>
Expand Down
4 changes: 2 additions & 2 deletions styleguide.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
"black": "#000000",
"light": "#EFEFEF",
"dark": "#222222",
"ateneo": "#113A62",
"ateneo": "#174069",
"blue": "#1F74D6",
"cloud": "#F7F0FE",
"dark-purple": "#7327CE",
"denim": "#003451",
"denim": "#002e47",
"green": "#2CDD93",
"halite": "#00293F",
"indigo": "#004163",
Expand Down

0 comments on commit 985205a

Please sign in to comment.