Package to optimize your site automatically which results in a 35%+ optimization

Overview

Laravel Page Speed logo

Build Status Latest Stable Version Total Downloads License

Laravel Page Speed

Simple package to minify HTML output on demand which results in a 35%+ optimization. Laravel Page Speed was created by Renato Marinho, and currently maintained by João Roberto P. Borges, Lucas Mesquita Borges and Renato Marinho.

Installation

Requires:

You can install the package via composer:

composer require renatomarinho/laravel-page-speed

This package supports Laravel Package Discovery.

Publish configuration file

php artisan vendor:publish --provider="RenatoMarinho\LaravelPageSpeed\ServiceProvider"

Do not forget to register middlewares

Next, the \RenatoMarinho\LaravelPageSpeed\Middleware\CollapseWhitespace::class and other middleware must be registered in the kernel, for example:

//app/Http/Kernel.php

protected $middleware = [
    ...
    \RenatoMarinho\LaravelPageSpeed\Middleware\InlineCss::class,
    \RenatoMarinho\LaravelPageSpeed\Middleware\ElideAttributes::class,
    \RenatoMarinho\LaravelPageSpeed\Middleware\InsertDNSPrefetch::class,
    \RenatoMarinho\LaravelPageSpeed\Middleware\RemoveComments::class,
    //\RenatoMarinho\LaravelPageSpeed\Middleware\TrimUrls::class, 
    //\RenatoMarinho\LaravelPageSpeed\Middleware\RemoveQuotes::class,
    \RenatoMarinho\LaravelPageSpeed\Middleware\CollapseWhitespace::class, // Note: This middleware invokes "RemoveComments::class" before it runs.
    \RenatoMarinho\LaravelPageSpeed\Middleware\DeferJavascript::class,
]

Middlewares Details

\RenatoMarinho\LaravelPageSpeed\Middleware\RemoveComments::class

The RemoveComments::class filter eliminates HTML, JS and CSS comments. The filter reduces the transfer size of HTML files by removing the comments. Depending on the HTML file, this filter can significantly reduce the number of bytes transmitted on the network.

\RenatoMarinho\LaravelPageSpeed\Middleware\CollapseWhitespace::class

The CollapseWhitespace::class filter reduces bytes transmitted in an HTML file by removing unnecessary whitespace. This middleware invoke RemoveComments::class filter before executation.

Note: Do not register the "RemoveComments::class" filter with it. Because it will be called automatically by "CollapseWhitespace::class"

Before

Before of Laravel Page Speed

After

After of Laravel Page Speed

\RenatoMarinho\LaravelPageSpeed\Middleware\RemoveQuotes::class

The RemoveQuotes::class filter eliminates unnecessary quotation marks from HTML attributes. While required by the various HTML specifications, browsers permit their omission when the value of an attribute is composed of a certain subset of characters (alphanumerics and some punctuation characters).

Quote removal produces a modest savings in byte count on most pages.

\RenatoMarinho\LaravelPageSpeed\Middleware\ElideAttributes::class

The ElideAttributes::class filter reduces the transfer size of HTML files by removing attributes from tags when the specified value is equal to the default value for that attribute. This can save a modest number of bytes, and may make the document more compressible by canonicalizing the affected tags.

\RenatoMarinho\LaravelPageSpeed\Middleware\InsertDNSPrefetch::class

The InsertDNSPrefetch::class filter Injects tags in the HEAD to enable the browser to do DNS prefetching.

DNS resolution time varies from <1ms for locally cached results, to hundreds of milliseconds due to the cascading nature of DNS. This can contribute significantly towards total page load time. This filter reduces DNS lookup time by providing hints to the browser at the beginning of the HTML, which allows the browser to pre-resolve DNS for resources on the page.

⚠️ \RenatoMarinho\LaravelPageSpeed\Middleware\TrimUrls::class,

The TrimUrls::class filter trims URLs by resolving them by making them relative to the base URL for the page.

Warning: TrimUrls::class is considered medium risk. It can cause problems if it uses the wrong base URL. This can happen, for example, if you serve HTML that will be pasted verbatim into other HTML pages. If URLs are trimmed on the first page, they will be incorrect for the page they are inserted into. In this case, just disable the middleware.

\RenatoMarinho\LaravelPageSpeed\Middleware\InlineCss::class

The InlineCss::class filter transforms the inline "style" attribute of tags into classes by moving the CSS to the header.

\RenatoMarinho\LaravelPageSpeed\Middleware\DeferJavascript::class

Defers the execution of javascript in the HTML.

If necessary cancel deferring in some script, use data-pagespeed-no-defer as script attribute to cancel deferring.


Configuration

After installing package, you may need to configure some options.

Disable Service

You would probably like to set up the local environment to get a readable output.

//config/laravel-page-speed.php

//Set this field to false to disable the laravel page speed service.
'enable' => env('LARAVEL_PAGE_SPEED_ENABLE', true),

Skip routes

You would probably like to configure the package to skip some routes.

//config/laravel-page-speed.php

//You can use * as wildcard.
'skip' => [
    '*.pdf', //Ignore all routes with final .pdf
    '*/downloads/*',//Ignore all routes that contain 'downloads'
    'assets/*', // Ignore all routes with the 'assets' prefix
];

By default this field comes configured with some options, so feel free to configure according to your needs...

Notice: This package skip automatically 'binary' and 'streamed' responses. See File Downloads.

Testing

$ composer test

Contributing

Please see CONTRIBUTING for details.

Contributors

Inspiration

Mod Page Speed (https://www.modpagespeed.com/)

License

The MIT License (MIT). Please see License File for more information.

Comments
  • [2.x] Fix bugs and code improvements

    [2.x] Fix bugs and code improvements

    Description

    This big PR will:

    • Drop support for Laravel <5.5;
    • Bump PHP minimun version to 7.1.3+;
    • Update dependency constraints in composer.json;
    • Recfator all tests:
      • Remove deprecated functions e prepare code to next phpunit 9.0 version;
      • Improvements tests coverage;
    • Fix RemoveComments middleware, now it remove JS and CSS comments;
    • Fix CollapseWhitespace, now dependent on 'RemoveComments' middleware;
    • Update the old phpunit.xml configuration file;
    • Update the .travis.yml file and run the tests against in PHP 7.3 / PHP 7.4;
    • Update README.md;

    Motivation and context

    Why is this change required? What problem does it solve?

    It fixes: #30 #46 #55 #57 #77 #82 #107 #108

    The CollapseWriteSpace::class filter was producing a bug when the HTML contains inline JS comments.... All JS code after the inline comment was also commented!

    For example:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <meta http-equiv="x-ua-compatible" content="ie=edge">
            <title></title>
            <meta name="description" content="">
        </head>
        <body>
            <script>
                // Alert Hello!!
                alert('Hello!!');
    
                // Log Hello!!
                console.log('Hello!!');
            </script>
        </body>
    </html>
    

    After filter apply:

    <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="x-ua-compatible" content="ie=edge"><title></title><meta name="description" content=""></head><body><script> // Alert Hello!! alert('Hello!!'); // Log Hello!! console.log('Hello!!'); </script></body></html>
    

    What is the solution?

    We have to remove all inline JS comments before the 'CollapseWriteSpace' filter is executed.

    :thinking: ... Okay, we need to make sure RemoveComments::class filter always runs before CollapseWriteSpace::class filter!

    All right, it's done:

    https://github.com/renatomarinho/laravel-page-speed/blob/efc2f37456c1ded881b7a158eaf5f53343be7b89/src/Middleware/CollapseWhitespace.php#L5-L25

    But...

    Oooh Nooo! The RemoveComments::class filter was only removing HTML comments :man_facepalming:...

    Not problem ... RemoveComments::class has been updated! Now, it removes HTML, JS and CSS comments:

    https://github.com/renatomarinho/laravel-page-speed/blob/332cbf6a774e05e17480584247697aa6397c8dba/src/Middleware/RemoveComments.php#L5-L16

    How has this been tested?

    Refactoring and improve test coverage.

    Types of changes

    What types of changes does your code introduce? Put an x in all the boxes that apply:

    • [x] Bugfix / Breaking change (fix or feature that would cause existing functionality to change)

    Checklist:

    • [x] I have read the CONTRIBUTING document.
    • [x] My pull request addresses exactly one patch/feature.
    • [x] I have created a branch for this patch/feature.
    • [x] Each individual commit in the pull request is meaningful.
    • [x] I have added tests to cover my changes.
    • [x] If my change requires a change to the documentation, I have updated it accordingly.

    I did a lot of testing and it seems to be working okay...

    Can someone help me to test this PR, please? :smile:

    Ping @renatomarinho

    opened by joaorobertopb 19
  • Issue with inline script comment & laravel-debugbar package conflicts

    Issue with inline script comment & laravel-debugbar package conflicts

    Detailed description

    In my application, sometimes I have a script in HTML:

    <script>
    // I need to comment what I want to do here
    console.log('something here');
    </script>

    Then it throws an error Uncaught SyntaxError: Unexpected end of input

    Context

    I think many people will get this bug when using your package in their apps.

    Possible implementation

    Remove script comment in HTML

    Your environment

    • PHP version: 7.1
    • Laravel 5.5
    bug help wanted 
    opened by sangnguyenplus 13
  • js errors after minification

    js errors after minification

    Laravel 5.4 Vue.js

    Clear installation of LPS package. Now we have errors:

    Uncaught SyntaxError: Unexpected end of input
    Uncaught SyntaxError: Invalid or unexpected token
    Uncaught ReferenceError: PhpDebugBar is not defined
        at search:4
    (anonymous) @ search:4
    app.js:sourcemap:4572 jQuery.Deferred exception: $ is not a function TypeError: $ is not a function
    Uncaught TypeError: $ is not a function
    • PhP 7.1
    • Windows 10 Pro
    • Vagrant - Homestead
    • local project
    opened by PhPPgAdminBug 8
  • Ignition not working after installing this package.

    Ignition not working after installing this package.

    The middleware CollapseWhitespace creates problems on the javascript inline part of ignition. Eliminating the indicated line everything works correctly. Laravel 6.5.1

    $replace = [
        "/\n([\S])/" => '$1',
        "/\r/" => '',
        "/\n/" => '', // Remove this no problem
        "/\t/" => '',
        "/ +/" => ' ',
        "/> + '><',
     ];

    thanks, I hope I was helpful

    opened by massimodellarovere 5
  • Facebook comment plugins doesn't work after install this package

    Facebook comment plugins doesn't work after install this package

    Doesn't show facebook comment system

    i use facebook comment plugins in frontend before install this package it worked perfectly . after install this package html's are minified and others function are work properly but my facebook comment section doesn' t show . how to overcome it.

    opened by HasanurHimel 5
  • Issue #97 - Always exclude StreamedResponse

    Issue #97 - Always exclude StreamedResponse

    • Always exclude StreamedResponse similar to BinaryFileResponse as it cannot be handled.

    Description

    This PR is a fix for the issue #97. It Checks the Response to see if it's and instance of StreamedResponse before allowing application of Page Speed very much so as BinaryFileResponse.

    Motivation and context

    In my App I had a lot of routes which dealt with StreamedReponses, and having to exclude them one by one was a real pain. As we know that StreamedResponse won't be handled similar to BinaryFileResponse this motivated this PR.

    fixes #97

    How has this been tested?

    I created a test which tried to pass a StreamedResponse to the Middleware. As expected it failed with message

    LogicException: The content cannot be set on a StreamedResponse instance.
    

    image

    I then added my edit to the PageSpeed middleware and ran my tests again which it passed.

    image

    Types of changes

    What types of changes does your code introduce? Put an x in all the boxes that apply:

    • [x] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)

    Checklist:

    Go over all the following points, and put an x in all the boxes that apply.

    Please, please, please, don't send your pull request until all of the boxes are ticked. Once your pull request is created, it will trigger a build on our continuous integration server to make sure your tests and code style pass.

    • [x] I have read the CONTRIBUTING document.
    • [x] My pull request addresses exactly one patch/feature.
    • [x] I have created a branch for this patch/feature.
    • [x] Each individual commit in the pull request is meaningful.
    • [x] I have added tests to cover my changes.
    • [x] If my change requires a change to the documentation, I have updated it accordingly.

    If you're unsure about any of these, don't hesitate to ask. We're here to help!

    opened by percymamedy 5
  • Always exclude StreamedResponse

    Always exclude StreamedResponse

    Detailed description

    Bug: currently it tries to handle streamed response. While there is the option to exclude pages, those are more for pages where the context cannot handle being processed and you do not know that it can't. StreamedResponse however does not work due to the code itself and throws an exception: content cannot be set on a StreamedResponse instance. To me it is the same as BinaryFileResponse - we know this can't be handled.

    Context

    Saves us the trouble of excluding every path that would respond in a streamed response.

    Possible implementation

    Like you check if response is instance of BinaryFileResponse, you should check if it is part of StreamedResponse and not handle such requests.

    Your environment

    Laravel: 5.7.8 OS: Ubuntu (Homestead)

    opened by TivoSoho 5
  • problem in illuminate/support

    problem in illuminate/support": "5.3.* || 5.4.* || 5.5.* || 5.6.*"

    I've been using that way on #69 by adding "illuminate/support": "5.3.* || 5.4.* || 5.5.* || 5.6.*", result, there is a problem ?

    Problem 1

    • Conclusion: don't install illuminate/support v5.5.34
    • Conclusion: don't install illuminate/support v5.5.33
    • Conclusion: don't install illuminate/support v5.5.28
    • Conclusion: don't install illuminate/support v5.5.17
    • Conclusion: don't install illuminate/support v5.5.16
    • Conclusion: don't install illuminate/support v5.5.2
    • Conclusion: don't install illuminate/support v5.5.0
    • Conclusion: don't install illuminate/support v5.4.36
    • Conclusion: don't install illuminate/support v5.4.27
    • Conclusion: don't install illuminate/support v5.4.19
    • Conclusion: don't install illuminate/support v5.4.17
    • Conclusion: don't install illuminate/support v5.4.13
    • Conclusion: don't install illuminate/support v5.4.9
    • Conclusion: don't install illuminate/support v5.4.0
    • Conclusion: don't install illuminate/support v5.3.23
    • Conclusion: don't install illuminate/support v5.3.16
    • Conclusion: don't install illuminate/support v5.3.4
    • Installation request for laravel/framework 5.6.* -> satisfiable by laravel/framework[v5.6.0, v5.6.1, v5.6.2, v5.6.3].
    • Installation request for laravel/framework (locked at v5.6.3, required as 5.6.) -> satisfiable by laravel/framework[v5.6.3].
    • Installation request for codecasts/laravel-jwt ^0.9.0 -> satisfiable by codecasts/laravel-jwt[0.9.0].
    • renatomarinho/laravel-page-speed 1.8.0 requires illuminate/support 5.3. || 5.4.* || 5.5.* -> satisfiable by illuminate/support[v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34].
    • renatomarinho/laravel-page-speed 1.8.1 requires illuminate/support 5.3.* || 5.4.* || 5.5.* -> satisfiable by illuminate/support[v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34].
    • renatomarinho/laravel-page-speed 1.8.2 requires illuminate/support 5.3.* || 5.4.* || 5.5.* -> satisfiable by illuminate/support[v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34].
    • renatomarinho/laravel-page-speed 1.8.3 requires illuminate/support 5.3.* || 5.4.* || 5.5.* -> satisfiable by illuminate/support[v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34].
    • renatomarinho/laravel-page-speed 1.8.4 requires illuminate/support 5.3.* || 5.4.* || 5.5.* -> satisfiable by illuminate/support[v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34].
    • renatomarinho/laravel-page-speed 1.8.5 requires illuminate/support 5.3.* || 5.4.* || 5.5.* -> satisfiable by illuminate/support[v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34].
    • renatomarinho/laravel-page-speed 1.8.6 requires illuminate/support 5.3.* || 5.4.* || 5.5.* -> satisfiable by illuminate/support[v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34].
    • Conclusion: don't install illuminate/support v5.3.0
    • Installation request for renatomarinho/laravel-page-speed ^1.8 -> satisfiable by renatomarinho/laravel-page-speed[1.8.0, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.8.6].
    opened by testdnmedia 5
  • [pt_BR] - CollapseWhitespace quebrando dropzone.js

    [pt_BR] - CollapseWhitespace quebrando dropzone.js

    Primeiramente parabéns pelo trabalho Renato, acompanho desde quando o projeto tinha 15 estrelas rsrs. Cheque a compatibilidade do CollapseWhitespace com o plugin dropzone, pois ele não funciona após a aplicação desse middleware, com o erro "Unexpected end of script".

    Mais especificamente, a regra

    "/\n/" => '',

    que está afetando o dropzone.js.

    • Php 7.1.10
    • Laravel 5.5
    • local
    opened by ibrunotome 5
  • Issue with select dropdown based on another dropdown

    Issue with select dropdown based on another dropdown

    Hi, I use Jquery to make select dropdown based on another dropdown, and it was working fine , when I use this package it select dropdown based on another dropdown not working anymore . do you know why ?

    Many Thanks

    help wanted good first issue 
    opened by allaghi 5
  • Added PHP 8 Support from 2.x branch

    Added PHP 8 Support from 2.x branch

    Description

    Basically just a copy of this https://github.com/renatomarinho/laravel-page-speed/pull/139/commits/022f1a867cbfdf8c7774293552eae8a129e61ae0 and use 2.x branch instead of master branch.

    Motivation and context

    Please support PHP 8, we need this.

    How has this been tested?

    Not tested.

    Screenshots (if appropriate)

    Types of changes

    What types of changes does your code introduce? Put an x in all the boxes that apply:

    • [x] Bug fix (non-breaking change which fixes an issue)
    • [ ] New feature (non-breaking change which adds functionality)
    • [ ] Breaking change (fix or feature that would cause existing functionality to change)

    Checklist:

    Go over all the following points, and put an x in all the boxes that apply.

    Please, please, please, don't send your pull request until all of the boxes are ticked. Once your pull request is created, it will trigger a build on our continuous integration server to make sure your tests and code style pass.

    • [x] I have read the CONTRIBUTING document.
    • [x] My pull request addresses exactly one patch/feature.
    • [x] I have created a branch for this patch/feature.
    • [x] Each individual commit in the pull request is meaningful.
    • [x] I have added tests to cover my changes.
    • [x] If my change requires a change to the documentation, I have updated it accordingly.

    If you're unsure about any of these, don't hesitate to ask. We're here to help!

    opened by lakuapik 4
  • Suggestion: There is any way to prevent code block to being minify.

    Suggestion: There is any way to prevent code block to being minify.

    I have a blog website build in laravel. I am using laravel page speed package for minify the output html to browser. But when i enable // \RenatoMarinho\LaravelPageSpeed\Middleware\CollapseWhitespace::class This class my code block section being minified and user unable to read code section on browser Before minify image After minify image

    So Is there any way to prevent code block or specific section of blade to stop minify. Thank you.

    opened by vikramparihar 0
  • LARAVEL 9 Code Debug Screen Not Showing After Enable Page speed

    LARAVEL 9 Code Debug Screen Not Showing After Enable Page speed

    I AM Using This PHP And Larvel Version

    "php": "^7.3|^8.0",

        "laravel/framework": "^9.19",
    
        "renatomarinho/laravel-page-speed": "^2.1"
    

    I Already Enable APP_DEBUG=true

    Laravel's code debugger screen blank show whenever there is a bug in the code

    opened by manish0197 1
  • Uri's in JS stripped of double slash

    Uri's in JS stripped of double slash

    Detailed description

    I noticed the URI's inside javascript blocks are stripped.

    For example:

    https://www.test.com/ were changed to https:www.test.com

    image

    What the script looks like after disabling the comment portion of laravel page speed.

    image

    Context

    Unexpected behavior which caused my script to error out.

    Possible implementation

    Ignore uri's.

    Your environment

    • Version used (e.g. PHP 7.1, HHVM 3): PHP 8, Laravel Page Speed 2.1
    opened by david-nguyen 0
  • dont run script file

    dont run script file

    dont run script file livewire

    hi dont run script file and livewire after enable this: 'enable' => env('LARAVEL_PAGE_SPEED_ENABLE', true),

    i use this