📜 ⬆️ ⬇️

Kohana 3: module “kohana-static-files”


When meeting with the framework, I first of all look not at its capabilities, but at the ready-made solutions that it provides. In particular, it is possible to conveniently assemble JS / CSS files in parts and “give away” according to the recommendations for client optimization (YSlow / Google PageSpeed). I did not see any of the implementations I looked at, I didn’t see, even in Django (which, in fact, was inspired), so I decided to make my decision in the form of a module ready for use for Kohana v.3.

So, we will describe the basic needs / wishes that were put before the development of the module:
1) Build inline CSS / JS bit by bit
2) The ability to give claim 1 by inserting into the page code, or by generating and writing a file with a unique name on the disk.
3) Ability to build external CSS / JS files in one build
4) The ability to specify the condition under which this or that build from item 3 is connected, as well as any other external file (
  <! - [if IE 7]> 
).
5) The ability to make static to another domain, the main thing that he was on the same physical server.
6) Use CDN
7) Minimize CSS / JS.
8) The most important thing: A METHOD that allows including static (and usually not only CSS / JS, but also, for example, images) in the distributed modules. Since the current method is when the module functionality itself is transferred and connected, and the static is either copied to an arbitrary place DOCUMENT_ROOT, or it is imperative that the modules be in DOCUMENT_ROOT.
9) The ability to easily change URLs with statics so that it doesn’t conflict with the routing, for example, it’s not good if you want to have a section on CSS for the URL / css / when you have done this with a really existing directory with style files.

Those. you need to come up with and comply with further agreements.
Much of what was planned was embodied in a really working module.

')
To show the work of the module, and not just give a link to it, I will try to set an easy task before it:
1) to base css-framework.ru
2) try to implement an example css-framework.ru/demo/css-framework-layout.html based on the module “kohana-static-files”.

Since I am interested in the largest number of those who have tried it, I will paint a way to deploy the module from scratch, may the experienced Cohanovods forgive me.

To do this, download the latest version of Kohana v.3.
We transfer the system, application, modules directories above DOCUMENT_ROOT and, accordingly, change the paths in index.php:
<? php
$application = '../application';
$modules = '../modules';
$system = '../system';

* This source code was highlighted with Source Code Highlighter .


Next, pick up the latest version from github.com/aberdnikov/kohana-static-files , copy the contents into modules.
In the file application / bootstrapper.php we connect the module

<? php
Kohana::modules ( array (
// 'auth' = > MODPATH.'auth', // Basic authentication
// 'cache' = > MODPATH.'cache', // Caching with multiple backends
// 'codebench' = > MODPATH.'codebench', // Benchmarking tool
// 'database' = > MODPATH.'database', // Database access
// 'image' = > MODPATH.'image', // Image manipulation
// 'orm' = > MODPATH.'orm', // Object Relationship Mapping
// 'oauth' = > MODPATH.'oauth', // OAuth authentication
// 'pagination' = > MODPATH.'pagination', // Paging of results
// 'unittest' = > MODPATH.'unittest', // Unit testing
// 'userguide' = > MODPATH.'userguide', // User guide and API documentation
' kohana-static-files' = > MODPATH.' kohana-static-files ', // Static Files (JS/CSS/pictures)
));
? >


* This source code was highlighted with Source Code Highlighter .


In the initialization file of the module “kohana-static-files” we prescribe the module routing, which we will find when we first access “/!/static/style.css” according to the logic Kohana :: find_file ()
- first in application / static-files / style.css
- then in modules / {module_name} /static-files/style.css (where {module_name} is enumeration of the connected modules in the order of connection in bootstrapper.php)
- and only then in system / static-files / style.css.

Accordingly, you noticed that next to the native directories: classes, views, config, etc ... a new kind of “static-files” directory appeared, this is where we will add the static. We recall about paragraph 9 of the women at the beginning of the topic. After all, we have no idea which static directory will be chosen by a particular owner of a specific site using the described module.

Agreement №1
Therefore, in the file “cssf-base.css” we search for strings with URLs and make edits, replace absolute and relative URLs, or rather, start them with a substring for “{staticfiles_url}” autochange, and from the type line
.corners-2 em.tl, .corners-2 em.tr, .corners-2 em.bl, .corners-2 em.br {width: 4px; height: 4px; background-image: url (../ i / corners / corners-2.png); }
We have to get
.corners-2 em.tl, .corners-2 em.tr, .corners-2 em.bl, .corners-2 em.br {width: 4px; height: 4px; background-image: url ({staticfiles_url} i / corners / corners-2.png); }
Afterwards
url ({staticfiles_url} i / corners / corners-2.png);
will become something like
url (http://static.site.ru/!/static/i/corners/corners-2.png);

Agreement number 2
To avoid collisions of static file names, place them according to the following principle:
1) for modules, they should be placed in a directory with the same name as the module, respectively, the final URL for the news module styles file will be: {staticfiles_url} news / style.css
Accordingly, this file in the file system will be located for example here:
MODDIR.'news / static-files / style.css'
2) for the themes of the current site design, the static should be placed without subdirectories, for example, the main style file for the site design will have a URL
{staticfiles_url} /style.css
and the path to it may be:
APPDIR. ' static-files / style.css'

Moving on:
We modify the base Conrtoller_Welcome controller, which we inherit from the Controller_Template, in order to be able to use Cohanov views.

Instead of dummy
public function action_index()
{
$this- > request- > response = 'hello, world!';
}


* This source code was highlighted with Source Code Highlighter .


We add everything that is needed to solve the problem, the code is clear without explanation:
public function action_index() {
StaticCss::instance()- > addCss(Kohana::config('staticfiles.url').'news/style.css');
StaticCss::instance()- > addCssStatic('news/style.css');
StaticCss::instance()- > addCssStatic('css/cssf-base.css');
StaticCss::instance()- > addCssStatic('css/cssf-ie6.css', 'lte IE 6');
StaticCss::instance()- > addCssStatic('css/cssf-ie7.css', 'IE 7');
StaticJs::instance()- > addJsStatic('js/common.js');
StaticCss::instance()- > addCssInline('
.lb-1 .corners { background: #818181; }
.lb-2 .corners { background: #9a9a9a; }
.lb-3 .corners { background: #b4b4b4; }
.lb-4 .corners { background: #dadada; }
');
StaticJs::instance()- > addJsInline('CornersInit();');
StaticJs::instance()- > addJsOnload('alert(123)');
}

* This source code was highlighted with Source Code Highlighter .


It is only necessary to clarify the difference between the methods of the form addJsStatic and addJs
They are essentially the same, just the first method contains a wrapper inside itself, adding a prefix from the config to the beginning of the URL. In the example with the style sheet for news {staticfiles_url} news / style.css
You can do either:
StaticCss::instance()- > addCss(Kohana::config('staticfiles.url').'news/style.css');

* This source code was highlighted with Source Code Highlighter .

either more simply
StaticCss::instance()- > addCssStatic('news/style.css');

* This source code was highlighted with Source Code Highlighter .


I would also like to draw attention to the assembly in parts of the script, which should be executed at the onload event. Since jQuery is adopted by the main JS framework in the module, when calling
StaticJs::instance()- > addJsOnload('alert(123)');

* This source code was highlighted with Source Code Highlighter .

the following construction will be generated:
< script language ="JavaScript" type ="text/javascript" >
jQuery( document ).ready(
function (){
alert(123)
}
);
</ script >

* This source code was highlighted with Source Code Highlighter .

Those. you will not have to bother with creating a wrapper (“jQuery (document) .ready”), or connecting jQuery, by default the first time you call addJsOnload will connect jQuery, for this there is a special needJquery () method in the Kohana_StaticJs class. Naturally, if you use the module on an intranet without going online, then simply redefine the needJquery () method in StaticJs by connecting the file from the disk.

Now let's turn our attention to the module configuration in parts.
'js' = > array(
//
'min' = > true,
// (external, inline, onload)
'build' = > false,
),
'css' = > array(
//
'min' = > true,
// (external, inline)
'build' = > true,
),

* This source code was highlighted with Source Code Highlighter .


At this point you have the ability to manage the need for smart assembly into one file by content type (JS / CSS), type (external, inline, onload), conditions (
  <! - [if IE 7]> 
),
minimization (removal of comments, extra spaces and line breaks).

Agreement number 3
If there is a substring “.min.” In the url before the file to be connected, it is considered to be already compressed, even if the compression option is enabled, this file will be ignored, and if the build option is turned on, build. That will be added accordingly in the “as is” build.

'path' = > realpath(DOCROOT),

* This source code was highlighted with Source Code Highlighter .

This is the DOCUMENT_ROOT directory for the static domain, by default it is the same domain.
//
'url' = > '/!/static/',
//
'cache' = > '/!/cache/',

* This source code was highlighted with Source Code Highlighter .

Here I would like to comment on the presence of an exclamation mark: this is exactly the case in point 9 of the "hotelok" about conflicts and the fight against them.
'host' = > 'http://'.$_SERVER['HTTP_HOST'],

* This source code was highlighted with Source Code Highlighter .

This is actually the domain from which the static will be distributed, the use cases:
1) "" - the links will look like: "/pic.jpg"
2) “ ya.ru ” - the links will look like: “ ya.ru/pic.jpg
* To use Coral CDN
* add suffix ".nyud.net" in the current domain name with static
* for example, for the google.com domain, set google.com.nyud.net
* More information here: habrahabr.ru/blogs/i_recommend/82739 3) “ ya.ru.nyud.net ” - the links will look like: “ ya.ru.nyud.net/pic.jpg

To be able to use AutoCorrect in the already generated response, we slightly change the after method of the controller:
public function after() {
parent::after();
$this- > request- > response = str_replace('{statifiles_url}',
STATICFILES_URL,
$this- > request- > response);
}

* This source code was highlighted with Source Code Highlighter .

And finally, it remains to tell about the view device (View)
According to the recommendations of YSlow / GooglePageSpeed ​​in the head section we insert CSS
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > <br> < html xmlns ="http://www.w3.org/1999/xhtml" > <br> < head profile ="http://gmpg.org/xfn/11" > <br> < title > css-framework / layout-box </ title > <br> < meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" /> <br> < meta http-equiv ="imagetoolbar" content ="no" /> <br> < link rel ="icon" href ="{statifiles_url}favicon.ico" type ="image/x-icon" /> <br> < link rel ="shortcut icon" href ="{statifiles_url}favicon.ico" type ="image/x-icon" /> <br> <? php echo StaticCss::instance () - > getCssAll(); ? > <br> </ head > <br> <br> * This source code was highlighted with Source Code Highlighter .

and before closing we call JS inserts
<? php echo StaticJs::instance () - > getJsAll(); ? > <br> </ body > <br> </ html > <br><br> * This source code was highlighted with Source Code Highlighter .


With the tasks, in my opinion, the module managed:
- reduced the number of HTTP requests;
- CDN is optionally connected;
- CSS is inserted at the top of the page;
- JS is inserted at the end of the page;
- ONLY the necessary files are connected (one by one or build) (there is also a small drawback - separate builds will be created for all use cases);
- inline styles and scripts can be rendered in include files;
- duplicate script and style connections are excluded.

Now we just have to call on nginx for help, so that he puts the correct headers for the statics returned (gzip, ETags, Expires).

Let me remind you once again that the module itself can be picked up / forked here:
github.com/aberdnikov/kohana-static-files

Just in case, I’ll show you what happened as a result of the module’s operation (I manually added line breaks to display HTML without horizontal scrolling)
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > <br> < html xmlns ="http://www.w3.org/1999/xhtml" > <br> < head profile ="http://gmpg.org/xfn/11" > <br> < title > css-framework / layout-box </ title > <br> < meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" /> <br> < meta http-equiv ="imagetoolbar" content ="no" /> <br> < link rel ="icon" href ="http://static.site.ru/!/static/favicon.ico" type ="image/x-icon" /> <br> < link rel ="shortcut icon" <br> href ="http://static.site.ru/!/static/favicon.ico" <br> type ="image/x-icon" /> <br> < link rel ="stylesheet" <br> href ="http://static.site.ru/!/cache/css/3/7/3741c0ac0c2f8409beea116d6f4d6922.css" <br> media ="all" type ="text/css" /> <br> <!--[lte IE 6]><link rel="stylesheet" <br> href="http://static.site.ru/!/cache/css/lte-ie-6/1/6/161456642f5cfc18e731472d29293b28.css" <br> media="all" type="text/css" /><![endif]--> <br> <!--[IE 7]><link rel="stylesheet" <br> href="http://static.site.ru/!/cache/css/ie-7/c/b/cb4a089038b23dd1bfc5d0dfbfd35a68.css" <br> media="all" type="text/css" /><![endif]--> <br> < link rel ="stylesheet" <br> href ="http://static.site.ru/!/cache/css/inline/e/c/ec905aaa7ee63d90a646593b7e665936.css" <br> media ="all" type ="text/css" /> <br> </ head > <br> < body > <br> ... [skip html code] ...<br> < script language ="JavaScript" <br> type ="text/javascript" <br> src ="http://static.site.ru/!/cache/js/8/e/8e022d3b6bcba59dcba5c586d408f7b2.js" ></ script > <br> <script language= "JavaScript" <br> type= "text/javascript" <br> src= "http://static.site.ru/!/cache/js/inline/b/2/b2044b150de0ef43233d3491d060a5f6.js" ></script><br> <script language= "JavaScript" <br> type= "text/javascript" <br> src= "http://static.site.ru/!/cache/js/onload/1/5/15fb097828dd52d44bf36e77a96144b6.js" > </ script > <br> </ body > <br> </ html > <br> <br> * This source code was highlighted with Source Code Highlighter .


PS: the main difference from the idea from the userguide module for the distribution of statics is that complex builds are generated upon the first request immediately BEFORE being called from the page code by a separate request, and simple statics are copied to the directory accessible via HTTP on the first request, and then it is given by the web server, and not via PHP.
Those. deploy is performed at the first request.
Among the shortcomings, I see only the impossibility of automatically detecting changes to the file from which the build was created, since the name of the build is obtained from the names of the included files (otherwise it will greatly affect the speed of the module), it is only in the case of inline styles / scripts that the build name is obtained based on the content.

Therefore, when updating, just kill the /! / Directory with builds and caches.

There are plans to add methods for automatically deploying statics (one that does not require assembly) + advice to warm up the cache before a large load, driving through the site, for example, siege, which will create most of the necessary caches.

Source: https://habr.com/ru/post/112852/


All Articles