Optimizing script loading
WordPress is using more and more JavaScript. A lot of features use AJAX and nearly all UI customizations and enhancements depend on it. In 2.7 there is some optimization for caching, especially when Turbo (Gears) is used all pages load in under 1 sec. However the cache control was left to the server and there seem to be a lot of servers with less than perfect settings for it.
There are many ways to optimize script loading in 2.8. Listing several of them roughly in order of ease of implementation/most effective:
- Minify (but not “pack”) all js files. Although the file size is larger, minified js loads faster than “packed” js, as it takes the browser some time to “unpack” it. Here’s a nice post on the subject. In 2.8 we should replace all “packed” js with minified and also minify all custom js when building the release.
- Load most js in the footer. Even with 15 – 20 js files a page will load a lot faster when most are in the footer. In theory we can load all but jQuery in the footer. There’s a ticket and patch for the script loader to do this. However in practice that will interfere with many plugins that load any of the default js files on admin pages. Seems that if we load jQuery and any jQuery UI parts in the head, the great majority of plugins won’t be affected. Another option would be to queue all UI parts for the footer but move them to the head if a plugin loaded js lists them as dependencies (that would complicate the script loader a bit).
- Setting custom caching headers in .htaccess. Although this may not work on all servers, chances are that the great majority of installations would benefit. There are several settings that can be added: the “expire far in the future” is a must, either configuring or disabling Etags for the js, css and image files is advisable, also several of the HTTP 1.0 cache control headers would be beneficial. Of course this would need testing on different production servers, but it would degrade gracefully (just wouldn’t work), so counting it as “must implement”.
- Adding all js and css files in both compressed and uncompressed state and setting the server (.htaccess) to use the compressed versions whenever possible. This would greatly improve the initial loading of all scripts (cold cache), but is not as trivial to set up as the cache control headers. Still worth a try even if not all WordPress installations would benefit. It is possible to set the server to compress “on the fly” or compress by using php, but both methods use a lot more of server CPU time/memory on each page load. Since this affects only cold cache hits, not sure if it’s worth it. The typical user case for the admin is the same user on the same computer and in the same browser accessing the admin at least several times per week. So making sure caching works best is a priority.
- Concatenating all default js files on per page basis so there’s only one js file to load. This combined with compressing the file would give the fastest loading time for both cold and hot cache, although for hot cache with proper cache control the difference is almost unnoticeable. It is possible to do this when building the release and include two versions of each file: compressed and uncompressed, then use .htaccess to output the compressed version when possible. However when there is a plugin that loads js and depends on other default js files, the performance degrades quickly and most blogs seem to have at least one such plugin. The workaround is to dynamically generate the concatenated file for each page, compress it and store it on the server. That would mean doing something similar to WP Super Cache but only for the js and css files in the admin. There seem to be at least one plugin that attempts to do this, also several regular WordPress contributors are interested in making such plugins. Perhaps for now it’s better to leave this for a plugin as there seem to be many server configurations where it would be difficult to set up or won’t work properly. We can also add some hooks in script loader to facilitate this if needed.
In terms of performance the concatenating and compressing of all js and css files for each page gives the best results, closely followed by the loading of most js files in the footer. If we decide not to do the concatenating/compressing, we should revisit it in about a year (for WordPress 3.0?) as most Web hosts would have upgraded to php 5 by then. The actual php version wouldn’t affect this, but it seems that while upgrading the hosts also improve their server and php configurations too.
Gregory 3:57 am on December 29, 2008 Permalink |
It would be great if wordpress was compatable with mod_concat and mod_jsmin. I have attempted to implement both apache modules with 2.7 with limited results
Jacob Santos 3:58 pm on December 29, 2008 Permalink |
If hosting servers don’t support PHP5 now, then they’ll probably won’t in another year or two.
Rahul Boss 10:44 am on December 30, 2008 Permalink |
mainly now all hosting servers support php5.
miloandrew 11:03 pm on December 31, 2008 Permalink |
Many of your ruminations are understandably taking into account the huge array of available WP plugins. While this is absolutely necessary, maybe taking a bit of a different tack can open up some options?
I have often wished that I could manage the load order of plugins and control which loads before another, or even WHEN a plugin loads at all. Could it be that implementing more internal plugin declaration and control could help with the overall compatibility of this optimization initiative?
If we make it possible for the system to detect the way certain plugin scenarios will affect optimization efforts, then the system can adapt on its own. Rather than making global decisions on optimization based upon what COULD exist with certain plugins, maybe taking the tack of allowing the plugins to tell the system what they load and require would do the trick?
The plugin header could potentially be extended to either allow the developer to state when the plugin should be loaded, or at least to specify other items that it either requires or loads itself. A “Loads:” field along with a “Requires:” field could go a long way to helping WP understand what the activated plugins require. It could also help the user make intelligent decisions by allowing the system to report if the activation of a specific plugin will necessitate the disabling of a specific optimization technique that would otherwise be used by the core.
Alternatively (or in addition to the above), you could allow the WP admin to specify where and when all active plugins are loaded. While I would love to see this type of completely configurable plugin management, I think that even just the additional declarations could be extremely helpful.
Sorry – I don’t mean to digress from optimization to plugin management, but it seems that there may be a few strong ties between the two.
Thanks for listening!
Cheers,
A
Blog Herald WordPress News: WordPress Scholarship, 800,000 WordPress 2.7 Downloads, XML-RPC Problem, and Top Plugin Authors « Lorelle on WordPress 4:24 am on January 3, 2009 Permalink |
[...] a lot of AJAX and JavaScript. Ozz offers a technical article on the WordPress Development Blog for optimizing script loading that is a must-read for all WordPress Plugin and Theme [...]
Andrew Ozz 10:22 am on January 3, 2009 Permalink |
@Jacob Santos, @Rahul Boss yes, but most hosts require the user to manually switch to php 5, sometimes by directly editing .htaccess. Don’t think that most users are comfortable doing that or even aware of it.
@miloandrew almost all of these features already exist in the API. In the case of script loading, plugins can enqueue both js and css and require any of the scripts included in WordPress. Unfortunately not all plugins use the script loader, but most do.
The optimization will have to be transparent for the plugins. For example setting appropriate caching headers for js, css and images in .htaccess would affect all scripts.
The load order can be managed from the filter/action priority quite well. The blog admin can edit the plugin’s file and change that if needed or have a small plugin that would set it up for the rest.
BTW the first step is already implemented. All js has been minified reducing the size by about 30% – 35%.
WordPress News: WordPress Resolutions, Tattoos, LiveJournal, Converters, Security, Plugins, and More « Lorelle on WordPress 8:27 pm on January 18, 2009 Permalink |
[...] TW-Sack or Simple AJAX Code-Kit (SACK) in his WordPress Plugins and talks about how the series by Andrew Ozz on Optimizing Script Loading on the WordPress Development blog has changed how he uses JavaScript in his Plugins, as well as the [...]
WordPress News: WordPress.tv, WordCamp Whistler, WordPress Logo, City Saves Money, and More | The Blog Herald 4:51 pm on January 23, 2009 Permalink |
[...] Optimizing script loading [...]
WordPress News Report: iPhone, Widgets API, WordCamps in Hong Kong and China, International WordPress.tv « Lorelle on WordPress 7:08 am on March 19, 2009 Permalink |
[...] Optimizing Script Loading [...]
Wordpress 2.8 para Abril de 2009 | aNieto2K 7:23 pm on March 19, 2009 Permalink |
[...] Mejoras en carga de ficheros Javascript y CSS. [...]
WordPress 2.8 previsto para abril » Comunidade WordPress-BR 2:16 am on March 20, 2009 Permalink |
[...] Melhorias no carregamento de arquivos Javascript e CSS. [...]
Milan 1:31 pm on March 22, 2009 Permalink |
I am not sure where to post this, but I’ll start from here since title of this post describes my intention.
When new comment threading for 2.7 was introduced, you recommended call to comment-reply.js in this form.
But problem with this is that comment-reply.js is called on all pages in all cases even there are many cases when it shouldn’t be called because it is simply not needed:
- when comments are turned off on site wide level
- when threaded comments are not enabled (this is default option)
- when comments are not enabled on that entry
- when there is no comments on that entry
- when page is used as front page (in reading options)
In all those situations comment-reply.js is loaded even though there is no need for it. Yes, it is cached after first page view, but what if visitor lands on that particular page that doesn’t need this file and that page already has ten javascript files? It will just increase page load time and you know that visitors that come from search engines or from links on other sites have low tolerance and don’t want to wait to much.
So what we need is that this script is loaded only when there is need for it and my suggestion is that you make some function that should be checked and that will return true or false value when asked if there is need for comment-reply.js. Maybe that script can’t solve all problems but at least it can return false value if comments are globally turned off or comment threading is not enabled (I’m quite sure it can do this).
Example of how this should work in theme’s files:
if ( comment_threading_entry_status() ) wp_enqueue_script( 'comment-reply' );
Example of functions:
function comment_threading_entry_status() {if (((get_option('default_comment_status')) == "open") && ((get_option('thread_comments')) == "1") && ( !is_front_page() ) && ( comments_open() ) && ( have_comments() )) {
return true;
} else
return false;
}
This function doesn’t work like this (it works without last two conditions), but you got a point.
I hope that you’ll at least respond me in reasonable time
(btw, why we don’t have subscribe to comments here, it should be enabled on wp.com?)
WordPress 2.8 kommt im April 2008 - Template, Nutzung, Scripte, WordPress, Sicht, SimplePie - WordPress Deutschland Blog 10:55 am on March 23, 2009 Permalink |
[...] Optimiertes laden von JavaScript Seit 2.7 kann sauber und geprüft das Laden von JS eingebunden werden. Zusätzliche Funktion sorgen für ein Kontrolle des Lade- und Abhängigkeitsprozesses. Nun werden via WordPress die Scripte zusammengefasst und in einem Aufruf zurück gegeben. Ebenso kann man Scripte nun im Footer einbinden, direkt durch die angesprochenen Funktionen. [...]
WordPress 2.8, small insights - SimplePie, WordPress, Template, More, Core, With - WP Engineer 12:46 pm on March 23, 2009 Permalink |
[...] Optimized loading of JavaScript Since 2.7 is clean and checked loading of JS involved. Additional functions provide a control of the loading process and dependency. Now, via WordPress, scripts are going to summarized and returned in a single call. You can also include scripts in the footer now, directly through the targeted functions. [...]
Tobbis Blog » WordPress 2.8 kommt im April 6:30 am on March 26, 2009 Permalink |
[...] v2.8 von WordPress nächsten Monat veröffentlicht werden. Interessante Neuerung ist das optimierte Laden von Java-Scripts. Veröffentlicht am 26. März 2009 um 07:30 in WordPress. Tags: Internet, WordPress Einen [...]
Preview do WordPress 2 .8 | ivanBogar.com | design e wordPress 11:38 am on March 26, 2009 Permalink |
[...] Otimizando o carregamento de JavaScript [...]
WordPress News: WordPress 2.8, Summer of Code, PodPress Returning, iPhone Update | The Blog Herald 6:52 pm on March 27, 2009 Permalink |
[...] Optimizing Script Loading improved with tips in part 2 and part 3. [...]
John Biddle 8:39 pm on April 2, 2009 Permalink |
This is a great idea. The problem is even bigger than you describe. It’s true that for second and subsequent pageloads the javascript is is the cache, it’s also true that unless the files has an expired header the browser still has to contact the host to determine if the file in cache is current. There won’t be a download for current files, but the round trip to the server just to check the currentness wastes time for every page. This problem exists for losts of files in lots of plugins and probably contributes to a 1 or 2 second page delay for the average page.
WordPress Plugins News: Coffee2Code Plugin Marathon, Plugin Podcast, Plugin Developer Center, Plugin Checklist « Lorelle on WordPress 5:16 pm on April 5, 2009 Permalink |
[...] WordPress Development – Optimizing Script Loading [...]