bridgetown-image-pipeline 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +49 -0
- data/LICENSE.txt +21 -0
- data/README.md +241 -0
- data/Rakefile +12 -0
- data/docs/INTERNALS.md +527 -0
- data/docs/adr/0001-bg-image-delivery-via-image-set.md +230 -0
- data/docs/adr/0002-initializer-kwargs-only.md +80 -0
- data/docs/adr/0003-conservative-defaults.md +81 -0
- data/docs/adr/0004-output-dir-under-bridgetown-prefix.md +77 -0
- data/docs/adr/0005-cache-key-versioning-lockstep.md +91 -0
- data/lib/bridgetown/image_pipeline/bg_image_set.rb +50 -0
- data/lib/bridgetown/image_pipeline/builder.rb +127 -0
- data/lib/bridgetown/image_pipeline/config.rb +32 -0
- data/lib/bridgetown/image_pipeline/helpers.rb +110 -0
- data/lib/bridgetown/image_pipeline/inspector.rb +74 -0
- data/lib/bridgetown/image_pipeline/manifest.rb +73 -0
- data/lib/bridgetown/image_pipeline/processor.rb +66 -0
- data/lib/bridgetown/image_pipeline/version.rb +7 -0
- data/lib/bridgetown/image_pipeline/view_helpers.rb +32 -0
- data/lib/bridgetown/image_pipeline.rb +43 -0
- data/lib/bridgetown-image-pipeline.rb +5 -0
- metadata +133 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4b506abefc78cfff32c2485ca39d6cd789486ffde30b52060e9aee52a2333510
|
|
4
|
+
data.tar.gz: 5bf51dd415078908778245b62003e4e36417519bb134e174e470bb77573f2f8c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8bd6e9145bf27b2ca0156ee67ce008bae9b3648d458baf7ec46adcbbddd34cc2e777c7436fee2a8882f8c90bb77954574e12149a937cd4d00290d5a7ab9001e3
|
|
7
|
+
data.tar.gz: 3d2cc00f6657d78ebf7c5777d6d28b8e1e46e116a500e991373c324d140c1c55f4b4ea9e28bfbace1d8d2f5b9c23249b4aa0e02e96633b4a2a1f1cbe08385f21
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this gem are recorded in this file. The format is
|
|
4
|
+
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
|
|
5
|
+
project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-05-15
|
|
10
|
+
|
|
11
|
+
Initial release. Extracted from
|
|
12
|
+
[rubycentral/rubyconf-2026](https://github.com/rubycentral/rubyconf-2026)
|
|
13
|
+
after six PRs of in-repo iteration (#97, #105, #106, #109, #110, #112).
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Build-time AVIF and WebP derivative generation via libvips at configurable
|
|
18
|
+
widths (defaults: 400, 600, 800, 1200, 1600).
|
|
19
|
+
- `picture_tag(src, alt:, sizes:, priority:, **attrs)` ERB helper for
|
|
20
|
+
responsive `<picture>` elements.
|
|
21
|
+
- `bg_image_block(src, breakpoint_only:, class_suffix:)` ERB helper that
|
|
22
|
+
emits an inline `<style>` block with `image-set(avif, webp)` declarations
|
|
23
|
+
plus Tailwind-breakpoint `@media` overrides.
|
|
24
|
+
- `bg_image_class(src, class_suffix:)` ERB helper that returns the derived
|
|
25
|
+
CSS class name without a `<style>` block, for cases that need the class
|
|
26
|
+
in multiple places after emitting the block once.
|
|
27
|
+
- `Inspector` (off by default) that walks rendered HTML and rewrites bare
|
|
28
|
+
`<img src="/images/...">` references into responsive `<picture>` tags.
|
|
29
|
+
- Per-derivative cache under `.bridgetown-cache/image_pipeline/`, keyed by
|
|
30
|
+
source SHA1 + gem version + config fingerprint.
|
|
31
|
+
- Configurable via initializer block:
|
|
32
|
+
```ruby
|
|
33
|
+
init "bridgetown-image-pipeline" do
|
|
34
|
+
widths [400, 800, 1600]
|
|
35
|
+
auto_rewrite true
|
|
36
|
+
end
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Notes for adopters
|
|
40
|
+
|
|
41
|
+
- `output_dir` defaults to `_bridgetown/image_pipeline` (under Bridgetown's
|
|
42
|
+
framework-reserved prefix). Override via `output_dir: "your/path"` if you
|
|
43
|
+
need to preserve URLs from a prior in-repo plugin layout.
|
|
44
|
+
- `auto_rewrite` and `fail_on_missing` both default to `false` (conservative
|
|
45
|
+
defaults). Enable explicitly if you want the Inspector or strict
|
|
46
|
+
missing-manifest behaviour.
|
|
47
|
+
|
|
48
|
+
[Unreleased]: https://github.com/beflagrant/bridgetown-image-pipeline/compare/v0.1.0...HEAD
|
|
49
|
+
[0.1.0]: https://github.com/beflagrant/bridgetown-image-pipeline/releases/tag/v0.1.0
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Flagrant LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# bridgetown-image-pipeline
|
|
2
|
+
|
|
3
|
+
A Bridgetown 2.0+ plugin that pre-generates responsive **AVIF** and **WebP**
|
|
4
|
+
image derivatives at multiple widths, plus ERB helpers for `<picture>`
|
|
5
|
+
elements and CSS `image-set()` backgrounds.
|
|
6
|
+
|
|
7
|
+
Used in production at [rubyconf.org](https://rubyconf.org) — homepage mobile
|
|
8
|
+
Lighthouse perf score went from **0.47 → 0.93** after the bg-image migration.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Build-time derivative generation** via libvips. AVIF + WebP at configurable
|
|
13
|
+
widths (default: 400, 600, 800, 1200, 1600). Source-width-aware (no upscaling).
|
|
14
|
+
- **`picture_tag` helper** — emits `<picture>` with `<source>` per format and
|
|
15
|
+
an `<img>` fallback with `srcset` + `sizes`.
|
|
16
|
+
- **`bg_image_block` helper** — emits an inline `<style>` block with
|
|
17
|
+
`background-image: image-set(...)` rules for backgrounds. Tailwind-breakpoint
|
|
18
|
+
aware. Drop-in replacement for `bg-[url(...)]` utilities.
|
|
19
|
+
- **`Inspector`** (optional, off by default) — rewrites bare `<img>` tags in
|
|
20
|
+
rendered HTML to wrap them in `<picture>` with the appropriate sources.
|
|
21
|
+
- **Per-derivative cache** keyed by source SHA1 + gem version + config
|
|
22
|
+
fingerprint. Rebuilds skip unchanged sources.
|
|
23
|
+
|
|
24
|
+
## Requirements
|
|
25
|
+
|
|
26
|
+
- Ruby >= 3.2
|
|
27
|
+
- Bridgetown >= 2.0, < 3.0
|
|
28
|
+
- libvips with **HEIF/AVIF plugin** installed (see Installation below)
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Add to your site's `Gemfile`:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
gem "bridgetown-image-pipeline"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then `bundle install`.
|
|
39
|
+
|
|
40
|
+
### libvips with HEIF/AVIF support
|
|
41
|
+
|
|
42
|
+
The plugin needs libvips compiled with HEIF support so it can encode AVIF.
|
|
43
|
+
|
|
44
|
+
**macOS (Homebrew):**
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
brew install vips
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Ubuntu / Debian:**
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
sudo apt-get install libvips libvips-tools \
|
|
54
|
+
libheif1 libheif-dev libheif-plugin-aomenc libheif-plugin-libde265
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Verify the encoder works:**
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
vips --vips-config | tr ',' '\n' | grep -i heif
|
|
61
|
+
vips black /tmp/_check.avif 16 16 && rm /tmp/_check.avif
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Both lines should succeed. If the second fails with "cannot encode AVIF", the
|
|
65
|
+
libheif AV1 encoder plugin (`libheif-plugin-aomenc` on Ubuntu) is missing.
|
|
66
|
+
|
|
67
|
+
### Activate the plugin
|
|
68
|
+
|
|
69
|
+
In `config/initializers.rb`:
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
Bridgetown.configure do |config|
|
|
73
|
+
init "bridgetown-image-pipeline"
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Or with overrides:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
Bridgetown.configure do |config|
|
|
81
|
+
init "bridgetown-image-pipeline" do
|
|
82
|
+
widths [400, 800, 1200, 1600]
|
|
83
|
+
auto_rewrite true # enable the Inspector
|
|
84
|
+
output_dir "_bridgetown/image_pipeline" # default
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Usage
|
|
90
|
+
|
|
91
|
+
### `picture_tag` — responsive `<picture>` elements
|
|
92
|
+
|
|
93
|
+
```erb
|
|
94
|
+
<%= picture_tag "/images/hero.jpg",
|
|
95
|
+
alt: "Sandstone formations at sunset",
|
|
96
|
+
sizes: "(min-width: 1024px) 50vw, 100vw",
|
|
97
|
+
priority: true,
|
|
98
|
+
class: "w-full h-auto" %>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Renders:
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<picture>
|
|
105
|
+
<source type="image/avif" srcset="/_bridgetown/image_pipeline/hero-400.avif 400w, ..." sizes="...">
|
|
106
|
+
<source type="image/webp" srcset="/_bridgetown/image_pipeline/hero-400.webp 400w, ..." sizes="...">
|
|
107
|
+
<img src="/_bridgetown/image_pipeline/hero-1600.jpg"
|
|
108
|
+
srcset="..." sizes="..."
|
|
109
|
+
width="2400" height="1600"
|
|
110
|
+
alt="Sandstone formations at sunset"
|
|
111
|
+
loading="eager" decoding="async" fetchpriority="high"
|
|
112
|
+
class="w-full h-auto">
|
|
113
|
+
</picture>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`priority: true` adds `loading="eager"` and `fetchpriority="high"`. Use for
|
|
117
|
+
LCP candidates only.
|
|
118
|
+
|
|
119
|
+
### `bg_image_block` — responsive CSS backgrounds
|
|
120
|
+
|
|
121
|
+
For decorative `background-image` use cases. Emits an inline `<style>`
|
|
122
|
+
block; the caller uses the returned class on the element:
|
|
123
|
+
|
|
124
|
+
```erb
|
|
125
|
+
<%= bg_image_block "/images/all-flora.jpg" %>
|
|
126
|
+
<section class="bg-img-all-flora bg-cover p-6 lg:p-20">
|
|
127
|
+
...
|
|
128
|
+
</section>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Class names are derived from the source basename:
|
|
132
|
+
`/images/all-flora.jpg` → `bg-img-all-flora`.
|
|
133
|
+
|
|
134
|
+
**Breakpoint-only backgrounds** (replicates Tailwind's `lg:bg-[url(...)]`):
|
|
135
|
+
|
|
136
|
+
```erb
|
|
137
|
+
<%= bg_image_block "/images/hero.jpg", breakpoint_only: 1024 %>
|
|
138
|
+
<section class="bg-img-hero bg-cover"> <!-- bg only shows >=1024px -->
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Same source in two contexts** (e.g. hero + decorative loop):
|
|
142
|
+
|
|
143
|
+
```erb
|
|
144
|
+
<%= bg_image_block "/images/flowers.png", class_suffix: "hero" %>
|
|
145
|
+
<section class="bg-img-flowers-hero ...">
|
|
146
|
+
|
|
147
|
+
<%= bg_image_block "/images/flowers.png" %>
|
|
148
|
+
<div class="bg-img-flowers ...">
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The `class_suffix:` kwarg keeps the two `<style>` blocks from colliding.
|
|
152
|
+
|
|
153
|
+
### `bg_image_class` — class name only, no style block
|
|
154
|
+
|
|
155
|
+
When you need to reference the class in multiple places after emitting the
|
|
156
|
+
block once:
|
|
157
|
+
|
|
158
|
+
```erb
|
|
159
|
+
<%= bg_image_block "/images/flowers.png" %>
|
|
160
|
+
<% klass = bg_image_class("/images/flowers.png") %>
|
|
161
|
+
<section class="<%= klass %> ...">...</section>
|
|
162
|
+
<aside class="<%= klass %> ...">...</aside>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### `Inspector` — auto-wrap bare `<img>` tags
|
|
166
|
+
|
|
167
|
+
Off by default. Enable in your initializer:
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
init "bridgetown-image-pipeline" do
|
|
171
|
+
auto_rewrite true
|
|
172
|
+
end
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
When on, any rendered `<img src="/images/foo.jpg">` whose source is in the
|
|
176
|
+
manifest is rewritten as a `<picture>` with the appropriate sources.
|
|
177
|
+
Opt-out on a per-tag basis with `data-no-pipeline`:
|
|
178
|
+
|
|
179
|
+
```html
|
|
180
|
+
<img src="/images/exact-bytes-required.jpg" data-no-pipeline>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Configuration
|
|
184
|
+
|
|
185
|
+
All options, with defaults:
|
|
186
|
+
|
|
187
|
+
| Option | Default | Description |
|
|
188
|
+
|--------|---------|-------------|
|
|
189
|
+
| `source_globs` | `["src/images/**/*.{jpg,jpeg,png}"]` | What to process. **Must live under `src/`** — public URLs are derived by stripping the `src/` prefix, so `src/images/foo.jpg` becomes `/images/foo.jpg` in `picture_tag` lookups. Sources outside `src/` are processed but unreachable from templates. |
|
|
190
|
+
| `exclude` | `[]` | Glob patterns to skip |
|
|
191
|
+
| `widths` | `[400, 600, 800, 1200, 1600]` | Derivative widths |
|
|
192
|
+
| `formats` | `[:avif, :webp]` | Output formats (plus original) |
|
|
193
|
+
| `output_dir` | `"_bridgetown/image_pipeline"` | Output path under `output/` |
|
|
194
|
+
| `quality` | `{ avif: 65, webp: 88, jpeg: 88 }` | Per-format quality |
|
|
195
|
+
| `auto_rewrite` | `false` | Enable the Inspector |
|
|
196
|
+
| `fail_on_missing` | `false` | Raise vs. warn on missing manifest |
|
|
197
|
+
| `breakpoints` | `{ 640 => 400, 768 => 600, 1024 => 800, 1280 => 1200 }` | Tailwind-style breakpoints for `bg_image_block` |
|
|
198
|
+
| `default_width` | `1600` | Default tier for `bg_image_block`'s un-prefixed rule |
|
|
199
|
+
|
|
200
|
+
## Gotcha: Tailwind v4 and `bg-[url(...)]` in docs
|
|
201
|
+
|
|
202
|
+
Tailwind v4 auto-scans every file from the CSS entrypoint's parent dir up to
|
|
203
|
+
the git root. If your repo has Markdown documentation that quotes raw
|
|
204
|
+
Tailwind classes like `bg-[url(...)]` (e.g. in a README that explains a
|
|
205
|
+
migration from the old utility to this plugin), Tailwind will pick those
|
|
206
|
+
literal strings up and try to emit CSS rules for them. esbuild will then
|
|
207
|
+
fail to resolve the `...` placeholder URL, breaking your build.
|
|
208
|
+
|
|
209
|
+
Fix: add `@source not` directives to your Tailwind CSS:
|
|
210
|
+
|
|
211
|
+
```css
|
|
212
|
+
@import "tailwindcss";
|
|
213
|
+
@source not "../../docs/**";
|
|
214
|
+
@source not "../../test/**";
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Architecture
|
|
218
|
+
|
|
219
|
+
See [`docs/INTERNALS.md`](docs/INTERNALS.md) for the design spec and
|
|
220
|
+
[`docs/adr/`](docs/adr/) for the architecture decision records covering
|
|
221
|
+
the helper API, output paths, defaults, and cache-key invariants.
|
|
222
|
+
|
|
223
|
+
## Development
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
bin/setup
|
|
227
|
+
bundle exec rake test
|
|
228
|
+
bundle exec rake rubocop
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
CI runs against Ruby 3.2/3.3/3.4 × Bridgetown 2.0/edge.
|
|
232
|
+
|
|
233
|
+
## License
|
|
234
|
+
|
|
235
|
+
MIT — see [`LICENSE.txt`](LICENSE.txt).
|
|
236
|
+
|
|
237
|
+
## Status
|
|
238
|
+
|
|
239
|
+
Maintained by [Flagrant](https://beflagrant.com) for use in production at
|
|
240
|
+
[rubyconf.org](https://rubyconf.org). No SLA. Issues and PRs welcome at
|
|
241
|
+
[github.com/beflagrant/bridgetown-image-pipeline](https://github.com/beflagrant/bridgetown-image-pipeline).
|