add Docker deployment with Alpine image, release config and health check
- Alpine multi-stage Dockerfile (131 MB image) - Release overlays (bin/server, bin/migrate), env.sh, Release module - Health check endpoint at GET /health - Fly.io config with SQLite volume mount - Fix hardcoded paths in optimizer.ex and variant_cache.ex to use Application.app_dir/2 (breaks in releases where Plug.Static serves from a different directory than CWD) - strip_beams: true in release config - Optimised .dockerignore and .gitignore for mockup variants Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,11 +13,10 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
||||
# Only affects <5% of users (legacy browsers without AVIF/WebP support)
|
||||
@pregenerated_formats [:avif, :webp]
|
||||
@thumb_size 200
|
||||
@cache_dir "priv/static/image_cache"
|
||||
@max_stored_width 2000
|
||||
@storage_quality 90
|
||||
|
||||
def cache_dir, do: @cache_dir
|
||||
def cache_dir, do: Application.app_dir(:simpleshop_theme, "priv/static/image_cache")
|
||||
def all_widths, do: @all_widths
|
||||
|
||||
@doc """
|
||||
@@ -72,7 +71,7 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
||||
{:ok, :svg_skipped}
|
||||
|
||||
%{data: data, source_width: width} = image ->
|
||||
File.mkdir_p!(@cache_dir)
|
||||
File.mkdir_p!(cache_dir())
|
||||
|
||||
with {:ok, vips_image} <- Image.from_binary(data) do
|
||||
widths = applicable_widths(width)
|
||||
@@ -93,7 +92,7 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
||||
end
|
||||
|
||||
defp generate_thumbnail(image, id) do
|
||||
path = Path.join(@cache_dir, "#{id}-thumb.jpg")
|
||||
path = Path.join(cache_dir(), "#{id}-thumb.jpg")
|
||||
|
||||
return_if_exists(path, fn ->
|
||||
with {:ok, thumb} <- Image.thumbnail(image, @thumb_size),
|
||||
@@ -104,7 +103,7 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
||||
end
|
||||
|
||||
defp generate_variant(image, id, width, format) do
|
||||
path = Path.join(@cache_dir, "#{id}-#{width}.#{format_ext(format)}")
|
||||
path = Path.join(cache_dir(), "#{id}-#{width}.#{format_ext(format)}")
|
||||
|
||||
return_if_exists(path, fn ->
|
||||
with {:ok, resized} <- Image.thumbnail(image, width),
|
||||
@@ -140,12 +139,12 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
||||
"""
|
||||
def disk_variants_exist?(image_id, source_width) do
|
||||
widths = applicable_widths(source_width)
|
||||
thumb = File.exists?(Path.join(@cache_dir, "#{image_id}-thumb.jpg"))
|
||||
thumb = File.exists?(Path.join(cache_dir(), "#{image_id}-thumb.jpg"))
|
||||
|
||||
variants =
|
||||
Enum.all?(widths, fn w ->
|
||||
Enum.all?(@pregenerated_formats, fn fmt ->
|
||||
File.exists?(Path.join(@cache_dir, "#{image_id}-#{w}.#{format_ext(fmt)}"))
|
||||
File.exists?(Path.join(cache_dir(), "#{image_id}-#{w}.#{format_ext(fmt)}"))
|
||||
end)
|
||||
end)
|
||||
|
||||
@@ -159,12 +158,12 @@ defmodule SimpleshopTheme.Images.Optimizer do
|
||||
"""
|
||||
def generate_variant_on_demand(image_data, image_id, width, format)
|
||||
when is_binary(image_data) and format in [:avif, :webp, :jpg] do
|
||||
path = Path.join(@cache_dir, "#{image_id}-#{width}.#{format_ext(format)}")
|
||||
path = Path.join(cache_dir(), "#{image_id}-#{width}.#{format_ext(format)}")
|
||||
|
||||
if File.exists?(path) do
|
||||
{:ok, path}
|
||||
else
|
||||
File.mkdir_p!(@cache_dir)
|
||||
File.mkdir_p!(cache_dir())
|
||||
|
||||
with {:ok, vips_image} <- Image.from_binary(image_data),
|
||||
{:ok, resized} <- Image.thumbnail(vips_image, width),
|
||||
|
||||
@@ -19,7 +19,7 @@ defmodule SimpleshopTheme.Images.VariantCache do
|
||||
alias SimpleshopTheme.Sync.ImageDownloadWorker
|
||||
import Ecto.Query
|
||||
|
||||
@mockup_dir "priv/static/mockups"
|
||||
defp mockup_dir, do: Application.app_dir(:simpleshop_theme, "priv/static/mockups")
|
||||
|
||||
def start_link(opts) do
|
||||
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
||||
@@ -87,9 +87,9 @@ defmodule SimpleshopTheme.Images.VariantCache do
|
||||
end
|
||||
|
||||
defp ensure_mockup_variants do
|
||||
if File.dir?(@mockup_dir) do
|
||||
if File.dir?(mockup_dir()) do
|
||||
sources =
|
||||
Path.wildcard(Path.join(@mockup_dir, "*.webp"))
|
||||
Path.wildcard(Path.join(mockup_dir(), "*.webp"))
|
||||
|> Enum.reject(&is_variant?/1)
|
||||
|
||||
missing = Enum.reject(sources, &mockup_variants_exist?/1)
|
||||
|
||||
Reference in New Issue
Block a user