Created
February 10, 2012 18:24
-
-
Save nikopol/1791459 to your computer and use it in GitHub Desktop.
html/php minifier
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
#html/php minifier - niko 2012 | |
#use: ./minify < tof.php > ../index.php | |
use strict; | |
use warnings; | |
use JSON; | |
use LWP::UserAgent; | |
use MIME::Base64; | |
my $read = 0; | |
sub load { | |
my( $file, $pfx ) = @_; | |
$pfx = '' unless $pfx; | |
warn $pfx."loading $file\n"; | |
open(FH, $file) or die "unable to read $file\n"; | |
$read += -s $file; | |
if( wantarray ){ | |
my @lines = <FH>; | |
close FH; | |
return @lines; | |
} | |
my $buf = ''; | |
$buf .= $_ while <FH>; | |
close FH; | |
$buf; | |
} | |
sub imagedata { | |
my( $file, $pfx ) = @_; | |
$pfx = '' unless $pfx; | |
return $file if $file =~ /^(http|data\:)/i; | |
my $ext = ( $file =~ /\.([^\.]+)$/ ) ? $1 : '?'; | |
my $raw = load $file, $pfx; | |
my $len = length $raw; | |
my $data = encode_base64($raw,''); | |
my $zip = length $data; | |
warn " | $file encoded from $len to $zip (",int(100*($len-$zip)/$len),"%)\n"; | |
'data:image/'.$ext.';base64,'.$data; | |
} | |
sub css_minify { | |
my( $file, $pfx ) = @_; | |
$pfx = '' unless $pfx; | |
my @css = load $file, $pfx; | |
$pfx .= ' | '; | |
my $path = $file; | |
$path =~ s/[^\/]+$//g; | |
$path = './' unless $path; | |
my $len = 0; | |
my $mini = ''; | |
for my $l ( @css ){ | |
$len += 1+length($l); | |
$l =~ s/\r+//g; #remove \r | |
$l =~ s/(^\s+|\s*$)//g; #remove lead/end spaces | |
$l =~ s/\s*\:\s*/:/g; #remove spaces around : | |
$l =~ s/\;\s+/;/g; #remove spaces after ; | |
$l =~ s/\s*\{\s*/{/g; #remove spaces around { | |
$l =~ s/\s*\}\s*/}/g; #remove spaces around } | |
$l =~ s/\s+/ /g; #reduce multiple spaces | |
$l =~ s/\s+/ /g; #reduce multiple spaces | |
$l =~ s/;?\}\s*/}\n/g; #remove ; ending a block and add line return after a block | |
if( $l =~ m/url\(\'?\"?([^\)'"]+)\'?\"?\)/ ){ | |
my $url = $1; | |
if( $url !~ /^(http|data\:)/i ){ | |
my $b64 = imagedata $path.$url, $pfx; | |
$l =~ s/$url/$b64/; | |
} | |
} | |
$mini .= $l unless $l =~ m|^/\*.*\*/$| || !$l; | |
} | |
my $zip = length($mini); | |
warn "$pfx$file minified from $len to $zip (",int(100*($len-$zip)/$len),"%)\n"; | |
split /\n+/,$mini; | |
} | |
sub js_minify { | |
my $file = shift; | |
my $js = load $file; | |
return split(/\r?\n+/,$js) if $file =~ /min\.js$/i; | |
my $len = length $js; | |
my $ua = LWP::UserAgent->new; | |
my $res = $ua->post( | |
'http://closure-compiler.appspot.com/compile', [ | |
'output_info' => 'compiled_code', | |
'output_info' => 'errors', | |
output_format => 'json', | |
warning_level => 'quiet', | |
#compilation_level => 'advanced_optimizations', | |
js_code => $js, | |
] | |
); | |
die $res->status_line,"\n" unless $res->is_success; | |
my $c = from_json($res->decoded_content); | |
if(exists $c->{serverErrors}){ | |
warn 'ERROR #',$_->{'code'},': ',$_->{error},"\n" | |
foreach @{$c->{serverErrors}}; | |
die "break on error\n"; | |
} | |
if($c->{errors} && @{$c->{errors}}){ | |
warn $_->{error},' line ',$_->{lineno},' near ',$_->{line},"\n" | |
foreach @{$c->{errors}}; | |
die "break on error\n"; | |
} | |
if($c->{compiledCode}) { | |
$js = $c->{compiledCode}; | |
$js =~ s/[\r\n]+//; | |
my $zip = length $js; | |
warn " | $file closured from $len to $zip (",int(100*($len-$zip)/$len),"%)\n"; | |
} else { | |
warn " | $file not closured\n"; | |
} | |
split /\r?\n+/,$js | |
} | |
warn "parsing stdin\n"; | |
my $mini = ''; | |
for my $l ( <STDIN> ) { | |
$read += length $l; | |
if( $l =~ /^(\s*)<script[^\>]+src=[\'\"]([^\'\"]+)[\'\"]/i ) { | |
my $pfx = $1; | |
my $src = $2; | |
$mini .= $src =~ /^http/i | |
? $l | |
: "$pfx<script>\n". | |
"$pfx\t".join("\n$pfx\t",js_minify($src))."\n". | |
"$pfx</script>\n"; | |
} elsif( $l =~ /^(\s*)<link[^\>]+href=[\'\"]([^\'\"]+\.css)[\'\"]/i ) { | |
my $pfx = $1; | |
my $src = $2; | |
$mini .= $src =~ /^http/i | |
? $l | |
: "$pfx<style>\n". | |
"$pfx\t".join("\n$pfx\t",css_minify($src))."\n". | |
"$pfx</style>\n"; | |
} elsif( $l =~ /=['"]([^'"]+\.(jpg|png|gif))[\'\"]/i ) { | |
my $file = $1; | |
if( -s $file < 32768 ){ | |
my $data = imagedata $file; | |
$l =~ s/$file/$data/; | |
} | |
$mini .= $l; | |
} else { | |
$mini .= $l; | |
} | |
} | |
my $zip = length $mini; | |
print $mini; | |
warn "done from $read to $zip (",int(100*($read-$zip)/$read),"%)\n"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment