futtta / autoptimize

Official Autoptimize repo on Github
https://autoptimize.com/pro/
GNU General Public License v2.0
282 stars 87 forks source link

HTTP2 Push Header - Feature Suggestion #49

Closed 2aces closed 1 year ago

2aces commented 8 years ago

Hey, @futtta . Celso Bessa, AO pt-br translator here.

As you know, HTTP2 push is a big deal in optimization now. We are getting great results in some of our projects with it and I think it would be great if AO included a mechanism to use those headers.

In some test setups we filtered AO final JS/CSS srcs and created our own headers using PHP/WP send headers ( https://codex.wordpress.org/Plugin_API/Action_Reference/send_headers ). this is not hard for us, but it might be not easy for an non technical user.

In other setups we used AO alongside http2 server push plugin by @daveros ), which is great, but it sends headers for all files in the original wp_enqueue queue but not for AO aggregated files (my guess is it uses a hook triggered before AO).

Looking this 2 cases, seems to me that having this on AO would help a lot of you user base.

What do you think? I won't be able to code anything for the next 4 weeks, but if you think it's a good feature, I can work on this in august.

tdtgit commented 6 years ago

@futtta Why not the whole AO'ed CSS & JS files? Split the big one file to smaller files to take the advantage of HTTP/2 for multiple request is should considered too.

futtta commented 6 years ago

Well ... -> the AO'ed JS is deferred by default, but if the file is pushed "defer" is useless, no? so pushing the AO'd JS would mean the "defer" attrib is to be removed -> as @trajano mentioned, push seems to only really work for resources that are loaded by JS. Linked CSS and sourced JS are downloaded again, even if already pushed? -> splitting big ones into smaller files is not an option. AO 2.4 (check out the beta-branch!) will have an option to optimize but not aggregate (combine) though. -> pushing too many files might not improve performance

So I'm not sure I should add it to AO until we're sure it indeed does work and we know how we should tweak it just right?

On Thu, Apr 19, 2018 at 10:35 AM, Anh Tuấn notifications@github.com wrote:

@futtta https://github.com/futtta Why not the whole AO'ed CSS & JS files? Split the big one file to smaller files to take the advantage of HTTP/2 for multiple request is should considered too.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49#issuecomment-382655701, or mute the thread https://github.com/notifications/unsubscribe-auth/AALEMSw8mnb1xOTGpIr8fQ3Wo7VwGrCyks5tqExYgaJpZM4JRNhx .

grzegorz-janoszka commented 6 years ago

@futta I have spent some time and for some reason I don't get the headers displayed. I know the code is executed with correct parameters as I've tried to put syslog into the function. I have disabled all our plugins and still couldn't get it. I am testing it on my test blog, where there is no cache and I tested it - any changes in the code are immediately visible. I guess the reason is that something is output before I call the header function. What is weird when I use echo in the function, I don't get the message in the html code. So I am not really sure when the code is executed as the echo doesn't get into the page and headers are not sent. Is there a way to check which output has been already sent or why the headers function didn't work? My error log and access log do not contain anything like "headers already sent".

futtta commented 6 years ago

maybe wrap the header() function in the snippet in a try-catch block and in catch block log stuff to your error-log?

On Fri, Apr 20, 2018 at 3:26 PM, grzegorz-janoszka <notifications@github.com

wrote:

@futta https://github.com/futta I have spent some time and for some reason I don't get the headers displayed. I know the code is executed with correct parameters as I've tried to put syslog into the function. I have disabled all our plugins and still couldn't get it. I am testing it on my test blog, where there is no cache and I tested it - any changes in the code are immediately visible. I guess the reason is that something is output before I call the header function. What is weird when I use echo in the function, I don't get the message in the html code. So I am not really sure when the code is executed as the echo doesn't get into the page and headers are not sent. Is there a way to check which output has been already sent or why the headers function didn't work? My error log and access log do not contain anything like "headers already sent".

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49#issuecomment-383095358, or mute the thread https://github.com/notifications/unsubscribe-auth/AALEMSVvkGmINZe2gkKzo41s28QpRwZFks5tqeIhgaJpZM4JRNhx .

grzegorz-janoszka commented 6 years ago

There are no exceptions thrown, but after putting syslog messages here and there in the code I see that the filter is mostly not called. It is sometimes called when I visit the dashboard, but I check the headers using curl -I and then the AO filter is not called at all. Why would that be?

futtta commented 6 years ago

Weird, as from a code point of view the logic dictates the filter is to be triggered each time AO gets triggered for all active minifiers (CSS or JS):

  1. for each minifier the steps are (see classes/autoptimizeMain.php in 2.4 or autoptimize.php in 2.3.x, code from 2.4)

                $instance->minify();
                $instance->cache();
                $instance->getcontent();
  2. in $instance->cache() autoptimizeCache's getname() is called unconditionally (below example for JS, cfr. classes/autoptimizeScripts.php):

        $this->url = AUTOPTIMIZE_CACHE_URL . $cache->getname();
  3. in cache->getname() the filter gets triggered, unconditionally (see classes/autoptimizeCache.php):

       apply_filters( 'autoptimize_filter_cache_getname', AUTOPTIMIZE_CACHE_URL . $this->filename );

I'll dive in later this weekend to see if I can reproduce somehow, but just tested on my dev-machine and the filter always gets triggered here.

grzegorz-janoszka commented 6 years ago

Actually I had some issues with multiple nginx processes logging the same stuff and it got mixed up. Indeed I see the function called all the time. I am not sure however it is called under template_redirect. I have my own function under template_redirect, I have put it now the the priority PHP_INT_MAX and in logs I still see my function trying to send headers (successfully) and then AO filter trying to send its own headers (unsuccessfully).

futtta commented 6 years ago

well, that's due to AO starting the output buffer at template_redirect, this does not mean that all things AO are done at that moment (which it could not as AO uses the full HTML "harvested" from the output buffer, meaning all hooks at that point already ran).

On Tue, Apr 24, 2018 at 3:35 PM, grzegorz-janoszka <notifications@github.com

wrote:

Actually I had some issues with multiple nginx processes logging the same stuff and it got mixed up. Indeed I see the function called all the time. I am not sure however it is called under template_redirect. I have my own function under template_redirect, I have put it now the the priority PHP_INT_MAX and in logs I still see my function trying to send headers (successfully) and then AO filter trying to send its own headers (unsuccessfully).

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49#issuecomment-383932669, or mute the thread https://github.com/notifications/unsubscribe-auth/AALEMVDAhc7VznJO8oHfGUNE3PYyYosWks5tryougaJpZM4JRNhx .

grzegorz-janoszka commented 6 years ago

Oh my, I've spent so much time on that and now I finally know. I was checking my headers using curl -I, but this thing calls only the head and somehow then the AO headers are not sent. When I called properly curl -v, I see all the headers. I am really sorry for false alarm. AO is a great plugin. So just to summary, is it good to link js files with "rel=preload; as=script" and css files with "rel=preload; type=style"?

grzegorz-janoszka commented 6 years ago

One last update, the original code: containing "Link: <'.$in.'>" doesn't work with nginx directive http2_push_preload. Finally I have push running on my website, but I had to use:

header('Link: <'.parse_url($in,PHP_URL_PATH).'>; rel=preload; as=script',false);

It would be awesome if AO could just push such headers all but itself :)

futtta commented 6 years ago

you indeed have to use "as=", not "type=" as in my original code snippet.

now that preloading works, is Chrome indeed not fetching those files any more, or are there (still) the warnings on the developer console mentioned earlier in this thread?

On Wed, Apr 25, 2018 at 10:52 PM, grzegorz-janoszka < notifications@github.com> wrote:

One last update, the original code: containing "Link: <'.$in.'>" doesn't work with nginx directive http2_push_preload. Finally I have push running on my website, but I had to use:

header('Link: <'.parse_url($in,PHP_URL_PATH).'>; rel=preload; as=script',false);

It would be awesome if AO could just push such headers all but itself :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49#issuecomment-384430222, or mute the thread https://github.com/notifications/unsubscribe-auth/AALEMUWeR37fE1Fla5FDYayJhQjPjDZtks5tsOIhgaJpZM4JRNhx .

grzegorz-janoszka commented 6 years ago

is "as=" also for styles? should it be "as=style"? I am not using Chrome, but I tested it with nghttp2 and https://http2-push.io/ and they are showing resources on website pushed. So far I am pushing only css and js from AO, The image files are not pushed. Well, actually the tiniest ones are pushed as I have 3 small SVG sprites that I put inline in the CSS just to save http requests on files that are 600-800 bytes long. I am aware of some disadvantages of this push (no caching for css/js on the browser side) and I will closely monitor how it works. Thank you so much for your fantastic support.

futtta commented 6 years ago

both should be "as=" indeed, cfr. the other code snippet that use the other AO hook.

On Wed, Apr 25, 2018 at 11:39 PM, grzegorz-janoszka < notifications@github.com> wrote:

is "as=" also for styles? should it be "as=style"? I am not using Chrome, but I tested it with nghttp2 and https://http2-push.io/ and they are showing resources on website pushed. So far I am pushing only css and js from AO, The image files are not pushed. Well, actually the tiniest ones are pushed as I have 3 small SVG sprites that I put inline in the CSS just to save http requests on files that are 600-800 bytes long. I am aware of some disadvantages of this push (no caching for css/js on the browser side) and I will closely monitor how it works. Thank you so much for your fantastic support.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49#issuecomment-384442891, or mute the thread https://github.com/notifications/unsubscribe-auth/AALEMb6QYsMvbeWoiUDyBmPw6SILOcg7ks5tsOz7gaJpZM4JRNhx .

grzegorz-janoszka commented 6 years ago

Last question - I see that just before the filtering you are adding the protocol and site name to to create URL from URI. But in the filter I have to do for nginx the opposite - to strip the protocol and site. Any possibility to simplify that?

futtta commented 6 years ago

AUTOPTIMIZE_CACHE_URL doesn't only contain protocol and site, but also the path to the AO cache directory. and the site is needed later on for CDN-replacement purposes, so guess you'll have to keep the your filter strip it :-)

tdtgit commented 6 years ago

Hi @futtta, have a good week.

I have spent my time to test 3 scenarios: inline all CSS, minify and aggregate, minify but not aggregate and I found out the third scenario work like a charm. Thanks to AO 2.4, HTTP/2 Push and you :)

screen shot 2018-04-30 at 14 01 34

Just more question:

1. Why not minify inline CSS to files and then include it like another. Or is there a problem or not effective to using it? Example:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .my-first-line-css-section { /* ... */ }
    </style>
</head>
<body>

</body>
</html>

Will become this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <!-- Will become this -->
    <link rel='preload' as='style' onload="this.onload=null;this.rel='stylesheet'" href="./ao-single.with-random-ID.css">
</head>
<body>
    <!-- Will become this -->
    <link rel='preload' as='style' onload="this.onload=null;this.rel='stylesheet'" href="./ao-single.with-random-ID.css">
    <div>
        <div>
            <div>
                <div>

                </div>
            </div>
        </div>
    </div>
    <!-- Will become this -->
    <link rel='preload' as='style' onload="this.onload=null;this.rel='stylesheet'" href="./ao-single.with-random-ID.css">
</body>
</html>

2. Exclude JS unexpected not working for me, AO 2.4 and latest stable even.

futtta commented 6 years ago

re 1. inline CSS has no perf impact that I know off, so don't really see a need to extract it and make it external?

re 2. can you give some more info?

tdtgit commented 6 years ago

1. I know, Pagespeed Insights doesn't judged inline CSS minify too. But every bytes count 🤓 So which AO's hook or filter I can research and write my own integration? If it's working, that will fixed my #124 too.

2. My current setting:

My Google Tagmanager tag is aggregated to AO minified JS too. So I check again and found out it's not working if I provide gtm or googletagmanager in option field even. I can't remember why and when it stopped exclude.

screen shot 2018-04-30 at 14 44 49

futtta commented 6 years ago
  1. I guess autoptimize_filter_html_before_minify, where you could try to extract all inline CSS and/ or JS, write it to a file and insert a link to the file where the minification can pick it up?
  2. should work, but let's not discuss here as not related to HTTP/2 at all. you can mail me at frank-at-optimizingmatters-dot-com so we can look into this
willstocks commented 5 years ago

Just a thought on the http2 server push - should the resource be listed as: Link: </wp-content/folder/structure/aostyle.css>; rel=preload; as=stylesheet or Link: <https://www.domain.name/wp-content/folder/structure/aostyle.css>; rel=preload; as=stylesheet

Whilst the same in principal, if I compare: https://http2-server-push-demo.keksi.io/ (https://github.com/KeksiLabs/http2-server-push-demo) - where I can see the assets are actually being pushed - vs on my site, they currently are not, while using the snippet from https://github.com/futtta/autoptimize/issues/49#issuecomment-305156931 and having changed type to as

grzegorz-janoszka commented 5 years ago

Depends on the web server you are using. With nginx only the first option works.

willstocks commented 5 years ago

I'm currently running a DigitalOcean droplet via Cloudways with HTTP/2 enabled on nginx: image

grzegorz-janoszka commented 5 years ago

It is not about http/2. There is a separate dedicated nginx directive for push: http2_push_preload.

willstocks commented 5 years ago

Aha! Right - bear with me, I'll confirm whether it's enabled or not!!!

willstocks commented 5 years ago

So I can confirm it is enabled - it looks like something was interfering, probably some form of caching. I restarted nginx for my site and cleared all caches and I'm now all good (I think)

willstocks commented 5 years ago

Just wanted to note - I've been using autoptimize's HTTP/2 push for a few months now and everything has been stable and working 😁

chrisb34 commented 5 years ago

Hi All

I've recently added some http2 functionality for a custom project. I've committed the changes back to my repository/branch https://github.com/chrisb34/autoptimize/tree/beta

I wanted to include the autoptimized css and js files which I did by adding a call to autoptimizeBase->inject_in_html

I also wanted to be able to include some misc files in the push, so included some modified code from the http_push_content plugin by piwebsolution.

futtta commented 5 years ago

Interesting Chris, I'll check this out!

On Tue, Feb 26, 2019 at 4:53 PM Chris Backhouse notifications@github.com wrote:

Hi All

I've recently added some http2 functionality for a custom project. I've committed the changes back to my repository/branch https://github.com/chrisb34/autoptimize/tree/beta

I wanted to include the autoptimized css and js files which I did by adding a call to autoptimizeBase->inject_in_html

I also wanted to be able to include some misc files in the push, so included some modified code from the http_push_content plugin by piwebsolution.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49#issuecomment-467494051, or mute the thread https://github.com/notifications/unsubscribe-auth/AALEMckXK-IeaWhYS4GZD-yJzYshqqMpks5vRViRgaJpZM4JRNhx .

LubomirGeorgiev commented 5 years ago

@futtta Any heads up on when do you think this feature will be officially released?

futtta commented 5 years ago

no date yet @LubomirGeorgiev I'm finalizing 2.5 now, so not in that one yet. Maybe 2.6, but no guarantees :)

willstocks commented 5 years ago

So this is an interesting one @futtta - I know we've discussed the use of things like quicklink/instant.page and I have mentioned I'm using quicklink. One thing I happened to forget I had implemented was the pushAOFiles function which I think was somewhere further up here:

function pushAOFiles($in) {
  $pushType = substr($in,strrpos($in,".")+1) === "js" ? "script" : "style"; 
  header('Link: <'.$in.'>; rel=preload; as='.$pushType,false);
  return $in;
}
add_filter('autoptimize_filter_cache_getname','pushAOFiles');

Only, today I noticed that (obviously) when using quicklink as well means that a lot of JS/CSS files are being HTTP2 pushed, despite those pages actually potentially not ever even being visited!

I'm contemplating getting rid of quicklink anyway. It's OK, but it's still fairly aggressive and loading a bunch of links to other pages/archives that likely will not be visited (you can only click on one of those links at a time!), but worth a consideration if you ever end up implementing both HTTP2 Push + page preloading 😄

image

Sasiko commented 5 years ago

Any update yet regarding supporting push?

futtta commented 5 years ago

No, not really.

On Sun, Aug 18, 2019 at 2:33 AM maidos notifications@github.com wrote:

Any update yet regarding supporting push?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49?email_source=notifications&email_token=AABMIMOY4IIE2QSFONBDOHDQFCKG5A5CNFSM4CKE3BY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4QV5UA#issuecomment-522280656, or mute the thread https://github.com/notifications/unsubscribe-auth/AABMIMODSVNWS34XC65GZVTQFCKG5ANCNFSM4CKE3BYQ .

Sasiko commented 5 years ago

i guess i will stop using autoptimize then. since my server support http2, having multiple requests is more beneficial anyway as it supports multiple requests from single connections, and i can enable http2 push with different plugin

chrisb34 commented 5 years ago

You could try my branch - it’s not bullet proof but it does add http2 https://github.com/chrisb34/autoptimize https://github.com/chrisb34/autoptimize

On 20 Aug 2019, at 02:59, maidos notifications@github.com wrote:

i guess i will stop using autoptimize then. since my server support http2, having multiple requests is more beneficial anyway as it supports multiple requests from single connections, and i can enable http2 push with different plugin

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/futtta/autoptimize/issues/49?email_source=notifications&email_token=ABCIFUUCU4DYU4FPZADPKDLQFM6Y3A5CNFSM4CKE3BY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4UXCYY#issuecomment-522809699, or mute the thread https://github.com/notifications/unsubscribe-auth/ABCIFUQD6HY7GY6T2DUGDVLQFM6Y3ANCNFSM4CKE3BYQ.

willstocks commented 5 years ago

@maidos just pop this in your functions.php - has been working great for me since implementation:

function pushAOFiles($in) {
  $pushType = substr($in,strrpos($in,".")+1) === "js" ? "script" : "style"; 
  header('Link: <'.$in.'>; rel=preload; as='.$pushType,false);
  return $in;
}
add_filter('autoptimize_filter_cache_getname','pushAOFiles');

From https://github.com/futtta/autoptimize/issues/49#issuecomment-305156931

Sasiko commented 5 years ago

@willstocks thanks for the reply but i dont see the files being pushed no do i see preload being inserted for the static files in source file. Beside checking source file i also use this site to test if files are being pushed https://http2-push.io/

willstocks commented 5 years ago

Are you able to share your URL? Did you clear any caches (probably mainly page caches) after you added the function to your functions.php? Does your server actually support HTTP2 Push Preload as well as HTTP2 (two different things - see https://github.com/futtta/autoptimize/issues/49#issuecomment-442860380)?

Sasiko commented 5 years ago

im using latest nginx version and have enabled http2 in my conf file so yes, it does support http2. (on a dedicated server) I cleared all caches before i checked the source code

https://artcommissions.me/

im only using cloudflare as a dns so im not using their services

Edit: my conf is already using preload

location / {

    http2_push_preload on;
willstocks commented 5 years ago

im only using cloudflare as a dns so im not using their services

It looks like you're also using their caching: CF-Cache-Status: HIT So make sure that your CF cache is cleared.

The only other thing I can think is that I have my http2_push_preload on; directive in server { rather than in a location block. So:

server {
  server_name   myservername; 
  root  /var/www/html/site/folder/; 
  index index.php index.html index.htm;

  http2_push_preload    on;

  location / {
    try_files   $uri $uri/ /index.php?$args;
  }

  #other locations here
}

Finally... I'm actually using Apache to process the PHP requests (as opposed to dealing with it via nginx directly)... on any host I've used (currently self-hosting/VPS, but I've seen on managed/shared hosting as well), I just dropped the function into my functions.php and the headers still showed in my request responses... so I'm not sure why they aren't for you - weird!!!

Sasiko commented 5 years ago

Yeah i enabled cloudflare service again after not receiving reply from you from a while. but before i enabled it, it still didnt push the static files from autopmize. And ive cleared the cached from cloudflare end but it just wont push the files. Ive moved push reload outside the location block with no changes.

juripaiusco commented 4 years ago

Hi,

with this solution:

function pushAOFiles($in) {

    $pushType = substr($in, strrpos($in, ".") + 1) === "js" ? "script" : "style";

    header('Link: <'.$in.'>; rel=preload; as=' . $pushType, false);

    return $in;

}
add_filter('autoptimize_filter_cache_getname','pushAOFiles');

The css is load twice time:

Schermata 2019-12-16 alle 16 54 01

I search in the code. Where can I remove the original css?