简体   繁体   中英

How do I compress HTML in laravel 5

In Laravel 4.0, I use the code below to compress the HTML laravel response outputs to browser, however it doesn't work in laravel 5.

App::after(function($request, $response)
{
    if($response instanceof Illuminate\Http\Response)
    {
        $buffer = $response->getContent();
        if(strpos($buffer,'<pre>') !== false)
        {
            $replace = array(
                '/<!--[^\[](.*?)[^\]]-->/s' => '',
                "/<\?php/"                  => '<?php ',
                "/\r/"                      => '',
                "/>\n</"                    => '><',
                "/>\s+\n</"                 => '><',
                "/>\n\s+</"                 => '><',
            );
        }
        else
        {
            $replace = array(
                '/<!--[^\[](.*?)[^\]]-->/s' => '',
                "/<\?php/"                  => '<?php ',
                "/\n([\S])/"                => '$1',
                "/\r/"                      => '',
                "/\n/"                      => '',
                "/\t/"                      => '',
                "/ +/"                      => ' ',
            );
        }
        $buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
        $response->setContent($buffer);
    }
});

Please how do i make this work in Laravel 5.

OR

Please provide a better way of compressing HTML in laravel 5 if any. Thanks in advance.

NB: I don't wish to use any laravel package for compressing html, just need a simple code that does the work without killing performance.

Complete code is this (with custom GZip enabled) :

<?php

namespace App\Http\Middleware;

use Closure;

class OptimizeMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $buffer = $response->getContent();
        if(strpos($buffer,'<pre>') !== false)
        {
            $replace = array(
                '/<!--[^\[](.*?)[^\]]-->/s' => '',
                "/<\?php/"                  => '<?php ',
                "/\r/"                      => '',
                "/>\n</"                    => '><',
                "/>\s+\n</"                 => '><',
                "/>\n\s+</"                 => '><',
            );
        }
        else
        {
            $replace = array(
                '/<!--[^\[](.*?)[^\]]-->/s' => '',
                "/<\?php/"                  => '<?php ',
                "/\n([\S])/"                => '$1',
                "/\r/"                      => '',
                "/\n/"                      => '',
                "/\t/"                      => '',
                "/ +/"                      => ' ',
            );
        }
        $buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
        $response->setContent($buffer);
        ini_set('zlib.output_compression', 'On'); // If you like to enable GZip, too!
        return $response;
    }
}

Please check your browser network inspector for Content-Length header before/after implement this code.

enjoy it ... :).. .

It is not very good solution to minify html in middleware as you can spend a lot of CPU time on it and it runs on every request.

Instead it is better to use htmlmin package ( https://github.com/HTMLMin/Laravel-HTMLMin ):

composer require htmlmin/htmlmin
php artisan vendor:publish

Minifying HTML on blade template level and caching it in storage should be much more effective.

The recommended way to do this in Larvel 5 is to rewrite your function as middleware . As stated in the docs:

..this middleware would perform its task after the request is handled by the application:

<?php namespace App\Http\Middleware;

class AfterMiddleware implements Middleware {

    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // Perform action

        return $response;
    }
}

I have created a webpack plugin to solve same purpose. MinifyHtmlWebpackPlugin

Install the plugin with npm:

$ npm install minify-html-webpack-plugin --save-dev

For Laravel Mix Users

Paste below snippets into mix.js file.

    const MinifyHtmlWebpackPlugin = require('minify-html-webpack-plugin');
    const mix = require('laravel-mix');

    mix.webpackConfig({
        plugins: [
            new MinifyHtmlWebpackPlugin({
                src: './storage/framework/views',
                ignoreFileNameRegex: /\.(gitignore)$/,
                rules: {
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeComments: true,
                    minifyJS: true,
                }
            })
        ]
    });

It will minify all view files during the Webpack build.

This is almost a copy of Vahid's answer but it fixes two problems.

1) It checks if a response is a BinaryFileResponse as any attempt to modify this type of response will throw an Exception.

2) It retained newline characters as the complete elimination of newlines will lead to bad Javascript code on lines with single-line comment.

For example, the code below

 var a; //This is a variable
 var b; //This will be commented out

Will become

 var a; //This is a variable var b; //This will be commented out

Note: At the time of this answer I couldn't get my hands on a good regex to match single line comments without complications or rather, ignore newlines on only lines with a single-line comment, so I'm hoping for a better fix.

Here's the modified version.

<?php

namespace App\Http\Middleware;

use Closure;

class OptimizeMiddleware {

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    $response = $next($request);
    if ($response instanceof \Symfony\Component\HttpFoundation\BinaryFileResponse) {
        return $response;
    } else {
        $buffer = $response->getContent();
        if (strpos($buffer, '<pre>') !== false) {
            $replace = array(
                '/<!--[^\[](.*?)[^\]]-->/s' => '',
                "/<\?php/" => '<?php ',
                "/\r/" => '',
                "/>\n</" => '><',
                "/>\s+\n</" => '><',
                "/>\n\s+</" => '><',
            );
        } else {
            $replace = array(
                '/<!--[^\[](.*?)[^\]]-->/s' => '',
                "/<\?php/" => '<?php ',
                "/\n([\S])/" => '$1',
                "/\r/" => '',
                "/\n+/" => "\n",
                "/\t/" => '',
                "/ +/" => ' ',
            );
        }
        $buffer = preg_replace(array_keys($replace), array_values($replace), $buffer);
        $response->setContent($buffer);
        ini_set('zlib.output_compression', 'On'); //enable GZip, too!
        return $response;
    }
  }
}

Edit

Compressing output for every request using the middleware truly is really a bad idea, I recommend you check out this solution by Jokerius

Just in case you are rendering the view manually:


echo view('example.site')->render(function($view, $content) { 
    return preg_replace(
            ['/\>[^\S ]+/s', '/[^\S ]+\</s', '/(\s)+/s'],
            ['>', '<', '\\1'],
            $content
    ); }
);

在我看来,这个包是更好的选择renatomarinho/laravel-page-speed

I did it with very simple code. Example: welcome.blade.php

Add the following code to the beginning of the page

<?php ob_start('compress_page');?>

Add the following code to the end of the page:

<?php   
ob_end_flush();
function compress_page($buffer) {
    $search = array("/>[[:space:]]+/", "/[[:space:]]+</");
    $replace = array(">","<");
    return preg_replace($search, $replace, $buffer);
}?>

Full page code example:

 <?php ob_start('compress_page');?> <!doctype html> <html lang="{{ app()->getLocale() }}"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel</title> <!-- Fonts --> <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css"> <!-- Styles --> <style> html, body { background-color: #fff; color: #636b6f; font-family: 'Raleway', sans-serif; font-weight: 100; height: 100vh; margin: 0; } .full-height { height: 100vh; } .flex-center { align-items: center; display: flex; justify-content: center; } .position-ref { position: relative; } .top-right { position: absolute; right: 10px; top: 18px; } .content { text-align: center; } .title { font-size: 84px; } .links > a { color: #636b6f; padding: 0 25px; font-size: 12px; font-weight: 600; letter-spacing: .1rem; text-decoration: none; text-transform: uppercase; } .mb-md { margin-bottom: 30px; } </style> </head> <body> <div class="flex-center position-ref full-height"> @if (Route::has('login')) <div class="top-right links"> @auth <a href="{{ url('/home') }}">Home</a> @else <a href="{{ route('login') }}">Login</a> <a href="{{ route('register') }}">Register</a> @endauth </div> @endif <div class="content"> <div class="title mb-md"> Laravel </div> <div class="links"> <a href="https://laravel.com/docs">Documentation</a> <a href="https://laracasts.com">Laracasts</a> <a href="https://laravel-news.com">News</a> <a href="https://forge.laravel.com">Forge</a> <a href="https://github.com/laravel/laravel">GitHub</a> </div> </div> </div> </body> </html> <?php ob_end_flush(); function compress_page($buffer) { $search = array("/>[[:space:]]+/", "/[[:space:]]+</"); $replace = array(">","<"); return preg_replace($search, $replace, $buffer); }?>

this is best way.. we don't need to use laravel packeges .Thanks..

 <?php namespace App\\Http\\Middleware; use Closure; class OptimizeMiddleware { /** * Handle an incoming request. * * @param \\Illuminate\\Http\\Request $request * @param \\Closure $next * @return mixed */ public function handle($request, Closure $next) { $response = $next($request); $buffer = $response->getContent(); if(strpos($buffer,'<pre>') !== false) { $replace = array( '/<!--[^\\[](.*?)[^\\]]-->/s' => '', "/<\\?php/" => '<?php ', "/\\r/" => '', "/>\\n</" => '><', "/>\\s+\\n</" => '><', "/>\\n\\s+</" => '><', ); } else { $replace = array( '/<!--[^\\[](.*?)[^\\]]-->/s' => '', "/<\\?php/" => '<?php ', "/\\n([\\S])/" => '$1', "/\\r/" => '', "/\\n/" => '', "/\\t/" => '', "/ +/" => ' ', ); } $buffer = preg_replace(array_keys($replace), array_values($replace), $buffer); $response->setContent($buffer); ini_set('zlib.output_compression', 'On'); // If you like to enable GZip, too! return $response; } }

For easy compression, I build my own laravel module. This module will compress all the final html output before sending to the client (browser).

You can also target multiple environment at a time using .env file.

More details on how to install and configure will be found here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM