Bug 977969: concatenate and slightly minify css files

r=gerv, a=glob


git-svn-id: svn://10.0.0.236/trunk@265401 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bzrmirror%bugzilla.org 2014-05-14 05:46:32 +00:00
parent 932733988c
commit 052c48cbdf
7 changed files with 115 additions and 65 deletions

View File

@ -1 +1 @@
9031 9032

View File

@ -10,5 +10,6 @@
/localconfig /localconfig
/index.html /index.html
/skins/assets
/skins/contrib/Dusk/admin.css /skins/contrib/Dusk/admin.css
/skins/contrib/Dusk/bug.css /skins/contrib/Dusk/bug.css

View File

@ -1 +1 @@
fca0b6cb7133f458352bd8547195f7f0822766f8 6d3857e31ab6d39625c2b5703a876d0b13930c18

View File

@ -199,6 +199,8 @@ sub FILESYSTEM {
dirs => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE }, dirs => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE },
"$datadir/db" => { files => CGI_WRITE, "$datadir/db" => { files => CGI_WRITE,
dirs => DIR_CGI_WRITE }, dirs => DIR_CGI_WRITE },
"$skinsdir/assets" => { files => WS_SERVE,
dirs => DIR_CGI_OVERWRITE | DIR_ALSO_WS_SERVE },
# Readable directories # Readable directories
"$datadir/mining" => { files => CGI_READ, "$datadir/mining" => { files => CGI_READ,
@ -269,6 +271,7 @@ sub FILESYSTEM {
$attachdir => DIR_CGI_WRITE, $attachdir => DIR_CGI_WRITE,
$graphsdir => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE, $graphsdir => DIR_CGI_WRITE | DIR_ALSO_WS_SERVE,
$webdotdir => 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. # Directories that contain content served directly by the web server.
"$skinsdir/custom" => DIR_WS_SERVE, "$skinsdir/custom" => DIR_WS_SERVE,
"$skinsdir/contrib" => DIR_WS_SERVE, "$skinsdir/contrib" => DIR_WS_SERVE,
@ -475,6 +478,7 @@ EOT
_remove_empty_css_files(); _remove_empty_css_files();
_convert_single_file_skins(); _convert_single_file_skins();
_remove_dynamic_css_files();
} }
sub _remove_empty_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 { sub create_htaccess {
_create_files(%{FILESYSTEM()->{htaccess}}); _create_files(%{FILESYSTEM()->{htaccess}});

View File

@ -26,9 +26,11 @@ use Bugzilla::Token;
use Cwd qw(abs_path); use Cwd qw(abs_path);
use MIME::Base64; use MIME::Base64;
use Date::Format (); use Date::Format ();
use Digest::MD5 qw(md5_hex);
use File::Basename qw(basename dirname); use File::Basename qw(basename dirname);
use File::Find; use File::Find;
use File::Path qw(rmtree mkpath); use File::Path qw(rmtree mkpath);
use File::Slurp;
use File::Spec; use File::Spec;
use IO::Dir; use IO::Dir;
use List::MoreUtils qw(firstidx); use List::MoreUtils qw(firstidx);
@ -422,10 +424,12 @@ sub mtime_filter {
# Set up the skin CSS cascade: # Set up the skin CSS cascade:
# #
# 1. YUI CSS # 1. standard/global.css
# 2. Standard Bugzilla stylesheet set (persistent) # 2. YUI CSS
# 3. Third-party "skin" stylesheet set, per user prefs (persistent) # 3. Standard Bugzilla stylesheet set
# 4. Custom Bugzilla stylesheet set (persistent) # 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 { sub css_files {
my ($style_urls, $yui, $yui_css) = @_; my ($style_urls, $yui, $yui_css) = @_;
@ -448,7 +452,12 @@ sub css_files {
push(@{ $by_type{$key} }, $set->{$key}); 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; return \%by_type;
} }
@ -456,30 +465,85 @@ sub _css_link_set {
my ($file_name) = @_; my ($file_name) = @_;
my %set = (standard => mtime_filter($file_name)); my %set = (standard => mtime_filter($file_name));
# We use (^|/) to allow Extensions to use the skins system if they # We use (?:^|/) to allow Extensions to use the skins system if they want.
# want. if ($file_name !~ m{(?:^|/)skins/standard/}) {
if ($file_name !~ m{(^|/)skins/standard/}) {
return \%set; return \%set;
} }
my $skin = Bugzilla->user->settings->{skin}->{value}; my $skin = Bugzilla->user->settings->{skin}->{value};
my $cgi_path = bz_locations()->{'cgi_path'}; my $cgi_path = bz_locations()->{'cgi_path'};
my $skin_file_name = $file_name; 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")) { if (my $mtime = _mtime("$cgi_path/$skin_file_name")) {
$set{skin} = mtime_filter($skin_file_name, $mtime); $set{skin} = mtime_filter($skin_file_name, $mtime);
} }
my $custom_file_name = $file_name; 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")) { if (my $custom_mtime = _mtime("$cgi_path/$custom_file_name")) {
$set{custom} = mtime_filter($custom_file_name, $custom_mtime); $set{custom} = mtime_filter($custom_file_name, $custom_mtime);
} }
return \%set; 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 # YUI dependency resolution
sub yui_resolve_deps { sub yui_resolve_deps {
my ($yui, $yui_deps) = @_; my ($yui, $yui_deps) = @_;

View File

@ -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 standard/ holds the standard stylesheets. These are used no matter what skin
what skin the user selects. If the user selects the "Classic" skin, the user selects. If the user selects the "Classic" skin, then *only* the
then *only* the standard/ stylesheets are used. standard/ stylesheets are used.
contrib/ holds "skins" that the user can select in their preferences. contrib/ holds "skins" that the user can select in their preferences. skins
skins are in directories, and they contain files with the same names are in directories, and they contain files with the same names as the files in
as the files in skins/standard/. Simply putting a new directory skins/standard/. Simply putting a new directory into the contrib/ directory
into the contrib/ directory adds a new skin as an option in users' adds a new skin as an option in users' preferences.
preferences.
custom/ allows you to locally override the standard/ and contrib/ CSS. custom/ allows you to locally override the standard/ and contrib/ CSS. If you
If you put files into the custom/ directory with the same names as the CSS put files into the custom/ directory with the same names as the CSS files in
files in skins/standard/, you can override the standard/ and contrib/ skins/standard/, you can override the standard/ and contrib/ CSS. For example,
CSS. For example, if you want to override some CSS in if you want to override some CSS in skins/standard/global.css, then you should
skins/standard/global.css, then you should create a file called "global.css" create a file called "global.css" in custom/ and put some CSS in it. The CSS
in custom/ and put some CSS in it. The CSS you put into files in custom/ will you put into files in custom/ will be used *in addition* to the CSS in
be used *in addition* to the CSS in skins/standard/ or the CSS in skins/standard/ or the CSS in skins/contrib/. It will apply to every skin.
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.

View File

@ -90,35 +90,20 @@
[% PROCESS 'global/setting-descs.none.tmpl' %] [% PROCESS 'global/setting-descs.none.tmpl' %]
[% SET yui = yui_resolve_deps(yui, yui_deps) %] [% SET yui = yui_resolve_deps(yui, yui_deps) %]
[% SET css_sets = css_files(style_urls, yui, yui_css) %] [% SET css_sets = css_files(style_urls, yui, yui_css) %]
<link href="[% css_sets.unified_standard_skin FILTER html %]"
rel="stylesheet" type="text/css">
[%# CSS cascade, parts 1 & 2: YUI & Standard Bugzilla stylesheet set (persistent).
# Always present. %]
<link href="[% 'skins/standard/global.css' FILTER mtime FILTER html %]"
rel="alternate stylesheet"
title="[% setting_descs.standard FILTER html %]">
[% 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 %]
[%# CSS cascade, part 4: page-specific styles. %]
[% IF style %] [% IF style %]
<style type="text/css"> <style type="text/css">
[% style %] [% style %]
</style> </style>
[% END %] [% END %]
[%# CSS cascade, part 5: Custom Bugzilla stylesheet set (persistent). [% IF css_sets.unified_custom %]
# Always present. Site administrators may override all other style <link href="[% css_sets.unified_custom FILTER html %]"
# definitions, including skins, using custom stylesheets. rel="stylesheet" type="text/css">
#%]
[% FOREACH style_url = css_sets.custom %]
[% PROCESS format_css_link css_set_name = 'standard' %]
[% END %] [% END %]
[%# YUI Scripts %] [%# YUI Scripts %]
@ -265,19 +250,6 @@
<div id="message">[% message %]</div> <div id="message">[% message %]</div>
[% END %] [% END %]
[% BLOCK format_css_link %]
[% IF css_set_name == 'standard' %]
[% SET css_title_link = '' %]
[% ELSE %]
[% css_title_link = BLOCK ~%]
title="[% setting_descs.${user.settings.skin.value} || user.settings.skin.value FILTER html %]"
[% END %]
[% END %]
<link href="[% style_url FILTER html %]" rel="stylesheet"
type="text/css" [% css_title_link FILTER none %]>
[% END %]
[% BLOCK format_js_link %] [% BLOCK format_js_link %]
<script type="text/javascript" src="[% javascript_url FILTER mtime FILTER html %]"></script> <script type="text/javascript" src="[% javascript_url FILTER mtime FILTER html %]"></script>
[% END %] [% END %]