keltanas
marty cats
Гоняя один макет в PageSpeed и находясь в поисках путей оптимизации обнаружил, что у меня в нем много мелких картинок используются в качестве фонов. Из за чего их не засунешь в спрайты. Решение нашлось в кодировании их в base64 и вставке в css.
В статье описываются некоторые инструменты, облегчающие этот процесс. Однако, это либо какие-то сервисы, либо sass/compas, ruby/jammit. А макет-то на обычном css и Symfony.
Вот и родилась идея написать фильтр для assetic (аналогично cssrewrite), который бы мне реплэйсил изображения в base64.
Вот примерный код класса, реализующего такой фильтр:
Чтобы подключить, надо добавить класс в качестве сервиса:
А при подключении в лэйауте ставить фильтр перед cssrewrite (а то после него пути уже не будут работать):
Собственно, выставляя параметр setMaxSize на нужное количество байт, можем выставить верхнюю границу размера изображений, до которой картинки будут кодироваться в CSS.
Благодаря такой конфигурации, мы в debug режиме можем преспокойно работать с обычными картинками. А в no-debug режиме (на продакшене) дампить файл с уже перезаписанными в base64 картинками. И не надо придумывать лишних инструментов.
Готов к любым критике, предложениям, пожеланиям. Может кто-то подскажет как улучшить решение.
Обкатав скрипт его можно будет и в бандл завернуть.
ЗЫЖ не смотря на простоту, мне не удалось найти уже готового фильтра.
ЗЫЖ2 Хотя библиотека Assetic, для которой написан фильтр, не является напрямую частью symfony. Однако, это наиболее популярный фреймворк, использующий её. Но, фильтр можно использовать в любых проектах, в том числе написанных не на symfony.
В статье описываются некоторые инструменты, облегчающие этот процесс. Однако, это либо какие-то сервисы, либо sass/compas, ruby/jammit. А макет-то на обычном css и Symfony.
Вот и родилась идея написать фильтр для assetic (аналогично cssrewrite), который бы мне реплэйсил изображения в base64.
Вот примерный код класса, реализующего такой фильтр:
PHP:
<?php
/**
* Encode images to css data:base64
* @author: keltanas <keltanas@gmail.com>
*/
namespace FT\SiteBundle\Component\Assetic\Filter;
use Assetic\Asset\AssetInterface;
use Assetic\Filter\BaseCssFilter;
class CssImageBase64Filter extends BaseCssFilter
{
protected $maxSize = 2048;
/**
* @param int $maxSize
*/
public function setMaxSize($maxSize)
{
$this->maxSize = $maxSize;
}
/**
* @return int
*/
public function getMaxSize()
{
return $this->maxSize;
}
/**
* Filters an asset after it has been loaded.
*
* @param AssetInterface $asset An asset
*/
public function filterLoad(AssetInterface $asset)
{
}
/**
* Filters an asset just before it's dumped.
*
* @param AssetInterface $asset An asset
*/
public function filterDump(AssetInterface $asset)
{
$sourceBase = $asset->getSourceRoot();
$sourcePath = $asset->getSourcePath();
$path = dirname($sourceBase . DIRECTORY_SEPARATOR . $sourcePath);
$content = $this->filterUrls($asset->getContent(), function($matches) use ($path) {
if (preg_match('@url\([\\\'" ]*(?:data|http|\/\/).*?[\\\'" ]*\)@u', $matches[0])) {
return $matches[0];
}
$img_path = realpath($path . DIRECTORY_SEPARATOR . $matches['url']);
if (file_exists($img_path) && filesize($img_path) < $this->getMaxSize()) {
$is = getimagesize($img_path);
return 'url("data:'.$is['mime'].';base64,'.base64_encode(file_get_contents($img_path)).'")';
}
return $matches[0];
});
$asset->setContent($content);
}
}
PHP:
parameters:
assetic_base64_filter_class: FT\SiteBundle\Component\Assetic\Filter\CssImageBase64Filter
services:
assetic_base64_filter:
class: %assetic_base64_filter_class%
tags:
- { name: assetic.filter, alias: cssrewriteb64 }
calls:
- [setMaxSize, [4096]]
PHP:
{% stylesheets 'bundles/ftsite/css/bootstrap.css'
'bundles/ftsite/css/style.css'
filter='?cssrewriteb64'
filter='cssrewrite'
filter='?yui_css'
output="css/style.css" %}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
Благодаря такой конфигурации, мы в debug режиме можем преспокойно работать с обычными картинками. А в no-debug режиме (на продакшене) дампить файл с уже перезаписанными в base64 картинками. И не надо придумывать лишних инструментов.
Готов к любым критике, предложениям, пожеланиям. Может кто-то подскажет как улучшить решение.
Обкатав скрипт его можно будет и в бандл завернуть.
ЗЫЖ не смотря на простоту, мне не удалось найти уже готового фильтра.
ЗЫЖ2 Хотя библиотека Assetic, для которой написан фильтр, не является напрямую частью symfony. Однако, это наиболее популярный фреймворк, использующий её. Но, фильтр можно использовать в любых проектах, в том числе написанных не на symfony.