From 7f29dd34a78737967912f7c7156451facde7051d Mon Sep 17 00:00:00 2001 From: Byron Jones Date: Thu, 22 May 2014 13:57:28 +0800 Subject: Bug 1014374: backport bug 977969 to bmo (concatenate and slightly minify css files) --- Bugzilla/Template.pm | 96 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 17 deletions(-) (limited to 'Bugzilla/Template.pm') diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index d2d6a7dd1..d367c47bb 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -51,9 +51,11 @@ use Bugzilla::Token; use Cwd qw(abs_path); use MIME::Base64; use Date::Format (); +use Digest::MD5 qw(md5_hex); use File::Basename qw(basename dirname); use File::Find; use File::Path qw(rmtree mkpath); +use File::Slurp; use File::Spec; use IO::Dir; use List::MoreUtils qw(firstidx); @@ -401,18 +403,18 @@ sub mtime_filter { # Set up the skin CSS cascade: # -# 1. YUI CSS -# 2. Standard Bugzilla stylesheet set (persistent) -# 3. Third-party "skin" stylesheet set, per user prefs (persistent) -# 4. Page-specific styles -# 5. Custom Bugzilla stylesheet set (persistent) +# 1. standard/global.css +# 2. YUI CSS +# 3. Standard Bugzilla stylesheet set +# 4. Third-party "skin" stylesheet set, per user prefs +# 5. Inline css passed to global/header.html.tmpl +# 6. Custom Bugzilla stylesheet set sub css_files { my ($style_urls, $yui, $yui_css) = @_; - - # global.css goes on every page, and so does IE-fixes.css. - my @requested_css = ('skins/standard/global.css', @$style_urls, - 'skins/standard/IE-fixes.css'); + + # global.css belongs on every page + my @requested_css = ( 'skins/standard/global.css', @$style_urls ); my @yui_required_css; foreach my $yui_name (@$yui) { @@ -429,7 +431,12 @@ sub css_files { push(@{ $by_type{$key} }, $set->{$key}); } } - + + # build unified + $by_type{unified_standard_skin} = _concatenate_css($by_type{standard}, + $by_type{skin}); + $by_type{unified_custom} = _concatenate_css($by_type{custom}); + return \%by_type; } @@ -437,30 +444,85 @@ sub _css_link_set { my ($file_name) = @_; my %set = (standard => mtime_filter($file_name)); - - # We use (^|/) to allow Extensions to use the skins system if they - # want. - if ($file_name !~ m{(^|/)skins/standard/}) { + + # We use (?:^|/) to allow Extensions to use the skins system if they want. + if ($file_name !~ m{(?:^|/)skins/standard/}) { return \%set; } my $skin = Bugzilla->user->settings->{skin}->{value}; my $cgi_path = bz_locations()->{'cgi_path'}; my $skin_file_name = $file_name; - $skin_file_name =~ s{(^|/)skins/standard/}{skins/contrib/$skin/}; + $skin_file_name =~ s{(?:^|/)skins/standard/}{skins/contrib/$skin/}; if (my $mtime = _mtime("$cgi_path/$skin_file_name")) { $set{skin} = mtime_filter($skin_file_name, $mtime); } my $custom_file_name = $file_name; - $custom_file_name =~ s{(^|/)skins/standard/}{skins/custom/}; + $custom_file_name =~ s{(?:^|/)skins/standard/}{skins/custom/}; if (my $custom_mtime = _mtime("$cgi_path/$custom_file_name")) { $set{custom} = mtime_filter($custom_file_name, $custom_mtime); } - + return \%set; } +sub _concatenate_css { + my @sources = map { @$_ } @_; + return unless @sources; + + my %files = + map { + (my $file = $_) =~ s/(^[^\?]+)\?.+/$1/; + $_ => $file; + } @sources; + + my $cgi_path = bz_locations()->{cgi_path}; + my $skins_path = bz_locations()->{skinsdir}; + + # build minified files + my @minified; + foreach my $source (@sources) { + next unless -e "$cgi_path/$files{$source}"; + my $file = $skins_path . '/assets/' . md5_hex($source) . '.css'; + if (!-e $file) { + my $content = read_file("$cgi_path/$files{$source}"); + + # minify + $content =~ s{/\*.*?\*/}{}sg; # comments + $content =~ s{(^\s+|\s+$)}{}mg; # leading/trailing whitespace + $content =~ s{\n}{}g; # single line + + # rewrite urls + $content =~ s{url\(([^\)]+)\)}{_css_url_rewrite($source, $1)}eig; + + write_file($file, "/* $files{$source} */\n" . $content . "\n"); + } + push @minified, $file; + } + + # concat files + my $file = $skins_path . '/assets/' . md5_hex(join(' ', @sources)) . '.css'; + if (!-e $file) { + my $content = ''; + foreach my $source (@minified) { + $content .= read_file($source); + } + write_file($file, $content); + } + + return mtime_filter($file); +} + +sub _css_url_rewrite { + my ($source, $url) = @_; + # rewrite relative urls as the unified stylesheet lives in a different + # directory from the source + $url =~ s/(^['"]|['"]$)//g; + return $url if substr($url, 0, 1) eq '/'; + return 'url(../../' . dirname($source) . '/' . $url . ')'; +} + # YUI dependency resolution sub yui_resolve_deps { my ($yui, $yui_deps) = @_; -- cgit v1.2.3-24-g4f1b