diff options
author | Byron Jones <glob@mozilla.com> | 2014-05-14 07:35:25 +0200 |
---|---|---|
committer | Byron Jones <glob@mozilla.com> | 2014-05-14 07:35:25 +0200 |
commit | 6d3857e31ab6d39625c2b5703a876d0b13930c18 (patch) | |
tree | 339102a76092e470644970679a37481d0163afc6 /Bugzilla | |
parent | fca0b6cb7133f458352bd8547195f7f0822766f8 (diff) | |
download | bugzilla-6d3857e31ab6d39625c2b5703a876d0b13930c18.tar.gz bugzilla-6d3857e31ab6d39625c2b5703a876d0b13930c18.tar.xz |
Bug 977969: concatenate and slightly minify css files
r=gerv, a=glob
Diffstat (limited to 'Bugzilla')
-rw-r--r-- | Bugzilla/Install/Filesystem.pm | 12 | ||||
-rw-r--r-- | Bugzilla/Template.pm | 88 |
2 files changed, 88 insertions, 12 deletions
diff --git a/Bugzilla/Install/Filesystem.pm b/Bugzilla/Install/Filesystem.pm index 4056d4994..b2ac04aca 100644 --- a/Bugzilla/Install/Filesystem.pm +++ b/Bugzilla/Install/Filesystem.pm @@ -199,6 +199,8 @@ sub FILESYSTEM { dirs => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE }, "$datadir/db" => { files => CGI_WRITE, dirs => DIR_CGI_WRITE }, + "$skinsdir/assets" => { files => WS_SERVE, + dirs => DIR_CGI_OVERWRITE | DIR_ALSO_WS_SERVE }, # Readable directories "$datadir/mining" => { files => CGI_READ, @@ -269,6 +271,7 @@ sub FILESYSTEM { $attachdir => DIR_CGI_WRITE, $graphsdir => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE, $webdotdir => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE, + "$skinsdir/assets" => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE, # Directories that contain content served directly by the web server. "$skinsdir/custom" => DIR_WS_SERVE, "$skinsdir/contrib" => DIR_WS_SERVE, @@ -475,6 +478,7 @@ EOT _remove_empty_css_files(); _convert_single_file_skins(); + _remove_dynamic_css_files(); } sub _remove_empty_css_files { @@ -519,6 +523,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()->{skinsdir} . '/assets/*.css')) { + unlink($file); + } +} + sub create_htaccess { _create_files(%{FILESYSTEM()->{htaccess}}); diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index b59ae2e08..c4da68802 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -26,9 +26,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); @@ -422,10 +424,12 @@ 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. 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) = @_; @@ -448,7 +452,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; } @@ -456,30 +465,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) = @_; |