Sprockets::WebP
This gem provides a Rails Asset Pipeline hook for converting PNG and JPEG assets to the WebP format.
Requirements
The main requirement is obviously libwebp itself. Please, consult the webp-ffi README for the installation instructions.
Installation
Rails 4
If you're using Rails 4 you need to add gem to the :production
group in to your application's Gemfile:
group :production do
# ...
gem 'sprockets-webp'
# ...
end
Rails 3
Minimal required version of Rails 3 is 3.2.9
, because of Sprockets ~> 2.2
dependency requirement. Simply add sprockets-web to the :assets
group:
group :assets do
# ...
gem 'sprockets-webp'
# ...
end
Configuration
You can configure encode options for webp by using encode_options
(in example default options):
Sprockets::WebP.encode_options = { quality: 100, lossless: 1, method: 6, alpha_filtering: 2, alpha_compression: 0, alpha_quality: 100 }
More options you can find in web-ffi readme.
Testing
Drop some PNGs and JPGs into app/assets/images
and you can test converter locally with the Rake task:
$ bundle exec rake assets:precompile RAILS_ENV=production
Capistrano
If you deploy your rails app by capistrano gem, you should update mtime for your webp images, because it will not present in manifest.json and will be cleanup automatically. To solve this problem you can use following capistrano task.
Capistrano 3
namespace :deploy do
namespace :assets do
namespace :webp do
desc 'Updates mtime for webp images'
task :touch => [:set_rails_env] do
on roles(:web) do
execute <<-CMD.gsub(/[\r\n\t]?/, '').squeeze(' ').strip
cd #{release_path.join('public/assets')};
for asset in $(
find . -regex ".*\.webp$" -type f | LC_COLLATE=C sort
); do
echo "Update webp asset: $asset";
touch -c -- "$asset";
done
CMD
end
end
end
end
end
after 'deploy:updated', 'deploy:assets:webp:touch'
Capistrano 2
after "deploy:update", "deploy:webp:touch"
load do
namespace :deploy do
namespace :webp do
desc <<-DESC
[internal] Updates mtime for webp images
DESC
task :touch, :roles => :app, :except => { :no_release => true } do
run <<-CMD.compact
cd -- #{shared_path.shellescape}/#{shared_assets_prefix}/ &&
for asset in $(
find . -regex ".*\.webp$" -type f | LC_COLLATE=C sort
); do
echo "Update webp asset: $asset";
touch -c -- "$asset";
done
CMD
end
end
end
end
Web Server
As not all browsers support webp
images (see Can I Use), so they need to be served conditionally based on the HTTP Accept
header sent by browsers capable to display this format.
Nginx
Here is a simple nginx recipe, which contrary to popular beliefs, do not require if
nor rewrite
, instead use lightweight map
and try_files
http {
# IMPORTANT!!! Make sure that mime.types below lists WebP like that:
# image/webp webp;
include /etc/nginx/mime.types;
##
# Is webp supported?
# (needs to be part of http section)
##
map $http_accept $webp_suffix {
default "";
"~*webp" ".webp";
}
##
# Server
##
server {
location ~* ^/images/.+\.(png|jpg)$ {
if ($webp_suffix != "") {
add_header Vary Accept;
}
try_files $uri$webp_suffix $uri =404;
}
}
}
Make sure that webp is defined in mime.types
file:
image/webp webp;
CDN
If you serve your assets using CDN, you need to make sure that it forwards Accept
header allowing to conditionally choose webp for browsers which support it.
Amazon AWS CloudFront
Following solution would not work if your CloudFront distribution points to S3. Instead it should point to your webserver, which will host the webp serving logic.
Take following steps to enable Accept
header forwarding:
- visit your CloudFront distributions page
- select distribution
- choose
Behaviors
tab - select behaviourrepresenting your assets end hit
Edit
- select
Whitelist
for theForward Headers
option - add
Accept
to the list on the right - approve your changes clicking
Yes, Edit
- wait until refreshed distribution will be deployed
Test with:
curl -I -H "Accept: image/webp" http://yourdomain.com/yourimage.png
curl -I http://yourdomain.com/yourimage.png
Returned Content-Type
should be image/webp
in the first case and image/png
in the second.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request