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) --- .gitignore | 1 + Bugzilla/Install/Filesystem.pm | 12 ++++ Bugzilla/Template.pm | 96 ++++++++++++++++++++++++----- skins/README | 35 ++++++----- template/en/default/global/header.html.tmpl | 49 ++------------- 5 files changed, 116 insertions(+), 77 deletions(-) diff --git a/.gitignore b/.gitignore index 0370a07e0..d55bf70ad 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,6 @@ /data /localconfig /index.html +/skins/assets /template_cache .DS_Store diff --git a/Bugzilla/Install/Filesystem.pm b/Bugzilla/Install/Filesystem.pm index cd1e76916..5ea0917fa 100644 --- a/Bugzilla/Install/Filesystem.pm +++ b/Bugzilla/Install/Filesystem.pm @@ -211,6 +211,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, @@ -284,6 +286,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, @@ -483,6 +486,7 @@ EOT _remove_empty_css_files(); _convert_single_file_skins(); + _remove_dynamic_css_files(); } sub _remove_empty_css_files { @@ -527,6 +531,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 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) = @_; diff --git a/skins/README b/skins/README index 111c00f03..1deac48a2 100644 --- a/skins/README +++ b/skins/README @@ -1,20 +1,21 @@ -There are three directories here, standard/, custom/, and contrib/. +There are four directories here, standard/, custom/, contrib/, and assets/. -standard/ holds the standard stylesheets. These are used no matter -what skin the user selects. If the user selects the "Classic" skin, -then *only* the standard/ stylesheets are used. +standard/ holds the standard stylesheets. These are used no matter what skin +the user selects. If the user selects the "Classic" skin, then *only* the +standard/ stylesheets are used. -contrib/ holds "skins" that the user can select in their preferences. -skins are in directories, and they contain files with the same names -as the files in skins/standard/. Simply putting a new directory -into the contrib/ directory adds a new skin as an option in users' -preferences. +contrib/ holds "skins" that the user can select in their preferences. skins +are in directories, and they contain files with the same names as the files in +skins/standard/. Simply putting a new directory into the contrib/ directory +adds a new skin as an option in users' preferences. -custom/ allows you to locally override the standard/ and contrib/ CSS. -If you put files into the custom/ directory with the same names as the CSS -files in skins/standard/, you can override the standard/ and contrib/ -CSS. For example, if you want to override some CSS in -skins/standard/global.css, then you should create a file called "global.css" -in custom/ and put some CSS in it. The CSS you put into files in custom/ will -be used *in addition* to the CSS in skins/standard/ or the CSS in -skins/contrib/. It will apply to every skin. +custom/ allows you to locally override the standard/ and contrib/ CSS. If you +put files into the custom/ directory with the same names as the CSS files in +skins/standard/, you can override the standard/ and contrib/ CSS. For example, +if you want to override some CSS in skins/standard/global.css, then you should +create a file called "global.css" in custom/ and put some CSS in it. The CSS +you put into files in custom/ will be used *in addition* to the CSS in +skins/standard/ or the CSS in skins/contrib/. It will apply to every skin. + +assets/ holds the minified and concatenated files which are created by +checksetup.pl and Bugzilla::Template. Do not edit the files in this directory. diff --git a/template/en/default/global/header.html.tmpl b/template/en/default/global/header.html.tmpl index c5b2c126a..d6fc78b11 100644 --- a/template/en/default/global/header.html.tmpl +++ b/template/en/default/global/header.html.tmpl @@ -108,34 +108,20 @@ [% PROCESS 'global/setting-descs.none.tmpl' %] [% SET yui = yui_resolve_deps(yui, yui_deps) %] - [% SET css_sets = css_files(style_urls, yui, yui_css) %] - - [%# CSS cascade, parts 1 & 2: YUI & Standard Bugzilla stylesheet set (persistent). - # Always present. %] - - [% FOREACH style_url = css_sets.standard %] - [% PROCESS format_css_link css_set_name = 'standard' %] - [% END %] - [%# CSS cascade, part 3: Third-party stylesheet set, per user prefs. %] - [% FOREACH style_url = css_sets.skin %] - [% PROCESS format_css_link css_set_name = user.settings.skin.value %] - [% END %] + [% SET css_sets = css_files(style_urls, yui, yui_css) %] + - [%# CSS cascade, part 4: page-specific styles. %] [% IF style %] [% END %] - [%# CSS cascade, part 5: Custom Bugzilla stylesheet set (persistent). - # Always present. Site administrators may override all other style - # definitions, including skins, using custom stylesheets. - #%] - [% FOREACH style_url = css_sets.custom %] - [% PROCESS format_css_link css_set_name = 'standard' %] + [% IF css_sets.unified_custom %] + [% END %] [%# YUI Scripts %] @@ -393,29 +379,6 @@
[% message %]
[% END %] -[% BLOCK format_css_link %] - [% IF style_url.match('/IE-fixes\.css') %] - ' IF style_url.match('/IE-fixes\.css') %] -[% END %] - [% BLOCK format_js_link %] [% END %] -- cgit v1.2.3-24-g4f1b