diff options
-rw-r--r-- | Bugzilla/Constants.pm | 7 | ||||
-rw-r--r-- | Bugzilla/Install/Filesystem.pm | 25 | ||||
-rw-r--r-- | Bugzilla/Template.pm | 51 | ||||
-rw-r--r-- | template/en/default/global/header.html.tmpl | 31 |
4 files changed, 100 insertions, 14 deletions
diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index 397a8e65f..97f4874b5 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -26,6 +26,8 @@ use Memoize; bz_locations + CONCATENATE_ASSETS + IS_NULL NOT_NULL @@ -210,6 +212,11 @@ use constant REST_DOC => "http://www.bugzilla.org/docs/tip/en/html/api/"; use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml'; use constant LOCAL_FILE => 'bugzilla-update.xml'; # Relative to datadir. +# When true CSS and JavaScript assets will be concatanted and minified at +# run-time, to reduce the number of requests required to render a page. +# Setting this to a false value can help debugging. +use constant CONCATENATE_ASSETS => 1; + # These are unique values that are unlikely to match a string or a number, # to be used in criteria for match() functions and other things. They start # and end with spaces because most Bugzilla stuff has trim() called on it, diff --git a/Bugzilla/Install/Filesystem.pm b/Bugzilla/Install/Filesystem.pm index 47b989f71..061ca53c7 100644 --- a/Bugzilla/Install/Filesystem.pm +++ b/Bugzilla/Install/Filesystem.pm @@ -31,6 +31,7 @@ use File::Path; use File::Basename; use File::Copy qw(move); use File::Spec; +use File::Slurp; use IO::File; use POSIX (); @@ -367,7 +368,7 @@ EOT "$assetsdir/.htaccess" => { perms => WS_SERVE, contents => <<EOT # Allow access to .css files -<FilesMatch \\.css\$> +<FilesMatch \\.(css|js)\$> Allow from all </FilesMatch> @@ -410,6 +411,7 @@ sub update_filesystem { my $datadir = bz_locations->{'datadir'}; my $graphsdir = bz_locations->{'graphsdir'}; + my $assetsdir = bz_locations->{'assetsdir'}; # If the graphs/ directory doesn't exist, we're upgrading from # a version old enough that we need to update the $datadir/mining # format. @@ -450,6 +452,13 @@ sub update_filesystem { _rename_file($oldparamsfile, "$datadir/$oldparamsfile"); } + # Remove old assets htaccess file to force recreation with correct values. + if (-e "$assetsdir/.htaccess") { + if (read_file("$assetsdir/.htaccess") =~ /<FilesMatch \\\.css\$>/) { + unlink("$assetsdir/.htaccess"); + } + } + _create_files(%files); if ($params->{index_html}) { _create_files(%{$fs->{index_html}}); @@ -493,7 +502,7 @@ EOT _remove_empty_css_files(); _convert_single_file_skins(); - _remove_dynamic_css_files(); + _remove_dynamic_assets(); } sub _remove_empty_css_files { @@ -538,10 +547,14 @@ sub _convert_single_file_skins { } } -# delete all automatically generated css files to force recreation at the next -# request. -sub _remove_dynamic_css_files { - foreach my $file (glob(bz_locations()->{assetsdir} . '/*.css')) { +# delete all automatically generated css/js files to force recreation at the +# next request. +sub _remove_dynamic_assets { + my @files = ( + glob(bz_locations()->{assetsdir} . '/*.css'), + glob(bz_locations()->{assetsdir} . '/*.js'), + ); + foreach my $file (@files) { unlink($file); } diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index aee7933ed..c8f56d73d 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -530,7 +530,7 @@ sub _concatenate_css { write_file($file, $content); } - $file =~ s/^\Q$cgi_path\E\///; + $file =~ s/^\Q$cgi_path\E\///o; return mtime_filter($file); } @@ -543,6 +543,54 @@ sub _css_url_rewrite { return 'url(../../' . dirname($source) . '/' . $url . ')'; } +sub _concatenate_js { + return @_ unless CONCATENATE_ASSETS; + my ($sources) = @_; + return [] unless $sources && ref($sources); + + my %files = + map { + (my $file = $_) =~ s/(^[^\?]+)\?.+/$1/; + $_ => $file; + } @$sources; + + my $cgi_path = bz_locations()->{cgi_path}; + my $skins_path = bz_locations()->{assetsdir}; + + # build minified files + my @minified; + foreach my $source (@$sources) { + next unless -e "$cgi_path/$files{$source}"; + my $file = $skins_path . '/' . md5_hex($source) . '.js'; + if (!-e $file) { + my $content = read_file("$cgi_path/$files{$source}"); + + # minimal minification + $content =~ s#/\*.*?\*/##sg; # block comments + $content =~ s#(^ +| +$)##gm; # leading/trailing spaces + $content =~ s#^//.+$##gm; # single line comments + $content =~ s#\n{2,}#\n#g; # blank lines + $content =~ s#(^\s+|\s+$)##g; # whitespace at the start/end of file + + write_file($file, "/* $files{$source} */\n" . $content . "\n"); + } + push @minified, $file; + } + + # concat files + my $file = $skins_path . '/' . md5_hex(join(' ', @$sources)) . '.js'; + if (!-e $file) { + my $content = ''; + foreach my $source (@minified) { + $content .= read_file($source); + } + write_file($file, $content); + } + + $file =~ s/^\Q$cgi_path\E\///o; + return [ $file ]; +} + # YUI dependency resolution sub yui_resolve_deps { my ($yui, $yui_deps) = @_; @@ -1054,6 +1102,7 @@ sub create { 'css_files' => \&css_files, yui_resolve_deps => \&yui_resolve_deps, + concatenate_js => \&_concatenate_js, # All classifications (sorted by sortkey, name) 'all_classifications' => sub { diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl index 4f6e187d8..63c5dd43d 100644 --- a/template/en/default/global/header.html.tmpl +++ b/template/en/default/global/header.html.tmpl @@ -90,8 +90,16 @@ [% SET yui = yui_resolve_deps(yui, yui_deps) %] [% SET css_sets = css_files(style_urls, yui, yui_css) %] - <link href="[% css_sets.unified_standard_skin FILTER html %]" - rel="stylesheet" type="text/css"> + [% IF constants.CONCATENATE_ASSETS %] + [% PROCESS format_css_link asset_url = css_sets.unified_standard_skin %] + [% ELSE %] + [% FOREACH asset_url = css_sets.standard %] + [% PROCESS format_css_link %] + [% END %] + [% FOREACH asset_url = css_sets.skin %] + [% PROCESS format_css_link %] + [% END %] + [% END %] [% IF style %] <style type="text/css"> @@ -100,8 +108,13 @@ [% END %] [% IF css_sets.unified_custom %] - <link href="[% css_sets.unified_custom FILTER html %]" - rel="stylesheet" type="text/css"> + [% IF constants.CONCATENATE_ASSETS %] + [% PROCESS format_css_link asset_url = css_sets.unified_custom %] + [% ELSE %] + [% FOREACH asset_rul = css_sets.custom %] + [% PROCESS format_css_link %] + [% END %] + [% END %] [% END %] [%# YUI Scripts %] @@ -110,7 +123,7 @@ [% END %] [% starting_js_urls.push('js/global.js') %] - [% FOREACH javascript_url = starting_js_urls %] + [% FOREACH asset_url = concatenate_js(starting_js_urls) %] [% PROCESS format_js_link %] [% END %] @@ -180,7 +193,7 @@ // --> </script> - [% FOREACH javascript_url = javascript_urls %] + [% FOREACH asset_url = concatenate_js(javascript_urls) %] [% PROCESS format_js_link %] [% END %] @@ -251,6 +264,10 @@ <div id="message">[% message %]</div> [% END %] +[% BLOCK format_css_link %] + <link href="[% asset_url FILTER html %]" rel="stylesheet" type="text/css"> +[% END %] + [% BLOCK format_js_link %] - <script type="text/javascript" src="[% javascript_url FILTER mtime FILTER html %]"></script> + <script type="text/javascript" src="[% asset_url FILTER mtime FILTER html %]"></script> [% END %] |