middleman-s3_sync 4.8.0 released

I’ve just released version 4.8.0 of middleman-s3_sync, a gem that synchronizes Middleman-built websites to Amazon S3, with optional CloudFront invalidation. This release tightens the HTTP caching story for hashed assets.

What’s new

immutable directive

Caching policies now support the immutable flag. Pair it with a long max_age on fingerprinted assets — the kind Middleman’s asset_hash extension produces — and browsers will skip revalidation entirely, even on a user-initiated reload:

1
2
3
4
caching_policy 'text/css',               max_age: 1.year, public: true, immutable: true
caching_policy 'application/javascript', max_age: 1.year, public: true, immutable: true
caching_policy 'image/png',              max_age: 1.year, public: true, immutable: true
caching_policy 'image/jpeg',             max_age: 1.year, public: true, immutable: true

Resulting header:

1
Cache-Control: max-age=31556952, public, immutable

This is the strongest cache hint you can give for content-addressed URLs. It’s safe whenever the URL changes the moment the bytes change — exactly the contract asset_hash provides. I’ve turned it on for this blog.

max-age now overrides Expires

When a policy sets max_age:, the Expires header is now suppressed — even if expires: is also configured. Per RFC 7234 §5.3, max-age takes precedence over Expires for HTTP/1.1 caches anyway, so emitting both adds no information. More importantly, it stops the expires: timestamp from drifting forward on every build, which used to force a metadata-only update on every cached object.

Configs that use expires: alone (without max_age:) continue to work unchanged.

If you currently have something like:

1
caching_policy 'text/css', max_age: 12.months, expires: 12.months.from_now

The expires: argument is now redundant. You can drop it next time you touch the file.

Tidier upload payloads

Resource#to_h and the streaming upload path no longer include empty cache_control or expires keys when the caching policy yields nil for them. Mostly invisible, but it keeps the AWS SDK request payload clean.

Other Improvements

  • Ruby 3.1 CI: dropped the timerizer development dependency. It monkey-patched Time.new in a way that’s incompatible with Ruby 3.1.7’s keyword-argument changes and crashed RSpec at startup on the 3.1 matrix. Three test usages were replaced with plain Time literals.

Upgrading

Update your Gemfile:

1
gem 'middleman-s3_sync', '~> 4.8'

Then run:

1
bundle update middleman-s3_sync

Adding immutable: true to your existing caching policies will trigger one re-upload per matching object the next time you sync — the new directive changes the Cache-Control string, which the metadata-match check correctly detects. Subsequent syncs settle back to the usual “no changes” pattern.

Thanks

As always, the source is on GitHub and the gem is on RubyGems. Feedback and PRs welcome!

I'm Back!

A whole lot has happened since I last wrote here. I’ve been busy with work, family, hobbies,and personal projects. I’ve also dealt with some personal issues and challenges that have shaped my perspective and priorities. I’ve learned a lot about myself and...

Read More...

Moving Out of the Home Office

New Office

I was mostly on distributed teams when I worked at Sun Microsystems. Sometimes it was on a multi-site team, but more often than not I was on teams where I was one of the few, if not only, members based in Colorado. As a result, I had a well appointed...

Read More...

Cups of Coffee

coffee Image by Toshiyuki IMAI

I measure my mornings in cups of coffee.

The first one is for me. It accompanies breakfast, is savored as I read my Twitter feed and some interesting stories and helps me ease out of sleepiness into awakeness.

The second cup...

Read More...

Page 1 of 8

Next page