How do I compress HTML in laravel 5
Solution 1
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;
}
}
Solution 2
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 ... :).. .
Solution 3
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.
Solution 4
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.
Solution 5
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
Related videos on Youtube
Emeka Mbah
I am a professional Full Stack Web Developer with over 10 years expertise in professional web application development; 6 years as Full Stack PHP/Laravel Developer with track record of tackling challenges, providing solutions and beating deadlines. I used: PHP, MySQL, Laravel, Angular, JQuery, Vue, GulpJs, TDD, HTML, CSS & CSS3, MySQL, Linux, Apache, API, Bootstrap, Git, Html5, Nginx, SVN, Team leadership, WordPress I am available for hire for projects or permanent employment.
Updated on March 17, 2021Comments
-
Emeka Mbah about 3 years
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.
-
Laurence about 9 yearsI know you said you dont want a pacakge - but github.com/GrahamCampbell/Laravel-HTMLMin is the perfect solution. And it wont 'kill performance' any differently than if you did it yourself.
-
CBroe about 9 yearsI would advise against what you are trying to do at all – a
pre
element is not the only thing where white space might matter, but also inside atextarea
/input
or basically in any element if it gets later on formatted via CSS (white-space
). Just GZip the output before sending it to the client, that is much more effective than messing with the HTML code itself. -
Emeka Mbah about 9 years@cbroe how do I use GZip? any working example
-
-
Emeka Mbah about 9 yearsNice. How do I use it? Am running this on each request?
-
darronz about 9 yearsYes you'd run it on every http request. You can register it globally by adding your class in
app/Http/Kernel.php
-
clearlight over 7 yearsCode snippet doesn't seem to run.
-
Rahul Tathod over 5 years(index):1 Uncaught SyntaxError: Unexpected end of input jquery not working after that
-
نرم افزار حضور و غیاب over 5 years@Rahul Tathod This middleware will only compress HTML, and enable GZip. These two compresses doesn't effect on Jquery, or CSS, JS files. If there is any problem, you should find root cause.
-
Holonaut about 4 yearswill this still work if there are variables in your template that need to be accounted for on every request? Or even whole blocks that depend on conditions?
-
ahinkle over 2 years2021 update: this package seems to have a lot of bugs and doesn't seem to be maintained.