Simple CSS minifier for twig, with basic caching
up vote
2
down vote
favorite
On part of a project, I have some CSS being read using twig's source()
function.
But sending a huge chunk of CSS is not optimal.
To reduce the size of the HTML, I've written this twig filter.
However, I've noticed that some big files would take a bit more to be minimified.
To reduce the time to re-minify the CSS, I've added a crude caching system.
Assuming that you have the following:
$twig = new Twig_Environment(new Twig_Loader_Filesystem( ... ), array( ... ));
You have the following code:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
str_replace(array("rn", "r", "n", "t", ' ', ' ', ' '), '', $css)
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
This filter takes 1 parameter, to indicate if there's or not caching, and returns the minified CSS when applicable.
An example of it's usage:
{% for file in css_files %}
<style>{{ source('assets/css/' ~ file ~ '.css') | minify_css }}</style>
{% endfor %}
This assumes that the template has access to the variable css_files
, containing the name of those files.
What else can I improve here?
Any speed improvements or readability improvements?
php css twig
add a comment |
up vote
2
down vote
favorite
On part of a project, I have some CSS being read using twig's source()
function.
But sending a huge chunk of CSS is not optimal.
To reduce the size of the HTML, I've written this twig filter.
However, I've noticed that some big files would take a bit more to be minimified.
To reduce the time to re-minify the CSS, I've added a crude caching system.
Assuming that you have the following:
$twig = new Twig_Environment(new Twig_Loader_Filesystem( ... ), array( ... ));
You have the following code:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
str_replace(array("rn", "r", "n", "t", ' ', ' ', ' '), '', $css)
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
This filter takes 1 parameter, to indicate if there's or not caching, and returns the minified CSS when applicable.
An example of it's usage:
{% for file in css_files %}
<style>{{ source('assets/css/' ~ file ~ '.css') | minify_css }}</style>
{% endfor %}
This assumes that the template has access to the variable css_files
, containing the name of those files.
What else can I improve here?
Any speed improvements or readability improvements?
php css twig
add a comment |
up vote
2
down vote
favorite
up vote
2
down vote
favorite
On part of a project, I have some CSS being read using twig's source()
function.
But sending a huge chunk of CSS is not optimal.
To reduce the size of the HTML, I've written this twig filter.
However, I've noticed that some big files would take a bit more to be minimified.
To reduce the time to re-minify the CSS, I've added a crude caching system.
Assuming that you have the following:
$twig = new Twig_Environment(new Twig_Loader_Filesystem( ... ), array( ... ));
You have the following code:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
str_replace(array("rn", "r", "n", "t", ' ', ' ', ' '), '', $css)
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
This filter takes 1 parameter, to indicate if there's or not caching, and returns the minified CSS when applicable.
An example of it's usage:
{% for file in css_files %}
<style>{{ source('assets/css/' ~ file ~ '.css') | minify_css }}</style>
{% endfor %}
This assumes that the template has access to the variable css_files
, containing the name of those files.
What else can I improve here?
Any speed improvements or readability improvements?
php css twig
On part of a project, I have some CSS being read using twig's source()
function.
But sending a huge chunk of CSS is not optimal.
To reduce the size of the HTML, I've written this twig filter.
However, I've noticed that some big files would take a bit more to be minimified.
To reduce the time to re-minify the CSS, I've added a crude caching system.
Assuming that you have the following:
$twig = new Twig_Environment(new Twig_Loader_Filesystem( ... ), array( ... ));
You have the following code:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
str_replace(array("rn", "r", "n", "t", ' ', ' ', ' '), '', $css)
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
This filter takes 1 parameter, to indicate if there's or not caching, and returns the minified CSS when applicable.
An example of it's usage:
{% for file in css_files %}
<style>{{ source('assets/css/' ~ file ~ '.css') | minify_css }}</style>
{% endfor %}
This assumes that the template has access to the variable css_files
, containing the name of those files.
What else can I improve here?
Any speed improvements or readability improvements?
php css twig
php css twig
asked Jul 29 '17 at 11:46
Ismael Miguel
4,29111452
4,29111452
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
The very obvious thing is that str_replace
.
Here, there are 2 things to change:
- Completely remove this line.
All that replace can be made into the following regular expression:@(?:s{2,}|[rnt])+@
This should be the very first regular expression.
Since all the other rules handle whitespace, one only needs to normalize it. The rest of the replacements will dictate if it needs to be replaced or not.
If the whitespace is simply removed, it will lead to removing needed whitespace.
Here's an example CSS:
#services img{
max-width: 100%;
}
#slide .carousel-caption {
display: none
}
With the replacement as an empty string, you would remove the double-space in
#services img
. Normalizing it to a single space will return#services img
instead of minifying into#servicesimg
.
With this said, and a bug fixed, the code will look like the following:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@(?:s{2,}|[rnt])+@', // normalize whitespace
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
' ',
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
$css
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
The very obvious thing is that str_replace
.
Here, there are 2 things to change:
- Completely remove this line.
All that replace can be made into the following regular expression:@(?:s{2,}|[rnt])+@
This should be the very first regular expression.
Since all the other rules handle whitespace, one only needs to normalize it. The rest of the replacements will dictate if it needs to be replaced or not.
If the whitespace is simply removed, it will lead to removing needed whitespace.
Here's an example CSS:
#services img{
max-width: 100%;
}
#slide .carousel-caption {
display: none
}
With the replacement as an empty string, you would remove the double-space in
#services img
. Normalizing it to a single space will return#services img
instead of minifying into#servicesimg
.
With this said, and a bug fixed, the code will look like the following:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@(?:s{2,}|[rnt])+@', // normalize whitespace
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
' ',
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
$css
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
add a comment |
up vote
0
down vote
The very obvious thing is that str_replace
.
Here, there are 2 things to change:
- Completely remove this line.
All that replace can be made into the following regular expression:@(?:s{2,}|[rnt])+@
This should be the very first regular expression.
Since all the other rules handle whitespace, one only needs to normalize it. The rest of the replacements will dictate if it needs to be replaced or not.
If the whitespace is simply removed, it will lead to removing needed whitespace.
Here's an example CSS:
#services img{
max-width: 100%;
}
#slide .carousel-caption {
display: none
}
With the replacement as an empty string, you would remove the double-space in
#services img
. Normalizing it to a single space will return#services img
instead of minifying into#servicesimg
.
With this said, and a bug fixed, the code will look like the following:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@(?:s{2,}|[rnt])+@', // normalize whitespace
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
' ',
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
$css
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
add a comment |
up vote
0
down vote
up vote
0
down vote
The very obvious thing is that str_replace
.
Here, there are 2 things to change:
- Completely remove this line.
All that replace can be made into the following regular expression:@(?:s{2,}|[rnt])+@
This should be the very first regular expression.
Since all the other rules handle whitespace, one only needs to normalize it. The rest of the replacements will dictate if it needs to be replaced or not.
If the whitespace is simply removed, it will lead to removing needed whitespace.
Here's an example CSS:
#services img{
max-width: 100%;
}
#slide .carousel-caption {
display: none
}
With the replacement as an empty string, you would remove the double-space in
#services img
. Normalizing it to a single space will return#services img
instead of minifying into#servicesimg
.
With this said, and a bug fixed, the code will look like the following:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@(?:s{2,}|[rnt])+@', // normalize whitespace
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
' ',
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
$css
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
The very obvious thing is that str_replace
.
Here, there are 2 things to change:
- Completely remove this line.
All that replace can be made into the following regular expression:@(?:s{2,}|[rnt])+@
This should be the very first regular expression.
Since all the other rules handle whitespace, one only needs to normalize it. The rest of the replacements will dictate if it needs to be replaced or not.
If the whitespace is simply removed, it will lead to removing needed whitespace.
Here's an example CSS:
#services img{
max-width: 100%;
}
#slide .carousel-caption {
display: none
}
With the replacement as an empty string, you would remove the double-space in
#services img
. Normalizing it to a single space will return#services img
instead of minifying into#servicesimg
.
With this said, and a bug fixed, the code will look like the following:
$twig->addFilter(new Twig_SimpleFilter('minify_css', function($css, $cache = true){
$path = $_SERVER['DOCUMENT_ROOT'] . '/cache/minify_css/';
$min_length = 1024;
if(!is_dir($path))
{
mkdir($path, 0755, true);
}
$length = strlen($css);
$result = '';
if($cache && $length > $min_length && @is_file($file = $path . ($hash = md5($css)) . '.css' ))
{
$result = file_get_contents($file);
}
else if($length >= 9)
{
$result = preg_replace(
array(
'@(?:s{2,}|[rnt])+@', // normalize whitespace
'@/*[^*]**+([^/][^*]**+)*/@', // /*abc*/ ->
'@([-;{]w*)s*:s*@', //a : b -> a:b
'@s*;s*}s*@', //a:b ; } -> a:b}
'@s*{s*@', // a { b:c} -> a{b:c}
'@s*!importants*@i', // a:b !important } -> a:b!important}
'@([,;}!:]|^)s*0+s*px@i', // a: 0px -> a:0
'@([,;:!.>~+=[{}(]|^)[srn]+@', // a, b -> a,b
'@[srn]+([,;!>~+=]{})]|$)@', // a ,b -> a,b
'@([,:( ])s*#([da-f])2([da-f])3([da-f])4@i' // a: #FF00CC -> a:#F0C
),
array(
' ',
'',
'$1:',
'}',
'{',
'!important',
'${1}0',
'$1',
'$1',
'$1#$2$3$4'
),
$css
);
if($cache && $length > $min_length)
{
file_put_contents($file, $result);
}
}
return $result;
}), array('is_safe' => array('html', 'css', 'js'))
);
answered Oct 5 '17 at 16:58
Ismael Miguel
4,29111452
4,29111452
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f171509%2fsimple-css-minifier-for-twig-with-basic-caching%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown