kavu/sprockets-webp

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# Sprockets::WebP

[![unstable](https://rawgithub.com/hughsk/stability-badges/master/dist/unstable.svg)](http://github.com/hughsk/stability-badges)

[![Gem Version](https://badge.fury.io/rb/sprockets-webp.png)](http://badge.fury.io/rb/sprockets-webp)
[![Code Climate](https://codeclimate.com/github/kavu/sprockets-webp.png)](https://codeclimate.com/github/kavu/sprockets-webp)
[![Dependency Status](https://gemnasium.com/kavu/sprockets-webp.png)](https://gemnasium.com/kavu/sprockets-webp)
[![Still Maintained](http://stillmaintained.com/kavu/sprockets-webp.png)](http://stillmaintained.com/kavu/sprockets-webp)

[![Coderwall](https://api.coderwall.com/kavu/endorsecount.png)](https://coderwall.com/kavu)

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](https://developers.google.com/speed/webp/) itself. Please, consult the [webp-ffi](https://github.com/le0pard/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:

```ruby
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:

```ruby
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](https://github.com/le0pard/webp-ffi#encode-webp-image).

## 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

```ruby
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

```ruby
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](http://caniuse.com/webp)), 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](http://nginx.org) recipe, which contrary to popular beliefs, do not require ``if`` nor ``rewrite``, instead use lightweight ``map`` and ``try_files``

```nginx
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:

```nginx
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 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