Important: The information in this article is over 12 months old, and may be out of date or no longer relevant.
But hey, you're here anyway, so give it a read see if it still applies to you.
I’ll be upfront – I don’t use Statamic’s Static Site Generator (SSG), however one client who wanted to handle their own deployment requested we ensure their Statamic site runs with the SSG so they can deploy through Netlify. When the site launched in 2021, everything was working fine, but an update to either Statamic or the SSG started to create issues.
There’s been a long-running issue discussing the problem on Github, but basically the SSG is unable to copy the glide-rendered images in to the deployed directory.
Workaround 1: asset caching
-
Urgh, local editing is a nuissance.
A workaround mentioned in the thread is to turn on image caching (so the cache directory, i.e. public/img
, can be copied during build), however that makes editing locally challenging as images are aggressively cached. This is great for production, but when you’re trying to tinker with cropping or focal points, having to manually clear the cache each time is a nuisance.
Workaround 2: updating code within the SSG package
-
Crazy talk. Update vendor files? Nuts. No.
Another workaround is to add a couple of lines of code to the bindGlide
function within SSG’s src/Generator.php
– more details are on the Github comment. Basically this goes after the $directory
variable is set:
1config([2 'statamic.assets.image_manipulation.cache' => true,3 'statamic.assets.image_manipulation.cache_path' => $this->config['destination'].'/'.$directory,4]);
With this in place, building the site works as expected. Nearly.
A by-product of this step is that the public/img
directory starts to get populated – which is good for build but bad for local use – so the editability was a bit of an issue still.
And, as we all know, changing a file in your vendor
folder is just a total no-no, so there’s that too. Just to re-iterate, don’t change files in any package in your vendor
folder – you’re asking for a world of pain for long-term maintenance when your changes get lost by another update.
The question then is – how can this be included in my client’s site?
As it turns out, really easily, and ticks off not touching vendor files, and also working flawlessly with local editability too.
Workaround 3: code within the actual site
-
Use the
AppServiceProvider
to have this as part of the site's codebase. Yes, please!
The basic gist of this solution is:
When running the
ssg:generate
command, configure Statamic to cache image manipulations (like workaround 1)After the site is generated, clear the image cache and reset configuration
Statamic’s SSG makes the second part possible with its super handy after
callback.
OK so let’s get things running first – how do we know we’re running the ssg:generate
command? We can look at the $_SERVER['argv']
property to see what arguments have been passed – which is when please
(or artisan
) is running via the command line only.
We can add this to our AppServiceProvider
boot method.
1if (isset($_SERVER['argv']) && count($_SERVER['argv']) >= 2 && (2 ($_SERVER['argv'][0] === 'please' && $_SERVER['argv'][1] === 'ssg:generate')3 ||4 ($_SERVER['argv'][0] === 'artisan' && $_SERVER['argv'][1] === 'statamic:ssg:generate')5 )) {6 // ...7}
Essentially what we’re doing here is:
Checking the
argv
property existsHas at least 2 arguments
Checking that these arguments are what we expect for an
ssg:generate
command, with support for either aplease
orartisan
call
While SSG’s docs say to call php please ssg:generate
, the please
command is essentially shortcutting to the Statamic namespace:
1php artisan statamic:ssg:generate
And hey, someone may use it. So just in case, my logic covers it.
So within this if statement, there are those two steps to do.
First of all, let’s get the original configuration, and update to enable image caching:
1if (isset($_SERVER['argv']) && count($_SERVER['argv']) >= 2 && ( 2 ($_SERVER['argv'][0] === 'please' && $_SERVER['argv'][1] === 'ssg:generate') 3 || 4 ($_SERVER['argv'][0] === 'artisan' && $_SERVER['argv'][1] === 'statamic:ssg:generate') 5 )) { 6 // get the directory 7 $directory = Arr::get(config('statamic.ssg'), 'glide.directory'); 8 9 // get the original config10 $originalCacheConfig = config('statamic.assets.image_manipulation');11 12 // update the config to enable image manipulation caching13 config([14 'statamic.assets.image_manipulation.cache' => true,15 'statamic.assets.image_manipulation.cache_path' => config('statamic.ssg.destination').DIRECTORY_SEPARATOR.$directory,16 ]);17}
Pretty straight forward, and essentially exactly what the Github comment suggests.
SSG comes with an after
callback too, which is run (funnily enough) after the build process is completed.
1SSG::after(function () use ($originalCacheConfig) {2 // ...3});
Notice here we’re also passing the $originalCacheConfig
in, as we will use that.
In this callback, we’re re-setting the config to what it was, and clearing the image cache by calling the please
(aka artisan statamic
) command:
1SSG::after(function () use ($originalCacheConfig) { 2 // reset the config to what it was before the script ran 3 config([ 4 'statamic.assets.image_manipulation.cache' => $originalCacheConfig['cache'], 5 'statamic.assets.image_manipulation.cache_path' => $originalCacheConfig['cache_path'], 6 ]); 7 8 // clear the image cache 9 Artisan::call('statamic:glide:clear');10});
And that’s it – when the ssg:generate
command is run, we’re updating the config on the fly, and then allowing the command to run – and when it’s done, clearing the image cache to maintain local editability.
And what do we get? A site that builds as expected, with local image editability, and a happy client. All in all, not a bad effort.
Here's the entire AppServiceProvider
just for a complete view:
1<?php 2 3namespace App\Providers; 4 5use Illuminate\Support\Facades\Artisan; 6use Illuminate\Support\ServiceProvider; 7use Statamic\StaticSite\SSG; 8use Statamic\Support\Arr; 9 10class AppServiceProvider extends ServiceProvider11{12 /**13 * Register any application services.14 */15 public function register(): void16 {17 //18 }19 20 /**21 * Bootstrap any application services.22 */23 public function boot(): void24 {25 if (isset($_SERVER['argv']) && count($_SERVER['argv']) >= 2 && (26 ($_SERVER['argv'][0] === 'please' && $_SERVER['argv'][1] === 'ssg:generate')27 ||28 ($_SERVER['argv'][0] === 'artisan' && $_SERVER['argv'][1] === 'statamic:ssg:generate')29 )) {30 // get the directory31 $directory = Arr::get(config('statamic.ssg'), 'glide.directory');32 33 // get the original config34 $originalCacheConfig = config('statamic.assets.image_manipulation');35 36 // update the config to enable image manipulation caching37 config([38 'statamic.assets.image_manipulation.cache' => true,39 'statamic.assets.image_manipulation.cache_path' => config('statamic.ssg.destination').DIRECTORY_SEPARATOR.$directory,40 ]);41 42 SSG::after(function () use ($originalCacheConfig) {43 // reset the config to what it was before the script ran44 config([45 'statamic.assets.image_manipulation.cache' => $originalCacheConfig['cache'],46 'statamic.assets.image_manipulation.cache_path' => $originalCacheConfig['cache_path'],47 ]);48 49 // clear the image cache50 Artisan::call('statamic:glide:clear');51 });52 }53 }54}
Why not submit a PR?
To be totally honest, I’ve considered it – but not using SSG myself day-to-day, I’m not 100% sure this is the best fix for every use case or if this adds any other repercussions that may be specific to actual users, whether that be a Netlify user or some other deployment target – so hey, if you’ve stumbled across this post and want to connect, reach out to me via the contact page here and let’s have a chat.
Happy to work through this in more detail with daily SSG users.