We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Volt minify

Hello!

Is there anyway to minify the HTML precompiled like Smarty does with the {strip} function ?

Thank you!



13.4k
Accepted
answer

Take a look here: https://stackoverflow.com/questions/24790579/how-to-minify-html-code-in-phalconphp

As most people say in there, it's best to do this with mod_pagespeed by Google which is a mod for Apache (and now nginx). It has many filters for minification along with many other settings: https://developers.google.com/speed/pagespeed/module/filters



8.1k
edited Sep '14

The big "Secret de Polichinelle" :)

For all framework and for PHP and for all servers :)


$di->set('view', function() {
        $eventsManager = new \Phalcon\Events\Manager();
        $eventsManager->attach("view:afterRenderView", function($event, $view) {
                #... your minify function of content
        });
        $view = new \Phalcon\Mvc\View();
        $view->setViewsDir(__DIR__ . '/views/');
        $view->setEventsManager($eventsManager);
        return $view;
}, true);

This wouldn't be for all frameworks & vanilla PHP... Just Phalcon.

If you do decide to minify your HTML this way remember that doing so may cost a lot of processing time, it's best to check how long an str_replace for example will take on your pages before attempting to roll it into production.

The big "Secret de Polichinelle" :)

For all framework and for PHP and for all servers :)


$di->set('view', function() {
       $eventsManager = new \Phalcon\Events\Manager();
       $eventsManager->attach("view:afterRenderView", function($event, $view) {
               #... your minify function of content
       });
       $view = new \Phalcon\Mvc\View();
       $view->setViewsDir(__DIR__ . '/views/');
       $view->setEventsManager($eventsManager);
       return $view;
}, true);


8.1k
edited Sep '14

May be. But...

Task of HTML minify is to get one line without extra spaces.

1) You may not be able to use mod_pagespeed when using hosting

2) For example, I don't use Apache on my servers. I used Nginx, but I using lighttpd now. Nginx need recompile with mod_pagespeed - this makes it difficult to support Lighttpd doesn't have pagespeed.

3) Lighty work very fast.

4) I use preg_replace and I have response near 2 ping latency on smallest server (1 core 32 bit)

5) I'm trying to create pages smaller then 256K

As result, I have no problem with HTML minify. All work in production.

As a complement - I use DigitalOcean VPS servers, thanks to them that I don't have problems with the speed :)

My usually configration - Debian 7 + lighttpd + PHP + MariaDB (or Redis), and, if need, Phalcon.

I had the experience with Linode and had a similar result.

P.S.

Meaning of the phrase - "for all framework" is as algorithm of work. Listening of view build fire and minify it before create response.

About your point 1, I don't know about you but you can't use Phalcon on 99% of shared hosting environments either.

PHP's processing power is slow as it's interpreted code, hence the reason why Phalcon is created as a C extension to PHP - doing this sort of work in PHP over C is just dumb IMO. You're going to waste about 100-500ms depending on the size of your HTML output in a time where user's expect everything to work instantly.

I wouldn't recommend using a preg_replace() because this will be even more expensive on processing time as it's using regular expressions, especially for a simple carriage return/whitespace stripper.

May be. But...

Task of HTML minify is to get one line without extra spaces.

1) You may not be able to use mod_pagespeed when using hosting

2) For example, I don't use Apache on my servers. I used Nginx, but I using lighttpd now. Nginx need recompile with mod_pagespeed - this makes it difficult to support Lighttpd doesn't have pagespeed.

3) Lighty work very fast.

4) I use preg_replace and I have response near 2 ping latency on smallest server (1 core 32 bit)

5) I'm trying to create pages smaller then 256K

As result, I have no problem with HTML minify. All work in production.

As a complement - I use DigitalOcean VPS servers, thanks to them that I don't have problems with the speed :)

My usually configration - Debian 7 + lighttpd + PHP + MariaDB (or Redis), and, if need, Phalcon.

I had the experience with Linode and had a similar result.

P.S.

Meaning of the phrase - "for all framework" is as algorithm of work. Listening of view build fire and minify it before create response.



8.1k
edited Sep '14

I have ping to my server 50ms

And I get page for 120ms.

With all images I get page near 600ms with browser cache . 27 requests withih 23 images + 2 stylesheets and 1 javascript.

When browser cache is off, I get page for 1.2 second. With 1.6Mbyte weight.

What else do I need to accelerate ?

If you want increase speed, you can use instance with more cores.

The question is, how many lines is your final HTML output? I know on a project I'm working on there are 2000+ lines per page, using PHP to minify the html here would be much more processor expensive than using a C mod or CloudFlare's AutoMinify. Plus you're more likely to break inline javascript (if used) when just using your own function to minify.



8.1k
edited Sep '14

So. Testing

I get html page from getbootstrap.com and clone it to big html file within 2152 strings.

wc bb.html 
 2151  7194 98937 bb.html

We have 2152 string 7194 words 98937 synbols

Small test :

<?php
function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

$html = file_get_contents('bb.html');
echo "Input content length : ", strlen($html), "\n";

                $search = array(
                    '/\>[^\S ]+/s', //strip whitespaces after tags, except space
                    '/[^\S ]+\</s', //strip whitespaces before tags, except space
                    '/(\s)+/s',  // shorten multiple whitespace sequences
                    '/>(\s)+</',
                    '/\n/',
                    '/\r/',
                    '/\t/',
                );
                $replace = array(
                    '>',
                    '<',
                    '\\1',
                    '><',
                    '',
                    '',
                    '',
                );

$time_start = microtime_float();

$content = preg_replace($search, $replace, $html);

$time_end = microtime_float();
$time = ($time_end - $time_start) *1000;

echo "Task time is : $time millisecond\n";

echo "Output content length : ", strlen($content);
$out_file = 'out.html';

file_put_contents($out_file, $content, LOCK_EX);

Start it and get result :

Input content length : 98937
Task time is : 7.7309608459473 millisecond
Output content length : 88109
wc out.html 
    0  5502 88109 out.html

About broken javascript :

If javascript is correct, it not broken.

In other words, correct javascript always works . :)

edited Sep '14

That isn't a real world representation, try running apachebench and see the performance.

And your comment about Javascript is completely wrong... Consider the following code:

<script type="text/javascript">
    // my comment
    alert('abc'); // another comment
    alert('def');
</script>

Your "minify" regex would make this become one long javascript comment rendering it useless, even though it is correct and valid javascript.



8.1k
edited Sep '14

Test on real site via siege (ping 50ms) :

Transactions:                    135 hits
Availability:                 100.00 %
Elapsed time:                   9.48 secs
Data transferred:               5.41 MB
Response time:                  0.56 secs
Transaction rate:              14.24 trans/sec
Throughput:                     0.57 MB/sec
Concurrency:                    7.94
Successful transactions:         135
Failed transactions:               0.5
Longest transaction:            1.23
Shortest transaction:           0.30

We have 135 hits on 10 sec with concurrency 15 users, this implies 13.5 hits 60 sec 60 min *24 hours = 1166400 hits per 24 hours .

Cpu loading near 30%.

About javascript - You have shown just a case of bad practice of coding. Try to avoid such comments. :)

Remove all comments from the code before production - it's best practice.

LMAO that isn't bad practice at all - I just found a flaw in your code.

Ideally there would be no inline js anyway but I was just pointing it out. If you want to spend time minifying your html output within PHP that's up to you...

any way to store minify volt cached files?

normal.volt.php

<!doctype html>
<html>
    <head>
        <?php echo $this->tag->gettitle(); ?>
    </head>
    <body>
        <?php echo $this->getContent(); ?>
    </body>
</html>

minify.volt.php

<!doctype html><html><head><?php echo $this->tag->gettitle(); ?></head><body><?php echo $this->getContent(); ?></body></html>


11.2k

any way to store minify volt cached files?

normal.volt.php

<!doctype html>
<html>
   <head>
       <?php echo $this->tag->gettitle(); ?>
   </head>
   <body>
       <?php echo $this->getContent(); ?>
   </body>
</html>

minify.volt.php

<!doctype html><html><head><?php echo $this->tag->gettitle(); ?></head><body><?php echo $this->getContent(); ?></body></html>

You would have to write custom logic to store and read that minified file. I would recomend you to use mod_pagespeed from google. As was recomended at answer #2. It is fast and pretty easy to implement

Thanks heptagono

I prefer to minimize once instead of all queries

FYI mod_pagespeed caches the changed output.

Thanks heptagono

I prefer to minimize once instead of all queries

Oh Thanks I didn't know but insist I prefer make minified htmls



17.5k

I was finded solution by use Grunt you may minify php compiled files by volt only once! Important config Gruntfile.js changes

/**
 * Created by yosefk on 01/09/2016.
 */

module.exports = function(grunt) {
    // load all grunt tasks matching the ['grunt-*', '@*/grunt-*'] patterns
    require('load-grunt-tasks')(grunt);

    //  Вся настройка находится здесь
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        concat: {
            options: {
                sourceMap: true
            },
            js_index: {
                src: [
                    'node_modules/admin-lte/plugins/jQuery/*.min.js',
                    'node_modules/admin-lte/bootstrap/js/bootstrap.min.js',
                    'node_modules/admin-lte/dist/js/app.min.js',
                    'build/js/index.min.js'

                ],
                dest: 'js/index.js'
            },
            css_index: {
                src: [
                    'node_modules/admin-lte/bootstrap/css/bootstrap.min.css',
                    'node_modules/ionicons/dist/css/ionicons.min.css',
                    'node_modules/font-awesome/css/font-awesome.min.css',
                    'node_modules/admin-lte/dist/css/AdminLTE.min.css',
                    'node_modules/admin-lte/dist/css/skins/_all-skins.min.css',
                    'build/css/index.min.css'
                ],
                dest: 'css/index.css'
            }
        },
        uglify: {
            js_index: {
                src:  ['node_modules/admin-lte/dist/js/demo.js','src/js/index.js'],
                dest: 'build/js/index.min.js'
            }
        },
        cssmin:{
            target: {
                files: {
                    'build/css/index.min.css': ['src/css/index.css']
                }
            }
        },
        watch: {
            options: {
                livereload: true,
                atBegin: true
            },
            scripts: {
                files: ['src/js/*','src/css/*'],
                tasks: ['uglify','cssmin','concat','clean'],
                options: {
                    spawn: false,
                    livereload: true
                }
            },
            php:{
                files: ['../cache/volt/*'],
                tasks: ['htmlmin'],
                options: {
                    spawn: false
                }
            }
        },
        livereload: {
            options: {
                livereload: true
            },
            files: [
                'src/**/*',
                'src/**/**/*'
            ]
        },
        copy: {
            fonts: {
                files: [
                    {expand: true, cwd: 'node_modules/font-awesome/fonts/',src: '*', dest: 'fonts/', filter: 'isFile'},
                    {expand: true, cwd: 'node_modules/ionicons/dist/fonts/', src: '*', dest: 'fonts/', filter: 'isFile'}
                ]
            }
        },
        clean: ['build'],
        htmlmin: {
            dist: {
                options: {
                    removeComments: true,
                    collapseWhitespace: true
                },
                tasks: ['clean:php'],
                files: [
                    {
                        expand: true,
                        cwd: '../cache/volt',
                        src: '*.php',
                        dest: '../cache/volt/'
                    }]
            }
        }
    });

    //  Указываем, какие задачи выполняются, когда мы вводим «grunt» в терминале
    grunt.registerTask('default', ['uglify','cssmin','concat','copy','clean']);

};

any way to store minify volt cached files?

normal.volt.php

<!doctype html>
<html>
   <head>
       <?php echo $this->tag->gettitle(); ?>
   </head>
   <body>
       <?php echo $this->getContent(); ?>
   </body>
</html>

minify.volt.php

<!doctype html><html><head><?php echo $this->tag->gettitle(); ?></head><body><?php echo $this->getContent(); ?></body></html>

On your main index.php file, replace:

echo $application->handle()->getContent();

with:

echo str_replace(["\n","\r","\t"], '', $application->handle()->getContent());


15.2k

This is a bad idea, if you are handling your content, not only html, like images, it would mess up all you content.

On your main index.php file, replace:

echo $application->handle()->getContent();

with:

echo str_replace(["\n","\r","\t"], '', $application->handle()->getContent());


1.3k

Thanks for sharing.

I implemented this but found one a big caveat:

afterRenderView (or other events for that matter) would only minify the rendred page, not the template in the cache.

This means that the "minification" is carried out repeatedly.

The big "Secret de Polichinelle" :)

For all framework and for PHP and for all servers :)


$di->set('view', function() {
       $eventsManager = new \Phalcon\Events\Manager();
       $eventsManager->attach("view:afterRenderView", function($event, $view) {
               #... your minify function of content
       });
       $view = new \Phalcon\Mvc\View();
       $view->setViewsDir(__DIR__ . '/views/');
       $view->setEventsManager($eventsManager);
       return $view;
}, true);