
There are a lot of tips on how to speed up the return of the site - this is both static through nginx and clustering, and a lot of all sorts of clever technologies. However, in all the books, advising how to increase the loading of sites, you can find two constantly repeating topics - “gluing CSS / JS” and “enabling compression”.
GlueingIt's simple - if, for example, you have 3 CSS files and 5 JS on your page, the browser will have to create 8 connections and download data for them, and as you know, several large files are better than many smaller ones. This is due to the fact that the browser spends time on each connection setup, and often rather big - up to 40% of download time.
Standard methods to write a certain batch file, which would run over the necessary files and glue them together into one I did not like in principle, for doing things with pens that can be done automatically is fundamentally wrong, in this case at least because it affects either in development or in production (additional actions).
')
As they say "never rewrite what you can just cut and paste";)
CompressionThe smaller the volume of “pumped” files, the less time is spent on downloading. Even if these files are compressed and we spend some time on unpacking - with modern computing power on the client, this time cost is practically insignificant.
Most modern browsers support the deflate compression method, sometimes called gzip by the name of the standard * nix utility that does this.
What can and should be compressed on the web? Any text queries like JS / CSS / JSON / HTML.
There is a wonderful module for Apache mod-deflate, which you can directly use .htaccess to specify what to compress and what not to compress, it is very easy to use, but alas! - usually prohibited on standard hostings due to the fact that they (hosters) fear for their CPU time.
Of course, there is a reasonable portion of it - this module presses everything “on the fly” and if you do not take some tricks, each time loading a page for a new user, it will be
re-pinch all css / js etc
If you have a VDS and you are your own master, use mod-deflate, because it is well debugged and there are a lot of examples of network applications.
And we will return to the usual hosts - is there a way out? Even if you have been eaten, you always have two ways out - there is a way out here too. And this task is very good to go to the previous one - now I will explain why.
Most JS / CSS and other texts are static, i.e. they do not change in the process of the site functioning - it makes sense to merge them in order to satisfy the “gluing” clause + immediately compress.
We put the received files in a certain cache, from where our Apache will take them and give. Moreover, we automate the process through mod-rewrite.
The algorithm will turn out like this :
- some file is requested from a special URL
- if the client supports compression and a compressed file of this type is in our cache, we give and terminate processing
- if compression is not supported and there is just a file of this type - give it up and finish processing
- otherwise, run our handler
Let us agree that our model will trigger when accessing the URL of the form "/ glue / ...."
And the files will be in “/ static / glue / ...”.In this case, we kill another rabbit - the files will be given through PHP only once - during the formation, and then everything will be like the big ones :) the statics should and will be given by the web server.
In principle, you can make the folder coincide with the URL, then the mod-rewrite config will be slightly easier but it will not be so interesting, in general, you can always simplify :)
I hope that in the root of your site already lives a .htaccess file with content like this:
RewriteEngine On
RewriteBase /
RewriteRule ^.*$ index.php [QSA,L]
Well, either like. The main condition is that if mod-rewrite did not find what to do with the URL that came in, it will eventually cause some kind of script file.
In this case, index.php
To add our algorithm, let's write the following in .htaccess:
Add support for compressed .gz files, as well as .jz.gz and .css.gz
AddEncoding gzip .gz
< FilesMatch " \. js.gz$" >
#
Header set Cache-control: private
Header append Vary User-Agent
ForceType "text/javascript"
Header set Content-Encoding: gzip
AddCharset windows- 1251 .js.gz
</ FilesMatch >
< FilesMatch " \. css.gz$" >
#
Header set Cache-control: private
Header append Vary User-Agent
ForceType "text/css"
Header set Content-Encoding: gzip
</ FilesMatch >
Add the rule of returning our files (dereference of the URL to the physical folder)
RewriteCond %{ENV:REDIRECT_GZ} = 1
RewriteCond %{REQUEST_URI} ^/glue/(.+)$
RewriteCond %{DOCUMENT_ROOT}/static/glue/%1 -f
RewriteRule . - [L]
We add check on support by client of compression
RewriteCond %{REQUEST_URI} ^/glue/(.+)$
RewriteCond %{DOCUMENT_ROOT}/static/glue/%1.gz -f
RewriteCond %{HTTP:Accept-Encoding} ^.*?gzip.*$ [NC]
RewriteCond %{HTTP_USER_AGENT} !^konqueror [NC]
RewriteRule ^siteglue/(.*)$ /static/glue/$1.gz [L,E=GZ: 1 ]
If compression is not supported
RewriteCond %{REQUEST_URI} ^/glue/(.+)$
RewriteCond %{DOCUMENT_ROOT}/static/glue/%1 -f
RewriteRule . static/glue/%1 [L,E=GZ: 1 ]
Now let's take on our most important magic - the automatic generation of these same files.
Here one more thing is a trick, in this case rather - one more convention -
in the html files we will write requests to css or js in the following form:
“/Glue/1.css—2.css— 3-4-5.css” , where “-” is a replacement for “/”, and “-” is a file separator.In addition, the names can only be English letters, numbers and the symbol "_", for me - this is more than enough.
Of course, these are conventions and you can choose other rules and other separators. For example, you can use "," or something else.
However, I chose the "-" because it is a completely normal and frequently occurring URL symbol and there can hardly be any stupid problems with it, such as cutting out curved scripts on the path from you to the client.
In the file in index.php (or what do you run there according to .htaccess?) We add a handler that checks the URL for compliance with our “/glue/.*” and, in case of coincidence, makes
echo (Glue :: generate ($ str)) where
$ str is what we have in the URL after the last slash, i.e. for "/glue/a.js" it will be "a.js"
Glue class itself
class Glue {
static $allowedExt = array (
"js" => array ( "check" => "/^js/.*?.js$/" , "delimeter" => ";n" , "mime" => “text / javascript” ) ,
"css" => array ( "check" => "/^css/.*.css$/" , "delimeter" => "n" , "mime" => “text / css” ) ,
) ;
static function generate ( $str ) {
if ( ! $str ) return null ; // URL
$files = array ( ) ;
preg_replace ( "/((?:[a-z0-9_.]+-)+[a-z0-9_.]+.([a-z0-9]+))(?:--|$)/ie" , " $files []=str_replace( '-', '/', " 1 ")" , $str ) ;
if ( count ( $files ) == 0 ) return null ; // URL
$srcF = “ / static ” ; // ,
$dstF = “ / glue” ; //,
$content = "" ;
$cext = substr ( strrchr ( $files [ 0 ] , '.' ) , 1 ) ;
if ( $cext === false ) return null ; //
$fd = null ;
foreach ( self :: $allowedExt as $k => $v ) {
if ( $k == $cext ) {
$fd = $v ;
break ;
}
}
if ( ! $fd ) return null ; //
$usedNames = array ( ) ;
$fdC = & $fd [ "check" ] ;
$fdD = & $fd [ "delimeter" ] ;
foreach ( $files as $name ) {
$ext = substr ( strrchr ( $name , '.' ) , 1 ) ;
if (
$ext === false ||
in_array ( $name , $usedNames ) ||
$ext != $cext ||
! preg_match ( $fdC , $name )
) return null ; // ,
$usedNames [ ] = $name ;
$filec = file_get_contents ( " {$srcF} / {$name} " ) ;
if ( ! $filec ) return null ; //
$content .= $content != "" ? $fdD . $filec : $filec ;
}
//
file_put_contents ( " {$dstF} / {$str} " , $content ) ;
//
$gzip = gzencode ( $content , 9 ) ;; //gzdeflate( $content, 9 );
if ( $gzip ) file_put_contents ( "/ {$dstF} / {$str} .gz" , $gzip ) ;
// mime-
header ( "Content-type: " . $fd [ "mime" ] , true ) ;
return $content ;
}
}
Again, this is only illustrated one way to HOW to do it - do not like the static class - you can choose any other way - with blackjack and ladies are not heavy behavior;)
That's basically everything, it remains to run through the files of the project - all the same, there is a piece of “manual” work: (- and prescribe instead of a heap of scripts one, but according to the rules described a bit Above.
All - at the first request, everything will automatically gather and begin to be given.
Another small addition - what to do with the content provided by PHP?It must also be squeezed!
To do this, in the place where you give the text files, where the generated content is given - for example,
echo ($ content);Do the following:
if ( isClientSupportGzip ( ) ) {
ob_start ( "ob_gzhandler" ) ;
echo ( $content ) ;
ob_end_flush ( ) ;
} else echo ( $content ) ;
This will compress the output dynamic content if the client supports compression. The function that tests it is taken from the Internet and looks like this:
function isClientSupportGzip ( ) {
if ( headers_sent ( ) || connection_aborted ( ) ) return false ;
if ( stripos ( getenv ( "HTTP_ACCEPT_ENCODING" ) , "gzip" ) === false ) return false ;
if ( stripos ( getenv ( "HTTP_USER_AGENT" ) , "konqueror" ) !== false ) return false ;
return true ;
}
For development, I recommend starting some kind of development mode constant, and in case it is set to 1, simply do not write files to the cache and do not compress the dynamics - you don’t have to climb and clear our cache directory every time you change it in any js file.
That's all - we slightly dispersed your site) According to my observations, the increase in the rate of return can be 30-40%.
If there are any corrections, suggestions or criticism - please, welcome in the comments - I will be very grateful, because as they say - learn a century)Fast sites, maximum compression and joyful customers;)
PSIf you use any library, for example jquery, on all pages of your project with the same location, I recommend to take it all the same to a hotel file, the same applies to a single css - so it is faster cached by the browser.
When gluing JS, remember the peculiarity - you need to glue it through “;”, since in the previous file after the last line may not be ";"
When writing a cache formation handler, remember about hackers - check everything and everything, with illiterate screening you can stick together and get a lot of interesting things as statics, at worst you can drive away your disk space to death, so even Mr. Proper will not help - more accurate in general .
If you have a site in the most unpopular coding, so that everything is chocolate, replace
ForceType "text / javascript" on ForceType "text / javascript; content = windows-1251 "
and add: AddCharset windows-1251 .js and AddCharset windows-1251 .css
And a little advice, keep the same order in specifying the files to be glued, because technically “/glue/a.js— b.js” and “/glue/b.js —a.js” are one and the same, but in practice you will get two files in the cache ...
From commentsImenem and
TrueDrago suggested that the optimal level for deflate compression is not 9, but 6