Hugo Theme (Part 6) : Imagekit

Intro

In this post, we will add ImageKit support to our theme. We will use ImageKit to store and deliver our images. We will also use ImageKit to create variants of the images for different resolutions/screen sizes for faster loading and bandwidth saving. You will need an ImageKit account. If you don’t already have one, you can sign up for a free account.

[!Tip]

Use online backup like Google Drive to save your entire Hugo site, use ImageKit to host images and use GitHub with images excluded for version control of other files

ImageKit

ImageKit can resize images to any size on the fly, but we want to restrict it to a few sizes that we want to use. We can use Named Transformations to use simpler names for complex transformations.

In ImageKit dashboard, navigate to Settings > Named transforms and add

Named TransformActual Transform StringStatus
thumbtr:w-400,c-at_maxEnabled
mobiletr:w-640,c-at_maxEnabled
smtr:w-768,c-at_maxEnabled
mdtr:w-1024,c-at_maxEnabled
lgtr:w-1280,c-at_maxEnabled
xltr:w-1536,c-at_maxEnabled
2xltr:w-1920,c-at_maxEnabled

Now we can use these named transformations with the images hosted at ImageKit to get a specific size. c-at_max makes sure that we don’t upscale or increase the image dimensions if its smaller than the one requested.

I will also disable dynamic transformations and enable only named transformations. Settings > Images > Restrict unnamed image transformations » ON

[!Tip]

If we want to create the variants on image upload rather than on request, we can also add the transformations to Settings > Media library > Default upload parameters > Post transformations.

Upload an image ImageKit media library so we can test the transformation. Then use the URL with the tr-<transformation_name> to use variants.

Test named transformations

![Test thumb](https://ik.imagekit.io/psxoierby/tr:n-thumb/pexels-chevanon-photography-1108099.jpg)

Test thumb

![Test md](https://ik.imagekit.io/psxoierby/tr:n-md/pexels-chevanon-photography-1108099.jpg)

Test md

Rclone

We will use Rclone to sync our images to ImageKit.

Follow instructions https://rclone.org/downloads/ to install rclone

% sudo -v ; curl https://rclone.org/install.sh | sudo bash
Password:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4734  100  4734    0     0   5706      0 --:--:-- --:--:-- --:--:--  5745
Archive:  rclone-current-osx-amd64.zip
   creating: tmp_unzip_dir_for_rclone/rclone-v1.65.2-osx-amd64/
  inflating: tmp_unzip_dir_for_rclone/rclone-v1.65.2-osx-amd64/git-log.txt  [text]  
  inflating: tmp_unzip_dir_for_rclone/rclone-v1.65.2-osx-amd64/rclone  [binary]
  inflating: tmp_unzip_dir_for_rclone/rclone-v1.65.2-osx-amd64/rclone.1  [text]  
  inflating: tmp_unzip_dir_for_rclone/rclone-v1.65.2-osx-amd64/README.html  [text]  
  inflating: tmp_unzip_dir_for_rclone/rclone-v1.65.2-osx-amd64/README.txt  [text]  

rclone v1.65.2 has successfully installed.
Now run "rclone config" for setup. Check https://rclone.org/docs/ for more details.

Configure rclone with ImageKit media library as remote folder. Start with rclone config and follow the prompts

% rclone config

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> n

Enter name for new remote.
name> imgkit

Option Storage.
Type of storage to configure.
Choose a number from below, or type in your own value.
...
23 / ImageKit.io
   \ (imagekit)
...
Storage> 23

Option endpoint.
You can find your ImageKit.io URL endpoint in your [dashboard](https://imagekit.io/dashboard/developer/api-keys)
Enter a value.
endpoint> https://ik.imagekit.io/somepath

Option public_key.
You can find your ImageKit.io public key in your [dashboard](https://imagekit.io/dashboard/developer/api-keys)
Enter a value.
public_key> <public_key>

Option private_key.
You can find your ImageKit.io private key in your [dashboard](https://imagekit.io/dashboard/developer/api-keys)
Enter a value.
private_key> <private_key>

Edit advanced config?
y) Yes
n) No (default)
y/n> n

Configuration complete.
Options:
- type: imagekit
- endpoint: https://ik.imagekit.io/psxoierby
- public_key: <public_key>
- private_key: <private_key>
Keep this "imgkit" remote?
y) Yes this is OK (default)
e) Edit this remote
d) Delete this remote
y/e/d> y

Current remotes:

Name                 Type
====                 ====
imgkit               imagekit

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> q

Sync the image files to ImageKit media library. Include all the image file extensions to sync. I used only jpg, jpeg and png

rclone sync blog/content imgkit: --include "*.{jpg,jpeg,png}"

Run this command after adding new images and they will automatically be available on ImageKit.

Configure Hugo to use ImageKit. In hugo.toml, set imgkit to true and imgkitURL to ImageKit URL endpoint

imagekit = true
imgkitUrl = "https://ik.imagekit.io/somepath"

Hugo Code

layouts/_default/_markup/render-image.html

For external images keep the existing code

{{- $isRemote := strings.HasPrefix .Destination "http" -}}
{{- if or $isRemote (not .Page.Site.Params.imagekit) -}}
<img src="{{ .Destination }}" class="p-0 m-0" {{ if .Page.Site.Params.mediumZoom }} data-zoomable data-zoom-src="{{ .Destination }}"{{ end }} alt="{{ .Text }}" {{ with .Title }} title="{{ . }}"{{ end }} />

For our own images, if imgkit variable is set in our site settings, we will use ImageKit URLs, otherwise default back to local image URLs

{{- else -}}
{{ $srcMobile := urls.JoinPath .Page.Site.Params.imgkitURL "tr:n-mobile" .Page.RelPermalink .Destination }}
{{ $srcSm := urls.JoinPath .Page.Site.Params.imgkitURL "tr:n-sm" .Page.RelPermalink .Destination }}
{{ $srcMd := urls.JoinPath .Page.Site.Params.imgkitURL "tr:n-md" .Page.RelPermalink .Destination }}
{{ $srcLg := urls.JoinPath .Page.Site.Params.imgkitURL "tr:n-lg" .Page.RelPermalink .Destination }}
{{ $srcXl := urls.JoinPath .Page.Site.Params.imgkitURL "tr:n-xl" .Page.RelPermalink .Destination }}
{{ $src2xl := urls.JoinPath .Page.Site.Params.imgkitURL "tr:n-2xl" .Page.RelPermalink .Destination }}
<img src='{{$srcMobile}}'
srcset='{{ $srcMobile }} 640w, {{ $srcSm }} 768w, {{ $srcMd }} 1024w, {{ $srcLg }} 1280w, {{ $srcXl }} 1536w, {{ $src2xl }} 1920w'
class="p-0 m-0" {{ if .Page.Site.Params.mediumZoom }} data-zoomable data-zoom-src="{{ $src2xl }}"{{ end }} alt="{{ .Text }}" {{ with .Title }} title="{{ . }}"{{ end }} />
{{- end -}}

Do the same thing for our gallery shortcode layouts/shortcodes/gallery.html

{{ $isRemote := strings.HasPrefix $src "http" }}
{{ if or $isRemote (not $page.Site.Params.imagekit) }}
<a href={{$src}} class="glightbox sm:max-w-72" data-gallery={{$gallery}}>
    {{ . | $page.RenderString }}
</a>
{{ else }}
{{ $srcThumb := urls.JoinPath $page.Site.Params.imgkitURL "tr:n-thumb" $page.RelPermalink $src }}
{{ $srcMobile := urls.JoinPath $page.Site.Params.imgkitURL "tr:n-mobile" $page.RelPermalink $src }}
{{ $srcSm := urls.JoinPath $page.Site.Params.imgkitURL "tr:n-sm" $page.RelPermalink $src }}
{{ $srcMd := urls.JoinPath $page.Site.Params.imgkitURL "tr:n-md" $page.RelPermalink $src }}
{{ $srcLg := urls.JoinPath $page.Site.Params.imgkitURL "tr:n-lg" $page.RelPermalink $src }}
{{ $srcXl := urls.JoinPath $page.Site.Params.imgkitURL "tr:n-xl" $page.RelPermalink $src }}
{{ $src2xl := urls.JoinPath $page.Site.Params.imgkitURL "tr:n-2xl" $page.RelPermalink $src }}
<a href={{$srcMobile}} class="glightbox sm:max-w-72" data-gallery={{$gallery}}
data-sizes="100%"
data-srcset='{{ $srcMobile }} 640w, {{ $srcSm }} 768w, {{ $srcMd }} 1024w, {{ $srcLg }} 1280w, {{ $srcXl }} 1536w, {{ $src2xl }} 1920w'
>
    <img src='{{$srcThumb}}'>
</a>
{{ end }}

We can add similar render blocks for other image hosts if needed in the future.

Thank you for reading. I will post more content shortly. You can also check out other posts in this series below.