Sprockets converter of PNG and JPEG assets to WebP
Ruby
Clone or download
Latest commit 8df7a9c Mar 18, 2015
Permalink
Failed to load latest commit information.
lib
.gitignore
Gemfile
LICENSE.txt
README.md
Rakefile
sprockets-webp.gemspec

README.md

Sprockets::WebP

unstable

Gem Version Code Climate Dependency Status Still Maintained

Coderwall

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 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 the Forward 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

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request